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

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19.  
  20. #include "xp.h"
  21. #include "net.h"
  22. #include "pa_parse.h"
  23. #include "layout.h"
  24. #include "laylayer.h"
  25. #include "np.h"
  26. #include "laystyle.h"
  27. #include "layers.h"
  28.  
  29.  
  30. #ifdef ANTHRAX /* 9.23.97 amusil */
  31. #include "prefapi.h"
  32. #endif /* ANTHRAX */
  33.  
  34. #ifdef XP_WIN16
  35. #define SIZE_LIMIT              32000
  36. #endif /* XP_WIN16 */
  37.  
  38.  
  39. #define EMBED_DEF_DIM            50
  40. #define EMBED_DEF_BORDER        0
  41. #define EMBED_DEF_VERTICAL_SPACE    0
  42. #define EMBED_DEF_HORIZONTAL_SPACE    0
  43.  
  44.  
  45. void lo_FinishEmbed(MWContext *, lo_DocState *, LO_EmbedStruct *);
  46. static void lo_FormatEmbedInternal(MWContext *, lo_DocState *, PA_Tag *,
  47.                                    LO_EmbedStruct *, Bool, Bool);
  48.                                   
  49.  
  50. void
  51. lo_AddEmbedData(MWContext *context, void *session_data, lo_FreeProc freeProc, int32 indx)
  52. {
  53.     int32 doc_id;
  54.     lo_TopState *top_state;
  55.     lo_DocState *state;
  56.     lo_SavedEmbedListData *embed_list;
  57.     lo_EmbedDataElement* embed_data_list;
  58.     int32 old_count;
  59.  
  60.     /*
  61.      * Get the state, so we can access the savedEmbedListData
  62.      * list for this document.
  63.      */
  64.     doc_id = XP_DOCID(context);
  65.     top_state = lo_FetchTopState(doc_id);
  66.     if ((top_state != NULL) && (top_state->doc_state != NULL))
  67.         state = top_state->doc_state;
  68.     else
  69.         return;
  70.  
  71.     embed_list = state->top_state->savedData.EmbedList;
  72.     if (embed_list == NULL)
  73.         return;
  74.  
  75.     /*
  76.      * We may have to grow the list to fit this new data.
  77.      */
  78.     if (indx >= embed_list->embed_count)
  79.     {
  80.         PA_Block old_embed_data_list; /* really a (lo_EmbedDataElement **) */
  81.  
  82. #ifdef XP_WIN16
  83.         /*
  84.          * On 16 bit windows arrays can just get too big.
  85.          */
  86.         if (((indx + 1) * sizeof(lo_EmbedDataElement)) > SIZE_LIMIT)
  87.             return;
  88. #endif /* XP_WIN16 */
  89.  
  90.         old_count = embed_list->embed_count;
  91.         embed_list->embed_count = indx + 1;
  92.         old_embed_data_list = NULL;
  93.         
  94.         if (old_count == 0)        /* Allocate new array */
  95.         {
  96.             embed_list->embed_data_list = PA_ALLOC(
  97.                 embed_list->embed_count * sizeof(lo_EmbedDataElement));
  98.         }
  99.         else                    /* Enlarge existing array */
  100.         {
  101.             old_embed_data_list = embed_list->embed_data_list;
  102.             embed_list->embed_data_list = PA_REALLOC(
  103.                 embed_list->embed_data_list,
  104.                 (embed_list->embed_count * sizeof(lo_EmbedDataElement)));
  105.         }
  106.         
  107.         /*
  108.          * If we ran out of memory to grow the array.
  109.          */
  110.         if (embed_list->embed_data_list == NULL)
  111.         {
  112.             embed_list->embed_data_list = old_embed_data_list;
  113.             embed_list->embed_count = old_count;
  114.             state->top_state->out_of_memory = TRUE;
  115.             return;
  116.         }
  117.         
  118.         /*
  119.          * We enlarged the array, so make sure
  120.          * the new slots are zero-filled.
  121.          */
  122.         PA_LOCK(embed_data_list, lo_EmbedDataElement*, embed_list->embed_data_list);
  123.         while (old_count < embed_list->embed_count)
  124.         {
  125.             embed_data_list[old_count].data = NULL;
  126.             embed_data_list[old_count].freeProc = NULL;
  127.             old_count++;
  128.         }
  129.         PA_UNLOCK(embed_list->embed_data_list);
  130.     }
  131.  
  132.     /*
  133.      * Store the new data into the list.
  134.      */
  135.     PA_LOCK(embed_data_list, lo_EmbedDataElement*, embed_list->embed_data_list);
  136.     embed_data_list[indx].data = session_data;
  137.     embed_data_list[indx].freeProc = freeProc;
  138.     PA_UNLOCK(embed_list->embed_data_list);
  139. }
  140.  
  141.  
  142. void
  143. LO_ClearEmbedBlock(MWContext *context, LO_EmbedStruct *embed)
  144. {
  145.     int32 doc_id;
  146.     lo_TopState *top_state;
  147.     lo_DocState *main_doc_state;
  148.     lo_DocState *state;
  149.  
  150.     /*
  151.      * Get the unique document ID, and retreive this
  152.      * documents layout state.
  153.      */
  154.     doc_id = XP_DOCID(context);
  155.     top_state = lo_FetchTopState(doc_id);
  156.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  157.     {
  158.         return;
  159.     }
  160.  
  161.     if (top_state->layout_blocking_element == (LO_Element *)embed)
  162.     {
  163.         if (embed->width == 0)
  164.         {
  165.             embed->width = EMBED_DEF_DIM;
  166.         }
  167.         if (embed->height == 0)
  168.         {
  169.             embed->height = EMBED_DEF_DIM;
  170.         }
  171.  
  172.         main_doc_state = top_state->doc_state;
  173.         state = lo_CurrentSubState(main_doc_state);
  174.  
  175.         lo_FinishEmbed(context, state, embed);
  176.         lo_FlushBlockage(context, state, main_doc_state);
  177.     }
  178. }
  179.  
  180.  
  181. void
  182. lo_FormatEmbed(MWContext *context, lo_DocState *state, PA_Tag *tag)
  183. {
  184.     LO_EmbedStruct *embed;
  185.     
  186. #ifdef    ANTHRAX
  187.     LO_ObjectStruct* object;
  188.     PA_Block buff;
  189.     NET_cinfo* fileInfo;
  190.     char* str;
  191.     char* appletName;
  192.     uint32 src_len;
  193.     
  194.     /* check to see if the type maps to an applet */
  195.     buff = lo_FetchParamValue(context, tag, PARAM_TYPE);
  196.     if(buff == NULL)
  197.         {
  198.         /* get SRC */
  199.         buff = lo_FetchParamValue(context, tag, PARAM_SRC);
  200.         PA_LOCK(str, char *, buff);
  201.         
  202.         /* if we didn't find a type param, look for an association in the SRC */
  203.         fileInfo = NET_cinfo_find_type(str);
  204.         str = fileInfo->type;
  205.         }
  206.     else
  207.         PA_LOCK(str, char *, buff);
  208.     
  209.     /* check to see if this mimetype has an applet handler */
  210.     if((appletName = NPL_FindAppletEnabledForMimetype(str)) != NULL)
  211.         {
  212.         PA_UNLOCK(buff);
  213.         if(buff)
  214.             XP_FREE(buff);
  215.  
  216.         /* just pass it to our object handler */
  217.         lo_FormatObject(context, state, tag);
  218.         
  219.         /* manually close the java app - this is normally done in lo_ProcessObjectTag */
  220.         lo_CloseJavaApp(context, state, state->current_java);
  221.         
  222.         XP_FREE(appletName);
  223.         }
  224.     else
  225.         {
  226.         PA_UNLOCK(buff);
  227.         if(buff)
  228.             XP_FREE(buff);
  229. #endif    /* ANTHRAX */
  230.  
  231.         embed = (LO_EmbedStruct *)lo_NewElement(context, state, LO_EMBED, NULL, 0);
  232.         if (embed == NULL)
  233.         {
  234.             return;
  235.         }
  236.  
  237.         embed->type = LO_EMBED;
  238.         embed->ele_id = NEXT_ELEMENT;
  239.         embed->x = state->x;
  240.         embed->x_offset = 0;
  241.         embed->y = state->y;
  242.         embed->y_offset = 0;
  243.         embed->width = 0;
  244.         embed->height = 0;
  245.         embed->next = NULL;
  246.         embed->prev = NULL;
  247.         embed->attribute_cnt = 0;
  248.         embed->attribute_list = NULL;
  249.         embed->value_list = NULL;
  250.  
  251.         embed->attribute_cnt = PA_FetchAllNameValues(tag,
  252.             &(embed->attribute_list), &(embed->value_list), CS_FE_ASCII);
  253.  
  254.         lo_FormatEmbedInternal(context, state, tag, embed, FALSE, FALSE);
  255. #ifdef    ANTHRAX
  256.         }
  257. #endif /* ANTHRAX */
  258. }
  259.  
  260.  
  261.  
  262. void
  263. lo_FormatEmbedObject(MWContext* context, lo_DocState* state,
  264.                      PA_Tag* tag , LO_EmbedStruct* embed, Bool streamStarted,
  265.                      uint32 param_count, char** param_names, char** param_values)
  266. {
  267.     uint32 count;
  268.     int32 typeIndex = -1;
  269.     int32 classidIndex = -1;
  270.  
  271.     embed->attribute_cnt = 0;
  272.     embed->attribute_list = NULL;
  273.     embed->value_list = NULL;
  274.  
  275.     embed->attribute_cnt = PA_FetchAllNameValues(tag,
  276.         &(embed->attribute_list), &(embed->value_list), CS_FE_ASCII);
  277.  
  278.  
  279.     /*
  280.      * Look through the parameters and replace "id"
  281.      * with "name" and "data" with "src", so that 
  282.      * other code that looks up parameters by name
  283.      * can believe this is a normal EMBED.
  284.      */
  285.     for (count = 0; count < (uint32)embed->attribute_cnt; count++)
  286.     {
  287.         if (XP_STRCASECMP(embed->attribute_list[count], PARAM_ID) == 0)
  288.             StrAllocCopy(embed->attribute_list[count], PARAM_NAME);
  289.         else if (XP_STRCASECMP(embed->attribute_list[count], PARAM_DATA) == 0)
  290.             StrAllocCopy(embed->attribute_list[count], "src");
  291.         else if (XP_STRCASECMP(embed->attribute_list[count], PARAM_TYPE) == 0)
  292.             typeIndex = count;
  293.         else if (XP_STRCASECMP(embed->attribute_list[count], PARAM_CLASSID) == 0)
  294.             classidIndex = count;
  295.     }
  296.     
  297.     /*
  298.      * If we have a CLASSID attribute, add the appropriate
  299.      * TYPE attribute.
  300.      */
  301.     if (classidIndex >= 0)
  302.     {
  303.         if (typeIndex >= 0)
  304.         {
  305.             /* Change current value of TYPE to application/oleobject */
  306.             if (XP_STRCASECMP(embed->value_list[typeIndex], APPLICATION_OLEOBJECT) != 0)
  307.                 StrAllocCopy(embed->value_list[typeIndex], APPLICATION_OLEOBJECT);
  308.         }
  309.         else
  310.         {
  311.             /* Add TYPE=application/oleobject to the attribute list */
  312.             char* names[1];
  313.             char* values[1];
  314.             names[0] = XP_STRDUP(PARAM_TYPE);
  315.             values[0] = XP_STRDUP(APPLICATION_OLEOBJECT);
  316.             
  317.             lo_AppendParamList((uint32*) &(embed->attribute_cnt),
  318.                                &(embed->attribute_list),
  319.                                &(embed->value_list),
  320.                                1, names, values);
  321.         }
  322.         
  323.         /* Lop off the "clsid:" prefix from the CLASSID attribute */
  324.         if (XP_STRNCASECMP(embed->value_list[classidIndex], "clsid:", 6) == 0)
  325.         {
  326.             char* classID = &(embed->value_list[classidIndex][6]);
  327.             XP_MEMMOVE(embed->value_list[classidIndex], classID,
  328.                        (XP_STRLEN(classID) + 1) * sizeof(char));
  329.         }
  330.     }
  331.  
  332.     /*
  333.      * Merge any parameters passed in with the ones in this tag.
  334.      * Separate the merged <PARAM> tag attributes from the
  335.      * <OBJECT> tag attributes with an extra "PARAM" attribute.
  336.      */
  337.     if (param_count > 0)
  338.     {
  339.         char* names[1];
  340.         char* values[1];
  341.         names[0] = XP_STRDUP(PT_PARAM);
  342.         values[0] = NULL;
  343.         
  344.         /* Add "PARAM" to the list */
  345.         lo_AppendParamList((uint32*) &(embed->attribute_cnt),
  346.                            &(embed->attribute_list),
  347.                            &(embed->value_list),
  348.                            1, names, values);
  349.  
  350.         /* Add all <PARAM> tag paramters to the list */
  351.         lo_AppendParamList((uint32*) &(embed->attribute_cnt),
  352.                            &(embed->attribute_list),
  353.                            &(embed->value_list),
  354.                            param_count,
  355.                            param_names,
  356.                            param_values);
  357.             
  358.         if (param_names != NULL)
  359.             XP_FREE(param_names);
  360.         if (param_values != NULL)
  361.             XP_FREE(param_values);
  362.     }
  363.  
  364.     lo_FormatEmbedInternal(context, state, tag, embed, TRUE, streamStarted);
  365. }
  366.  
  367.  
  368. static void
  369. lo_FormatEmbedInternal(MWContext *context, lo_DocState *state, PA_Tag *tag,
  370.                           LO_EmbedStruct *embed, Bool isObject, Bool streamStarted)
  371. {
  372.     PA_Block buff;
  373.     char *str;
  374.     int32 val;
  375.     int32 doc_width;
  376.     XP_Bool widthSpecified = FALSE;
  377.     XP_Bool heightSpecified = FALSE;
  378.     lo_DocLists *doc_lists;
  379.  
  380.     embed->nextEmbed= NULL;
  381. #ifdef MOCHA
  382.     embed->mocha_object = NULL;
  383. #endif
  384.  
  385.     embed->FE_Data = NULL;
  386.     embed->session_data = NULL;
  387.     embed->line_height = state->line_height;
  388.     embed->embed_src = NULL;
  389.     embed->alignment = LO_ALIGN_BASELINE;
  390.     embed->border_width = EMBED_DEF_BORDER;
  391.     embed->border_vert_space = EMBED_DEF_VERTICAL_SPACE;
  392.     embed->border_horiz_space = EMBED_DEF_HORIZONTAL_SPACE;
  393.     embed->tag = tag;
  394.     embed->ele_attrmask = 0;
  395.  
  396.     if (streamStarted)
  397.         embed->ele_attrmask |= LO_ELE_STREAM_STARTED;
  398.  
  399.     /*
  400.      * Convert any javascript in the values
  401.      */
  402.     lo_ConvertAllValues(context, embed->value_list, embed->attribute_cnt,
  403.                         tag->newline_count);
  404.  
  405.     /* don't double-count loading plugins due to table relayout */
  406.     if (!state->in_relayout)
  407.     {
  408.         state->top_state->mocha_loading_embeds_count++;
  409.     }
  410.  
  411.     /*
  412.      * Assign a unique index for this object 
  413.      * and increment the master index.
  414.      */
  415.     embed->embed_index = state->top_state->embed_count++;
  416.  
  417.     /*
  418.      * Check for the hidden attribute value.
  419.      * HIDDEN embeds have no visible part.
  420.      */
  421.     if (!isObject)        /* OBJECT tag can't have "hidden" attribute */
  422.     {
  423.         buff = lo_FetchParamValue(context, tag, PARAM_HIDDEN);
  424.         if (buff != NULL)
  425.         {
  426.             Bool hidden;
  427.  
  428.             hidden = TRUE;
  429.             PA_LOCK(str, char *, buff);
  430.             if (pa_TagEqual("no", str))
  431.             {
  432.                 hidden = FALSE;
  433.             }
  434.             else if (pa_TagEqual("false", str))
  435.             {
  436.                 hidden = FALSE;
  437.             }
  438.             else if (pa_TagEqual("off", str))
  439.             {
  440.                 hidden = FALSE;
  441.             }
  442.             PA_UNLOCK(buff);
  443.             PA_FREE(buff);
  444.  
  445.             if (hidden != FALSE)
  446.             {
  447.                 embed->ele_attrmask |= LO_ELE_HIDDEN;
  448.                 /* marcb says:  had to disable the printed hidden audio feature   */
  449.                 if (context->type==MWContextPrint){
  450.                     return;
  451.                 }
  452.  
  453.             }
  454.         }
  455.     }
  456.     
  457.     /*
  458.      * Check for an align parameter
  459.      */
  460.     buff = lo_FetchParamValue(context, tag, PARAM_ALIGN);
  461.     if (buff != NULL)
  462.     {
  463.         Bool floating;
  464.  
  465.         floating = FALSE;
  466.         PA_LOCK(str, char *, buff);
  467.         embed->alignment = lo_EvalAlignParam(str, &floating);
  468.         if (floating != FALSE)
  469.         {
  470.             embed->ele_attrmask |= LO_ELE_FLOATING;
  471.         }
  472.         PA_UNLOCK(buff);
  473.         PA_FREE(buff);
  474.     }
  475.  
  476.     /*
  477.      * Get the optional src parameter.
  478.      */
  479.     if (isObject)
  480.         buff = lo_FetchParamValue(context, tag, PARAM_DATA);
  481.     else
  482.         buff = lo_FetchParamValue(context, tag, PARAM_SRC);
  483.     if (buff != NULL)
  484.     {
  485.         PA_Block new_buff;
  486.         char *new_str;
  487.         int32 len;
  488.  
  489.         len = 1;
  490.         PA_LOCK(str, char *, buff);
  491.         if (str != NULL)
  492.         {
  493.  
  494.             len = lo_StripTextWhitespace(str, XP_STRLEN(str));
  495.         }
  496.         if (str != NULL)
  497.         {
  498.             /* bing: make sure this deals with "data:" URLs */
  499.             new_str = NET_MakeAbsoluteURL(
  500.                 state->top_state->base_url, str);
  501.         }
  502.         else
  503.         {
  504.             new_str = NULL;
  505.         }
  506.  
  507.         if ((new_str == NULL)||(len == 0))
  508.         {
  509.             new_buff = NULL;
  510.         }
  511.         else
  512.         {
  513.             char *enbed_src;
  514.  
  515.             new_buff = PA_ALLOC(XP_STRLEN(new_str) + 1);
  516.             if (new_buff != NULL)
  517.             {
  518.                 PA_LOCK(enbed_src, char *, new_buff);
  519.                 XP_STRCPY(enbed_src, new_str);
  520.                 PA_UNLOCK(new_buff);
  521.             }
  522.             else
  523.             {
  524.                 state->top_state->out_of_memory = TRUE;
  525.             }
  526.             XP_FREE(new_str);
  527.         }
  528.         PA_UNLOCK(buff);
  529.         PA_FREE(buff);
  530.         buff = new_buff;
  531.     }
  532.     embed->embed_src = buff;
  533.  
  534.     doc_width = state->right_margin - state->left_margin;
  535.  
  536.     /*
  537.      * Get the width parameter, in absolute or percentage.
  538.      * If percentage, make it absolute.  If the height is
  539.      * zero, make the embed hidden so the FE knows that the
  540.      * size really is zero (zero size normally means that
  541.      * we're blocking).
  542.      */
  543.     buff = lo_FetchParamValue(context, tag, PARAM_WIDTH);
  544.     if (buff != NULL)
  545.     {
  546.         Bool is_percent;
  547.  
  548.         PA_LOCK(str, char *, buff);
  549.         val = lo_ValueOrPercent(str, &is_percent);
  550.         if (is_percent != FALSE)
  551.         {
  552.             embed->percent_width = val;
  553.         }
  554.         else
  555.         {
  556.             embed->percent_width = 0;
  557.             embed->width = val;
  558.             val = FEUNITS_X(val, context);
  559.         }
  560.         PA_UNLOCK(buff);
  561.         PA_FREE(buff);
  562.         widthSpecified = TRUE;
  563.     }
  564.     val = LO_GetWidthFromStyleSheet(context, state);
  565.     if(val)
  566.       {
  567.         embed->width = val;
  568.         embed->percent_width = 0;
  569.         widthSpecified = TRUE;
  570.       }
  571.  
  572.     /*
  573.      * Get the height parameter, in absolute or percentage.
  574.      * If percentage, make it absolute.  If the height is
  575.      * zero, make the embed hidden so the FE knows that the
  576.      * size really is zero (zero size normally means that
  577.      * we're blocking).
  578.      */
  579.     buff = lo_FetchParamValue(context, tag, PARAM_HEIGHT);
  580.     if (buff != NULL)
  581.     {
  582.         Bool is_percent;
  583.  
  584.         PA_LOCK(str, char *, buff);
  585.         val = lo_ValueOrPercent(str, &is_percent);
  586.         if (is_percent != FALSE)
  587.         {
  588.             embed->percent_height = val;
  589.         }
  590.         else
  591.         {
  592.             embed->percent_height = 0;
  593.             val = FEUNITS_Y(val, context);
  594.         }
  595.         embed->height = val;
  596.         PA_UNLOCK(buff);
  597.         PA_FREE(buff);
  598.         heightSpecified = TRUE;
  599.     }
  600.  
  601.     val = LO_GetHeightFromStyleSheet(context, state);
  602.     if(val)
  603.       {
  604.         embed->height = val;
  605.         embed->percent_height = 0;
  606.         heightSpecified = TRUE;
  607.       }
  608.  
  609. #ifndef XP_WIN
  610.     /*
  611.      * If they forgot to specify a width or height, make one up.
  612.      * Don't do this for Windows, because they want to block
  613.      * layout for unsized OLE objects.  (Eventually all FEs will
  614.      * want to support this behavior when there's a plug-in API
  615.      * to specify the desired size of the object.)
  616.      */
  617.     if (!widthSpecified)
  618.     {
  619.         if (heightSpecified)
  620.             embed->width = embed->height;
  621.         else
  622.             embed->width = EMBED_DEF_DIM;
  623.     }
  624.     
  625.     if (!heightSpecified)
  626.     {
  627.         if (widthSpecified)
  628.             embed->height = embed->width;
  629.         else
  630.             embed->height = EMBED_DEF_DIM;
  631.     }
  632. #endif /* ifndef XP_WIN */
  633.  
  634.     lo_FillInEmbedGeometry(state, embed, FALSE);
  635.  
  636.     /*
  637.      * Get the extra vertical space parameter.
  638.      */
  639.     buff = lo_FetchParamValue(context, tag, PARAM_VSPACE);
  640.     if (buff != NULL)
  641.     {
  642.         PA_LOCK(str, char *, buff);
  643.         val = XP_ATOI(str);
  644.         if (val < 0)
  645.         {
  646.             val = 0;
  647.         }
  648.         embed->border_vert_space = val;
  649.         PA_UNLOCK(buff);
  650.         PA_FREE(buff);
  651.     }
  652.     embed->border_vert_space = FEUNITS_Y(embed->border_vert_space, context);
  653.  
  654.     /*
  655.      * Get the extra horizontal space parameter.
  656.      */
  657.     buff = lo_FetchParamValue(context, tag, PARAM_HSPACE);
  658.     if (buff != NULL)
  659.     {
  660.         PA_LOCK(str, char *, buff);
  661.         val = XP_ATOI(str);
  662.         if (val < 0)
  663.         {
  664.             val = 0;
  665.         }
  666.         embed->border_horiz_space = val;
  667.         PA_UNLOCK(buff);
  668.         PA_FREE(buff);
  669.     }
  670.     embed->border_horiz_space = FEUNITS_X(embed->border_horiz_space,
  671.                         context);
  672.  
  673.     /*
  674.      * See if we have some saved embed session data to restore.
  675.      */
  676.     if (state->top_state->savedData.EmbedList != NULL)
  677.     {
  678.         lo_SavedEmbedListData *embed_list;
  679.         embed_list = state->top_state->savedData.EmbedList;
  680.  
  681.         /*
  682.          * If there is still valid data to restore available.
  683.          */
  684.         if (embed->embed_index < embed_list->embed_count)
  685.         {
  686.             lo_EmbedDataElement* embed_data_list;
  687.  
  688.             PA_LOCK(embed_data_list, lo_EmbedDataElement*,
  689.                 embed_list->embed_data_list);
  690.             embed->session_data =
  691.                 embed_data_list[embed->embed_index].data;
  692.             PA_UNLOCK(embed_list->embed_data_list);
  693.         }
  694.     }
  695.  
  696.     /*
  697.      * Put the embed onto the embed list for later
  698.      * possible reflection.
  699.      */
  700.     doc_lists = lo_GetCurrentDocLists(state);
  701.     if (state->in_relayout) {
  702.         int32 i, count;
  703.         LO_EmbedStruct *prev_embed, *cur_embed;
  704.         
  705.         /*
  706.          * In the interest of changing as little as possible, I'm not
  707.          * going to change the embed_list to be in the order of layout
  708.          * (it is currently in reverse order). Instead, we do what 
  709.          * everybody else does - iterate till the end of the list to get
  710.          * find an element with the correct index.
  711.          * If we're in table relayout, we need to replace the element
  712.          * of the same index in this list with the new layout element
  713.          * to prevent multiple reflection.
  714.          */
  715.         count = 0;
  716.         cur_embed = doc_lists->embed_list;
  717.         while (cur_embed) {
  718.             cur_embed = cur_embed->nextEmbed;
  719.             count++;
  720.         }
  721.         
  722.         /* reverse order... */
  723.         prev_embed = NULL;
  724.         cur_embed = doc_lists->embed_list;
  725.         for (i = count-1; i >= 0; i--) {
  726.             if (i == doc_lists->embed_list_count) {
  727.                 /* Copy over the mocha object (it might not exist) */
  728.                 embed->mocha_object = cur_embed->mocha_object;
  729.  
  730.                 embed->nextEmbed = cur_embed->nextEmbed;
  731.                 
  732.                 /* Replace the old embed with the new one */
  733.                 if (prev_embed == NULL)
  734.                     doc_lists->embed_list = embed;
  735.                 else
  736.                     prev_embed->nextEmbed = embed;
  737.                 doc_lists->embed_list_count++;
  738.                 break;
  739.             }
  740.             prev_embed = cur_embed;
  741.             cur_embed = cur_embed->nextEmbed;
  742.         }
  743.     }
  744.     else {
  745.         embed->nextEmbed = doc_lists->embed_list;
  746.         doc_lists->embed_list = embed;
  747.         doc_lists->embed_list_count++;
  748.     }
  749.  
  750.     /*
  751.      * Plug-ins won't be happy if we use a special colormap.
  752.      */
  753. #ifndef M12N                    /* XXXM12N Fix me, this has gone away. Sets
  754.                                    cx->colorSpace->install_colormap_forbidden*/
  755.     IL_UseDefaultColormapThisPage(context);
  756. #endif /* M12N */
  757.  
  758.     /* Create an initially hidden layer for this plugin to inhabit.  If the plugin is 
  759.        a windowless plugin, this will later become a "normal" layer.  If the plugin is
  760.        a windowed plugin, the layer will become a cutout layer. */
  761.     embed->layer =
  762.       lo_CreateEmbeddedObjectLayer(context, state, (LO_Element*)embed);
  763.  
  764.     /*
  765.      * Have the front end fetch this embed data, and tell us
  766.      * the embed's dimensions if it knows them.
  767.      */
  768.     FE_GetEmbedSize(context, embed, state->top_state->force_reload);
  769.  
  770.     /*
  771.      * Hidden embeds always have 0 width and height
  772.      */
  773.     if (embed->ele_attrmask & LO_ELE_HIDDEN)
  774.     {
  775.         embed->width = 0;
  776.         embed->height = 0;
  777.     }
  778.  
  779.     /*
  780.      * We may have to block on this embed until later
  781.      * when the front end can give us the width and height.
  782.      * Never block on hidden embeds.
  783.      */
  784.     if (((embed->width == 0)||(embed->height == 0))&&
  785.         ((embed->ele_attrmask & LO_ELE_HIDDEN) == 0))
  786.     {
  787.         state->top_state->layout_blocking_element = (LO_Element *)embed;
  788.     }
  789.     else
  790.     {
  791.         lo_FinishEmbed(context, state, embed);
  792.     }
  793. }
  794.  
  795.  
  796. void
  797. lo_FinishEmbed(MWContext *context, lo_DocState *state, LO_EmbedStruct *embed)
  798. {
  799.     int32 baseline_inc;
  800.     int32 line_inc;
  801.     int32 embed_height, embed_width;
  802.  
  803.     /*
  804.      * Eventually this will never happen since we always
  805.      * have dims here from either the embed tag itself or the
  806.      * front end.
  807.      * Hidden embeds are supposed to have 0 width and height.
  808.      */
  809.     if ((embed->ele_attrmask & LO_ELE_HIDDEN) == 0)
  810.     {
  811.         if (embed->width == 0)
  812.         {
  813.             embed->width = EMBED_DEF_DIM;
  814.         }
  815.         if (embed->height == 0)
  816.         {
  817.             embed->height = EMBED_DEF_DIM;
  818.         }
  819.     }
  820.  
  821.     embed_width = embed->width + (2 * embed->border_width) +
  822.         (2 * embed->border_horiz_space);
  823.     embed_height = embed->height + (2 * embed->border_width) +
  824.         (2 * embed->border_vert_space);
  825.  
  826.     /*
  827.      * SEVERE FLOW BREAK!  This may be a floating embed,
  828.      * which means at this point we go do something completely
  829.      * different.
  830.      */
  831.     if (embed->ele_attrmask & LO_ELE_FLOATING)
  832.     {
  833.  
  834.         embed->x_offset += (int16)embed->border_horiz_space;
  835.         embed->y_offset += (int32)embed->border_vert_space;
  836.  
  837.  
  838.         /*
  839.          * Insert this element into the float list.
  840.          */
  841.         embed->next = state->float_list;
  842.         state->float_list = (LO_Element *)embed;
  843.  
  844.         lo_AppendFloatInLineList(state, (LO_Element*)embed, NULL);
  845.  
  846.         lo_LayoutFloatEmbed(context, state, embed, TRUE);
  847.  
  848.     }
  849.     else
  850.     {
  851.  
  852.         /*
  853.          * Figure out how to align this embed.
  854.          * baseline_inc is how much to increase the baseline
  855.          * of previous element of this line.  line_inc is how
  856.          * much to increase the line height below the baseline.
  857.          */
  858.         baseline_inc = 0;
  859.         line_inc = 0;
  860.         /*
  861.          * If we are at the beginning of a line, with no baseline,
  862.          * we first set baseline and line_height based on the current
  863.          * font, then place the embed.
  864.          */
  865.         if (state->baseline == 0)
  866.         {
  867.             state->baseline = 0;
  868.         }
  869.  
  870.  
  871.         embed->x_offset += (int16)embed->border_horiz_space;
  872.         embed->y_offset += (int32)embed->border_vert_space;
  873.  
  874.         lo_LayoutInflowEmbed(context, state, embed, FALSE, &line_inc, &baseline_inc);
  875.  
  876.         lo_AppendToLineList(context, state,
  877.             (LO_Element *)embed, baseline_inc);
  878.  
  879.         lo_UpdateStateAfterEmbedLayout(state, embed, line_inc, baseline_inc);
  880.  
  881.     }
  882. }
  883.  
  884. void
  885. lo_RelayoutEmbed ( MWContext *context, lo_DocState *state, LO_EmbedStruct * embed, PA_Tag * tag )
  886. {
  887.     lo_DocLists *doc_lists;
  888.  
  889.     lo_PreLayoutTag ( context, state, tag );
  890.     if (state->top_state->out_of_memory)
  891.     {
  892.         return;
  893.     }
  894.  
  895.     LO_LockLayout();
  896.     
  897.     /*
  898.      * Fill in the embed structure with default data
  899.      */
  900.     embed->type = LO_EMBED;
  901.     embed->ele_id = NEXT_ELEMENT;
  902.     embed->x = state->x;
  903.     embed->x_offset = 0;
  904.     embed->y = state->y;
  905.     embed->y_offset = 0;
  906.     embed->next = NULL;
  907.     embed->prev = NULL;
  908.  
  909.     embed->line_height = state->line_height;
  910.  
  911.     /*
  912.      * Assign a unique index for this object 
  913.      * and increment the master index.
  914.      */
  915.     embed->embed_index = state->top_state->embed_count++;
  916.  
  917.     /*
  918.      * Since we saved the embed_list_count during table relayout,
  919.      * we increment it as if we were reprocessing the EMBED tag.
  920.      */
  921.     doc_lists = lo_GetCurrentDocLists(state);
  922.     doc_lists->embed_list_count++;
  923.  
  924.     /*
  925.      * Plug-ins won't be happy if we use a special colormap.
  926.      */
  927. #ifndef M12N                    /* XXXM12N Fix me, this has gone away. Sets
  928.                                    cx->colorSpace->install_colormap_forbidden*/
  929.     IL_UseDefaultColormapThisPage(context);
  930. #endif /* M12N */
  931.  
  932.     /*
  933.      * I don't think we need to worry about blocking at all since we're in
  934.      * relayout, but I'd rather be safe.
  935.      */
  936.     if (((embed->width == 0)||(embed->height == 0))&&
  937.         ((embed->ele_attrmask & LO_ELE_HIDDEN) == 0))
  938.     {
  939.         state->top_state->layout_blocking_element = (LO_Element *)embed;
  940.     }
  941.     else
  942.     {
  943.         lo_FinishEmbed(context, state, embed);
  944.     }
  945.  
  946.     lo_PostLayoutTag ( context, state, tag, FALSE );
  947.     LO_UnlockLayout();
  948. }
  949.  
  950. void
  951. LO_CopySavedEmbedData(MWContext *context, SHIST_SavedData *saved_data)
  952. {
  953.     int32 doc_id;
  954.     lo_TopState *top_state;
  955.     lo_DocState *state;
  956.     lo_SavedEmbedListData *embed_list, *new_embed_list;
  957.     lo_EmbedDataElement *embed_data_list, *new_embed_data_list;
  958.     PA_Block old_embed_data_list = NULL;
  959.     int32 old_count = 0;
  960.     int32 index;
  961.  
  962.     /*
  963.      * Get the state, so we can access the savedEmbedListData
  964.      * list for this document.
  965.      */
  966.     doc_id = XP_DOCID(context);
  967.     top_state = lo_FetchTopState(doc_id);
  968.     if ((top_state != NULL)&&(top_state->doc_state != NULL))
  969.         state = top_state->doc_state;
  970.     else
  971.         return;
  972.  
  973.     embed_list = state->top_state->savedData.EmbedList;
  974.     if (embed_list == NULL || embed_list->embed_data_list == NULL)
  975.         return;
  976.         
  977.     
  978.     PA_LOCK(embed_data_list, lo_EmbedDataElement*, embed_list->embed_data_list);
  979.  
  980.     if (saved_data->EmbedList == NULL)
  981.         saved_data->EmbedList = XP_NEW_ZAP(lo_SavedEmbedListData);
  982.     new_embed_list = saved_data->EmbedList;
  983.     
  984.     if (new_embed_list->embed_data_list == NULL)
  985.     {
  986.         /* Allocate new array */
  987.         new_embed_list->embed_data_list = PA_ALLOC(
  988.             embed_list->embed_count * sizeof(lo_EmbedDataElement));
  989.     }
  990.     else if (new_embed_list->embed_count < embed_list->embed_count)
  991.     {    
  992.         /* Enlarge existing array */
  993.         old_embed_data_list = new_embed_list->embed_data_list;
  994.         old_count = new_embed_list->embed_count;
  995.         new_embed_list->embed_data_list = PA_REALLOC(
  996.             new_embed_list->embed_data_list,
  997.             (embed_list->embed_count * sizeof(lo_EmbedDataElement)));
  998.     }
  999.  
  1000.     /*
  1001.      * If we ran out of memory to grow the array.
  1002.      */
  1003.     if (new_embed_list->embed_data_list == NULL)
  1004.     {
  1005.         new_embed_list->embed_data_list = old_embed_data_list;
  1006.         new_embed_list->embed_count = old_count;
  1007.         state->top_state->out_of_memory = TRUE;
  1008.         return;
  1009.     }
  1010.     
  1011.     /*
  1012.      * Copy all the elements from the old array to the new one.
  1013.      */
  1014.     PA_LOCK(new_embed_data_list, lo_EmbedDataElement*, new_embed_list->embed_data_list);
  1015.     for (index = 0; index < embed_list->embed_count; index++)
  1016.         new_embed_data_list[index] = embed_data_list[index];
  1017.     new_embed_list->embed_count = embed_list->embed_count;
  1018.     PA_UNLOCK(new_embed_list->embed_data_list);
  1019.     
  1020.     PA_UNLOCK(embed_list->embed_data_list);
  1021. }
  1022.  
  1023.  
  1024. void
  1025. LO_AddEmbedData(MWContext *context, LO_EmbedStruct* embed, void *session_data)
  1026. {
  1027.     lo_AddEmbedData(context, session_data, NPL_DeleteSessionData, embed->embed_index);
  1028. }
  1029.  
  1030.  
  1031. void
  1032. lo_FillInEmbedGeometry(lo_DocState *state,
  1033.                        LO_EmbedStruct *embed,
  1034.                        Bool relayout)
  1035. {
  1036.     int32 doc_width;
  1037.  
  1038.     if (relayout == TRUE)
  1039.     {
  1040.         embed->ele_id = NEXT_ELEMENT;
  1041.     }
  1042.     embed->x = state->x;
  1043.     embed->y = state->y;
  1044.  
  1045.     doc_width = state->right_margin - state->left_margin;
  1046.  
  1047.     /*
  1048.      * Get the width parameter, in absolute or percentage.
  1049.      * If percentage, make it absolute.
  1050.      */
  1051.  
  1052.     if (embed->percent_width > 0) {
  1053.         int32 val = embed->percent_width;
  1054.         if (state->allow_percent_width == FALSE) {
  1055.             val = 0;
  1056.         }
  1057.         else {
  1058.             val = doc_width * val / 100;
  1059.         }
  1060.         embed->width = val;
  1061.     }
  1062.  
  1063.     /* Set embed->height if embed has a % height specified */
  1064.     if (embed->percent_height > 0) {
  1065.         int32 val = embed->percent_height;
  1066.         if (state->allow_percent_height == FALSE) {
  1067.             val = 0;
  1068.         }
  1069.         else {
  1070.             val = state->win_height * val / 100;
  1071.         }
  1072.         embed->height = val;
  1073.     }
  1074. }
  1075.  
  1076. void
  1077. lo_LayoutInflowEmbed(MWContext *context,
  1078.                      lo_DocState *state,
  1079.                      LO_EmbedStruct *embed,
  1080.                      Bool inRelayout,
  1081.                      int32 *line_inc,
  1082.                      int32 *baseline_inc)
  1083. {
  1084.   int32 embed_width, embed_height;
  1085.   Bool line_break;
  1086.   PA_Block buff;
  1087.   char *str;
  1088.   LO_TextStruct tmp_text;
  1089.   LO_TextInfo text_info;
  1090.   lo_TopState *top_state;
  1091.   
  1092.   top_state = state->top_state;
  1093.   
  1094.   /*
  1095.    * All this work is to get the text_info filled in for the current
  1096.    * font in the font stack. Yuck, there must be a better way.
  1097.    */
  1098.   memset (&tmp_text, 0, sizeof (tmp_text));
  1099.   buff = PA_ALLOC(1);
  1100.   if (buff == NULL)
  1101.     {
  1102.       top_state->out_of_memory = TRUE;
  1103.       return;
  1104.     }
  1105.   PA_LOCK(str, char *, buff);
  1106.   str[0] = ' ';
  1107.   PA_UNLOCK(buff);
  1108.   tmp_text.text = buff;
  1109.   tmp_text.text_len = 1;
  1110.   tmp_text.text_attr =
  1111.     state->font_stack->text_attr;
  1112.   FE_GetTextInfo(context, &tmp_text, &text_info);
  1113.   PA_FREE(buff);
  1114.   
  1115.   embed_width = embed->width + (2 * embed->border_width) +
  1116.     (2 * embed->border_horiz_space);
  1117.   embed_height = embed->height + (2 * embed->border_width) +
  1118.     (2 * embed->border_vert_space);
  1119.   
  1120.   /*
  1121.    * Will this embed make the line too wide.
  1122.    */
  1123.   if ((state->x + embed_width) > state->right_margin)
  1124.     {
  1125.       line_break = TRUE;
  1126.     }
  1127.   else
  1128.     {
  1129.       line_break = FALSE;
  1130.     }
  1131.   
  1132.   /*
  1133.    * if we are at the beginning of the line.  There is
  1134.    * no point in breaking, we are just too wide.
  1135.    * Also don't break in unwrapped preformatted text.
  1136.    * Also can't break inside a NOBR section.
  1137.    */
  1138.   if ((state->at_begin_line != FALSE)||
  1139.       (state->preformatted == PRE_TEXT_YES)||
  1140.       (state->breakable == FALSE))
  1141.     {
  1142.       line_break = FALSE;
  1143.     }
  1144.   
  1145.   /*
  1146.    * break on the embed if we have
  1147.    * a break.
  1148.    */
  1149.   if (line_break != FALSE)
  1150.     {
  1151.       /*
  1152.        * We need to make the elements sequential, linefeed
  1153.        * before embed.
  1154.        */
  1155.         top_state->element_id = embed->ele_id;      
  1156.  
  1157.         if (!inRelayout)
  1158.         {
  1159.             lo_SoftLineBreak(context, state, TRUE);
  1160.         }
  1161.         else 
  1162.         {
  1163.             lo_rl_AddSoftBreakAndFlushLine(context, state);
  1164.         }
  1165.         embed->x = state->x;
  1166.         embed->y = state->y;
  1167.         embed->ele_id = NEXT_ELEMENT;
  1168.     }
  1169.  
  1170.   lo_CalcAlignOffsets(state, &text_info, (intn)embed->alignment,
  1171.                       embed_width, embed_height,
  1172.                       &embed->x_offset, &embed->y_offset, line_inc, baseline_inc);
  1173. }
  1174.  
  1175. void
  1176. lo_LayoutFloatEmbed(MWContext *context,
  1177.                     lo_DocState *state,
  1178.                     LO_EmbedStruct *embed,
  1179.                     Bool updateFE )
  1180. {
  1181.   int32 embed_width;
  1182.  
  1183.   embed_width = embed->width + (2 * embed->border_width) +
  1184.     (2 * embed->border_horiz_space);
  1185.   if (embed->alignment == LO_ALIGN_RIGHT)
  1186.     {
  1187.       if (state->right_margin_stack == NULL)
  1188.         {
  1189.           embed->x = state->right_margin - embed_width;
  1190.         }
  1191.       else
  1192.         {
  1193.           embed->x = state->right_margin_stack->margin -
  1194.             embed_width;
  1195.         }
  1196.       if (embed->x < 0)
  1197.         {
  1198.           embed->x = 0;
  1199.         }
  1200.     }
  1201.   else
  1202.     {
  1203.       embed->x = state->left_margin;
  1204.     }
  1205.   
  1206.   embed->y = -1;
  1207.  
  1208.   lo_AddMarginStack(state, embed->x, embed->y,
  1209.                     embed->width, embed->height,
  1210.                     embed->border_width,
  1211.                     embed->border_vert_space, embed->border_horiz_space,
  1212.                     (intn)embed->alignment);
  1213.   
  1214.   if (state->at_begin_line != FALSE)
  1215.     {
  1216.       lo_FindLineMargins(context, state, updateFE);
  1217.       state->x = state->left_margin;
  1218.     }
  1219. }
  1220.  
  1221. void
  1222. lo_UpdateStateAfterEmbedLayout(lo_DocState *state,
  1223.                                LO_EmbedStruct *embed,
  1224.                                int32 line_inc,
  1225.                                int32 baseline_inc )
  1226. {
  1227.   int32 embed_width;
  1228.   int32 x, y;
  1229.  
  1230.   embed_width = embed->width + (2 * embed->border_width) +
  1231.     (2 * embed->border_horiz_space);
  1232.  
  1233.   state->baseline += (intn) baseline_inc;
  1234.   state->line_height += (intn) (baseline_inc + line_inc);
  1235.   
  1236.   /*
  1237.    * Clean up state
  1238.    */
  1239.   state->x = state->x + embed->x_offset +
  1240.     embed_width - embed->border_horiz_space;
  1241.   state->linefeed_state = 0;
  1242.   state->at_begin_line = FALSE;
  1243.   state->trailing_space = FALSE;
  1244.   state->cur_ele_type = LO_EMBED;
  1245.  
  1246.   /* Determine the new position of the layer. */
  1247.   x = embed->x + embed->x_offset + embed->border_width;
  1248.   y = embed->y + embed->y_offset + embed->border_width;
  1249.   
  1250.   /* Move layer to new position */
  1251.   CL_MoveLayer(embed->layer, x, y);
  1252. }
  1253.  
  1254. void
  1255. LO_SetEmbedSize( MWContext *context, LO_EmbedStruct *embed, int32 width, int32 height )
  1256. {
  1257.     /* For now, just setting the embed's dimensions.  Do we need to lock/unlock layout here? */
  1258.     embed->width = width;
  1259.     embed->height = height;
  1260. }
  1261.