home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / layout / layblock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  83.0 KB  |  2,833 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 "pa_parse.h"
  22. #include "pa_tags.h"
  23. #include "layout.h"
  24. #include "laylayer.h"
  25. #include "laystyle.h"
  26. #include "libmocha.h"
  27. #include "libevent.h"
  28. #include "layers.h"
  29. #include "intl_csi.h"
  30.  
  31. extern Bool lo_IsEmptyTag(TagType type);
  32.  
  33. /* This struct is used during the processing of a <LAYER> or <ILAYER>
  34.  * tag, but discarded after the tag is closed. It is used to store the
  35.  * current document state while process the tag and channel everything
  36.  * into the layer.
  37.  */
  38. struct lo_Block {
  39.     MWContext *context;
  40.  
  41.     /* Saved document state, restored after block is layed out */
  42.     lo_DocState *saved_state;
  43.  
  44.     int32 start_x, start_y;     /* Initial upper-left corner of block,
  45.                                    in parent layer coord system */
  46.     char *old_base_url;
  47.     uint8 old_body_attr;
  48.  
  49.     char * name;        /* Identifier for this layer */
  50.     char * above;        /* Name of layer above this layer or NULL */
  51.     char * below;        /* Name of layer below this layer or NULL */
  52.     int32 z_order;        /* Z-order if above/below unspecified */
  53.  
  54.     int32 x_offset, y_offset;   /* Layer coordinate translation
  55.                                    (for in-flow layers) */
  56.     PRPackedBool is_inflow; /* Is this an out-of-flow or in-flow layer ? */
  57.     PRPackedBool is_inline; /* Is this inline or SRCed */
  58.     PRPackedBool is_dynamic; /* Has the SRC been dynamically changed?  */
  59.     PRPackedBool uses_ss_positioning; /* Created using style-sheet 'position'
  60.                                          property instead of tag ? */
  61.     int clip_expansion_policy;  /* Expand clip to contain layer content ? */
  62.  
  63.     CL_Layer *layer;
  64.     LO_CellStruct *cell;
  65.  
  66.     lo_LayerDocState *old_layer_state;  /* Used during table relayout */
  67.     char *match_code;           /* Value of layer tag's MATCH parameter */
  68.     char *source_url;
  69. };
  70.  
  71. static int lo_AppendLayerElement(MWContext *context, lo_DocState *state, int32 is_end);
  72.  
  73. #ifdef XP_MAC
  74. PRIVATE
  75. #endif
  76. lo_LayerDocState *
  77. lo_GetLayerStateFromId(MWContext *context, int32 layer_id)
  78. {
  79.     int32 doc_id;
  80.     lo_TopState *top_state;
  81.     lo_LayerDocState *layer_state;
  82.  
  83.     doc_id = XP_DOCID(context);
  84.     top_state = lo_FetchTopState(doc_id);
  85.     XP_ASSERT(top_state);
  86.     if (!top_state)
  87.         return NULL;
  88.  
  89.     XP_ASSERT(layer_id <= top_state->max_layer_num);
  90.     if (layer_id > top_state->max_layer_num)
  91.         return NULL;
  92.     layer_state = top_state->layers[layer_id];
  93. /*    XP_ASSERT(layer_state); */
  94.     return layer_state;
  95. }
  96.  
  97. void *
  98. LO_GetLayerMochaObjectFromId(MWContext *context, int32 layer_id)
  99. {
  100.     lo_LayerDocState *layer_state = lo_GetLayerStateFromId(context, layer_id);
  101.     if (!layer_state)
  102.         return NULL;
  103.     return layer_state->mocha_object;
  104. }
  105.  
  106. void *
  107. LO_GetLayerMochaObjectFromLayer(MWContext *context, CL_Layer *layer)
  108. {
  109.     lo_LayerDocState *layer_state = lo_GetLayerState(layer);
  110.     if (!layer_state)
  111.         return NULL;
  112.     return layer_state->mocha_object;
  113. }
  114.  
  115. void
  116. LO_SetLayerMochaObject(MWContext *context, int32 layer_id, void *mocha_object)
  117. {
  118.     lo_LayerDocState *layer_state = lo_GetLayerStateFromId(context, layer_id);
  119.     if (!layer_state)
  120.         return;
  121.     layer_state->mocha_object = mocha_object;
  122. }
  123.  
  124. CL_Layer *
  125. LO_GetLayerFromId(MWContext *context, int32 layer_id)
  126. {
  127.     lo_LayerDocState *layer_state = lo_GetLayerStateFromId(context, layer_id);
  128.     if (!layer_state)
  129.         return NULL;
  130.     return layer_state->layer;
  131. }
  132.  
  133. int32
  134. LO_GetIdFromLayer(MWContext *context, CL_Layer *layer)
  135. {
  136.     lo_LayerDocState *layer_state = lo_GetLayerState(layer);
  137.     XP_ASSERT(layer_state);
  138.     if (!layer_state)
  139.         return 0;
  140.     return layer_state->id;
  141. }
  142.  
  143. int32
  144. LO_GetNumberOfLayers(MWContext *context)
  145. {
  146.     int32 doc_id;
  147.     lo_TopState *top_state;
  148.  
  149.     doc_id = XP_DOCID(context);
  150.     top_state = lo_FetchTopState(doc_id);
  151.     if (!top_state)
  152.         return 0;
  153.  
  154.     return (top_state->max_layer_num);
  155. }
  156.  
  157. PRBool
  158. lo_IsCurrentLayerDynamic(lo_DocState *state)
  159. {
  160.     lo_LayerDocState *layer_state = lo_CurrentLayerState(state);
  161.     lo_Block *block = layer_state->temp_block;
  162.  
  163.     if (layer_state->id == LO_DOCUMENT_LAYER_ID)
  164.         return PR_FALSE;
  165.  
  166.     XP_ASSERT(block);
  167.     if (!block)
  168.         return PR_FALSE;
  169.  
  170.     return (PRBool)block->is_dynamic;
  171. }
  172.  
  173. PRBool
  174. lo_IsAnyCurrentAncestorSourced(lo_DocState *state)
  175. {
  176.     lo_LayerStack *lptr;
  177.     lo_TopState *top_state = state->top_state;
  178.  
  179.     if (top_state->layer_stack == NULL)
  180.         return PR_FALSE;
  181.  
  182.     lptr = top_state->layer_stack;
  183.     while (lptr && lptr->layer_state &&
  184.            (lptr->layer_state->id != LO_DOCUMENT_LAYER_ID)) {
  185.         lo_Block *block = lptr->layer_state->temp_block;
  186.         if (block && !block->is_inline)
  187.             return PR_TRUE;
  188.  
  189.         lptr = lptr->next;
  190.     }
  191.  
  192.     return PR_FALSE;
  193. }
  194.  
  195. PRBool
  196. lo_IsTagInSourcedLayer(lo_DocState *state, PA_Tag *tag)
  197. {
  198.     PRBool ancestor_sourced = PR_FALSE;
  199.     PRBool current_layer_sourced = PR_FALSE;
  200.     lo_LayerStack *lptr;
  201.     lo_TopState *top_state = state->top_state;
  202.  
  203.     if (top_state->layer_stack == NULL)
  204.         return PR_FALSE;
  205.  
  206.     lptr = top_state->layer_stack;
  207.     while (lptr && lptr->layer_state &&
  208.            (lptr->layer_state->id != LO_DOCUMENT_LAYER_ID)) {
  209.         lo_Block *block = lptr->layer_state->temp_block;
  210.         if (block && !block->is_inline) {
  211.             if (top_state->layer_stack == lptr)
  212.                 current_layer_sourced = PR_TRUE;
  213.             else {
  214.                 ancestor_sourced = PR_TRUE;
  215.                 break;
  216.             }
  217.         }
  218.         lptr = lptr->next;
  219.     }
  220.  
  221.     /*
  222.      * If we're not dealing with a </LAYER> or </ILAYER> tag,
  223.      * then we just return whether any current layer ancestor
  224.      * has a SRC attribute.
  225.      */
  226.     if (((tag->type != P_LAYER) && (tag->type != P_ILAYER)) ||
  227.         (tag->is_end == FALSE) ||
  228.         (top_state->ignore_layer_nest_level != 0))
  229.         return (PRBool)(ancestor_sourced || current_layer_sourced);
  230.     /*
  231.      * Otherwise, it may be possible that the current close tag
  232.      * actually closes out the sourced layer and isn't actually
  233.      * part of the content of the sourced layer.
  234.      */
  235.     else
  236.         return ancestor_sourced;
  237. }
  238.  
  239.  
  240. /*
  241.  * Are there any dynamic layers on the current layer_stack?
  242.  */
  243. PRBool
  244. lo_IsAnyCurrentAncestorDynamic(lo_DocState *state)
  245. {
  246.     lo_LayerStack *lptr;
  247.     lo_TopState *top_state = state->top_state;
  248.  
  249.     if (top_state->layer_stack == NULL)
  250.         return PR_FALSE;
  251.  
  252.     lptr = top_state->layer_stack;
  253.     while (lptr && lptr->layer_state &&
  254.            (lptr->layer_state->id != LO_DOCUMENT_LAYER_ID)) {
  255.         lo_Block *block = lptr->layer_state->temp_block;
  256.         if (block && block->is_dynamic)
  257.             return PR_TRUE;
  258.  
  259.         lptr = lptr->next;
  260.     }
  261.  
  262.     return PR_FALSE;
  263. }
  264.  
  265. static void
  266. lo_init_block_cell(MWContext *context, lo_DocState *state, lo_Block *block)
  267. {
  268.     LO_CellStruct *cell;
  269.  
  270.     if ((block == NULL)||(block->cell == NULL))
  271.     {
  272.         return;
  273.     }
  274.  
  275.     cell = block->cell;
  276.  
  277.     cell->type = LO_CELL;
  278.     cell->ele_id = NEXT_ELEMENT;
  279.     cell->x = state->x;
  280.     cell->x_offset = 0;
  281.     cell->y = state->y;
  282.     cell->y_offset = 0;
  283.     cell->width = 0;
  284.     cell->height = 0;
  285.     cell->line_height = state->line_height;
  286.     cell->next = NULL;
  287.     cell->prev = NULL;
  288.     cell->FE_Data = NULL;
  289.     cell->cell_float_list = NULL;
  290.     cell->backdrop.bg_color = NULL;
  291.     cell->backdrop.url = NULL;
  292.     cell->border_width = 0;
  293.     cell->border_vert_space = 0;
  294.     cell->border_horiz_space = 0;
  295.     cell->ele_attrmask = 0;
  296.     cell->sel_start = -1;
  297.     cell->sel_end = -1;
  298.     cell->cell_list = NULL;
  299.     cell->cell_list_end = NULL;
  300.     cell->cell_float_list = NULL;
  301.     cell->cell_inflow_layer = NULL;
  302.     cell->cell_bg_layer = NULL;
  303.     cell->table_cell = NULL;
  304.     cell->table_row = NULL;
  305.     cell->table = NULL;
  306. }
  307.  
  308. lo_LayerDocState *
  309. lo_NewLayerState(MWContext *context)
  310. {
  311.     lo_LayerDocState *layer_state;
  312.     XP_Rect everything = CL_MAX_RECT;
  313.  
  314.     layer_state = XP_NEW_ZAP(lo_LayerDocState);
  315.     if (layer_state == NULL)
  316.         return NULL;
  317.  
  318.     layer_state->id = 0;  /* This will be filled in later */
  319.     layer_state->cell = NULL;
  320.     layer_state->viewRect = everything;
  321.     layer_state->doc_lists = XP_NEW_ZAP(lo_DocLists);
  322.     if (!layer_state->doc_lists) {
  323.         XP_FREE(layer_state);
  324.         return NULL;
  325.     }
  326.     if (!lo_InitDocLists(context, layer_state->doc_lists)) {
  327.         XP_FREE(layer_state->doc_lists);
  328.         XP_FREE(layer_state);
  329.         return NULL;
  330.     }
  331.  
  332.     return layer_state;
  333. }
  334.  
  335. #ifdef XP_MAC
  336. PRIVATE
  337. #endif
  338. void
  339. lo_DeleteBlock(lo_Block* block)
  340. {
  341.     XP_FREEIF(block->name);
  342.     XP_FREEIF(block->above);
  343.     XP_FREEIF(block->below);
  344.     XP_FREEIF(block->saved_state);
  345.     XP_FREEIF(block->match_code);
  346.     XP_FREEIF(block->source_url);
  347.     XP_FREE(block);
  348. }
  349.  
  350. void
  351. lo_DeleteLayerState(MWContext *context, lo_DocState *state,
  352.                     lo_LayerDocState *layer_state)
  353. {
  354.     /* Get rid of the layer_state's contents */
  355.     if (layer_state->cell)
  356.         lo_RecycleElements(context, state, (LO_Element *)layer_state->cell);
  357.  
  358.     /* Get rid of the layer_state's layer */
  359.     if (layer_state->layer) {
  360.         CL_Layer *parent_layer = CL_GetLayerParent(layer_state->layer);
  361.         if (parent_layer)
  362.             CL_RemoveChild(parent_layer, layer_state->layer);
  363.         LO_LockLayout();
  364.         CL_DestroyLayerTree(layer_state->layer);
  365.         LO_UnlockLayout();
  366.     }
  367.  
  368.     lo_DeleteDocLists(context, layer_state->doc_lists);
  369.     if (layer_state->id != LO_DOCUMENT_LAYER_ID)
  370.         XP_FREE(layer_state->doc_lists);
  371.     if (layer_state->temp_block)
  372.         lo_DeleteBlock(layer_state->temp_block);
  373.     XP_FREE(layer_state);
  374. }
  375.  
  376. /* Number of entries to grow layers array when it is too small */
  377. #define LAYER_ARRAY_GROW_SIZE  50
  378.  
  379. /*
  380.  * Adds the layer_state to the layer list. If one with the same
  381.  * id already exists (because of table relayout), we replace
  382.  * it with the new one. The old layer_state is returned, so that
  383.  * it may be discarded when the new layer is done loading.
  384.  */
  385. lo_LayerDocState *
  386. lo_append_to_layer_array(MWContext *context, lo_TopState *top_state,
  387.                          lo_DocState *state,
  388.                          lo_LayerDocState *layer_state)
  389. {
  390.     int32 id;
  391.  
  392.     XP_ASSERT(top_state);
  393.     if (!top_state)
  394.         return NULL;
  395.  
  396.     id = ++top_state->current_layer_num;
  397.     layer_state->id = id;
  398.  
  399.     if (state)
  400.         state->current_layer_num_max = id;
  401.  
  402.     /*
  403.      * If we're doing table relayout, we find the corresponding layer in
  404.      * the layer list from a previous pass and replace it with the current
  405.      * layer.
  406.      */
  407.     if (state && state->in_relayout) {
  408.         lo_LayerDocState **old_layer_statep = &top_state->layers[id];
  409.         lo_LayerDocState *old_layer_state = *old_layer_statep;
  410.  
  411.         XP_ASSERT(old_layer_state);
  412.         XP_ASSERT(old_layer_state->id == id);
  413.  
  414.         /*
  415.          * Copy over the mocha object, since the reflection might
  416.          * already have happened.
  417.          */
  418.         layer_state->mocha_object = old_layer_state->mocha_object;
  419.  
  420.         /* Out with the old and in with the new */
  421.         *old_layer_statep = layer_state;
  422.         return old_layer_state;
  423.     }
  424.  
  425.     /* Extend the layers array if it's full */
  426.     if (id >= top_state->num_layers_allocated) {
  427.         int32 new_count = top_state->num_layers_allocated + LAYER_ARRAY_GROW_SIZE;
  428.         int32 nsize = new_count * sizeof(lo_LayerDocState*);
  429.         lo_LayerDocState **new_layers;
  430.  
  431.         if (top_state->num_layers_allocated == 0)
  432.             new_layers = (lo_LayerDocState**)XP_ALLOC(nsize);
  433.         else
  434.             new_layers = (lo_LayerDocState**)XP_REALLOC(top_state->layers, nsize);
  435.  
  436.         XP_ASSERT(new_layers);
  437.         if (!new_layers)
  438.             return NULL;
  439.         top_state->layers = new_layers;
  440.         top_state->num_layers_allocated = new_count;
  441.     }
  442.  
  443.     top_state->layers[id] = layer_state;
  444.  
  445.     if (id > top_state->max_layer_num)
  446.         top_state->max_layer_num = id;
  447.     return NULL;
  448. }
  449.  
  450. static void
  451. lo_block_src_exit_fn(URL_Struct *url_struct, int status, MWContext *context)
  452. {
  453.     int32 doc_id;
  454.     lo_TopState *top_state;
  455.     lo_DocState *state;
  456.  
  457.     /* XXX need state to be subdoc state? */
  458.     doc_id = XP_DOCID(context);
  459.     top_state = lo_FetchTopState(doc_id);
  460.     if ((top_state == NULL) ||
  461.         ((state = top_state->doc_state) == NULL)) {
  462.         return;
  463.     }
  464.  
  465.     /* Flush tags blocked by this <LAYER SRC="URL"> tag. We treat
  466.        the special case of an interrupted stream as normal completion,
  467.        as this is the resulting error code when we do
  468.        <LAYER SRC=some.gif> and some.gif is in the image cache. */
  469.     if (status >= 0 || status == MK_INTERRUPTED) {
  470.         top_state->layout_blocking_element = NULL;
  471.         lo_FlushBlockage(context, state, state);
  472.     }
  473.     /* XXX What's the right thing to do when we fail???
  474.      * Presumably we don't want to flush the blockage and
  475.      * continue as if nothing happened. But in some cases,
  476.      * we do want to recover in some way.
  477.      */
  478.     NET_FreeURLStruct(url_struct);
  479. }
  480.  
  481. static void
  482. lo_free_stream(MWContext *context, NET_StreamClass *stream)
  483. {
  484.     XP_DELETE(stream);
  485. }
  486.  
  487. int32
  488. lo_GetEnclosingLayerWidth(lo_DocState *state)
  489. {
  490.     lo_LayerDocState *layer_state = lo_CurrentLayerState(state);
  491.  
  492.     /* Special case 100% value for top-level document so that
  493.        it doesn't include window margins. */
  494.     if (layer_state->id == LO_DOCUMENT_LAYER_ID)
  495.         return state->win_left + state->win_width + state->win_right;
  496.  
  497.     return state->right_margin - state->left_margin;
  498. }
  499.  
  500. /* Convert a string containing a horizontal dimension into layout coordinates,
  501.    handling percentages if necessary. */
  502. static int32
  503. lo_parse_horizontal_param(char *value, lo_DocState *state, MWContext *context)
  504. {
  505.     int32 parent_width = lo_GetEnclosingLayerWidth(state);
  506.     XP_Bool is_percent;
  507.     int32 ival;
  508.  
  509.     ival = lo_ValueOrPercent(value, &is_percent);
  510.     if (is_percent)
  511.     {
  512.         if (state->allow_percent_width == FALSE)
  513.         {
  514.             ival = 0;
  515.         }
  516.         else
  517.         {
  518.             ival = (parent_width * ival) / 100;
  519.         }
  520.     }
  521.     else
  522.     {
  523.         ival = FEUNITS_X(ival, context);
  524.     }
  525.     return ival;
  526. }
  527.  
  528. int32
  529. lo_GetEnclosingLayerHeight(lo_DocState *state)
  530. {
  531.     lo_LayerDocState *layer_state = lo_CurrentLayerState(state);
  532.     return layer_state->height;
  533. }
  534.  
  535. /* Convert a string containing a vertical dimension into layout coordinates,
  536.    handling percentages if necessary. */
  537. static int32
  538. lo_parse_vertical_param(char *value, lo_DocState *state, MWContext *context)
  539. {
  540.     XP_Bool is_percent;
  541.     int32 ival;
  542.     int32 parent_height = lo_GetEnclosingLayerHeight(state);
  543.  
  544.     ival = lo_ValueOrPercent(value, &is_percent);
  545.     if (is_percent)
  546.         ival = (parent_height * ival) / 100;
  547.     else
  548.         ival = FEUNITS_Y(ival, context);
  549.     return ival;
  550. }
  551.  
  552. #ifdef XP_MAC
  553. PRIVATE
  554. #endif
  555. int
  556. lo_parse_clip(char *str, XP_Rect *clip,
  557.               lo_DocState *state, MWContext *context)
  558. {
  559.     int32 coord, coords[4];
  560.     int coord_count;
  561.     int clip_expansion_policy = LO_AUTO_EXPAND_NONE;
  562.     for (coord_count = 0; coord_count <= 3; coord_count++) {
  563.  
  564.         /* Skip leading whitespace and commas */
  565.         while (XP_IS_SPACE(*str) || (*str == ','))
  566.             str++;
  567.  
  568.         if (!*str)
  569.             break;
  570.  
  571.         /* Parse distinguished "auto" value */
  572.         if (!XP_STRNCASECMP(str, "auto", 4)) {
  573.             str += 4;
  574.             clip_expansion_policy |= 1;
  575.             coords[coord_count] = 0;
  576.         } else {
  577.             if (coord_count & 1)
  578.                 coord = lo_parse_vertical_param(str, state, context);
  579.             else
  580.                 coord = lo_parse_horizontal_param(str, state, context);
  581.             coords[coord_count] = coord;
  582.  
  583.             /* Skip over the number and percentage sign */
  584.             while (*str && !XP_IS_SPACE(*str) && !(*str == ','))
  585.                 str++;
  586.         }
  587.         clip_expansion_policy <<= 1;
  588.     }
  589.     clip_expansion_policy >>= 1;
  590.  
  591.     if (coord_count == 2) {
  592.         clip->right  = coords[0];
  593.         clip->bottom = coords[1];
  594.         return clip_expansion_policy;
  595.     } else if (coord_count >= 4) {
  596.         clip->left   = coords[0];
  597.         clip->top    = coords[1];
  598.         clip->right  = coords[2];
  599.         clip->bottom = coords[3];
  600.         return clip_expansion_policy;
  601.     }
  602.  
  603.     /* Error - don't clip at all */
  604.     return LO_AUTO_EXPAND_CLIP;
  605. }
  606.  
  607. extern XP_Bool
  608. lo_BeginLayer(MWContext *context,
  609.               lo_DocState *state,
  610.               LO_BlockInitializeStruct *param,
  611.               XP_Bool is_inflow);
  612.  
  613. #ifdef XP_MAC
  614. PRIVATE
  615. #endif
  616. void
  617. lo_FreeBlockInitializeStruct(LO_BlockInitializeStruct *param)
  618. {
  619.     if(param)
  620.     {
  621.         XP_FREEIF(param->clip);
  622.         XP_FREEIF(param->overflow);
  623.         XP_FREEIF(param->name);
  624.         XP_FREEIF(param->id);
  625.         XP_FREEIF(param->above);
  626.         XP_FREEIF(param->below);
  627.         XP_FREEIF(param->visibility);
  628.         XP_FREEIF(param->bgcolor);
  629.         XP_FREEIF(param->bgimage);
  630.         XP_FREEIF(param->src);
  631.  
  632.         XP_FREE(param);
  633.     }
  634. }
  635.  
  636. /* Start a <LAYER> or an <ILAYER>. */
  637. void
  638. lo_BeginLayerTag(MWContext *context, lo_DocState *state, PA_Tag *tag)
  639. {
  640.     INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
  641.     int16 win_csid = INTL_GetCSIWinCSID(c);
  642.     LO_BlockInitializeStruct *param;
  643.     char *val;
  644.     lo_LayerDocState *layer_state;
  645.     CL_Layer *parent_layer;
  646.  
  647.  
  648.     if (!context->compositor)
  649.         return;
  650.  
  651.     layer_state = lo_CurrentLayerState(state);
  652.     parent_layer = layer_state->layer;
  653.  
  654.     param = XP_NEW_ZAP(LO_BlockInitializeStruct);
  655.  
  656.     if(!param)
  657.     {
  658.         state->top_state->out_of_memory = TRUE;
  659.         return;
  660.     }
  661.  
  662.     /*
  663.      * Get the horizontal position of the block
  664.      */
  665.     val = (char*) lo_FetchParamValue(context, tag, PARAM_LEFT);
  666.     if(val)
  667.     {
  668.         param->has_left = TRUE;
  669.         param->left = lo_parse_horizontal_param(val, state, context);
  670.         XP_FREE(val);
  671.     } else {
  672.         /* No LEFT attribute.  Is there an X attribute ? */
  673.         val = (char*) lo_FetchParamValue(context, tag, PARAM_PAGEX);
  674.         if(val)
  675.         {
  676.             param->has_left = TRUE;
  677.             param->left = (int32)XP_ATOI(val);
  678.  
  679.             /* Convert from absolute coordinates to layer-relative coordinates */
  680.             param->left -= CL_GetLayerXOrigin(parent_layer);
  681.             XP_FREE(val);
  682.         }
  683.     }
  684.  
  685.     /*
  686.      * Get the vertical position of the block
  687.      */
  688.     val = (char*)lo_FetchParamValue(context, tag, PARAM_TOP);
  689.     if (val)
  690.     {
  691.         param->has_top = TRUE;
  692.         param->top = lo_parse_vertical_param(val, state, context);
  693.         XP_FREE(val);
  694.     } else {
  695.         /* No TOP attribute.  Is there a Y attribute ? */
  696.         val = (char*) lo_FetchParamValue(context, tag, PARAM_PAGEY);
  697.         if(val)
  698.         {
  699.             param->has_top = TRUE;
  700.             param->top = (int32)XP_ATOI(val);
  701.  
  702.             /* Convert from absolute coordinates to layer-relative coordinates */
  703.             param->top -= CL_GetLayerYOrigin(parent_layer);
  704.             XP_FREE(val);
  705.         }
  706.     }
  707.  
  708.     /*
  709.      * Parse the comma separated coordinate list into an
  710.      * array of integers.
  711.      */
  712.     val = (char*)lo_FetchParamValue(context, tag, PARAM_CLIP);
  713.     if(val)
  714.     {
  715.         param->clip = XP_NEW_ZAP(XP_Rect);
  716.  
  717.         if(param->clip)
  718.         {
  719.             XP_BZERO(param->clip, sizeof(XP_Rect));
  720.             param->clip_expansion_policy =
  721.                 lo_parse_clip(val, param->clip, state, context);
  722.         }
  723.     }
  724.     else
  725.         param->clip_expansion_policy = LO_AUTO_EXPAND_CLIP;
  726.  
  727.     /*
  728.      * Get the width parameter, in absolute or percentage.
  729.      * If percentage, make it absolute.
  730.      */
  731.     val = (char*)lo_FetchParamValue(context, tag, PARAM_WIDTH);
  732.     if(val)
  733.     {
  734.         param->has_width = TRUE;
  735.         param->width = lo_parse_horizontal_param(val, state, context);
  736.         XP_FREE(val);
  737.     }
  738.  
  739.     /*
  740.      * Get the height parameter, in absolute or percentage.
  741.      * If percentage, make it absolute.
  742.      */
  743.     val = (char*)lo_FetchParamValue(context, tag, PARAM_HEIGHT);
  744.     if(val)
  745.     {
  746.         param->has_height = TRUE;
  747.         param->height = lo_parse_vertical_param(val, state, context);
  748.         XP_FREE(val);
  749.     }
  750.  
  751.     /* Get the OVERFLOW attribute. */
  752.     param->overflow = (char*)lo_FetchParamValue(context, tag, PARAM_OVERFLOW);
  753.  
  754.     /*
  755.      * Get the optional name for this layer.
  756.      */
  757.     param->name = (char*)PA_FetchParamValue(tag, PARAM_NAME, win_csid);
  758.  
  759.     /* Use either NAME or ID, since we will probably be switching to
  760.        the latter */
  761.     param->id = (char*)PA_FetchParamValue(tag, PARAM_ID, win_csid);
  762.  
  763.     /*
  764.      * Get the optional "above" name for the layer we are above.
  765.      */
  766.     param->above = (char*)PA_FetchParamValue(tag, PARAM_ABOVE, win_csid);
  767.  
  768.     /*
  769.      * Get the optional "below" name for the layer we are below.
  770.      */
  771.     param->below = (char*)PA_FetchParamValue(tag, PARAM_BELOW, win_csid);
  772.  
  773.     /*
  774.      * Get the Z-order of the block
  775.      */
  776.     val  = (char*)lo_FetchParamValue(context, tag, PARAM_ZINDEX);
  777.     if (val) {
  778.         param->zindex = XP_ATOI(val);
  779.         param->has_zindex = TRUE;
  780.         XP_FREE(val);
  781.     }
  782.     else
  783.         param->has_zindex = FALSE;
  784.  
  785.     /* Get the VISIBILITY parameter to know if this layer starts hidden. */
  786.     param->visibility = (char*)PA_FetchParamValue(tag, PARAM_VISIBILITY, win_csid);
  787.  
  788.     /* Process background color (BGCOLOR) attribute, if present. */
  789.     param->bgcolor = (char*)PA_FetchParamValue(tag, PARAM_BGCOLOR, win_csid);
  790.  
  791.     /* Process backdrop (BACKGROUND) image attribute, if present. */
  792.     param->bgimage = lo_ParseBackgroundAttribute(context,
  793.                                                      state,
  794.                                                      tag, FALSE);
  795.  
  796.     param->src = (char*)PA_FetchParamValue(tag, PARAM_SRC, win_csid);
  797.  
  798.     param->tag = tag;
  799.     param->ss_tag = NULL;
  800.  
  801.     if (lo_BeginLayer(context, state, param, tag->type == P_ILAYER))
  802.         lo_FreeBlockInitializeStruct(param);
  803. }
  804.  
  805. static int lo_AppendLayerElement(MWContext *context, lo_DocState *state, int32 is_end)
  806. {
  807.     LO_LayerStruct *layer;
  808.     layer = (LO_LayerStruct*)lo_NewElement(context, state, LO_LAYER, NULL, 0);
  809.  
  810.     XP_ASSERT(layer);
  811.     if (!layer) 
  812.         return FALSE;
  813.  
  814.     layer->lo_any.type = LO_LAYER;
  815.     layer->lo_any.x = state->x;
  816.     layer->lo_any.y = state->y;
  817.     layer->lo_any.x_offset = 0;
  818.     layer->lo_any.y_offset = 0;
  819.     layer->lo_any.width = 0;
  820.     layer->lo_any.height = 0;
  821.     layer->lo_any.line_height = 0;
  822.     layer->lo_any.ele_id = NEXT_ELEMENT;
  823.  
  824.     layer->is_end = is_end;
  825.     layer->initParams = NULL;    /* Not keeping params for now.  Just trying to fix ILAYER crash. */
  826.     
  827.     lo_AppendToLineList(context, state, (LO_Element*)layer, 0);
  828.  
  829.     return TRUE;
  830. }
  831.  
  832. /* parse a comma separated list of 2 or 4 values
  833.  *
  834.  * Format is "rect(top, right, bottom, left)"
  835.  * or "rect(right, bottom)"
  836.  * or degenerate case of "top,right,bottom,left" with no rect()
  837.  */
  838. #ifdef XP_MAC
  839. PRIVATE
  840. #endif
  841. XP_Rect *
  842. lo_ParseStyleCoords(MWContext *context,
  843.                     lo_DocState *state,
  844.                     StyleStruct *style_struct,
  845.                     char *coord_string)
  846. {
  847.  
  848.     XP_Rect *coords = XP_NEW_ZAP(XP_Rect);
  849.     int32 val[4];
  850.     int index=0;
  851.     char *value;
  852.     SS_Number *ss_num;
  853.  
  854.     if(!coords)
  855.         return(NULL);
  856.  
  857.     coord_string = XP_StripLine(coord_string);
  858.  
  859.     /* go past "rect(" and kill ")" character */
  860. #define _RECT "rect"
  861.     if(!strncasecomp(coord_string, _RECT, sizeof(_RECT)-1)) {
  862.         char *t;
  863.  
  864.         /* go past "rect" */
  865.         coord_string += sizeof(_RECT)-1;
  866.  
  867.         /* go past spaces */
  868.         while(XP_IS_SPACE(*coord_string)) coord_string++;
  869.  
  870.         /* go past '(' */
  871.         if(*coord_string == '(')
  872.             coord_string++;
  873.  
  874.         /* kill any more spaces */
  875.         while(XP_IS_SPACE(*coord_string)) coord_string++;
  876.  
  877.         /* Kill the ending ')' */
  878.         t = XP_STRCHR(coord_string, ')');
  879.         if (t)
  880.             *t = '\0';
  881.     }
  882.  
  883.     value = XP_STRTOK(coord_string, ", ");
  884.  
  885.     while(value && index < 4)
  886.     {
  887.         ss_num = STYLESTRUCT_StringToSSNumber(style_struct, value);
  888.  
  889.         /* First and third args are heights.  Note that we use
  890.            LAYER_WIDTH_STYLE instead of WIDTH_STYLE, since the two are
  891.            subtly different. (For the top-level DOCUMENT layer, 100%
  892.            WIDTH is the distance between the margins and 100%
  893.            LAYER_WIDTH is the width of the window.) */
  894.         if(index & 1)
  895.             LO_AdjustSSUnits(ss_num, LAYER_WIDTH_STYLE, context, state);
  896.         else
  897.             LO_AdjustSSUnits(ss_num, HEIGHT_STYLE, context, state);
  898.  
  899.         val[index++] = (int32)ss_num->value;
  900.  
  901.         value = XP_STRTOK(NULL, ",) ");
  902.     }
  903.  
  904.     if (index == 2)
  905.     {
  906.         coords->right  = FEUNITS_X(val[0], context);
  907.         coords->bottom = FEUNITS_Y(val[1], context);
  908.     }
  909.     else if (index == 4)
  910.     {
  911.         coords->top    = FEUNITS_Y(val[0], context);
  912.         coords->right  = FEUNITS_X(val[1], context);
  913.         coords->bottom = FEUNITS_Y(val[2], context);
  914.         coords->left   = FEUNITS_X(val[3], context);
  915.     }
  916.     else
  917.     {
  918.         XP_FREE(coords);
  919.         return NULL;
  920.     }
  921.  
  922.     return coords;
  923. }
  924.  
  925. void
  926. lo_SetStyleSheetLayerProperties(MWContext *context,
  927.                                 lo_DocState *state,
  928.                                 StyleStruct *style_struct,
  929.                                 PA_Tag *tag)
  930. {
  931.     LO_BlockInitializeStruct *param;
  932.     char *prop;
  933.     char *src_prop;
  934.     XP_Bool is_inflow;
  935.     SS_Number *ss_num;
  936.  
  937.     if(!style_struct)
  938.         return;
  939.  
  940.     prop = STYLESTRUCT_GetString(style_struct, POSITION_STYLE);
  941.     src_prop = STYLESTRUCT_GetString(style_struct, LAYER_SRC_STYLE);
  942.  
  943.     if(!prop && !src_prop)
  944.         return;
  945.  
  946.     if(lo_IsEmptyTag(tag->type))
  947.     {
  948.         /* setting positioning on an empty tag will
  949.          * cause things to not work because of blocked image
  950.          * problems, so don't allow it.
  951.          */
  952.         return;
  953.     }
  954.  
  955.     if(prop && !strcasecomp(prop, ABSOLUTE_STYLE))
  956.     {
  957.         is_inflow = FALSE;
  958.     }
  959.     else if(prop && !strcasecomp(prop, RELATIVE_STYLE))
  960.     {
  961.         is_inflow = TRUE;
  962.     }
  963.     else if(src_prop)
  964.     {
  965.         /* not positioned, but an include src attribute */
  966.         is_inflow = TRUE;
  967.     }
  968.     else
  969.     {
  970.         XP_FREEIF(prop);
  971.         return;  /* don't do layers */
  972.     }
  973.  
  974.     XP_FREEIF(prop);
  975.  
  976.     param = XP_NEW_ZAP(LO_BlockInitializeStruct);
  977.  
  978.     if(!param)
  979.         return;
  980.  
  981.     param->name = (char*)lo_FetchParamValue(context, tag, PARAM_NAME);
  982.     param->id = (char*)lo_FetchParamValue(context, tag, PARAM_ID);
  983.  
  984.     ss_num = STYLESTRUCT_GetNumber(style_struct, LEFT_STYLE);
  985.     if(ss_num)
  986.     {
  987.         LO_AdjustSSUnits(ss_num, LEFT_STYLE, context, state);
  988.         param->left = FEUNITS_X((int32)ss_num->value, context);
  989.         param->has_left = TRUE;
  990.         STYLESTRUCT_FreeSSNumber(style_struct, ss_num);
  991.     }
  992.  
  993.     ss_num = STYLESTRUCT_GetNumber(style_struct, TOP_STYLE);
  994.     if(ss_num)
  995.     {
  996.         LO_AdjustSSUnits(ss_num, TOP_STYLE, context, state);
  997.         param->top = FEUNITS_Y((int32)ss_num->value, context);
  998.         param->has_top = TRUE;
  999.         STYLESTRUCT_FreeSSNumber(style_struct, ss_num);
  1000.     }
  1001.  
  1002.     ss_num = STYLESTRUCT_GetNumber(style_struct, HEIGHT_STYLE);
  1003.     if(ss_num)
  1004.     {
  1005.         LO_AdjustSSUnits(ss_num, HEIGHT_STYLE, context, state);
  1006.         param->height = FEUNITS_Y((int32)ss_num->value, context);
  1007.         param->has_height = TRUE;
  1008.         STYLESTRUCT_FreeSSNumber(style_struct, ss_num);
  1009.     }
  1010.  
  1011.     /* don't set width. normal style sheets will handle it */
  1012.  
  1013.     prop = STYLESTRUCT_GetString(style_struct, CLIP_STYLE);
  1014.  
  1015.     if(prop) {
  1016.         param->clip = lo_ParseStyleCoords(context, state, style_struct, prop);
  1017.         param->clip_expansion_policy = LO_AUTO_EXPAND_NONE;
  1018.     }
  1019.  
  1020.     param->above = NULL;
  1021.     param->below = NULL;
  1022.     ss_num = STYLESTRUCT_GetNumber(style_struct, ZINDEX_STYLE);
  1023.     if (ss_num) {
  1024.         param->zindex = (int32)ss_num->value;
  1025.         param->has_zindex = TRUE;
  1026.         STYLESTRUCT_FreeSSNumber(style_struct, ss_num);
  1027.     }
  1028.     else
  1029.         param->has_zindex = FALSE;
  1030.  
  1031.     param->visibility = STYLESTRUCT_GetString(style_struct, VISIBILITY_STYLE);
  1032.  
  1033.     param->src = src_prop;
  1034.     if(param->src)
  1035.     {
  1036.         char *tmp = param->src;
  1037.  
  1038.         param->src = lo_ParseStyleSheetURL(param->src);
  1039.         param->src = NET_MakeAbsoluteURL(state->top_state->base_url, param->src);
  1040.         XP_FREE(tmp);
  1041.     }
  1042.  
  1043.     param->overflow = STYLESTRUCT_GetString(style_struct, OVERFLOW_STYLE);
  1044.  
  1045.     param->bgcolor = STYLESTRUCT_GetString(style_struct, LAYER_BG_COLOR_STYLE);
  1046.     param->is_style_bgcolor = TRUE;
  1047.     param->bgimage = STYLESTRUCT_GetString(style_struct, LAYER_BG_IMAGE_STYLE);
  1048.     if(param->bgimage)
  1049.     {
  1050.         char *tmp = param->bgimage;
  1051.         if(!strcasecomp(param->bgimage, "none"))
  1052.         {
  1053.             param->bgimage = NULL;
  1054.         }
  1055.         else
  1056.         {
  1057.             param->bgimage = lo_ParseStyleSheetURL(param->bgimage);
  1058.             param->bgimage = NET_MakeAbsoluteURL(state->top_state->base_url, param->bgimage);
  1059.         }
  1060.         XP_FREE(tmp);
  1061.     }
  1062.  
  1063.     STYLESTRUCT_SetString(style_struct, STYLE_NEED_TO_POP_LAYER, "1", 0);
  1064.  
  1065.     param->tag = NULL;
  1066.     param->ss_tag = tag;
  1067.  
  1068.     if (lo_BeginLayer(context, state, param, is_inflow))
  1069.         lo_FreeBlockInitializeStruct(param);
  1070. }
  1071.  
  1072. static void
  1073. lo_expand_parent_bbox(CL_Layer *layer); /* Forward declaration */
  1074.  
  1075.  
  1076. /* Save a copy of the document state, so that we can restore it later. */
  1077. static PRBool
  1078. lo_SaveDocState(lo_Block *block, lo_DocState *state)
  1079. {
  1080.     lo_DocState *saved_state;
  1081.  
  1082.     block->start_x = state->x;
  1083.     block->start_y = state->y;
  1084.  
  1085.     saved_state = XP_NEW(lo_DocState);
  1086.     if (!saved_state)
  1087.         return PR_FALSE;
  1088.  
  1089.     block->saved_state = saved_state;
  1090.     XP_BCOPY(state, saved_state, sizeof *saved_state);
  1091.     if (!block->is_inflow) {
  1092.         state->top_state->in_head = TRUE;
  1093.         state->top_state->in_body = FALSE;
  1094.     }
  1095.     block->old_body_attr = state->top_state->body_attr;
  1096.     state->top_state->body_attr = 0;
  1097.     return PR_TRUE;
  1098. }
  1099.  
  1100. static void
  1101. lo_RestoreDocState(lo_Block *block, lo_DocState *state)
  1102. {
  1103.     lo_DocState *saved = block->saved_state;
  1104.     lo_FontStack *font_stack;
  1105.     PA_Tag *subdoc_tags_end, *subdoc_tags;
  1106.     LO_TextInfo text_info;
  1107.     intn layer_nest_level;
  1108.     int32 layer_num_max;
  1109.  
  1110.     /*
  1111.      * If there was a BODY tag with a TEXT attribute in this layer,
  1112.      * then we pop the font that was pushed to enable layer-specific
  1113.      * text coloring.
  1114.      */
  1115.     if (state->top_state->body_attr & BODY_ATTR_TEXT) {
  1116.         lo_PopFont(state, P_BODY);
  1117.     }
  1118.     state->top_state->body_attr = block->old_body_attr;
  1119.  
  1120.     lo_SetBaseUrl(state->top_state, block->old_base_url, FALSE);
  1121.  
  1122.     if (block->is_inflow) {
  1123.         state->line_num = saved->line_num;
  1124.         state->float_list = saved->float_list;
  1125.         state->line_list = saved->line_list;
  1126.         state->end_last_line = saved->end_last_line;
  1127.  
  1128.         /* Push the cell representing the inflow layer onto the line
  1129.            list, so that it appears like any other (non-layer)
  1130.            element. */
  1131.         if (state->line_list == NULL) {
  1132.             state->line_list = (LO_Element*)block->cell;
  1133.         } else {
  1134.             LO_Element *eptr = state->line_list;
  1135.             while (eptr->lo_any.next != NULL)
  1136.                 eptr = eptr->lo_any.next;
  1137.             eptr->lo_any.next = (LO_Element*)block->cell;
  1138.             block->cell->prev = eptr;
  1139.         }
  1140.  
  1141.         if (state->end_last_line != NULL)
  1142.            state->end_last_line->lo_any.next = NULL;
  1143.         state->linefeed_state = 0;
  1144.         state->text_fg = saved->text_fg;
  1145.         state->text_bg = saved->text_bg;
  1146.         state->anchor_color = saved->anchor_color;
  1147.         state->visited_anchor_color = saved->visited_anchor_color;
  1148.         state->active_anchor_color = saved->active_anchor_color;
  1149.         return;
  1150.     }
  1151.  
  1152.     state->top_state->in_head = FALSE;
  1153.     state->top_state->in_body = TRUE;
  1154.  
  1155.     /* Save a few special state variables that we *don't* restore.
  1156.        See lo_InitDocState(). */
  1157.  
  1158.     /* XXX - Right now, font info is not reset when entering and
  1159.        exiting layers.  Is that right ? */
  1160.     font_stack       = state->font_stack;
  1161.     text_info        = state->text_info;
  1162.     layer_nest_level = state->layer_nest_level;
  1163.     layer_num_max    = state->current_layer_num_max;
  1164.     subdoc_tags_end  = state->subdoc_tags_end;
  1165.     subdoc_tags      = state->subdoc_tags;
  1166.  
  1167.     /* First, free up the pieces of the document state that we're
  1168.        about to overwrite with their restored values. This gets rid of
  1169.        default values or values left on the stack because the document
  1170.        author didn't properly close tags inside the layer. */
  1171.     state->font_stack = NULL;   /* But, don't free the font stack */
  1172.     lo_free_layout_state_data(block->context, state);
  1173.  
  1174.     /* Restore the entire document state ... */
  1175.     XP_BCOPY(saved, state, sizeof *state);
  1176.  
  1177.     /* ...except for these variables which are retained across LAYERs */
  1178.     state->font_stack            = font_stack;
  1179.     state->text_info             = text_info;
  1180.     state->layer_nest_level      = layer_nest_level;
  1181.     state->current_layer_num_max = layer_num_max;
  1182.     state->subdoc_tags_end       = subdoc_tags_end;
  1183.     state->subdoc_tags           = subdoc_tags;
  1184.  
  1185.     if (state->end_last_line != NULL)
  1186.         state->end_last_line->lo_any.next = NULL;
  1187.  
  1188.     XP_FREE(block->saved_state);
  1189.     block->saved_state = NULL;
  1190. }
  1191.  
  1192. static PRBool
  1193. lo_SetupDocStateForLayer(lo_DocState *state,
  1194.                          lo_LayerDocState *layer_state,
  1195.                          int32 width,
  1196.                          int32 height,
  1197.                          PRBool is_inflow)
  1198. {
  1199.     lo_Block *block = layer_state->temp_block;
  1200.     MWContext *context = block->context;
  1201.     lo_DocState *saved_state;
  1202.  
  1203.     block->is_inflow = is_inflow;
  1204.  
  1205.     /* Save old document state so that we can selectively restore
  1206.        parts of it after the layer is closed. */
  1207.     if (!lo_SaveDocState(block, state))
  1208.         return PR_FALSE;
  1209.  
  1210.     state->float_list = NULL;
  1211.     state->line_list = NULL;
  1212.  
  1213.     if (state->top_state->base_url)
  1214.         block->old_base_url = XP_STRDUP(state->top_state->base_url);
  1215.  
  1216.     if (is_inflow)
  1217.         return PR_TRUE;
  1218.  
  1219.     /*
  1220.      * XXX This doesn't seem right. We're saving some of the doc's
  1221.      * layout state and resetting all of it while the block
  1222.      * is laid out. This layout state will be restored once the block
  1223.      * is completed. However, things like the float_list are part of the
  1224.      * incremental layout state as well as a representation of the final
  1225.      * document. So, if we're asked to redraw while the block is being laid
  1226.      * out, we will probably do the wrong thing for floating elements.
  1227.      */
  1228.  
  1229.     /* Unspecified height won't change state's height property. */
  1230.     if (height == 0)
  1231.         height = state->win_height;
  1232.  
  1233.     state = lo_InitDocState(state, context,
  1234.                             width, height,
  1235.                             0, 0, /* margin_width, margin_height */
  1236.                             NULL, /* clone_state */
  1237.                             layer_state->doc_lists, PR_TRUE);
  1238.  
  1239.     if (!state)
  1240.         return PR_FALSE;
  1241.  
  1242.     /* Though most state variables are reset to their virgin state (in
  1243.        lo_InitDocState, above), there are a few state variables
  1244.        related to table layout that are preserved when a layer tag is
  1245.        opened. */
  1246.     saved_state = block->saved_state;
  1247.     state->is_a_subdoc = saved_state->is_a_subdoc;
  1248.     state->in_relayout = saved_state->in_relayout;
  1249.     state->subdoc_tags = saved_state->subdoc_tags;
  1250.     state->subdoc_tags_end = saved_state->subdoc_tags_end;
  1251.  
  1252.     state->text_fg = saved_state->text_fg;
  1253.     state->text_bg = saved_state->text_bg;
  1254.     state->anchor_color = saved_state->anchor_color;
  1255.     state->visited_anchor_color = saved_state->visited_anchor_color;
  1256.     state->active_anchor_color = saved_state->active_anchor_color;
  1257.  
  1258.     return PR_TRUE;
  1259. }
  1260.  
  1261. static char layer_end_tag[] = "</" PT_LAYER ">";
  1262. static char layer_suppress_tag[] = "<" PT_LAYER " suppress>";
  1263. static char display_none_style[] = PARAM_STYLE "='display:none'>";
  1264.  
  1265. #ifdef XP_MAC
  1266. PRIVATE
  1267. #endif
  1268. void
  1269. lo_insert_suppress_tags(MWContext *context, lo_TopState *top_state,
  1270.                         LO_BlockInitializeStruct *param)
  1271. {
  1272.     PA_Tag *end_tag;
  1273.     int32 i;
  1274.  
  1275.     /*
  1276.      * Since we're adding tags to the blocked tags list without going through
  1277.      * lo_BlockTag, we need to see if this is a flushed to block transition
  1278.      * and, if so, add to the doc_data's ref count. We don't want to do this
  1279.      * if we're in the process of flushing blockage - in that case, the count
  1280.      *  has already been incremented.
  1281.      */
  1282.     if (top_state->tags == NULL && top_state->flushing_blockage == FALSE)
  1283.     PA_HoldDocData(top_state->doc_data);
  1284.  
  1285.     /* If we can here through a LAYER or ILAYER tag */
  1286.     if (param->tag) {
  1287.         /*
  1288.          * Shove in a </LAYER><LAYER suppress> sequence into the
  1289.          * tag stream so that all inline content of this layer is
  1290.          * suppressed. The sourced content comes in before the
  1291.          * first end tag, the inline conent comes in after the
  1292.          * <LAYER suppress> tag.
  1293.          */
  1294.         end_tag = pa_CreateMDLTag(top_state->doc_data,
  1295.                                   layer_end_tag,
  1296.                                   sizeof layer_end_tag - 1);
  1297.  
  1298.         if (end_tag) {
  1299.             end_tag->newline_count = LO_IGNORE_TAG_MARKER;
  1300.             end_tag->next = pa_CreateMDLTag(top_state->doc_data,
  1301.                                             layer_suppress_tag,
  1302.                                             sizeof layer_suppress_tag - 1);
  1303.             if (end_tag->next) {
  1304.                 end_tag->next->newline_count = LO_IGNORE_TAG_MARKER;
  1305.                 if (top_state->tags == NULL)
  1306.                     top_state->tags_end = &end_tag->next->next;
  1307.                 else
  1308.                     end_tag->next->next = top_state->tags;
  1309.                 top_state->tags = end_tag;
  1310.  
  1311.                 /*
  1312.                  * If there are any other input_write_levels on the stack
  1313.                  * that correspond to the front of the tag list, move them
  1314.                  * to account for the newly inserted tags.
  1315.                  */
  1316.                 for (i = 0; i < top_state->input_write_level; i++)
  1317.                     if (top_state->input_write_point[i] == &top_state->tags)
  1318.                         top_state->input_write_point[i] = &end_tag->next->next;
  1319.             }
  1320.             else {
  1321.                 top_state->out_of_memory = TRUE;
  1322.                 PA_FreeTag(end_tag);
  1323.             }
  1324.         }
  1325.         else
  1326.             top_state->out_of_memory = TRUE;
  1327.     }
  1328.     /*
  1329.      * If we came here through the include-source style and
  1330.      * the tag is a container tag
  1331.      */
  1332.     else if (param->ss_tag && !lo_IsEmptyTag(param->ss_tag->type)) {
  1333.         /*
  1334.          * Shove in a </Foo><Foo STYLE="display:none"> sequence into
  1335.          * the tag stream. The sourced content comes in before the
  1336.          * first end tag, the inline conent comes in after the
  1337.          * display:none tag and is ignored.
  1338.          */
  1339.         end_tag = (PA_Tag *)XP_NEW_ZAP(PA_Tag);
  1340.  
  1341.         if (end_tag) {
  1342.             end_tag->type = param->ss_tag->type;
  1343.             end_tag->is_end = TRUE;
  1344.             end_tag->newline_count = LO_IGNORE_TAG_MARKER;
  1345.  
  1346.             end_tag->next = PA_CloneMDLTag(param->ss_tag);
  1347.             if (end_tag->next) {
  1348.                 PA_Tag *begin_tag = end_tag->next;
  1349.  
  1350.                 begin_tag->newline_count = LO_IGNORE_TAG_MARKER;
  1351.                 if (begin_tag->data)
  1352.                     PA_FREE(begin_tag->data);
  1353.                 /* Can't do a strdup because it's parser memory */
  1354.                 begin_tag->data_len = XP_STRLEN(display_none_style);
  1355.                 begin_tag->true_len = begin_tag->data_len;
  1356.                 begin_tag->data = PA_ALLOC(begin_tag->data_len + 1);
  1357.                 if (begin_tag->data) {
  1358.                     char *buff;
  1359.  
  1360.                     /* Copy over the new tag data */
  1361.                     PA_LOCK(buff, char *, begin_tag->data);
  1362.                     XP_BCOPY(display_none_style, buff, begin_tag->data_len);
  1363.                     buff[begin_tag->data_len] = '\0';
  1364.                     PA_UNLOCK(buff);
  1365.  
  1366.                     if (top_state->tags == NULL)
  1367.                         top_state->tags_end = &begin_tag->next;
  1368.                     else
  1369.                         begin_tag->next = top_state->tags;
  1370.                     top_state->tags = end_tag;
  1371.                 }
  1372.                 else {
  1373.                     top_state->out_of_memory = TRUE;
  1374.                     PA_FreeTag(begin_tag);
  1375.                     PA_FreeTag(end_tag);
  1376.                 }
  1377.             }
  1378.             else {
  1379.                 top_state->out_of_memory = TRUE;
  1380.                 PA_FreeTag(end_tag);
  1381.             }
  1382.         }
  1383.         else
  1384.             top_state->out_of_memory = TRUE;
  1385.     }
  1386. }
  1387.  
  1388.  
  1389. /* Start a <LAYER> or an <ILAYER>. */
  1390. #ifdef XP_MAC
  1391. PRIVATE
  1392. #endif
  1393. void
  1394. lo_begin_layer_internal(MWContext *context,
  1395.                         lo_DocState *state,
  1396.                         LO_BlockInitializeStruct *param,
  1397.                         XP_Bool is_inflow)
  1398. {
  1399.     INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
  1400.     int16 win_csid = INTL_GetCSIWinCSID(c);
  1401.     lo_Block *block;
  1402.     lo_LayerDocState *layer_state, *parent_layer_state;
  1403.     char *str, *layer_name;
  1404.     int32 block_wrap_width, x_parent_offset, y_parent_offset;
  1405.     int32 block_x, block_y;
  1406.     lo_TopState *top_state;
  1407.     XP_Rect bbox;
  1408.     PRBool hidden, inherit_visibility;
  1409.     CL_Layer *layer, *parent_layer;
  1410.     char *backdrop_image_url = NULL;
  1411.     LO_Color rgb, *bg_color = NULL;
  1412.     char *url = NULL;
  1413.  
  1414.     if (!context->compositor || !param)
  1415.         return;
  1416.  
  1417.     /*
  1418.      * If this is a nested inflow layer, then flush the line list into our parent
  1419.      * (without introducing a line break). This ensures that whatever line changes
  1420.      * (specifically shifting of cell origin) that occur while laying out this ilayer
  1421.      * are reflected in our parent.
  1422.      */
  1423.     if (lo_InsideInflowLayer(state) && is_inflow)
  1424.     {
  1425.         lo_FlushLineList(context, state, LO_LINEFEED_BREAK_SOFT, LO_CLEAR_NONE, FALSE);
  1426.     }
  1427.  
  1428.     top_state = state->top_state;
  1429.     block = XP_NEW_ZAP(lo_Block);
  1430.     if (block == NULL)
  1431.     {
  1432.         state->top_state->out_of_memory = TRUE;
  1433.         return;
  1434.     }
  1435.     block->context = context;
  1436.     layer_state = lo_NewLayerState(context);
  1437.     if (layer_state == NULL) {
  1438.         state->top_state->out_of_memory = TRUE;
  1439.         lo_DeleteBlock(block);
  1440.         return;
  1441.     }
  1442.     layer_state->temp_block = block;
  1443.  
  1444.     /* Retain MATCH attribute for use in comparison of attribute of
  1445.        same name in matching closing layer tag. */
  1446.     block->match_code = NULL;
  1447.     if (param->tag) {
  1448.         char *match =
  1449.             (char*)PA_FetchParamValue(param->tag, PARAM_MATCH, win_csid);
  1450.         if (match) {
  1451.             block->match_code = XP_STRDUP(match);
  1452.             PA_FREE(match);
  1453.         }
  1454.     }
  1455.  
  1456.     block->name = NULL;
  1457.     block->above = NULL;
  1458.     block->below = NULL;
  1459.     hidden = PR_FALSE;
  1460.     inherit_visibility = PR_TRUE;
  1461.     block->z_order = -1;
  1462.     block->old_layer_state = NULL;
  1463.  
  1464.     /* If there is no tag associated with this layer, then it was
  1465.        created as a result of a style sheet. */
  1466.     block->uses_ss_positioning = (param->tag == NULL);
  1467.  
  1468.     block->is_inflow = is_inflow;
  1469.  
  1470.     /* In-flow layers use coordinates that are relative to their
  1471.        "natural", in-flow position. */
  1472.     if (block->is_inflow) {
  1473.         block->x_offset = state->x;
  1474.         block->y_offset = state->y;
  1475.     } else {
  1476.         block->x_offset = 0;
  1477.         block->y_offset = 0;
  1478.     }
  1479.  
  1480.  
  1481.     x_parent_offset = y_parent_offset = 0;
  1482.     parent_layer_state = lo_CurrentLayerState(state);
  1483.     parent_layer = parent_layer_state->layer;
  1484.     if (parent_layer)           /* Paranoia */
  1485.         lo_GetLayerXYShift(parent_layer, &x_parent_offset, &y_parent_offset);
  1486.  
  1487.     /*
  1488.      * Get the X position of the block
  1489.      */
  1490.     if (param->has_left)
  1491.     {
  1492.         block_x = param->left;
  1493.     } else {
  1494.         if (block->is_inflow) {
  1495.             block_x = 0;
  1496.         } else {
  1497.             block_x = state->x - x_parent_offset;
  1498.         }
  1499.     }
  1500.  
  1501.     /*
  1502.      * Get the Y position of the block
  1503.      */
  1504.     if (param->has_top)
  1505.     {
  1506.         block_y = param->top;
  1507.     } else {
  1508.         if (block->is_inflow) {
  1509.             block_y = 0;
  1510.         } else {
  1511.             block_y = state->y - y_parent_offset;
  1512.         }
  1513.     }
  1514.  
  1515.     XP_BZERO(&bbox, sizeof(bbox));
  1516.  
  1517.     /*
  1518.      * Get the width parameter, in absolute or percentage.
  1519.      * If percentage, make it absolute.
  1520.      */
  1521.     if (param->has_width)
  1522.         block_wrap_width = param->width;
  1523.     else if (param->has_left)
  1524.         block_wrap_width = state->right_margin - param->left;
  1525.     else
  1526.         block_wrap_width = state->right_margin - state->x;
  1527.  
  1528.     /*
  1529.      * Parse the comma separated coordinate list into an
  1530.      * array of integers.
  1531.      */
  1532.     if (param->clip)
  1533.     {
  1534.         bbox = *param->clip;
  1535.  
  1536.         /* Don't allow the layer's clip to expand */
  1537.         block->clip_expansion_policy = param->clip_expansion_policy;
  1538.     } else {
  1539.         /* Allow the clip to expand to include the layer's contents. */
  1540.         block->clip_expansion_policy = LO_AUTO_EXPAND_CLIP;
  1541.         if (param->has_width)
  1542.             bbox.right = block_wrap_width;
  1543.     }
  1544.  
  1545.     if (param->has_height) {
  1546.         layer_state->height = param->height;
  1547.         /* If no CLIP set, set initial bottom edge of layer clip to be
  1548.            the same as HEIGHT. */
  1549.         if (block->clip_expansion_policy & LO_AUTO_EXPAND_CLIP_BOTTOM)
  1550.             bbox.bottom = param->height;
  1551.     }
  1552.  
  1553.     /* Treat any value of OVERFLOW, except "hidden" to be the same as
  1554.        "visible".  For compatibility with the older CSS positioning
  1555.        spec, we also treat "none" specially.  Can't set OVERFLOW
  1556.        unless HEIGHT is provided. */
  1557.     if (param->has_height &&
  1558.         param->overflow &&
  1559.         XP_STRCASECMP(param->overflow, "none") &&
  1560.         XP_STRCASECMP(param->overflow, "visible")) {
  1561.  
  1562.         /* Constrain all drawing to {0, 0, width, height} box */
  1563.         XP_Rect *viewRect = &layer_state->viewRect;
  1564.         viewRect->left = 0;
  1565.         viewRect->top = 0;
  1566.         viewRect->right = block_wrap_width;
  1567.         viewRect->bottom = param->height;
  1568.     }
  1569.  
  1570.     /*
  1571.      * Get the optional name for this layer.
  1572.      */
  1573.     layer_name = NULL;
  1574.     if(param->name)
  1575.         layer_name = param->name;
  1576.     else if(param->id)
  1577.         layer_name = param->id;
  1578.  
  1579.     /* Don't allow layer names that start with a number or underscore */
  1580.     if (layer_name && ((layer_name[0] < '0') || (layer_name[0] > '9')) &&
  1581.         (layer_name[0] != '_'))
  1582.         block->name = XP_STRDUP(layer_name);
  1583.  
  1584.     /*
  1585.      * Get the optional "above" name for the layer we are above.
  1586.      */
  1587.     if(param->above)
  1588.         block->above = XP_STRDUP(param->above);
  1589.  
  1590.     /*
  1591.      * Get the optional "below" name for the layer we are below.
  1592.      */
  1593.     if (!block->above)
  1594.     {
  1595.         if(param->below)
  1596.             block->below = XP_STRDUP(param->below);
  1597.  
  1598.         if (!block->below)
  1599.         {
  1600.             /*
  1601.              * Get the Z-order of the block
  1602.              */
  1603.             if (param->has_zindex)
  1604.             {
  1605.                 block->z_order = param->zindex;
  1606.             }
  1607.         }
  1608.     }
  1609.  
  1610.     /* Get the VISIBILITY parameter to know if this layer starts hidden. */
  1611.     if (param->visibility)
  1612.     {
  1613.         /* Handle "HIDE", "HIDDEN", etc. */
  1614.         hidden = (PRBool)!XP_STRNCASECMP(param->visibility, "hid", 3);
  1615.         inherit_visibility = (PRBool)!XP_STRCASECMP(param->visibility, "inherit");
  1616.     }
  1617.  
  1618.     if (is_inflow)
  1619.     {
  1620.         /* Add a new LO_LAYER dummy layout element to the line list.  Relayout will step through
  1621.            the line list and reflow the layer when the LO_LAYER element is encountered. */
  1622.         if (!lo_AppendLayerElement(context, state, FALSE)) 
  1623.             return;
  1624.     }
  1625.     
  1626.     /* Reset document layout state, saving old state to be restored
  1627.        after we lay out this layer. */
  1628.     if (!lo_SetupDocStateForLayer(state, layer_state,
  1629.                                   block_wrap_width, layer_state->height,
  1630.                                   (PRBool)is_inflow)) {
  1631.         state->top_state->out_of_memory = TRUE;
  1632.         lo_DeleteLayerState(context, state, layer_state);
  1633.         return;
  1634.     }
  1635.  
  1636.     block->cell = layer_state->cell =
  1637.         (LO_CellStruct *)lo_NewElement(context, state,
  1638.                                        LO_CELL, NULL, 0);
  1639.     if (block->cell == NULL)
  1640.     {
  1641.         state->top_state->out_of_memory = TRUE;
  1642.         lo_DeleteLayerState(context, state, layer_state);
  1643.         return;
  1644.     }
  1645.     lo_init_block_cell(context, state, block);
  1646.  
  1647.     /* Create the layer that corresponds to this block, initially invisible
  1648.        and with empty clip and [0,0] origin. */
  1649.     PA_LOCK(str, char *, block->name);
  1650.     layer = lo_CreateBlockLayer(context,
  1651.                                 str,
  1652.                                 (PRBool)block->is_inflow,
  1653.                                 block->x_offset,
  1654.                                 block->y_offset,
  1655.                                 block_wrap_width,
  1656.                                 layer_state, state);
  1657.     PA_UNLOCK(block->name);
  1658.     if (!layer) {
  1659.         state->top_state->out_of_memory = TRUE;
  1660.         lo_DeleteLayerState(context, state, layer_state);
  1661.         return;
  1662.     }
  1663.     block->layer = layer_state->layer = layer;
  1664.     if (block->is_inflow)
  1665.         block->cell->cell_inflow_layer = layer;
  1666.  
  1667.     /* Indicate that this layer's contents were not obtained as a
  1668.        result of setting the JavaScript 'src' property of the layer. */
  1669.     block->is_dynamic = FALSE;
  1670.     block->is_inline = TRUE;
  1671.  
  1672.     /*
  1673.      * Attach the layer doc_state to the layer list. The return
  1674.      * value is the old layer_state if we're in table relayout.
  1675.      * We need to wait till we're done processing this layer tag
  1676.      * before we actually get rid of the layer_state and its
  1677.      * contents.
  1678.      */
  1679.     block->old_layer_state = lo_append_to_layer_array(context, state->top_state,
  1680.                                                       state,
  1681.                                                       layer_state);
  1682.  
  1683.     /* Attach the layer into the layer tree */
  1684.     lo_AttachHTMLLayer(context, layer, parent_layer,
  1685.                        block->above, block->below, block->z_order);
  1686.  
  1687.     /* Reflect the layer into JavaScript */
  1688.     ET_ReflectObject(context, NULL, param->tag,
  1689.                      parent_layer_state->id,
  1690.                      layer_state->id, LM_LAYERS);
  1691.  
  1692.     /* Process background color (BGCOLOR) attribute, if present. */
  1693.     if (param->bgcolor) {
  1694.  
  1695.         XP_Bool rv;
  1696.         if(param->is_style_bgcolor)
  1697.             rv = LO_ParseStyleSheetRGB(param->bgcolor, &rgb.red, &rgb.green, &rgb.blue);
  1698.         else
  1699.             rv = LO_ParseRGB(param->bgcolor, &rgb.red, &rgb.green, &rgb.blue);
  1700.         if(rv)
  1701.             bg_color = &rgb;
  1702.     }
  1703.     if (bg_color)
  1704.         LO_SetLayerBgColor(layer, bg_color);
  1705.  
  1706.     /* Process backdrop (BACKGROUND) image attribute, if present. */
  1707.     if(param->bgimage)
  1708.         backdrop_image_url = XP_STRDUP(param->bgimage);
  1709.  
  1710.     if (!bg_color && !backdrop_image_url) {
  1711.         /* This is a transparent block, so let's go offscreen */
  1712.         CL_ChangeLayerFlag(layer, CL_PREFER_DRAW_OFFSCREEN, PR_TRUE);
  1713.     }
  1714.     if (backdrop_image_url) {
  1715.         LO_SetLayerBackdropURL(layer, backdrop_image_url);
  1716.         XP_FREE(backdrop_image_url);
  1717.     }
  1718.  
  1719.     lo_SetLayerClipExpansionPolicy(layer, block->clip_expansion_policy);
  1720.  
  1721.     /* Move layer into position.  Set clip dimensions and initial visibility. */
  1722.     LO_MoveLayer(layer, block_x, block_y);
  1723.     LO_SetLayerBbox(layer, &bbox);
  1724.     lo_expand_parent_bbox(layer);
  1725.     CL_ChangeLayerFlag(layer, CL_HIDDEN, hidden);
  1726. #ifdef XP_MAC
  1727.     CL_ChangeLayerFlag(layer, CL_OVERRIDE_INHERIT_VISIBILITY,
  1728.                        (PRBool)!inherit_visibility);
  1729. #else
  1730.     CL_ChangeLayerFlag(layer, CL_OVERRIDE_INHERIT_VISIBILITY,
  1731.                        (int32)!inherit_visibility);
  1732. #endif
  1733.  
  1734.     /* Push this layer on the layer stack */
  1735.     lo_PushLayerState(state->top_state, layer_state);
  1736. #ifdef MOCHA
  1737.     ET_SetActiveLayer(context, layer_state->id);
  1738. #endif /* MOCHA */
  1739.     state->layer_nest_level++;
  1740.  
  1741.     if (param->src) {
  1742.         url = NET_MakeAbsoluteURL(top_state->base_url, param->src);
  1743.         if (url == NULL) {
  1744.             top_state->out_of_memory = TRUE;
  1745.             return;
  1746.         }
  1747.     }
  1748.  
  1749.     if ((url != NULL) && (top_state->doc_data != NULL)) {
  1750.         URL_Struct *url_struct;
  1751.         int status;
  1752.  
  1753.         block->source_url = XP_STRDUP(url);
  1754.         block->is_inline = FALSE;
  1755.         url_struct = NET_CreateURLStruct(url, top_state->force_reload);
  1756.         if (block->source_url == NULL || url_struct == NULL) {
  1757.             top_state->out_of_memory = TRUE;
  1758.             if (url_struct != NULL)
  1759.                 NET_FreeURLStruct(url_struct);
  1760.         }
  1761.         else {
  1762.             char *referer;
  1763.             lo_LayerStack *lptr;
  1764.  
  1765.             /*
  1766.              * The referer for this SRC="url" fetch will be the base document
  1767.              * url if there are no enclosing out-of-line or dynamic layer tags,
  1768.              * otherwise it will be the nearest enclosing layer block's source
  1769.              * url (set via a previous SRC= or by LO_PrepareLayerForWriting).
  1770.              */
  1771.             referer = top_state->base_url;
  1772.             lptr = top_state->layer_stack->next;
  1773.             while (lptr && lptr->layer_state &&
  1774.                    (lptr->layer_state->id != LO_DOCUMENT_LAYER_ID)) {
  1775.                 lo_Block *temp_block;
  1776.  
  1777.                 temp_block = lptr->layer_state->temp_block;
  1778.                 if (temp_block &&
  1779.                     (!temp_block->is_inline || temp_block->is_dynamic)) {
  1780.                     referer = temp_block->source_url;
  1781.                     break;
  1782.                 }
  1783.                 lptr = lptr->next;
  1784.             }
  1785.  
  1786.             url_struct->referer = XP_STRDUP(referer);
  1787.             if (url_struct->referer == NULL) {
  1788.                 top_state->out_of_memory = TRUE;
  1789.                 NET_FreeURLStruct(url_struct);
  1790.                 return;
  1791.             }
  1792.  
  1793.             /*
  1794.              * We're blocking on the current element till we
  1795.              * read in the new stream.
  1796.              */
  1797.             top_state->layout_blocking_element = (LO_Element *)block->cell;
  1798.  
  1799.             lo_insert_suppress_tags(context, top_state, param);
  1800.  
  1801.             /*
  1802.              * New tags will be inserted at the start of the
  1803.              * blocked tags list.
  1804.              */
  1805.              top_state->input_write_point[top_state->input_write_level] =
  1806.                  &top_state->tags;
  1807.  
  1808.             lo_SetBaseUrl(state->top_state, url, FALSE);
  1809.             XP_FREEIF(top_state->inline_stream_blocked_base_url);
  1810.  
  1811.             status = NET_GetURL(url_struct, FO_CACHE_AND_PRESENT_INLINE, context,
  1812.                                 lo_block_src_exit_fn);
  1813.  
  1814.             if (status < 0)
  1815.                 top_state->layout_blocking_element = NULL;
  1816.  
  1817.         }
  1818.         XP_FREE(url);
  1819.     }
  1820. }
  1821.  
  1822. static Bool
  1823. lo_create_layer_blockage(MWContext *context, lo_DocState *state)
  1824. {
  1825.     lo_TopState *top_state;
  1826.     top_state = state->top_state;
  1827.  
  1828.     top_state->layout_blocking_element
  1829.         = lo_NewElement(context, state, LO_CELL, NULL, 0);
  1830.     if (top_state->layout_blocking_element == NULL) {
  1831.         top_state->out_of_memory = TRUE;
  1832.     } else {
  1833.         top_state->layout_blocking_element->type = LO_CELL;
  1834.         top_state->layout_blocking_element->lo_any.ele_id = NEXT_ELEMENT;
  1835.         top_state->layout_blocking_element->lo_cell.cell_list = NULL;
  1836.         top_state->layout_blocking_element->lo_cell.cell_list_end = NULL;
  1837.         top_state->layout_blocking_element->lo_cell.cell_float_list = NULL;
  1838.         top_state->layout_blocking_element->lo_cell.cell_bg_layer = NULL;
  1839.         top_state->layout_blocking_element->lo_cell.backdrop.bg_color = NULL;
  1840.     }
  1841.  
  1842.     return(top_state->layout_blocking_element != NULL);
  1843. }
  1844.  
  1845. typedef struct
  1846. {
  1847.     MWContext *context;
  1848.     lo_DocState *state;
  1849.     XP_Bool is_inflow;
  1850.     int32 doc_id;
  1851. } lo_RestoreLayerClosure;
  1852.  
  1853. static void
  1854. lo_RestoreLayerExitFn(void *myclosure,
  1855.                       LO_BlockInitializeStruct *param)
  1856. {
  1857.     lo_RestoreLayerClosure *closure = (lo_RestoreLayerClosure *)myclosure;
  1858.     MWContext *context = closure->context;
  1859.     lo_DocState *state = closure->state;
  1860.     lo_TopState *top_state;
  1861.     int32 doc_id = closure->doc_id;
  1862.     PRBool flushp = (PRBool)(param->src == NULL);
  1863.     LO_Element *blocking_element;
  1864.  
  1865.     if (doc_id == XP_DOCID(context)) {
  1866.         top_state = state->top_state;
  1867.         /*
  1868.          * We check that we're still blocking, since it's possible that
  1869.          * something's come along and changed things under us e.g. if
  1870.          * the context is interrupted while we were out to mocha.
  1871.          */
  1872.         blocking_element = top_state->layout_blocking_element;
  1873.         if (blocking_element)
  1874.             lo_begin_layer_internal(context, state, param, closure->is_inflow);
  1875.     }
  1876.  
  1877.     XP_FREE(closure);
  1878.  
  1879.     /* Get rid of the cloned tag */
  1880.     if(param->tag) {
  1881.         PA_FreeTag(param->tag);
  1882.     }
  1883.     else if (param->ss_tag) {
  1884.         PA_FreeTag(param->ss_tag);
  1885.     }
  1886.  
  1887.     lo_FreeBlockInitializeStruct(param);
  1888.  
  1889.     /* Get rid of the fake layout blocking element */
  1890.     if ((doc_id == XP_DOCID(context)) &&
  1891.         (blocking_element)) {
  1892.         lo_FreeElement(context, blocking_element, FALSE);
  1893.  
  1894.         /*
  1895.          * If there was a SRC attribute in the param list, then
  1896.          * the block layout will have created a new blocking element.
  1897.          * Otherwise, flush the blocked list and carry on as if
  1898.          * nothing happened.
  1899.          */
  1900.         if (flushp) {
  1901.             top_state->layout_blocking_element = NULL;
  1902.             lo_FlushBlockage(context, state, state->top_state->doc_state);
  1903.         }
  1904.     }
  1905. }
  1906.  
  1907. XP_Bool
  1908. lo_BeginLayer(MWContext *context,
  1909.               lo_DocState *state,
  1910.               LO_BlockInitializeStruct *param,
  1911.               XP_Bool is_inflow)
  1912. {
  1913.     if (!context->compositor || !param)
  1914.         return TRUE;
  1915.  
  1916.     if (state->top_state->resize_reload && !state->in_relayout &&
  1917.         !lo_IsAnyCurrentAncestorDynamic(state) && LM_CanDoJS(context)) {
  1918.         lo_RestoreLayerClosure *closure;
  1919.         PA_Tag *new_tag;
  1920.  
  1921.         /* I guess this whole section can go away, now that we have resize
  1922.            without reload a la Mariner??? */
  1923.  
  1924.         closure = XP_NEW_ZAP(lo_RestoreLayerClosure);
  1925.         if (!closure)
  1926.             return TRUE;
  1927.  
  1928.         closure->context = context;
  1929.         closure->state = state;
  1930.         closure->is_inflow = is_inflow;
  1931.         closure->doc_id = XP_DOCID(context);
  1932.  
  1933.         /*
  1934.          * Block layout and send an event mocha to restore the layer
  1935.          * state from the preserved mocha object.
  1936.          */
  1937.         lo_create_layer_blockage(context, state);
  1938.         lo_BlockLayerTag(context, state, NULL);
  1939.  
  1940.         if (param->tag) {
  1941.             new_tag = PA_CloneMDLTag(param->tag);
  1942.             if (!new_tag) {
  1943.                 state->top_state->out_of_memory = TRUE;
  1944.                 return TRUE;
  1945.             }
  1946.             param->tag = new_tag;
  1947.         }
  1948.         else if (param->ss_tag) {
  1949.             new_tag = PA_CloneMDLTag(param->ss_tag);
  1950.             if (!new_tag) {
  1951.                 state->top_state->out_of_memory = TRUE;
  1952.                 return TRUE;
  1953.             }
  1954.             param->ss_tag = new_tag;
  1955.         }
  1956.  
  1957.         ET_RestoreLayerState(context, state->top_state->current_layer_num + 1,
  1958.                              param, lo_RestoreLayerExitFn, closure);
  1959.         return FALSE;
  1960.     }
  1961.     else {
  1962.         lo_begin_layer_internal(context, state, param, is_inflow);
  1963.         return TRUE;
  1964.     }
  1965. }
  1966.  
  1967. void
  1968. lo_BlockLayerTag(MWContext *context, lo_DocState *state, PA_Tag *tag)
  1969. {
  1970.     lo_TopState *top_state;
  1971.     pa_DocData *doc_data;
  1972.  
  1973.     top_state = state->top_state;
  1974.     doc_data = top_state->doc_data;
  1975.     XP_ASSERT(doc_data != NULL && doc_data->url_struct != NULL);
  1976.     if (doc_data == NULL || doc_data->url_struct == NULL)   /* Paranoia */
  1977.         return;
  1978. }
  1979.  
  1980. void
  1981. lo_UnblockLayerTag(lo_DocState *state)
  1982. {
  1983.     /*
  1984.      * I guess we don't really need this anymore, since we're not
  1985.      * maintaining a blocked_tag count.
  1986.      */
  1987. }
  1988.  
  1989. static void
  1990. lo_set_layer_bbox(CL_Layer *layer, XP_Rect *bbox, PRBool grow_parent);
  1991.  
  1992. /* A layer has expanded in order to contain its content.  Expand it's
  1993.    parent also.*/
  1994. static void
  1995. lo_expand_parent_bbox(CL_Layer *layer)
  1996. {
  1997.     XP_Rect parent_bbox, child_bbox;
  1998.     CL_Compositor *compositor = CL_GetLayerCompositor(layer);
  1999.  
  2000.     /* Get the parent's and child's bbox */
  2001.     CL_Layer *parent_layer = CL_GetLayerParent(layer);
  2002.  
  2003.     if (! parent_layer)
  2004.       return;
  2005.  
  2006.     CL_GetLayerBbox(parent_layer, &parent_bbox);
  2007.     CL_GetLayerBbox(layer, &child_bbox);
  2008.  
  2009.     /* Convert the child and parent to the same coordinate system. */
  2010.     CL_LayerToWindowRect(compositor, parent_layer, &parent_bbox);
  2011.     CL_LayerToWindowRect(compositor, layer, &child_bbox);
  2012.  
  2013.     /* Expand the parent's bbox to encompass the child layer. */
  2014.     XP_RectsBbox(&child_bbox, &parent_bbox, &parent_bbox);
  2015.     CL_WindowToLayerRect(compositor, parent_layer, &parent_bbox);
  2016.     lo_set_layer_bbox(parent_layer, &parent_bbox, PR_TRUE);
  2017.  
  2018.     lo_expand_parent_bbox(parent_layer);
  2019. }
  2020.  
  2021. /* Set the clipping bounds of a layer, but don't override any
  2022.    explicit clip set by the user with the CLIP attribute. */
  2023. static void
  2024. lo_set_layer_bbox(CL_Layer *layer, XP_Rect *bbox, PRBool grow_parent)
  2025. {
  2026.     XP_Rect new_bbox, old_bbox;
  2027.  
  2028.     int clip_expansion_policy = lo_GetLayerClipExpansionPolicy(layer);
  2029.  
  2030.     CL_GetLayerBbox(layer, &old_bbox);
  2031.     XP_CopyRect(&old_bbox, &new_bbox);
  2032.  
  2033.     if (clip_expansion_policy & LO_AUTO_EXPAND_CLIP_LEFT)
  2034.         new_bbox.left = bbox->left;
  2035.  
  2036.     if (clip_expansion_policy & LO_AUTO_EXPAND_CLIP_RIGHT)
  2037.         new_bbox.right = bbox->right;
  2038.  
  2039.     if (clip_expansion_policy & LO_AUTO_EXPAND_CLIP_TOP)
  2040.         new_bbox.top = bbox->top;
  2041.  
  2042.     if (clip_expansion_policy & LO_AUTO_EXPAND_CLIP_BOTTOM)
  2043.         new_bbox.bottom = bbox->bottom;
  2044.  
  2045.     /* If the layer's clip didn't change, there's nothing to do */
  2046.     if (XP_EqualRect(&old_bbox, &new_bbox))
  2047.         return;
  2048.  
  2049.     LO_SetLayerBbox(layer, &new_bbox);
  2050.  
  2051.     /* Expand the parent layer's bbox to contain this child's bbox */
  2052.     if (grow_parent)
  2053.         lo_expand_parent_bbox(layer);
  2054. }
  2055.  
  2056. /* Expand the layer associated with an HTML block in case the block
  2057.    has grown.  Don't expand the layer's width if the width is fixed
  2058.    and don't expand the layer's height if the height is fixed.  */
  2059. static void
  2060. lo_block_grown(lo_Block *block)
  2061. {
  2062.     CL_Layer *layer = block->layer;
  2063.     lo_LayerDocState *layer_state;
  2064.     LO_CellStruct *cell = block->cell;
  2065.  
  2066.     XP_Rect clip, existing_clip;
  2067.  
  2068.     clip.left = cell->x;
  2069.     clip.top  = cell->y;
  2070.     clip.right = cell->x + cell->width;
  2071.     clip.bottom = cell->y + cell->height;
  2072.  
  2073.     layer_state = lo_GetLayerState(layer);
  2074.     layer_state->contentWidth = cell->width;
  2075.     layer_state->contentHeight = cell->height;
  2076.  
  2077.     /* The coordinates of elements inside in-flow layers is with respect
  2078.        to the containing layer. */
  2079.     if (block->is_inflow)
  2080.         XP_OffsetRect(&clip, -block->start_x, -block->start_y);
  2081.  
  2082.     /* Don't allow a layer's clip to shrink. */
  2083.     CL_GetLayerBbox(layer, &existing_clip);
  2084.     XP_RectsBbox(&existing_clip, &clip, &clip);
  2085.  
  2086.     lo_set_layer_bbox(layer, &clip, (PRBool)!block->is_dynamic);
  2087. }
  2088.  
  2089. static LO_CellStruct *
  2090. lo_compose_block(MWContext *context, lo_DocState *state, lo_Block *block)
  2091. {
  2092.     int32 shift;
  2093.     XP_Rect update_rect, ele_bbox;
  2094.     LO_Element *tptr;
  2095.     LO_CellStruct *cell;
  2096.  
  2097.     cell = block->cell;
  2098.  
  2099.     XP_BZERO(&update_rect, sizeof(XP_Rect));
  2100.  
  2101.     /* Expands the dimensions of the cell to encompass any floating
  2102.      * elements that are outside its bounds.
  2103.      */
  2104.     tptr = state->float_list;
  2105.     while (tptr != NULL) {
  2106.         lo_GetElementBbox(tptr, &ele_bbox);
  2107.  
  2108.         shift = cell->x - ele_bbox.left;
  2109.         if (shift > 0) {
  2110.             cell->x -= shift;
  2111.             cell->width += shift;
  2112.         }
  2113.         shift = ele_bbox.right - (cell->x + cell->width);
  2114.         if (shift > 0)
  2115.             cell->width += shift;
  2116.         shift = cell->y - ele_bbox.top;
  2117.         if (shift > 0) {
  2118.             cell->y -= shift;
  2119.             cell->height += shift;
  2120.         }
  2121.         shift = ele_bbox.bottom - (cell->y + cell->height);
  2122.         if (shift > 0)
  2123.             cell->height += shift;
  2124.  
  2125.         XP_RectsBbox(&ele_bbox, &update_rect, &update_rect);
  2126.  
  2127.         tptr = tptr->lo_any.next;
  2128.     }
  2129.     tptr = state->float_list;
  2130.     cell->cell_float_list = tptr;
  2131.  
  2132.     if (context->compositor) {
  2133.         /* Expand the block layer. */
  2134.         lo_block_grown(block);
  2135.  
  2136.         if (block->is_inflow)
  2137.             XP_OffsetRect(&update_rect, -block->start_x, -block->start_y);
  2138.  
  2139.         /* Update the area occupied by the floating elements. */
  2140.         CL_UpdateLayerRect(context->compositor, block->layer, &update_rect,
  2141.                            PR_FALSE);
  2142.     }
  2143.  
  2144.     return(cell);
  2145. }
  2146.  
  2147. /* Process a </LAYER> or </ILAYER> tag. */
  2148. void
  2149. lo_EndLayerTag(MWContext *context,
  2150.                lo_DocState *state,
  2151.                PA_Tag *tag)
  2152. {
  2153.     INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
  2154.     int16 win_csid = INTL_GetCSIWinCSID(c);
  2155.     lo_LayerDocState *layer_state = lo_CurrentLayerState(state);
  2156.     lo_Block *block = layer_state->temp_block;
  2157.  
  2158.     if (! block)
  2159.         return;
  2160.  
  2161.     /* If opening layer tag had a MATCH attribute.  The value of the
  2162.        MATCH attribute in the closing tag must be identical or we
  2163.        refuse to really close the layer.  This capability is used by
  2164.        libmime to prevent renegade mail messages from escaping the
  2165.        bounds of their layer-enforced encapsulation using extra layer
  2166.        end tags in the message. */
  2167.     if (block->match_code) {
  2168.         char *attempted_match =
  2169.             (char*)PA_FetchParamValue(tag, PARAM_MATCH, win_csid);
  2170.         if (!attempted_match)
  2171.             return;
  2172.         if (XP_STRCMP(attempted_match, block->match_code)) {
  2173.             XP_TRACE(("Failed attempt to circumvent mail message security"));
  2174.             XP_ASSERT(0);
  2175.             PA_FREE(attempted_match);
  2176.             return;
  2177.         }
  2178.         PA_FREE(attempted_match);
  2179.     }
  2180.  
  2181.     lo_EndLayer(context, state, PR_TRUE);
  2182. }
  2183.  
  2184. static PRBool
  2185. lo_destroy_ancillary_child_layers(CL_Layer *layer, void *unused)
  2186. {
  2187.     LO_LayerType type;
  2188.     type = LO_GetLayerType(layer);
  2189.     if (type == LO_GROUP_LAYER)
  2190.         return PR_TRUE;
  2191.     CL_DestroyLayer(layer);
  2192.     return PR_TRUE;
  2193. }
  2194.  
  2195. void
  2196. lo_EndLayer(MWContext *context,
  2197.             lo_DocState *state,
  2198.             PRBool send_load_event)
  2199. {
  2200.     int32 right_edge;
  2201.     LO_CellStruct *cell;
  2202.     lo_LayerDocState *enclosing_layer_state;
  2203.     lo_LayerDocState *layer_state = lo_CurrentLayerState(state);
  2204.     lo_Block *block = layer_state->temp_block;
  2205.  
  2206.     /* During destruction, the compositor can disappear out from underneath us. */
  2207.     if (!context->compositor)
  2208.         return;
  2209.  
  2210.     /*
  2211.      * Protect from bad params.
  2212.      */
  2213.     if (! block) {
  2214.         return;
  2215.     }
  2216.  
  2217.     if (! block->is_inflow) {
  2218.         lo_CloseOutLayout(context, state);
  2219.     }
  2220.     else {
  2221.         /*
  2222.          * Flush out the last line of the block, without
  2223.          * introducing a line break.
  2224.          * BUGBUG In reality, calling lo_FlushLineList
  2225.          * also introduces a linefeed. We've set it up
  2226.          * so that linefeeds within blocks are of 0
  2227.          * size, so the linefeed is effectively ignored.
  2228.          * The 0 linefeed stuff is a hack!
  2229.          */
  2230.         lo_FlushLineList(context, state, LO_LINEFEED_BREAK_SOFT, LO_CLEAR_NONE, FALSE);
  2231.     }
  2232.  
  2233.     cell = lo_compose_block(context, state, block);
  2234.  
  2235.     /* For an in-flow layer, expand the enclosing cell's size on the
  2236.        right and bottom edges to contain any descendant
  2237.        layers. However, we only do this for ILAYER tags, not for
  2238.        layers created as a result of 'position:relative' applied to
  2239.        style-sheet elements. */
  2240.     if (block->is_inflow && !block->uses_ss_positioning) {
  2241.         int32 grow_width, grow_height;
  2242.         XP_Rect bbox;
  2243.  
  2244.         CL_GetLayerBbox(block->layer, &bbox);
  2245.         grow_width = (bbox.right - cell->width);
  2246.         grow_height = (bbox.bottom - cell->height);
  2247.  
  2248.         /* Position of right-edge of cell containing layer */
  2249.         right_edge = state->x;
  2250.  
  2251.         /* If the inflow layer is caused to grow vertically, force a
  2252.            line break. */
  2253.         if (grow_height > 0) {
  2254.             lo_SetSoftLineBreakState(context, state, FALSE, 1);
  2255.             cell->height = bbox.bottom;
  2256.             state->y += grow_height;
  2257.         }
  2258.  
  2259.         /* Compute new position of cell's right edge. */
  2260.         if (grow_width > 0) {
  2261.             right_edge += grow_width;
  2262.             cell->width = bbox.right;
  2263.         }
  2264.  
  2265.         /* Set minimum and maximum possible layout widths so that any
  2266.            enclosing table cells will be dimensioned properly. */
  2267.         if (right_edge + state->win_right > state->max_width)
  2268.             state->max_width = right_edge + state->win_right;
  2269.         if (right_edge + state->win_right > state->min_width)
  2270.             state->min_width = right_edge + state->win_right;
  2271.     }
  2272.  
  2273.     /* Restore document layout state, if necessary */
  2274.     lo_RestoreDocState(block, state);
  2275.  
  2276.     if (block->is_inflow)
  2277.     {
  2278.         /* Mark the </LAYER> tag by appending a LO_LAYER element to the line list. */
  2279.         if (!lo_AppendLayerElement(context, state, TRUE)) 
  2280.             return;
  2281.     }
  2282.  
  2283.     if (cell != NULL  && !block->is_inflow)
  2284.     {
  2285.         int32 max_y;
  2286.  
  2287.         cell->next = NULL;
  2288.         cell->ele_id = NEXT_ELEMENT;
  2289.         lo_RenumberCell(state, cell);
  2290.  
  2291.         /* XXX - Do we really want to expand the document size to
  2292.            include the layer ? */
  2293.         max_y = cell->y + cell->y_offset + cell->height;
  2294.         if (max_y > state->max_height)
  2295.         {
  2296.             state->max_height = max_y;
  2297.         }
  2298.     }
  2299.  
  2300.     /*
  2301.      * If we're in table relayout, we can now safely delete the
  2302.      * layer from a previous layout pass.
  2303.      */
  2304.     if (state->in_relayout && block->old_layer_state) {
  2305.         /* Get rid of child image layers, cell background layers, embedded window layers and blink layers */
  2306.         CL_ForEachChildOfLayer(block->old_layer_state->layer,
  2307.                            lo_destroy_ancillary_child_layers,
  2308.                            (void *)block->old_layer_state->layer);
  2309.         CL_DestroyLayer(block->old_layer_state->layer);
  2310.     }
  2311.  
  2312.     state->layer_nest_level--;
  2313.     lo_PopLayerState(state);
  2314. #ifdef MOCHA
  2315.     enclosing_layer_state = lo_CurrentLayerState(state);
  2316.     ET_SetActiveLayer(context, enclosing_layer_state->id);
  2317. #endif /* MOCHA */
  2318.  
  2319.     if (block->is_dynamic) {
  2320.         lo_TopState * top_state;
  2321.  
  2322.         top_state = state->top_state;
  2323.         top_state->nurl = NULL;
  2324.         top_state->layout_status = PA_COMPLETE;
  2325.  
  2326.             lo_CloseMochaWriteStream(top_state, EVENT_LOAD);
  2327.  
  2328.         lo_FreeLayoutData(context, state);
  2329.  
  2330.         /*
  2331.          * We force a composite so that the layer is drawn, even
  2332.          * if it is immediately changed again (as is sometimes the
  2333.          * case when we're dynamically resizing layers.
  2334.          */
  2335.         if (context->compositor) {
  2336.             XP_Rect bbox;
  2337.  
  2338.             CL_GetLayerBbox(block->layer, &bbox);
  2339.             CL_UpdateLayerRect(context->compositor, block->layer,
  2340.                                &bbox, PR_TRUE);
  2341.         }
  2342.     }
  2343.  
  2344. #ifdef MOCHA
  2345.     if (send_load_event)
  2346.         ET_SendLoadEvent(context, EVENT_LOAD, NULL, NULL, layer_state->id,
  2347.                          state->top_state->resize_reload);
  2348. #endif
  2349.  
  2350.     lo_DeleteBlock(block);
  2351.     layer_state->temp_block = NULL;
  2352. }
  2353.  
  2354. void
  2355. lo_AddLineListToLayer(MWContext *context,
  2356.                       lo_DocState *state,
  2357.                       LO_Element *line_list_end)
  2358. {
  2359.     int32 max_y, max_x, min_x, height, width;
  2360.     LO_Element *line_list;
  2361.     LO_CellStruct *cell;
  2362.     lo_LayerDocState *layer_state = lo_CurrentLayerState(state);
  2363.     lo_Block *block = layer_state->temp_block;
  2364.  
  2365.     line_list = state->line_list;
  2366.     if (line_list == NULL)
  2367.         return;
  2368.  
  2369.     cell = block->cell;
  2370.  
  2371.     /*
  2372.      * For dynamic src changing, we just refresh the area occupied by
  2373.      * the old layer. For the autoexpanding case, we reset the size
  2374.      * of the layer to zero.
  2375.      */
  2376.     if ((cell->cell_list == NULL) && (cell->cell_float_list == NULL)) {
  2377.  
  2378.             /* If no page background color is specified, we must
  2379.                commit to one as soon as any layout element is
  2380.                displayed in order to avoid the excessive flashing that
  2381.                would occur had we created the background later. */
  2382.             if (state->top_state->nothing_displayed != FALSE) {
  2383.                 lo_use_default_doc_background(context, state);
  2384.                 state->top_state->nothing_displayed = FALSE;
  2385.             }
  2386.  
  2387.             if (block->is_dynamic) {
  2388.         XP_Rect bbox;
  2389.  
  2390.         CL_GetLayerBbox(block->layer, &bbox);
  2391.         CL_UpdateLayerRect(context->compositor, block->layer, &bbox, PR_FALSE);
  2392.  
  2393.         if (block->clip_expansion_policy == LO_AUTO_EXPAND_CLIP)
  2394.         {
  2395.             XP_Rect empty_bbox = {0, 0, 0, 0};
  2396.  
  2397.             CL_SetLayerBbox(block->layer, &empty_bbox);
  2398.         }
  2399.             }
  2400.         }
  2401.  
  2402.     if (cell->cell_list_end == NULL)
  2403.     {
  2404.         line_list->lo_any.prev = NULL;
  2405.         cell->cell_list = line_list;
  2406.         line_list_end->lo_any.next = NULL;
  2407.         cell->cell_list_end = line_list_end;
  2408.     }
  2409.     else
  2410.     {
  2411.         cell->cell_list_end->lo_any.next = line_list;
  2412.         line_list->lo_any.prev = cell->cell_list_end;
  2413.         line_list_end->lo_any.next = NULL;
  2414.         cell->cell_list_end = line_list_end;
  2415.     }
  2416.  
  2417.     max_y = line_list_end->lo_any.y + line_list_end->lo_any.y_offset +
  2418.             line_list_end->lo_any.height;
  2419.  
  2420.     if (block->is_inflow)
  2421.         height = max_y - cell->y;
  2422.     else
  2423.         height = max_y;
  2424.     if (height > cell->height)
  2425.         cell->height = height;
  2426.  
  2427.     /*
  2428.      * If the new line extends past the previous bounds of the
  2429.      * cell, extend the bounds of the cell.
  2430.      */
  2431.     max_x = line_list_end->lo_any.x + line_list_end->lo_any.x_offset +
  2432.         line_list_end->lo_any.width;
  2433.  
  2434.     if (block->is_inflow)
  2435.         width = max_x - cell->x;
  2436.     else
  2437.         width = max_x;
  2438.     if (width > cell->width)
  2439.         cell->width = width;
  2440.  
  2441.     /*
  2442.      * This deals with the case where the new line laid out
  2443.      * has a start position to the left of the start of the
  2444.      * block. This can happen if the layer (with no absolute
  2445.      * positioning starts to the right of an element that
  2446.      * been aligned left and then its contents flow to the
  2447.      * left of the start position below the aligned element i.e.
  2448.      *
  2449.      *     *******
  2450.      *     ******* -----
  2451.      *     ******* -----
  2452.      *     ******* -----
  2453.      *     -------------
  2454.      *     -------------
  2455.      *
  2456.      * where * represents the element aligned left (an image
  2457.      * for instance) and - represents the contents of the layer.
  2458.      * The layer is shifted left (to the start position of
  2459.      * the new line and expanded) i.e.
  2460.      *
  2461.      *     *******
  2462.      *     ####### -----
  2463.      *     ####### -----
  2464.      *     ####### -----
  2465.      *     -------------
  2466.      *     -------------
  2467.      *
  2468.      * where # represents the (transparent) part of the layer
  2469.      * overlapping the aligned element.
  2470.      */
  2471.     min_x = line_list->lo_any.x + line_list->lo_any.x_offset;
  2472.     if (min_x < cell->x) {
  2473.         cell->width += cell->x - min_x;
  2474.         cell->x = min_x;
  2475.     }
  2476.  
  2477.     if (context->compositor && (block->layer != NULL)) {
  2478.         int32 min_y;
  2479.         XP_Rect update_rect;
  2480.  
  2481.         /* Expand the block layer. */
  2482.         lo_block_grown(block);
  2483.  
  2484.         /* Update the area of the line we just added. */
  2485.         min_y = max_y - state->line_height;
  2486.         update_rect.left = min_x;
  2487.         update_rect.top = min_y;
  2488.         update_rect.right = max_x;
  2489.         update_rect.bottom = max_y;
  2490.  
  2491.         if (block->is_inflow)
  2492.             XP_OffsetRect(&update_rect, -block->start_x, -block->start_y);
  2493.  
  2494.         CL_UpdateLayerRect(context->compositor, block->layer, &update_rect,
  2495.                            PR_FALSE);
  2496.     }
  2497. }
  2498.  
  2499.  
  2500. void
  2501. lo_FinishLayerLayout(MWContext *context, lo_DocState *state, int mocha_event)
  2502. {
  2503.     lo_TopState *top_state = state->top_state;
  2504.     PA_Tag *tag;
  2505.  
  2506.     /* End the current block if we're done processing all tags */
  2507.     if ((top_state->layout_blocking_element == NULL) &&
  2508.         (top_state->tags == NULL))
  2509.         lo_EndLayer(context, state, PR_TRUE);
  2510.     /* We're still blocked on something, so
  2511.      * create a fake </LAYER> tag and add it to the end of the
  2512.      * blocked list. Processing this tag will eventually close
  2513.      * out layout.
  2514.      */
  2515.     else
  2516.     {
  2517.         tag = pa_CreateMDLTag(top_state->doc_data,
  2518.                               layer_end_tag,
  2519.                               sizeof layer_end_tag - 1);
  2520.  
  2521.         if (tag != NULL) {
  2522.             /* Put it at the end of the tag list */
  2523.             if (top_state->tags == NULL)
  2524.                 top_state->tags = tag;
  2525.             else
  2526.                 *top_state->tags_end = tag;
  2527.             top_state->tags_end = &tag->next;
  2528.         }
  2529.         else
  2530.             top_state->out_of_memory = TRUE;
  2531.     }
  2532. }
  2533.  
  2534. static void
  2535. lo_block_src_setter_exit_fn(URL_Struct *url_struct,
  2536.                             int status,
  2537.                             MWContext *context)
  2538. {
  2539.     NET_FreeURLStruct(url_struct);
  2540. }
  2541.  
  2542. static lo_Block *
  2543. lo_init_block(MWContext *context, lo_DocState *state,
  2544.               lo_LayerDocState *layer_state, int32 block_x, int32 block_y,
  2545.               int32 width)
  2546. {
  2547.     lo_Block *block;
  2548.  
  2549.     /* Create a new block and initialize it */
  2550.     block = XP_NEW_ZAP(lo_Block);
  2551.     if (block == NULL)
  2552.         return NULL;
  2553.     block->context = context;
  2554.  
  2555.     layer_state->temp_block = block;
  2556.  
  2557.     if (!lo_SetupDocStateForLayer(state, layer_state,
  2558.                                   width, layer_state->height, PR_FALSE)) {
  2559.         lo_DeleteBlock(block);
  2560.         layer_state->temp_block = NULL;
  2561.         return NULL;
  2562.     }
  2563.  
  2564.     return block;
  2565. }
  2566.  
  2567. static PRBool
  2568. lo_remove_extra_layers(CL_Layer *child, void *closure)
  2569. {
  2570.     LO_LayerType type;
  2571.     CL_Layer *parent = (CL_Layer *)closure;
  2572.  
  2573.     type = LO_GetLayerType(child);
  2574.     if ((type == LO_HTML_BLOCK_LAYER) || (type == LO_HTML_BACKGROUND_LAYER))
  2575.         return PR_TRUE;
  2576.     CL_RemoveChild(parent, child);
  2577.     LO_LockLayout();
  2578.     CL_DestroyLayerTree(child);
  2579.     LO_UnlockLayout();
  2580.     return PR_TRUE;
  2581. }
  2582.  
  2583. Bool
  2584. LO_PrepareLayerForWriting(MWContext *context, int32 layer_id,
  2585.                           const char *referer, int32 width)
  2586. {
  2587.     int32 doc_id;
  2588.     lo_TopState *top_state;
  2589.     lo_DocState *state;
  2590.     CL_Layer *layer;
  2591.     lo_LayerDocState *layer_state;
  2592.     lo_Block *block;
  2593.     int32 block_x, block_y;
  2594.  
  2595.     /* Get the top state of the document */
  2596.     doc_id = XP_DOCID(context);
  2597.     top_state = lo_FetchTopState(doc_id);
  2598.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  2599.     {
  2600.         return FALSE;
  2601.     }
  2602.     state = top_state->doc_state;
  2603.  
  2604.     /*
  2605.      * XXX For now, if we're still loading, we can't
  2606.      * change the src of a layer. Is this the right
  2607.      * thing to check that we're done with the original
  2608.      * HTML stream?
  2609.      */
  2610.     if ((top_state->doc_data != NULL) || lo_InsideLayer(state))
  2611.         return FALSE;
  2612.  
  2613.     layer_state = lo_GetLayerStateFromId(context, layer_id);
  2614.     if (!layer_state)
  2615.         return FALSE;
  2616.     layer = layer_state->layer;
  2617.  
  2618.     /* Delete the contents of the old layer */
  2619.     lo_SaveFormElementStateInFormList(context,
  2620.                                       layer_state->doc_lists->form_list,
  2621.                                       TRUE);
  2622.     if (layer_state->cell)
  2623.         lo_RecycleElements(context, state, (LO_Element *)layer_state->cell);
  2624.     lo_DeleteDocLists(context, layer_state->doc_lists);
  2625.  
  2626.     /*
  2627.      * Get rid of all "extra" layers associated (blink, cell_bg, images, etc.)
  2628.      * associated with this layer and its content.  Get rid of all group
  2629.      * layer descendants, too.
  2630.      */
  2631.     CL_ForEachChildOfLayer(layer,
  2632.                            lo_remove_extra_layers,
  2633.                            (void *)layer);
  2634.     /*
  2635.      * XXX We're assuming that FinishLayout has already been called and
  2636.      * some of the doc_state has been trashed. Here we reset some of the
  2637.      * state so that new tags can be parsed.
  2638.      */
  2639.     state->base_font_size = DEFAULT_BASE_FONT_SIZE;
  2640.     state->font_stack = lo_DefaultFont(state, context);
  2641.     state->line_buf = PA_ALLOC(LINE_BUF_INC * sizeof(char));
  2642.     if (state->line_buf == NULL) {
  2643.         state->top_state->out_of_memory = TRUE;
  2644.         return FALSE;
  2645.     }
  2646.     state->line_buf_size = LINE_BUF_INC;
  2647.     state->line_buf_len = 0;
  2648.  
  2649.     /*
  2650.      * We reset the script_tag_count so that we'll reset the
  2651.      * mocha decoder stream.
  2652.      */
  2653.     top_state->script_tag_count = 0;
  2654.  
  2655.     block_x = CL_GetLayerXOffset(layer);
  2656.     block_y = CL_GetLayerYOffset(layer);
  2657.  
  2658.     if (!lo_InitDocLists(context, layer_state->doc_lists)) {
  2659.         state->top_state->out_of_memory = FALSE;
  2660.         return FALSE;
  2661.     }
  2662.  
  2663.     block = lo_init_block(context, state, layer_state, block_x, block_y,
  2664.                           width);
  2665.     if (block)
  2666.         block->cell = (LO_CellStruct *)lo_NewElement(context, state,
  2667.                                                   LO_CELL, NULL, 0);
  2668.  
  2669.     if ((block == NULL) || (block->cell == NULL))
  2670.     {
  2671.         state->top_state->out_of_memory = TRUE;
  2672.         if (block) {
  2673.             lo_DeleteBlock(block);
  2674.             layer_state->temp_block = NULL;
  2675.         }
  2676.  
  2677.         return FALSE;
  2678.     }
  2679.  
  2680.     layer_state->cell = block->cell;
  2681.  
  2682.     lo_init_block_cell(context, state, block);
  2683.  
  2684.     block->layer = layer;
  2685.     block->is_dynamic = TRUE;
  2686.     block->is_inline = TRUE;
  2687.     block->source_url = referer ? XP_STRDUP(referer) : NULL;
  2688.  
  2689.     state->layer_nest_level++;
  2690.     /* Push this layer on the layer stack */
  2691.     lo_PushLayerState(state->top_state, layer_state);
  2692. #ifdef MOCHA
  2693.     ET_SetActiveLayer(context, layer_state->id);
  2694. #endif /* MOCHA */
  2695.  
  2696.     block->clip_expansion_policy = lo_GetLayerClipExpansionPolicy(layer);
  2697.  
  2698.     return TRUE;
  2699. }
  2700.  
  2701.  
  2702. Bool
  2703. LO_SetLayerSrc(MWContext *context, int32 layer_id, char *str,
  2704.                const char *referer, int32 width)
  2705. {
  2706.     int32 doc_id;
  2707.     lo_TopState *top_state;
  2708.     lo_DocState *state;
  2709.     char *url;
  2710.     URL_Struct *url_struct;
  2711.     int status;
  2712.     lo_LayerDocState *layer_state;
  2713.  
  2714.     /* Get the top state of the document */
  2715.     doc_id = XP_DOCID(context);
  2716.     top_state = lo_FetchTopState(doc_id);
  2717.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  2718.     {
  2719.         return FALSE;
  2720.     }
  2721.     state = top_state->doc_state;
  2722.  
  2723.     if (!LO_PrepareLayerForWriting(context, layer_id, referer, width))
  2724.         return FALSE;
  2725.  
  2726.     layer_state = lo_CurrentLayerState(state);
  2727.     if (layer_state && layer_state->temp_block)
  2728.         layer_state->temp_block->is_inline = FALSE;
  2729.  
  2730.     /* Ask netlib to start loading the new URL */
  2731.     url = NET_MakeAbsoluteURL(top_state->base_url, str);
  2732.     if (url == NULL) {
  2733.       /*lo_Block *block;*/
  2734.  
  2735.         top_state->out_of_memory = TRUE;
  2736. /* XXX        block = state->current_block;
  2737.         if (block) {
  2738.             lo_RecycleElements(context, state, (LO_Element *)block->cell);
  2739.             XP_DELETE(block);
  2740.         }
  2741.         state->current_block = NULL; */
  2742.         return FALSE;
  2743.     }
  2744.  
  2745.     url_struct = NET_CreateURLStruct(url, top_state->force_reload);
  2746.     if (url_struct == NULL)
  2747.         top_state->out_of_memory = TRUE;
  2748.     else {
  2749.         url_struct->referer = XP_STRDUP(referer);
  2750.         if (!url_struct->referer) {
  2751.             top_state->out_of_memory = TRUE;
  2752.             NET_FreeURLStruct(url_struct);
  2753.             XP_FREE(url);
  2754.             return FALSE;
  2755.         }
  2756.  
  2757.         lo_SetBaseUrl(state->top_state, url, FALSE);
  2758.         XP_FREEIF(top_state->inline_stream_blocked_base_url);
  2759.  
  2760.         status = NET_GetURL(url_struct, FO_CACHE_AND_PRESENT_INLINE, context,
  2761.                             lo_block_src_setter_exit_fn);
  2762.     }
  2763.  
  2764.     XP_FREE(url);
  2765.     return TRUE;
  2766. }
  2767.  
  2768. /* Create an anonymous layer, not tied to the HTML source.
  2769.    Returns -1 on error, 0 if unable to create a new layer because the parser
  2770.    stream is still active. */
  2771. int32
  2772. LO_CreateNewLayer(MWContext *context, int32 wrap_width, int32 parent_layer_id)
  2773. {
  2774.     int32 doc_id, layer_id;
  2775.     LO_BlockInitializeStruct *param;
  2776.     CL_Layer *parent_layer;
  2777.     lo_TopState *top_state;
  2778.     lo_DocState *state;
  2779.     lo_LayerDocState *layer_state;
  2780.     CL_Layer *layer;
  2781.  
  2782.     doc_id = XP_DOCID(context);
  2783.     top_state = lo_FetchTopState(doc_id);
  2784.     if (!top_state)
  2785.         return 0;
  2786.  
  2787.     /*
  2788.      * XXX For now, if we're still loading, we can't
  2789.      * change the src of a layer. Is this the right
  2790.      * thing to check that we're done with the original
  2791.      * HTML stream?
  2792.      */
  2793.     state = top_state->doc_state;
  2794.     if ((top_state->doc_data != NULL) || lo_InsideLayer(state))
  2795.         return 0;
  2796.  
  2797.     param = XP_NEW_ZAP(LO_BlockInitializeStruct);
  2798.     if(!param)
  2799.         return -1;
  2800.  
  2801.     param->has_width = PR_TRUE;
  2802.     param->width = wrap_width;
  2803.     param->has_left = PR_TRUE;
  2804.     param->left = 0;
  2805.     param->has_top = PR_TRUE;
  2806.     param->top = 0;
  2807.     param->visibility = "hide";
  2808.     param->clip_expansion_policy = LO_AUTO_EXPAND_CLIP;
  2809.  
  2810.     layer_id = top_state->max_layer_num;
  2811.  
  2812.     /* Create a fake layer and append it to the document */
  2813.     lo_begin_layer_internal(context, state, param, FALSE);
  2814.     lo_EndLayer(context, state, PR_FALSE);
  2815.     XP_FREE(param);
  2816.  
  2817.     /* The only way we know if we succeeded is to see if the
  2818.        top_state->layers array has grown. */
  2819.     if (layer_id == top_state->max_layer_num)
  2820.         return -1;
  2821.  
  2822.     /* Reparent the layer, in case the parent wasn't the _DOCUMENT */
  2823.     parent_layer = LO_GetLayerFromId(context, parent_layer_id);
  2824.     layer_id = top_state->max_layer_num;
  2825.     layer_state = lo_GetLayerStateFromId(context, layer_id);
  2826.     layer_state->is_constructed_layer = PR_TRUE;
  2827.     layer = layer_state->layer;
  2828.     CL_RemoveChild(CL_GetLayerParent(layer), layer);
  2829.     CL_InsertChild(parent_layer, layer, NULL, CL_ABOVE);
  2830.  
  2831.     return layer_id;
  2832. }
  2833.