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

  1. /* -*- Mode: C++; tab-width: 8; 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.  * layimage.c - Image layout and fetching/prefetching
  21.  *
  22.  */
  23.  
  24. #include "xp.h"
  25. #include "net.h"
  26. #include "xp_rgb.h"
  27. #include "pa_parse.h"
  28. #include "layout.h"
  29. #include "laylayer.h"
  30. #include "laystyle.h"
  31. #include "secnav.h"
  32. #include "prefapi.h"
  33. #include "xlate.h"
  34. #include "layers.h"
  35.  
  36. extern int MK_OUT_OF_MEMORY;
  37.  
  38. #define IL_CLIENT               /* Defined by Image Library clients */
  39. #include "libimg.h"             /* Image Library public API. */
  40.  
  41. #ifdef MOCHA
  42. #include "libevent.h"
  43. #endif /* MOCHA */
  44.  
  45. #ifdef PROFILE
  46. #pragma profile on
  47. #endif
  48.  
  49. #define IMAGE_DEF_DIM            50
  50. #define IMAGE_DEF_BORDER        0
  51. #define IMAGE_DEF_ANCHOR_BORDER        2
  52. #define IMAGE_DEF_VERTICAL_SPACE    0
  53. #define IMAGE_DEF_HORIZONTAL_SPACE    0
  54. #define IMAGE_DEF_FLOAT_HORIZONTAL_SPACE    3
  55.  
  56. /* Closure data to be passed into lo_ImageObserver. */
  57. typedef struct lo_ImageObsClosure {
  58.     MWContext *context;
  59.     LO_ImageStruct *lo_image;
  60.     XP_ObserverList obs_list;
  61. } lo_ImageObsClosure;
  62.  
  63. extern LO_TextStruct *lo_AltTextElement(MWContext *context);
  64.  
  65. PUBLIC char *
  66. LO_GetBookmarkIconURLForPage(MWContext *context, BMIconType type)
  67. {
  68.     int32 doc_id;
  69.     lo_TopState *top_state;
  70.  
  71.     /*
  72.      * Get the unique document ID, and retreive this
  73.      * documents layout state.
  74.      */
  75.     doc_id = XP_DOCID(context);
  76.     top_state = lo_FetchTopState(doc_id);
  77.     if (!top_state)
  78.         return NULL;
  79.  
  80.     if(type == SMALL_BM_ICON)
  81.         return top_state->small_bm_icon;
  82.     else if(type == SMALL_BM_ICON)
  83.         return top_state->large_bm_icon;
  84.  
  85.     return NULL;
  86. }
  87.  
  88.  
  89. /* Primitive image allocator also sets defaults for image structure */
  90. static LO_ImageStruct *
  91. lo_new_image_element(MWContext *context, lo_DocState *state,
  92.                      void *edit_element, LO_TextAttr *tptr)
  93. {
  94.     LO_ImageStruct *image;
  95.     image = (LO_ImageStruct *)lo_NewElement(context, state, LO_IMAGE, edit_element, 0);
  96.     if (image == NULL)
  97.         return NULL;
  98.  
  99.     /*
  100.      * preserve the edit element and offset across the bzero.
  101.      * The edit_element and edit_offset were set in lo_NewElement.
  102.      */
  103.     {
  104.         void* save_edit_element = image->edit_element;
  105.         int32 save_edit_offset = image->edit_offset;
  106.         XP_BZERO(image, sizeof(*image));
  107.         image->edit_element = save_edit_element;
  108.         image->edit_offset = save_edit_offset;
  109.     }
  110.  
  111.     image->type = LO_IMAGE;
  112.  
  113.     /*
  114.      * Fill in default font information.
  115.      */
  116.     if (tptr == NULL)
  117.     {
  118.         LO_TextAttr tmp_attr;
  119.  
  120.         lo_SetDefaultFontAttr(state, &tmp_attr, context);
  121.         tptr = lo_FetchTextAttr(state, &tmp_attr);
  122.     }
  123.     image->text_attr = tptr;
  124.     image->image_attr = XP_NEW(LO_ImageAttr);
  125.     if (image->image_attr == NULL)
  126.     {    /* clean up all previously allocated objects */
  127.         lo_FreeElement(context, (LO_Element *)image, FALSE);
  128.         state->top_state->out_of_memory = TRUE;
  129.         return 0;
  130.     }
  131.  
  132.     image->image_attr->attrmask = 0;
  133.     image->image_attr->layer_id = LO_DOCUMENT_LAYER_ID;
  134.     image->image_attr->form_id = -1;
  135.     image->image_attr->alignment = LO_ALIGN_BASELINE;
  136.     image->image_attr->usemap_name = NULL;
  137.     image->image_attr->usemap_ptr = NULL;
  138.     
  139.     image->ele_attrmask = 0;
  140.  
  141.     image->sel_start = -1;
  142.     image->sel_end = -1;
  143.  
  144.     image->is_icon = FALSE;
  145.     image->image_status = IL_START_URL;
  146.     
  147.     return image; 
  148. }
  149.  
  150. PRIVATE
  151. Bool
  152. lo_parse_rgb(char *rgb, uint8 *red_ptr, uint8 *green_ptr, uint8 *blue_ptr, XP_Bool double_three_byte_codes)
  153. {
  154.     char *ptr;
  155.     int32 i, j, len;
  156.     int32 val, bval;
  157.     int32 red_val, green_val, blue_val;
  158.     intn bytes_per_val;
  159.  
  160.     *red_ptr = 0;
  161.     *green_ptr = 0;
  162.     *blue_ptr = 0;
  163.     red_val = 0;
  164.     green_val = 0;
  165.     blue_val = 0;
  166.  
  167.     if (rgb == NULL)
  168.     {
  169.         return FALSE;
  170.     }
  171.  
  172.     len = XP_STRLEN(rgb);
  173.     if (len == 0)
  174.     {
  175.         return FALSE;
  176.     }
  177.  
  178.     /*
  179.      * Strings not starting with a '#' are probably named colors.
  180.      * look them up in the xp lookup table.
  181.      */
  182.     ptr = rgb;
  183.     if (*ptr == '#')
  184.     {
  185.         ptr++;
  186.         len--;
  187.     }
  188.     else
  189.     {
  190.         /*
  191.          * If we successfully look up a color name, return its RGB.
  192.          */
  193.         if (XP_ColorNameToRGB(ptr, red_ptr, green_ptr, blue_ptr) == 0)
  194.         {
  195.             return TRUE;
  196.         }
  197.     }
  198.  
  199.     if (len == 0)
  200.     {
  201.         return FALSE;
  202.     }
  203.  
  204.     bytes_per_val = (intn)((len + 2) / 3);
  205.     if (bytes_per_val > 4)
  206.     {
  207.         bytes_per_val = 4;
  208.     }
  209.  
  210.     for (j=0; j<3; j++)
  211.     {
  212.         val = 0;
  213.         for (i=0; i<bytes_per_val; i++)
  214.         {
  215.             if (*ptr == '\0')
  216.             {
  217.                 bval = 0;
  218.             }
  219.             else
  220.             {
  221.                 bval = TOLOWER((unsigned char)*ptr);
  222.                 if ((bval >= '0')&&(bval <= '9'))
  223.                 {
  224.                     bval = bval - '0';
  225.                 }
  226.                 else if ((bval >= 'a')&&(bval <= 'f'))
  227.                 {
  228.                     bval = bval - 'a' + 10;
  229.                 }
  230.                 else
  231.                 {
  232.                     bval = 0;
  233.                 }
  234.                 ptr++;
  235.             }
  236.             val = (val << 4) + bval;
  237.         }
  238.         if (j == 0)
  239.         {
  240.             red_val = val;
  241.         }
  242.         else if (j == 1)
  243.         {
  244.             green_val = val;
  245.         }
  246.         else
  247.         {
  248.             blue_val = val;
  249.         }
  250.     }
  251.  
  252.     if(double_three_byte_codes && bytes_per_val == 1)
  253.     {
  254.         red_val = (red_val << 4) + red_val;
  255.         green_val = (green_val << 4) + green_val;
  256.         blue_val = (blue_val << 4) + blue_val;
  257.     }
  258.  
  259.     while ((red_val > 255)||(green_val > 255)||(blue_val > 255))
  260.     {
  261.         red_val = (red_val >> 4);
  262.         green_val = (green_val >> 4);
  263.         blue_val = (blue_val >> 4);
  264.     }
  265.     *red_ptr = (uint8)red_val;
  266.     *green_ptr = (uint8)green_val;
  267.     *blue_ptr = (uint8)blue_val;
  268.     return TRUE;
  269. }
  270.  
  271. Bool
  272. LO_ParseRGB(char *rgb, uint8 *red_ptr, uint8 *green_ptr, uint8 *blue_ptr)
  273. {
  274.     return lo_parse_rgb(rgb, red_ptr, green_ptr, blue_ptr, FALSE);
  275. }
  276.  
  277.  
  278. /* parse a comma separated list of 3 values
  279.  *
  280.  * Format is "rgb(red, green, blue)"
  281.  * color values can be in integer 1-255 or percent 1%-100%
  282.  * illegal values must be truncated 
  283.  *
  284.  * if there are fewer than three arguments this function will
  285.  * set colors for whatever number exist.
  286.  * if more than 3 args are passed in they will be ignored
  287.  */
  288. static Bool
  289. lo_parse_style_RGB_functional_notation(char *rgb, 
  290.              uint8 *red_ptr, 
  291.              uint8 *green_ptr, 
  292.              uint8 *blue_ptr)
  293. {
  294.     int index=0;
  295.     char *value, *end;
  296.     int num_value;
  297.  
  298.     rgb = XP_StripLine(rgb);
  299.  
  300.     /* go past rgb(  and remove the last ')' */
  301. #define _RGB "rgb"
  302.     if(!strncasecomp(rgb, _RGB, sizeof(_RGB)-1))
  303.     {
  304.         char *end;
  305.  
  306.         /* go past "RGB" */
  307.         rgb += sizeof(_RGB)-1;
  308.  
  309.         /* go past spaces */
  310.         while(XP_IS_SPACE(*rgb)) rgb++;
  311.  
  312.         /* go past '(' */
  313.         if(*rgb == '(')
  314.             rgb++;
  315.  
  316.         /* kill any more spaces */
  317.         while(XP_IS_SPACE(*rgb)) rgb++;
  318.  
  319.         end = &rgb[XP_STRLEN(rgb)-1];
  320.         if(*end == ')')
  321.             *end = '\0';
  322.     }
  323.  
  324.     value = XP_STRTOK(rgb, ",");
  325.  
  326.     while(value && index < 3)
  327.     {
  328.         XP_Bool is_percentage = FALSE;
  329.         int scaled_value;
  330.  
  331.         value = XP_StripLine(value);
  332.  
  333.         num_value = XP_ATOI(value);
  334.  
  335.         if(num_value < 0)
  336.             num_value = 0;
  337.  
  338.         end = &rgb[XP_STRLEN(rgb)-1];
  339.         if(*end == '%')
  340.         {
  341.             /* percentage value */
  342.  
  343.             if(num_value > 100)
  344.                 num_value = 100;
  345.  
  346.             scaled_value = (255 * num_value) / 100;
  347.             
  348.         }
  349.         else
  350.         {
  351.             if(num_value > 255)
  352.                 num_value = 255;
  353.  
  354.             scaled_value = num_value;
  355.         }
  356.  
  357.         if(index == 0)
  358.             *red_ptr = scaled_value;
  359.         else if(index == 1)
  360.             *green_ptr = scaled_value;
  361.         else if(index == 2)
  362.             *blue_ptr = scaled_value;
  363.  
  364.         index++;
  365.         value = XP_STRTOK(NULL, ",");
  366.     }
  367.  
  368.     if(index < 3)
  369.         return FALSE;
  370.     else
  371.         return TRUE;
  372. }
  373.  
  374. Bool
  375. LO_ParseStyleSheetRGB(char *rgb, uint8 *red_ptr, uint8 *green_ptr, uint8 *blue_ptr)
  376. {
  377.     /* can take the form of:
  378.      * #f00
  379.      * #ff0000
  380.      * or rgb(255, 0, 0)
  381.      * or rgb(100%, 0%, 0%)
  382.      * all are equivalent values
  383.      * need to truncate illegal values like 265 or 110%
  384.      */
  385.  
  386.     rgb = XP_StripLine(rgb);
  387.  
  388.     if(!strcasecomp(rgb, "transparent"))
  389.     {
  390.         *red_ptr = 0;
  391.         *green_ptr = 0;
  392.         *blue_ptr = 0;
  393.         return FALSE;
  394.     }
  395.     else if(!strncasecomp(rgb, _RGB, sizeof(_RGB)-1)) /* functional notation */
  396.     {
  397.         return lo_parse_style_RGB_functional_notation(rgb, 
  398.                                                       red_ptr,
  399.                                                       green_ptr,
  400.                                                       blue_ptr);
  401.     }
  402.     else /* assume #FF0000 or #F00 notation */
  403.     {
  404.         return lo_parse_rgb(rgb, red_ptr, green_ptr, blue_ptr, TRUE);
  405.     }
  406. }
  407.  
  408. /* 
  409.  * Parses the BACKGROUND attribute (if one exists) and returns a url.
  410.  * If there is no attribute specified, it returns NULL. For code sharing
  411.  * between tags that have a BACKGROUND attribute.
  412.  */
  413. char *
  414. lo_ParseBackgroundAttribute(MWContext *context, lo_DocState *state, 
  415.                             PA_Tag *tag, Bool from_user)
  416. {
  417.     PA_Block buff, image_url;
  418.     char *str;
  419.  
  420.     /*
  421.      * Get the required src parameter, and make the resulting
  422.      * url and absolute url.
  423.      */
  424.     buff = lo_FetchParamValue(context, tag, PARAM_BACKGROUND);
  425.     if (buff != NULL)
  426.     {
  427.         PA_Block new_buff;
  428.         char *new_str;
  429.  
  430.         PA_LOCK(str, char *, buff);
  431.         if (str != NULL)
  432.         {
  433.             int32 len;
  434.  
  435.             len = lo_StripTextWhitespace(str, XP_STRLEN(str));
  436.         }
  437.         /*
  438.          * Do not allow BACKGROUND=""
  439.          */
  440.         if ((str != NULL)&&(*str != '\0'))
  441.         {
  442.             new_str = NET_MakeAbsoluteURL(
  443.                     state->top_state->base_url, str);
  444.         }
  445.         else
  446.         {
  447.             new_str = NULL;
  448.         }
  449.         if (new_str == NULL)
  450.         {
  451.             new_buff = NULL;
  452.         }
  453.         else
  454.         {
  455.             char *url;
  456.  
  457.             new_buff = PA_ALLOC(XP_STRLEN(new_str) + 1);
  458.             if (new_buff != NULL)
  459.             {
  460.                 PA_LOCK(url, char *, new_buff);
  461.                 XP_STRCPY(url, new_str);
  462.                 PA_UNLOCK(new_buff);
  463.             }
  464.             else
  465.             {
  466.                 state->top_state->out_of_memory = TRUE;
  467.             }
  468.             XP_FREE(new_str);
  469.         }
  470.         PA_UNLOCK(buff);
  471.         PA_FREE(buff);
  472.         image_url = new_buff;
  473.  
  474.         /*
  475.          * Make sure we don't load insecure images inside
  476.          * a secure document.
  477.          */
  478.         if (state->top_state->security_level > 0)
  479.         {
  480.             PA_LOCK(str, char *, image_url);
  481.             
  482.             if (((from_user == FALSE)&&(str != NULL))||
  483.                 ((from_user != FALSE)&&(str != NULL)&&
  484.                  (XP_STRNCMP(str, "file:/", 6) != 0)))
  485.              {
  486.                  if (NET_IsURLSecure(str) == FALSE)
  487.                  {
  488.                      PA_UNLOCK(image_url);
  489.                      PA_FREE(image_url);
  490.                      image_url = PA_ALLOC(
  491.                          XP_STRLEN("internal-icon-insecure") + 1);
  492.                      PA_LOCK(str, char *, image_url);
  493.                      if (image_url != NULL)
  494.                      {
  495.                          XP_STRCPY(str, "internal-icon-insecure");
  496.                      }
  497.                      else
  498.                      {
  499.                          state->top_state->out_of_memory = TRUE;
  500.                      }
  501.                      if (state->top_state->insecure_images == FALSE)
  502.                      {
  503.                          state->top_state->insecure_images = TRUE;
  504.                          SECNAV_SecurityDialog(context,
  505.                                                SD_INSECURE_DOCS_WITHIN_SECURE_DOCS_NOT_SHOWN);
  506.                      }
  507.                  }
  508.              }
  509.             PA_UNLOCK(image_url);
  510.         }
  511.         
  512.         return (char*)image_url;
  513.     }
  514.     else
  515.         return NULL;
  516. }
  517.  
  518.  
  519. void
  520. lo_BodyForeground(MWContext *context, lo_DocState *state, PA_Tag *tag)
  521. {
  522.     PA_Block buff;
  523.     char *str;
  524.     uint8 red, green, blue;
  525.  
  526.     /*
  527.      * Don't do this is we had a TEXT from a previous BODY tag.
  528.      */
  529.     if ((state->top_state->body_attr & BODY_ATTR_TEXT) == 0)
  530.     {
  531.         /*
  532.          * Get the document text TEXT parameter.
  533.          */
  534.         buff = lo_FetchParamValue(context, tag, PARAM_TEXT);
  535.         if (buff != NULL)
  536.         {
  537.             LO_Color text_fg;
  538.             
  539.             PA_LOCK(str, char *, buff);
  540.             LO_ParseRGB(str, &red, &green, &blue);
  541.             PA_UNLOCK(buff);
  542.             PA_FREE(buff);
  543.  
  544.             text_fg.red = red;
  545.             text_fg.green = green;
  546.             text_fg.blue = blue;
  547.             lo_ChangeBodyTextFGColor(context, state, &text_fg);
  548.         }
  549.     }
  550.  
  551.     /*
  552.      * Don't do this is we had a LINK from a previous BODY tag.
  553.      */
  554.     if ((state->top_state->body_attr & BODY_ATTR_LINK) == 0)
  555.     {
  556.         /*
  557.          * Get the anchor text LINK parameter.
  558.          */
  559.         buff = lo_FetchParamValue(context, tag, PARAM_LINK);
  560.         if (buff != NULL)
  561.         {
  562.             state->top_state->body_attr |= BODY_ATTR_LINK;
  563.             PA_LOCK(str, char *, buff);
  564.             LO_ParseRGB(str, &red, &green, &blue);
  565.             PA_UNLOCK(buff);
  566.             PA_FREE(buff);
  567.  
  568.             state->anchor_color.red = red;
  569.             state->anchor_color.green = green;
  570.             state->anchor_color.blue = blue;
  571.         }
  572.     }
  573.  
  574.     /*
  575.      * Don't do this is we had a VLINK from a previous BODY tag.
  576.      */
  577.     if ((state->top_state->body_attr & BODY_ATTR_VLINK) == 0)
  578.     {
  579.         /*
  580.          * Get the visited anchor text VLINK parameter.
  581.          */
  582.         buff = lo_FetchParamValue(context, tag, PARAM_VLINK);
  583.         if (buff != NULL)
  584.         {
  585.             state->top_state->body_attr |= BODY_ATTR_VLINK;
  586.             PA_LOCK(str, char *, buff);
  587.             LO_ParseRGB(str, &red, &green, &blue);
  588.             PA_UNLOCK(buff);
  589.             PA_FREE(buff);
  590.  
  591.             state->visited_anchor_color.red = red;
  592.             state->visited_anchor_color.green = green;
  593.             state->visited_anchor_color.blue = blue;
  594.         }
  595.     }
  596.  
  597.     /*
  598.      * Don't do this is we had a ALINK from a previous BODY tag.
  599.      */
  600.     if ((state->top_state->body_attr & BODY_ATTR_ALINK) == 0)
  601.     {
  602.         /*
  603.          * Get the active anchor text ALINK parameter.
  604.          */
  605.         buff = lo_FetchParamValue(context, tag, PARAM_ALINK);
  606.         if (buff != NULL)
  607.         {
  608.             state->top_state->body_attr |= BODY_ATTR_ALINK;
  609.             PA_LOCK(str, char *, buff);
  610.             LO_ParseRGB(str, &red, &green, &blue);
  611.             PA_UNLOCK(buff);
  612.             PA_FREE(buff);
  613.  
  614.             state->active_anchor_color.red = red;
  615.             state->active_anchor_color.green = green;
  616.             state->active_anchor_color.blue = blue;
  617.         }
  618.     }
  619. }
  620.  
  621.  
  622. static void
  623. lo_GetStyleSheetBodyBackgroundAndColor(MWContext *context,
  624.                                        lo_DocState *state, 
  625.                                        char **image_urlp,
  626.                                        char **color_str,
  627.                                        lo_TileMode *tile_mode)
  628. {
  629.     char *image_url;
  630.     char *absolute_image_url;
  631.     char *tile_mode_prop;
  632.     StyleStruct *ss;
  633.  
  634.     /* Set defaults in case something goes wrong below. */
  635.     *color_str = NULL;
  636.     *image_urlp = NULL;
  637.     
  638.     /* //CLM: This is null in Editor (sometimes?)*/
  639.     if(!state->top_state->style_stack)
  640.         return;
  641.   
  642.     /* get the top style */
  643.     ss = STYLESTACK_GetStyleByIndex(state->top_state->style_stack, 0);
  644.  
  645.     /* see if it has a bgcolor attribute */
  646.     if(!ss)
  647.         return;
  648.  
  649.     *color_str = STYLESTRUCT_GetString(ss, BG_COLOR_STYLE);
  650.  
  651.     image_url = STYLESTRUCT_GetString(ss, BG_IMAGE_STYLE);
  652.  
  653.     if(!image_url)
  654.         return;
  655.  
  656.     if(!strcasecomp(image_url, "none"))
  657.     {
  658.         XP_FREE(image_url);
  659.         return;    
  660.     }
  661.  
  662.     absolute_image_url = NET_MakeAbsoluteURL(state->top_state->base_url, 
  663.                                              lo_ParseStyleSheetURL(image_url));
  664.     XP_FREE(image_url);
  665.  
  666.     if(!absolute_image_url)
  667.         return;
  668.     
  669.     *image_urlp = absolute_image_url;
  670.  
  671.     /* get the tiling mode */
  672.     tile_mode_prop = STYLESTRUCT_GetString(ss, BG_REPEAT_STYLE);
  673.     if(tile_mode_prop)
  674.     {
  675.         if(!strcasecomp(tile_mode_prop, BG_REPEAT_NONE_STYLE))
  676.             *tile_mode = LO_NO_TILE;
  677.         else if(!strcasecomp(tile_mode_prop, BG_REPEAT_X_STYLE))
  678.             *tile_mode = LO_TILE_HORIZ;
  679.         else if(!strcasecomp(tile_mode_prop, BG_REPEAT_Y_STYLE))
  680.             *tile_mode = LO_TILE_VERT;
  681.         else 
  682.             *tile_mode = LO_TILE_BOTH;
  683.     }
  684. }
  685.  
  686.  
  687. void
  688. lo_BodyBackground(MWContext *context, lo_DocState *state, PA_Tag *tag,
  689.     Bool from_user)
  690. {
  691.     LO_Color rgb;
  692.     PA_Block buff=NULL;
  693.     char *color_str = NULL;
  694.     char *image_url = NULL;
  695.     CL_Layer *layer;
  696.     lo_TileMode tile_mode = LO_TILE_BOTH;
  697.  
  698.     if (! context->compositor)
  699.         return;
  700.  
  701.     /* if we are here then we must be in the BODY tag.
  702.      * Get the top state from the style sheet and get BG color and
  703.      * BG Image from it
  704.      */
  705.     lo_GetStyleSheetBodyBackgroundAndColor(context,
  706.                                            state, 
  707.                                            &image_url,
  708.                                            &color_str,
  709.                                            &tile_mode);
  710.  
  711.     /* If there isn't a style sheet backdrop get one from the BODY's
  712.        BACKGROUND attribute, if present */
  713.     if (!image_url)
  714.         image_url = lo_ParseBackgroundAttribute(context, state, tag, from_user);
  715.  
  716.     /*
  717.      * Get the BGCOLOR parameter.  This is for a color background
  718.      * instead of an image backdrop.  BACKGROUND if it exists overrides
  719.      * the BGCOLOR specification.
  720.      *
  721.      * If color_str is already set then we got the color from a stylesheet
  722.      */
  723.     if(!color_str)
  724.     {
  725.         buff = lo_FetchParamValue(context, tag, PARAM_BGCOLOR);
  726.         if (buff) {
  727.             PA_LOCK(color_str, char *, buff);
  728.             LO_ParseRGB(color_str, &rgb.red, &rgb.green, &rgb.blue);
  729.             PA_UNLOCK(buff);
  730.             PA_FREE(buff);
  731.         }
  732.     }
  733.     else
  734.     {
  735.         LO_ParseStyleSheetRGB(color_str, &rgb.red, &rgb.green, &rgb.blue);
  736.         XP_FREE(color_str);
  737.     }
  738.  
  739.     layer = lo_CurrentLayer(state);
  740.  
  741.     /*
  742.      * Don't do this is we had a BGCOLOR from a previous BODY tag.
  743.      */
  744.     if (((state->top_state->body_attr & BODY_ATTR_BGCOLOR) == 0)||
  745.     (from_user != FALSE))
  746.     {
  747.     if ((color_str != NULL)&&(!lo_InsideLayer(state))&&(from_user == FALSE))
  748.     {
  749.         state->top_state->body_attr |= BODY_ATTR_BGCOLOR;
  750.     }
  751.     /* Set the document's solid background color */
  752.     if (color_str && !lo_InsideLayer(state)) {
  753.         state->top_state->doc_specified_bg = TRUE;
  754.         state->text_bg.red = rgb.red;
  755.         state->text_bg.green = rgb.green;
  756.         state->text_bg.blue = rgb.blue;
  757.     }
  758.     
  759.     if (color_str)
  760.         LO_SetLayerBgColor(layer, &rgb);
  761.     else if (!lo_InsideLayer(state))
  762.         LO_SetLayerBgColor(layer, &state->text_bg);
  763.     }
  764.     
  765.     /*
  766.      * Don't do this is we had a BACKGROUND from a previous BODY tag.
  767.      */
  768.     if (((state->top_state->body_attr & BODY_ATTR_BACKGROUND) == 0)||
  769.     (from_user != FALSE))
  770.     {
  771.     if ((image_url != NULL)&&(!lo_InsideLayer(state))&&(from_user == FALSE))
  772.     {
  773.         state->top_state->body_attr |= BODY_ATTR_BACKGROUND;
  774.     }
  775.     /* Set the document's backdrop */
  776.     if (image_url) {
  777.         if (!lo_InsideLayer(state))
  778.             state->top_state->doc_specified_bg = TRUE;
  779.         LO_SetLayerBackdropURL(layer, image_url);
  780.         lo_SetLayerBackdropTileMode(layer, tile_mode);
  781.         XP_FREE(image_url);
  782.     }
  783.     }
  784.     
  785.     lo_BodyForeground(context, state, tag);
  786. }
  787.  
  788. static void lo_edt_AvoidImageBlock(LO_ImageStruct *image);
  789.  
  790. static void lo_edt_AvoidImageBlock(LO_ImageStruct *image)
  791. {
  792.     int originalWidth = 0;
  793.     int originalHeight = 0;
  794.     IL_GetNaturalDimensions( image->image_req, &originalWidth, &originalHeight);
  795.     if ( originalWidth <= 0 ) {
  796.         originalWidth = 10;
  797.     }
  798.     if ( originalHeight <= 0 ) {
  799.         originalHeight = 10;
  800.     }
  801.     if (image->width == 0 )
  802.     {
  803.         image->width = originalWidth;
  804.     }
  805.     if (image->height == 0)
  806.     {
  807.         image->height = originalHeight;
  808.     }
  809. }
  810.  
  811. extern Bool
  812. lo_FindMochaExpr(char *str, char **expr_start, char **expr_end);
  813.  
  814. void
  815. lo_BlockedImageLayout(MWContext *context, lo_DocState *state, PA_Tag *tag,
  816.                       char *base_url)
  817. {
  818.     LO_ImageStruct *image;
  819.     PA_Block buff;
  820.     char *str;
  821.     int32 val;
  822.     /* int32 doc_width; */
  823.     PushTagStatus push_status;
  824.     char *start, *end;
  825.     
  826.     XP_ObserverList image_obs_list;   /* List of observers for an image request. */
  827.  
  828.     /* this image layout is going on outside the context
  829.      * of normal layout.  We therfore need to manage the
  830.      * style stack in here as well as in normal layout
  831.      * mode so that we can set image widths
  832.      */
  833.     push_status = LO_PushTagOnStyleStack(context, state, tag);
  834.  
  835.     /* 
  836.      * if there are any entities in this tag don't prefetch
  837.      *   it --- wait until we have had a chance to redo it
  838.      */
  839.     if (lo_FindMochaExpr((char *)tag->data, &start, &end))
  840.         return;
  841.  
  842.     /*
  843.      * Fill in the image structure with default data
  844.      */
  845.     image = lo_new_image_element(context, state, tag->edit_element, NULL);
  846.     if (!image)
  847.         return;
  848.     image->ele_id = NEXT_ELEMENT;
  849.  
  850.     image->border_width = -1;
  851.     image->border_vert_space = IMAGE_DEF_VERTICAL_SPACE;
  852.     image->border_horiz_space = IMAGE_DEF_HORIZONTAL_SPACE;
  853.  
  854.     /*
  855.      * Check for the ISMAP parameter
  856.      */
  857.     buff = lo_FetchParamValue(context, tag, PARAM_ISMAP);
  858.     if (buff != NULL)
  859.     {
  860.         image->image_attr->attrmask |= LO_ATTR_ISMAP;
  861.         PA_FREE(buff);
  862.     }
  863.  
  864.     /*
  865.      * Check for the USEMAP parameter.  The name is stored in the
  866.      * image attributes immediately, the map pointer will be
  867.      * stored in later.
  868.      */
  869.     buff = lo_FetchParamValue(context, tag, PARAM_USEMAP);
  870.     if (buff != NULL)
  871.     {
  872.         char *new_str;
  873.         char *map_name;
  874.         char *tptr;
  875.  
  876.         map_name = NULL;
  877.         PA_LOCK(str, char *, buff);
  878.  
  879.         /*
  880.          * Make this an absolute URL
  881.          */
  882.         if (str != NULL)
  883.         {
  884.             int32 len;
  885.  
  886.             len = lo_StripTextWhitespace(str, XP_STRLEN(str));
  887.         }
  888.         /*
  889.          * The IETF draft says evaluate #name relative to real,
  890.          * and not the base url.
  891.          */
  892.         if ((str != NULL)&&(*str == '#'))
  893.         {
  894.             new_str = NET_MakeAbsoluteURL(
  895.                 state->top_state->url, str);
  896.         }
  897.         else
  898.         {
  899.             new_str = NET_MakeAbsoluteURL(
  900.                 base_url, str);
  901.         }
  902.  
  903.         /*
  904.          * If we have a local URL, we can use the USEMAP.
  905.          */
  906.         if ((new_str != NULL)&&
  907.             (lo_IsAnchorInDoc(state, new_str) != FALSE))
  908.         {
  909.             tptr = strrchr(new_str, '#');
  910.             if (tptr == NULL)
  911.             {
  912.                 tptr = new_str;
  913.             }
  914.             else
  915.             {
  916.                 tptr++;
  917.             }
  918.             map_name = XP_STRDUP(tptr);
  919.             XP_FREE(new_str);
  920.         }
  921.         /*
  922.          * Else a non-local URL, right now we don't support this.
  923.          */
  924.         else if (new_str != NULL)
  925.         {
  926.             XP_FREE(new_str);
  927.         }
  928.         PA_UNLOCK(buff);
  929.         PA_FREE(buff);
  930.         image->image_attr->usemap_name = map_name;
  931.     }
  932.  
  933.     /*
  934.      * Check for an align parameter
  935.      */
  936.     buff = lo_FetchParamValue(context, tag, PARAM_ALIGN);
  937.     if (buff != NULL)
  938.     {
  939.         Bool floating;
  940.  
  941.         floating = FALSE;
  942.         PA_LOCK(str, char *, buff);
  943.         image->image_attr->alignment = lo_EvalAlignParam(str,
  944.             &floating);
  945.         if (floating != FALSE)
  946.         {
  947.             image->ele_attrmask |= LO_ELE_FLOATING;
  948.         }
  949.         PA_UNLOCK(buff);
  950.         PA_FREE(buff);
  951.     }
  952.  
  953.     if(state->top_state->style_stack)
  954.     {
  955.         Bool floating = FALSE;
  956.  
  957.         lo_EvalStyleSheetAlignment(
  958.                 STYLESTACK_GetStyleByIndex(state->top_state->style_stack, 0), 
  959.                 &(image->image_attr->alignment),
  960.                 &floating);     
  961.         
  962.         if (floating != FALSE)
  963.         {
  964.             image->ele_attrmask |= LO_ELE_FLOATING;
  965.         }
  966.     }
  967.  
  968.     /*
  969.      * Get the required src parameter, and make the resulting
  970.      * url and absolute url.
  971.      */
  972.     buff = lo_FetchParamValue(context, tag, PARAM_SRC);
  973.     if (buff != NULL)
  974.     {
  975.         PA_Block new_buff;
  976.         char *new_str;
  977.  
  978.         new_buff = NULL;
  979.         PA_LOCK(str, char *, buff);
  980.         if (str != NULL)
  981.         {
  982.             int32 len;
  983.  
  984.             len = lo_StripTextWhitespace(str, XP_STRLEN(str));
  985.         }
  986.         new_str = NET_MakeAbsoluteURL(base_url, str);
  987.         if (new_str != NULL)
  988.         {
  989.             char *url;
  990.  
  991.             new_buff = PA_ALLOC(XP_STRLEN(new_str) + 1);
  992.             if (new_buff != NULL)
  993.             {
  994.                 PA_LOCK(url, char *, new_buff);
  995.                 XP_STRCPY(url, new_str);
  996.                 PA_UNLOCK(new_buff);
  997.             }
  998.             XP_FREE(new_str);
  999.         }
  1000.         PA_UNLOCK(buff);
  1001.         PA_FREE(buff);
  1002.         buff = new_buff;
  1003.         
  1004.         if (new_str == NULL || new_buff == NULL)
  1005.         {    /* clean up all previously allocated objects */
  1006.             lo_FreeElement(context, (LO_Element *)image, TRUE);
  1007.             state->top_state->out_of_memory = TRUE;
  1008.             return;
  1009.         }
  1010.     }
  1011.     image->image_url = buff;
  1012.  
  1013.     /*
  1014.      * Get the optional lowsrc parameter, and make the resulting
  1015.      * url and absolute url.
  1016.      */
  1017.     buff = lo_FetchParamValue(context, tag, PARAM_LOWSRC);
  1018.     if (buff != NULL)
  1019.     {
  1020.         PA_Block new_buff;
  1021.         char *new_str;
  1022.  
  1023.         new_buff = NULL;
  1024.         PA_LOCK(str, char *, buff);
  1025.         if (str != NULL)
  1026.         {
  1027.         int32 len;
  1028.  
  1029.         len = lo_StripTextWhitespace(str, XP_STRLEN(str));
  1030.         }
  1031.         new_str = NET_MakeAbsoluteURL(base_url, str);
  1032.         if (new_str != NULL)
  1033.         {
  1034.             char *url;
  1035.  
  1036.             new_buff = PA_ALLOC(XP_STRLEN(new_str) + 1);
  1037.             if (new_buff != NULL)
  1038.             {
  1039.                 PA_LOCK(url, char *, new_buff);
  1040.                 XP_STRCPY(url, new_str);
  1041.                 PA_UNLOCK(new_buff);
  1042.             }
  1043.             XP_FREE(new_str);
  1044.         }
  1045.         PA_UNLOCK(buff);
  1046.         PA_FREE(buff);
  1047.         buff = new_buff;
  1048.  
  1049.         if (new_str == NULL || new_buff == NULL)
  1050.         {       /* clean up all previously allocated objects */
  1051.             lo_FreeElement(context, (LO_Element *)image, TRUE);
  1052.             state->top_state->out_of_memory = TRUE;
  1053.             return;
  1054.         }
  1055.     }
  1056.     image->lowres_image_url = buff;
  1057.  
  1058.     /*
  1059.      * Get the alt parameter, and store the resulting
  1060.      * text, and its length.
  1061.      */
  1062.     buff = lo_FetchParamValue(context, tag, PARAM_ALT);
  1063.     if (buff != NULL)
  1064.     {
  1065.         PA_LOCK(str, char *, buff);
  1066.         image->alt_len = XP_STRLEN(str);
  1067.         image->alt_len = (int16)lo_StripTextNewlines(str,
  1068.                         (int32)image->alt_len);
  1069.         PA_UNLOCK(buff);
  1070.     }
  1071.     image->alt = buff;
  1072.  
  1073.     /*
  1074.      * Get the suppress feedback parameter, which suppresses the delayed icon,
  1075.      * temporary border and alt text when the image is coming in, and also
  1076.      * suppresses keyboard navigation feedback.
  1077.      */
  1078.     buff = lo_FetchParamValue(context, tag, PARAM_SUPPRESS);
  1079.     if (buff != NULL)
  1080.     {
  1081.         PA_LOCK(str, char *, buff);
  1082.  
  1083.         if (!XP_STRNCASECMP(str, "true", 4))
  1084.             image->suppress_mode = LO_SUPPRESS;
  1085.         else if (!XP_STRNCASECMP(str, "false", 5))
  1086.             image->suppress_mode = LO_DONT_SUPPRESS;
  1087.         else
  1088.             image->suppress_mode = LO_SUPPRESS_UNDEFINED;
  1089.  
  1090.         PA_UNLOCK(buff);
  1091.         PA_FREE(buff);
  1092.     }
  1093.     
  1094.     /*
  1095.     doc_width = state->right_margin - state->left_margin;
  1096.     */
  1097.  
  1098.     /*
  1099.      * Get the width parameter, in absolute or percentage.
  1100.      * If percentage, make it absolute.
  1101.      */
  1102.     /*
  1103.     buff = lo_FetchParamValue(context, tag, PARAM_WIDTH);
  1104.     if (buff != NULL)
  1105.     {
  1106.         Bool is_percent;
  1107.  
  1108.         PA_LOCK(str, char *, buff);
  1109.         val = lo_ValueOrPercent(str, &is_percent);
  1110.         if (is_percent != FALSE)
  1111.         {
  1112.             if (state->allow_percent_width == FALSE)
  1113.             {
  1114.                 val = 0;
  1115.             }
  1116.             else
  1117.             {
  1118.                 val = doc_width * val / 100;
  1119.             }
  1120.         }
  1121.         else
  1122.         {
  1123.             val = FEUNITS_X(val, context);
  1124.         }
  1125.         image->width = val;
  1126.         PA_UNLOCK(buff);
  1127.         PA_FREE(buff);
  1128.     }
  1129.     */
  1130.  
  1131.     buff = lo_FetchParamValue(context, tag, PARAM_WIDTH);
  1132.     if (buff != NULL)
  1133.     {
  1134.         Bool is_percent;
  1135.  
  1136.         PA_LOCK(str, char *, buff);
  1137.         val = lo_ValueOrPercent(str, &is_percent);
  1138.         if (is_percent != FALSE)
  1139.         {
  1140.             image->percent_width = val;
  1141.         }
  1142.         else
  1143.         {
  1144.             image->percent_width = 0;
  1145.             val = FEUNITS_X(val, context);
  1146.         }
  1147.         image->width = val;
  1148.         PA_UNLOCK(buff);
  1149.         PA_FREE(buff);
  1150.     }
  1151.     
  1152.  
  1153.     /* disabled because it is broken by JS threading 
  1154.      *
  1155.      * val = LO_GetWidthFromStyleSheet(context, state);
  1156.      * if(val)
  1157.      *    image->width = val;
  1158.      */
  1159.  
  1160.     /*
  1161.      * Get the height parameter, in absolute or percentage.
  1162.      * If percentage, make it absolute.
  1163.      */
  1164.  
  1165.     /*
  1166.     buff = lo_FetchParamValue(context, tag, PARAM_HEIGHT);
  1167.     if (buff != NULL)
  1168.     {
  1169.         Bool is_percent;
  1170.  
  1171.         PA_LOCK(str, char *, buff);
  1172.         val = lo_ValueOrPercent(str, &is_percent);
  1173.         if (is_percent != FALSE)
  1174.         {
  1175.             if (state->allow_percent_height == FALSE)
  1176.             {
  1177.                 val = 0;
  1178.             }
  1179.             else
  1180.             {
  1181.                 val = state->win_height * val / 100;
  1182.             }
  1183.         }
  1184.         else
  1185.         {
  1186.             val = FEUNITS_Y(val, context);
  1187.         }
  1188.         image->height = val;
  1189.         PA_UNLOCK(buff);
  1190.         PA_FREE(buff);
  1191.     }
  1192.     */
  1193.  
  1194.     buff = lo_FetchParamValue(context, tag, PARAM_HEIGHT);
  1195.     if (buff != NULL)
  1196.     {
  1197.         Bool is_percent;
  1198.  
  1199.         PA_LOCK(str, char *, buff);
  1200.         val = lo_ValueOrPercent(str, &is_percent);
  1201.         if (is_percent != FALSE)
  1202.         {
  1203.             image->percent_height = val;
  1204.         }
  1205.         else
  1206.         {
  1207.             image->percent_height = 0;
  1208.             val = FEUNITS_Y(val, context);
  1209.         }
  1210.         image->height = val;
  1211.         PA_UNLOCK(buff);
  1212.         PA_FREE(buff);
  1213.     }
  1214.  
  1215.     /* disabled because it is broken by JS threading 
  1216.      *
  1217.      * val = LO_GetHeightFromStyleSheet(context, state);
  1218.      * if(val)
  1219.      *    image->height = val;
  1220.      */
  1221.  
  1222.     /*
  1223.      * Get the border parameter.
  1224.      */
  1225.     buff = lo_FetchParamValue(context, tag, PARAM_BORDER);
  1226.     if (buff != NULL)
  1227.     {
  1228.         PA_LOCK(str, char *, buff);
  1229.         val = XP_ATOI(str);
  1230.         if (val < 0)
  1231.         {
  1232.             val = 0;
  1233.         }
  1234.         image->border_width = val;
  1235.         PA_UNLOCK(buff);
  1236.         PA_FREE(buff);
  1237.     }
  1238.     image->border_width = FEUNITS_X(image->border_width, context);
  1239.  
  1240.     /*
  1241.      * Get the extra vertical space parameter.
  1242.      */
  1243.     buff = lo_FetchParamValue(context, tag, PARAM_VSPACE);
  1244.     if (buff != NULL)
  1245.     {
  1246.         PA_LOCK(str, char *, buff);
  1247.         val = XP_ATOI(str);
  1248.         if (val < 0)
  1249.         {
  1250.             val = 0;
  1251.         }
  1252.         image->border_vert_space = val;
  1253.         PA_UNLOCK(buff);
  1254.         PA_FREE(buff);
  1255.     }
  1256.     image->border_vert_space = FEUNITS_Y(image->border_vert_space, context);
  1257.  
  1258.     /*
  1259.      * Get the extra horizontal space parameter.
  1260.      */
  1261.     if (image->ele_attrmask & LO_ELE_FLOATING)
  1262.     {
  1263.         image->border_horiz_space = IMAGE_DEF_FLOAT_HORIZONTAL_SPACE;
  1264.     }
  1265.     else
  1266.     {
  1267.         image->border_horiz_space = IMAGE_DEF_HORIZONTAL_SPACE;
  1268.     }
  1269.     buff = lo_FetchParamValue(context, tag, PARAM_HSPACE);
  1270.     if (buff != NULL)
  1271.     {
  1272.         PA_LOCK(str, char *, buff);
  1273.         val = XP_ATOI(str);
  1274.         if (val < 0)
  1275.         {
  1276.             val = 0;
  1277.         }
  1278.         image->border_horiz_space = val;
  1279.         PA_UNLOCK(buff);
  1280.         PA_FREE(buff);
  1281.     }
  1282.     image->border_horiz_space = FEUNITS_X(image->border_horiz_space,
  1283.                         context);
  1284.  
  1285.     /*
  1286.      * Make sure we don't load insecure images inside
  1287.      * a secure document.
  1288.      */
  1289.     if (state->top_state->security_level > 0)
  1290.     {
  1291.         if (image->image_url != NULL)
  1292.         {
  1293.             PA_LOCK(str, char *, image->image_url);
  1294.             if (NET_IsURLSecure(str) == FALSE)
  1295.             {
  1296.                 PA_UNLOCK(image->image_url);
  1297.                 PA_FREE(image->image_url);
  1298.                 image->image_url = PA_ALLOC(
  1299.                     XP_STRLEN("internal-icon-insecure") + 1);
  1300.                 if (image->image_url != NULL)
  1301.                 {
  1302.                     PA_LOCK(str, char *, image->image_url);
  1303.                     XP_STRCPY(str, "internal-icon-insecure");
  1304.                     PA_UNLOCK(image->image_url);
  1305.                 }
  1306.                 else
  1307.                 {
  1308.                     state->top_state->out_of_memory = TRUE;
  1309.                 }
  1310.                 if (state->top_state->insecure_images == FALSE)
  1311.                 {
  1312.                     state->top_state->insecure_images = TRUE;
  1313.                     SECNAV_SecurityDialog(context, SD_INSECURE_DOCS_WITHIN_SECURE_DOCS_NOT_SHOWN);
  1314.                 }
  1315.             }
  1316.             else
  1317.             {
  1318.                 PA_UNLOCK(image->image_url);
  1319.             }
  1320.         }
  1321.     }
  1322.  
  1323.     if (context->compositor) {
  1324.         image->layer = lo_CreateImageLayer(context, image, NULL);
  1325.     }
  1326.  
  1327.     /* Initiate the loading of this image. */
  1328.     image_obs_list = lo_NewImageObserverList(context, image);
  1329.     if (!image_obs_list)
  1330.         return;
  1331.     lo_GetImage(context, context->img_cx, image, image_obs_list,
  1332.                 state->top_state->force_reload);
  1333.  
  1334.     tag->lo_data = (void *)image;
  1335.  
  1336.     if (state->top_state->style_stack)
  1337.         STYLESTACK_PopTag(state->top_state->style_stack,
  1338.                           (char*)pa_PrintTagToken((int32)tag->type));
  1339.  
  1340. }
  1341.  
  1342.  
  1343. void
  1344. lo_PartialFormatImage(MWContext *context, lo_DocState *state, PA_Tag *tag)
  1345. {
  1346.     LO_ImageStruct *image;
  1347.     int32 layer_id;
  1348. #ifdef MOCHA
  1349.     LM_ImageEvent mocha_event;
  1350. #endif /* MOCHA */
  1351.  
  1352.     image = (LO_ImageStruct *)tag->lo_data;
  1353.     if (image == NULL)
  1354.     {
  1355.         return;
  1356.     }
  1357.  
  1358. #ifdef MOCHA
  1359.     layer_id = lo_CurrentLayerId(state);
  1360.     image->layer_id = layer_id;
  1361.     /* Reflect the image into Javascript */
  1362.     lo_ReflectImage(context, state, tag, image, FALSE, layer_id);
  1363.  
  1364.     /* Send any pending events to JavaScript */
  1365.     if ((image->image_status == IL_IMAGE_COMPLETE) || 
  1366.         (image->image_status == IL_FRAME_COMPLETE) ||
  1367.         (image->image_status == IL_NOT_IN_CACHE)) {
  1368.         mocha_event = LM_IMGLOAD;
  1369.         ET_SendImageEvent(context, image, mocha_event);
  1370.     }
  1371.     else if (image->image_status == IL_ABORTED) {
  1372.         mocha_event = LM_IMGABORT;
  1373.         ET_SendImageEvent(context, image, mocha_event);
  1374.     }
  1375.     else if ((image->image_status == IL_ERROR_NO_DATA) ||
  1376.              (image->image_status == IL_ERROR_IMAGE_DATA_CORRUPT) ||
  1377.              (image->image_status == IL_ERROR_IMAGE_DATA_TRUNCATED) ||
  1378.              (image->image_status == IL_ERROR_IMAGE_DATA_ILLEGAL) ||
  1379.              (image->image_status == IL_ERROR_INTERNAL)) {
  1380.         mocha_event = LM_IMGERROR;
  1381.         ET_SendImageEvent(context, image, mocha_event);
  1382.     }
  1383. #endif
  1384.  
  1385.     tag->lo_data = NULL;
  1386.  
  1387.     /*
  1388.      * Assign it a properly sequencial element id.
  1389.      */
  1390.  
  1391.     /*
  1392.     image->ele_id = NEXT_ELEMENT;
  1393.     image->x = state->x;
  1394.     image->y = state->y;
  1395.     */
  1396.  
  1397.  
  1398.     image->anchor_href = state->current_anchor;
  1399.  
  1400.     if (image->border_width < 0)
  1401.     {
  1402.         if ((image->anchor_href != NULL)||
  1403.             (image->image_attr->usemap_name != NULL))
  1404.         {
  1405.             image->border_width = IMAGE_DEF_ANCHOR_BORDER;
  1406.         }
  1407.         else
  1408.         {
  1409.             image->border_width = IMAGE_DEF_BORDER;
  1410.         }
  1411.     
  1412.         image->border_width = FEUNITS_X(image->border_width, context);
  1413.  
  1414.     }
  1415.  
  1416.     if (state->font_stack == NULL)
  1417.     {
  1418.         LO_TextAttr tmp_attr;
  1419.         LO_TextAttr *tptr;
  1420.  
  1421.         /*
  1422.          * Fill in default font information.
  1423.          */
  1424.         lo_SetDefaultFontAttr(state, &tmp_attr, context);
  1425.         tptr = lo_FetchTextAttr(state, &tmp_attr);
  1426.         image->text_attr = tptr;
  1427.     }
  1428.     else
  1429.     {
  1430.         image->text_attr = state->font_stack->text_attr;
  1431.     }
  1432.  
  1433.     if ((image->text_attr != NULL)&&
  1434.         (image->text_attr->attrmask & LO_ATTR_ANCHOR))
  1435.     {
  1436.         image->image_attr->attrmask |= LO_ATTR_ANCHOR;
  1437.     }
  1438.  
  1439.     if (image->image_attr->usemap_name != NULL)
  1440.     {
  1441.         LO_TextAttr tmp_attr;
  1442.  
  1443.         lo_CopyTextAttr(image->text_attr, &tmp_attr);
  1444.         tmp_attr.fg.red =   STATE_UNVISITED_ANCHOR_RED(state);
  1445.         tmp_attr.fg.green = STATE_UNVISITED_ANCHOR_GREEN(state);
  1446.         tmp_attr.fg.blue =  STATE_UNVISITED_ANCHOR_BLUE(state);
  1447.         image->text_attr = lo_FetchTextAttr(state, &tmp_attr);
  1448.     }
  1449.  
  1450.     lo_FillInImageGeometry( state, image );
  1451.  
  1452.     /* During relayout the editor is not allowed to block. */
  1453.     if ( (image->width == 0)||(image->height == 0))
  1454.     {
  1455.         if ( EDT_IN_RELAYOUT( context ) ){
  1456.             lo_edt_AvoidImageBlock(image);
  1457.         }
  1458.     }
  1459.  
  1460.     /*
  1461.      * We may have to block on this image until later
  1462.      * when the front end can give us the width and height.
  1463.      */
  1464.     if ((image->width == 0)||(image->height == 0))
  1465.     {
  1466.         state->top_state->layout_blocking_element = (LO_Element *)image;
  1467.     }
  1468.     else
  1469.     {
  1470.         lo_FinishImage(context, state, image);
  1471.     }
  1472. }
  1473.  
  1474.  
  1475. /*************************************
  1476.  * Function: lo_FormatImage
  1477.  *
  1478.  * Description: This function does all the work to format
  1479.  *    and lay out an image on a line of elements.
  1480.  *    Creates the new image structure.  Fills it
  1481.  *    in based on the parameters in the image tag.
  1482.  *    Calls the front end to start fetching the image
  1483.  *    and get image dimentions if necessary.
  1484.  *    Places image on line, breaking line if necessary.
  1485.  *
  1486.  * Params: Window context, document state, and the image tag data.
  1487.  *
  1488.  * Returns: Nothing.
  1489.  *************************************/
  1490. void
  1491. lo_FormatImage(MWContext *context, lo_DocState *state, PA_Tag *tag)
  1492. {
  1493.     LO_ImageStruct *image;
  1494.     LO_TextAttr *tptr = NULL;
  1495.     PA_Block buff;
  1496.     char *str;
  1497.     int32 val;
  1498.     /* int32 doc_width; */
  1499.     Bool is_a_form;
  1500.     XP_ObserverList image_obs_list;   /* List of observers for an image request. */
  1501.     lo_DocLists *doc_lists;
  1502.     int32 layer_id;
  1503.  
  1504.     doc_lists = lo_GetCurrentDocLists(state);
  1505.     
  1506.     if (state->font_stack)
  1507.         tptr = state->font_stack->text_attr;
  1508.  
  1509.     /*
  1510.      * Fill in the image structure with default data
  1511.      */
  1512.     image = lo_new_image_element(context, state, tag->edit_element, tptr);
  1513.     if (!image)
  1514.         return;
  1515.  
  1516.     
  1517.     /*
  1518.     image->ele_id = NEXT_ELEMENT;
  1519.     image->x = state->x;
  1520.     image->y = state->y;
  1521.     */
  1522.     image->anchor_href = state->current_anchor;
  1523.  
  1524.     if (image->anchor_href != NULL)
  1525.     {
  1526.         image->border_width = IMAGE_DEF_ANCHOR_BORDER;
  1527.     }
  1528.     else
  1529.     {
  1530.         image->border_width = IMAGE_DEF_BORDER;
  1531.     }
  1532.     image->border_vert_space = IMAGE_DEF_VERTICAL_SPACE;
  1533.     image->border_horiz_space = IMAGE_DEF_HORIZONTAL_SPACE;
  1534.  
  1535.     if ((image->text_attr != NULL)&&
  1536.         (image->text_attr->attrmask & LO_ATTR_ANCHOR))
  1537.     {
  1538.         image->image_attr->attrmask |= LO_ATTR_ANCHOR;
  1539.     }
  1540.  
  1541.     if (tag->type == P_INPUT)
  1542.     {
  1543.         is_a_form = TRUE;
  1544.     }
  1545.     else
  1546.     {
  1547.         is_a_form = FALSE;
  1548.     }
  1549.  
  1550.     if (is_a_form != FALSE)
  1551.     {
  1552.         LO_TextAttr tmp_attr;
  1553.  
  1554.         image->image_attr->layer_id = lo_CurrentLayerId(state);
  1555.         image->image_attr->form_id = doc_lists->current_form_num;
  1556.         image->image_attr->attrmask |= LO_ATTR_ISFORM;
  1557.         image->border_width = IMAGE_DEF_ANCHOR_BORDER;
  1558.         lo_CopyTextAttr(image->text_attr, &tmp_attr);
  1559.         tmp_attr.fg.red =   STATE_UNVISITED_ANCHOR_RED(state);
  1560.         tmp_attr.fg.green = STATE_UNVISITED_ANCHOR_GREEN(state);
  1561.         tmp_attr.fg.blue =  STATE_UNVISITED_ANCHOR_BLUE(state);
  1562.         image->text_attr = lo_FetchTextAttr(state, &tmp_attr);
  1563.     }
  1564.  
  1565.     image->image_attr->usemap_name = NULL;
  1566.     image->image_attr->usemap_ptr = NULL;
  1567.  
  1568.     image->ele_attrmask = 0;
  1569.  
  1570.     image->sel_start = -1;
  1571.     image->sel_end = -1;
  1572.  
  1573.     /*
  1574.      * Check for the ISMAP parameter
  1575.      */
  1576.     buff = lo_FetchParamValue(context, tag, PARAM_ISMAP);
  1577.     if (buff != NULL)
  1578.     {
  1579.         image->image_attr->attrmask |= LO_ATTR_ISMAP;
  1580.         PA_FREE(buff);
  1581.     }
  1582.  
  1583.     /*
  1584.      * Check for the USEMAP parameter.  The name is stored in the
  1585.      * image attributes immediately, the map pointer will be
  1586.      * stored in later.
  1587.      */
  1588.     buff = lo_FetchParamValue(context, tag, PARAM_USEMAP);
  1589.     if (buff != NULL)
  1590.     {
  1591.         char *new_str;
  1592.         char *map_name;
  1593.         char *tptr;
  1594.  
  1595.         map_name = NULL;
  1596.         PA_LOCK(str, char *, buff);
  1597.  
  1598.         /*
  1599.          * Make this an absolute URL
  1600.          */
  1601.         if (str != NULL)
  1602.         {
  1603.             int32 len;
  1604.  
  1605.             len = lo_StripTextWhitespace(str, XP_STRLEN(str));
  1606.         }
  1607.         /*
  1608.          * The IETF draft says evaluate #name relative to real,
  1609.          * and not the base url.
  1610.          */
  1611.         if ((str != NULL)&&(*str == '#'))
  1612.         {
  1613.             new_str = NET_MakeAbsoluteURL(
  1614.                 state->top_state->url, str);
  1615.         }
  1616.         else
  1617.         {
  1618.             new_str = NET_MakeAbsoluteURL(
  1619.                 state->top_state->base_url, str);
  1620.         }
  1621.  
  1622.         /*
  1623.          * If we have a local URL, we can use the USEMAP.
  1624.          */
  1625.         if ((new_str != NULL)&&
  1626.             (lo_IsAnchorInDoc(state, new_str) != FALSE))
  1627.         {
  1628.             tptr = strrchr(new_str, '#');
  1629.             if (tptr == NULL)
  1630.             {
  1631.                 tptr = new_str;
  1632.             }
  1633.             else
  1634.             {
  1635.                 tptr++;
  1636.             }
  1637.             map_name = XP_STRDUP(tptr);
  1638.             XP_FREE(new_str);
  1639.         }
  1640.         /*
  1641.          * Else a non-local URL, right now we don't support this.
  1642.          */
  1643.         else if (new_str != NULL)
  1644.         {
  1645.             XP_FREE(new_str);
  1646.         }
  1647.  
  1648.         PA_UNLOCK(buff);
  1649.         PA_FREE(buff);
  1650.         image->image_attr->usemap_name = map_name;
  1651.         if (image->image_attr->usemap_name != NULL)
  1652.         {
  1653.             LO_TextAttr tmp_attr;
  1654.  
  1655.             image->border_width = IMAGE_DEF_ANCHOR_BORDER;
  1656.             lo_CopyTextAttr(image->text_attr, &tmp_attr);
  1657.             tmp_attr.fg.red =   STATE_UNVISITED_ANCHOR_RED(state);
  1658.             tmp_attr.fg.green = STATE_UNVISITED_ANCHOR_GREEN(state);
  1659.             tmp_attr.fg.blue =  STATE_UNVISITED_ANCHOR_BLUE(state);
  1660.             image->text_attr = lo_FetchTextAttr(state, &tmp_attr);
  1661.         }
  1662.     }
  1663.  
  1664.     /*
  1665.      * Check for an align parameter
  1666.      */
  1667.     buff = lo_FetchParamValue(context, tag, PARAM_ALIGN);
  1668.     if (buff != NULL)
  1669.     {
  1670.         Bool floating;
  1671.  
  1672.         floating = FALSE;
  1673.         PA_LOCK(str, char *, buff);
  1674.         image->image_attr->alignment = lo_EvalAlignParam(str,
  1675.             &floating);
  1676.         if (floating != FALSE)
  1677.         {
  1678.             image->ele_attrmask |= LO_ELE_FLOATING;
  1679.         }
  1680.         PA_UNLOCK(buff);
  1681.         PA_FREE(buff);
  1682.     }
  1683.     
  1684.     if(state->top_state->style_stack)
  1685.     {
  1686.         Bool floating = FALSE;
  1687.  
  1688.         lo_EvalStyleSheetAlignment(
  1689.                 STYLESTACK_GetStyleByIndex(state->top_state->style_stack, 0), 
  1690.                 &(image->image_attr->alignment),
  1691.                 &floating);     
  1692.         
  1693.         if (floating != FALSE)
  1694.         {
  1695.             image->ele_attrmask |= LO_ELE_FLOATING;
  1696.         }
  1697.     }
  1698.  
  1699.     /*
  1700.      * Get the required src parameter, and make the resulting
  1701.      * url and absolute url.
  1702.      */
  1703.     buff = lo_FetchParamValue(context, tag, PARAM_SRC);
  1704.     if (buff != NULL)
  1705.     {
  1706.         PA_Block new_buff;
  1707.         char *new_str;
  1708.  
  1709.         PA_LOCK(str, char *, buff);
  1710.         if (str != NULL)
  1711.         {
  1712.             int32 len;
  1713.  
  1714.             len = lo_StripTextWhitespace(str, XP_STRLEN(str));
  1715.         }
  1716.         new_str = NET_MakeAbsoluteURL(state->top_state->base_url, str);
  1717.         if (new_str == NULL)
  1718.         {
  1719.             new_buff = NULL;
  1720.         }
  1721.         else
  1722.         {
  1723.             char *url;
  1724.  
  1725.             new_buff = PA_ALLOC(XP_STRLEN(new_str) + 1);
  1726.             if (new_buff != NULL)
  1727.             {
  1728.                 PA_LOCK(url, char *, new_buff);
  1729.                 XP_STRCPY(url, new_str);
  1730.                 PA_UNLOCK(new_buff);
  1731.             }
  1732.             else
  1733.             {
  1734.                 state->top_state->out_of_memory = TRUE;
  1735.             }
  1736.  
  1737.             /* Complete kludge: if this image has the magic SRC,
  1738.              * then also parse an HREF from it (the IMG tag doesn't
  1739.              * normally have an HREF parameter.)
  1740.              *
  1741.              * The front ends know that when the user clicks on an
  1742.              * image with the magic SRC, that they may find the
  1743.              * "real" URL in the HREF... Gag me.
  1744.              */
  1745.             if (!XP_STRCMP(new_str, "internal-external-reconnect"))
  1746.             {
  1747.                 PA_Block hbuf;
  1748.  
  1749.                 hbuf = lo_FetchParamValue(context, tag, PARAM_HREF);
  1750.                 if (hbuf != NULL)
  1751.                 {
  1752.                     image->anchor_href =
  1753.                         lo_NewAnchor(state, hbuf, NULL);
  1754.                 }
  1755.             }
  1756.  
  1757.             XP_FREE(new_str);
  1758.         }
  1759.         PA_UNLOCK(buff);
  1760.         PA_FREE(buff);
  1761.         buff = new_buff;
  1762.     }
  1763.     image->image_url = buff;
  1764.  
  1765.     /*
  1766.      * Get the optional lowsrc parameter, and make the resulting
  1767.      * url and absolute url.
  1768.      */
  1769.     buff = lo_FetchParamValue(context, tag, PARAM_LOWSRC);
  1770.     if (buff != NULL)
  1771.     {
  1772.         PA_Block new_buff;
  1773.         char *new_str;
  1774.  
  1775.         PA_LOCK(str, char *, buff);
  1776.         if (str != NULL)
  1777.         {
  1778.         int32 len;
  1779.  
  1780.         len = lo_StripTextWhitespace(str, XP_STRLEN(str));
  1781.         }
  1782.         new_str = NET_MakeAbsoluteURL(state->top_state->base_url, str);
  1783.         if (new_str == NULL)
  1784.         {
  1785.             new_buff = NULL;
  1786.         }
  1787.         else
  1788.         {
  1789.             char *url;
  1790.  
  1791.             new_buff = PA_ALLOC(XP_STRLEN(new_str) + 1);
  1792.             if (new_buff != NULL)
  1793.             {
  1794.                 PA_LOCK(url, char *, new_buff);
  1795.                 XP_STRCPY(url, new_str);
  1796.                 PA_UNLOCK(new_buff);
  1797.             }
  1798.             else
  1799.             {
  1800.                 state->top_state->out_of_memory = TRUE;
  1801.             }
  1802.             XP_FREE(new_str);
  1803.         }
  1804.         PA_UNLOCK(buff);
  1805.         PA_FREE(buff);
  1806.         buff = new_buff;
  1807.     }
  1808.     image->lowres_image_url = buff;
  1809.  
  1810.     /*
  1811.      * Get the alt parameter, and store the resulting
  1812.      * text, and its length.  Form the special image form
  1813.      * element, store the name in alt.
  1814.      */
  1815.     if (is_a_form != FALSE)
  1816.     {
  1817.         buff = lo_FetchParamValue(context, tag, PARAM_NAME);
  1818.     }
  1819.     else
  1820.     {
  1821.         buff = lo_FetchParamValue(context, tag, PARAM_ALT);
  1822.     }
  1823.     if (buff != NULL)
  1824.     {
  1825.         PA_LOCK(str, char *, buff);
  1826.         image->alt_len = XP_STRLEN(str);
  1827.         image->alt_len = (int16)lo_StripTextNewlines(str,
  1828.                         (int32)image->alt_len);
  1829.         PA_UNLOCK(buff);
  1830.     }
  1831.     image->alt = buff;
  1832.  
  1833.     /*
  1834.     doc_width = state->right_margin - state->left_margin;
  1835.     */
  1836.  
  1837.     /*
  1838.      * Get the width parameter, in absolute or percentage.
  1839.      * If percentage, make it absolute.
  1840.      */
  1841.  
  1842.     /*
  1843.     buff = lo_FetchParamValue(context, tag, PARAM_WIDTH);
  1844.     if (buff != NULL)
  1845.     {
  1846.         Bool is_percent;
  1847.  
  1848.         PA_LOCK(str, char *, buff);
  1849.         val = lo_ValueOrPercent(str, &is_percent);
  1850.         if (is_percent != FALSE)
  1851.         {
  1852.             if (state->allow_percent_width == FALSE)
  1853.             {
  1854.                 val = 0;
  1855.             }
  1856.             else
  1857.             {
  1858.                 val = doc_width * val / 100;
  1859.             }
  1860.         }
  1861.         else
  1862.         {
  1863.             val = FEUNITS_X(val, context);
  1864.         }
  1865.         image->width = val;
  1866.         PA_UNLOCK(buff);
  1867.         PA_FREE(buff);
  1868.     }
  1869.     */
  1870.  
  1871.  
  1872.     buff = lo_FetchParamValue(context, tag, PARAM_WIDTH);
  1873.     if (buff != NULL)
  1874.     {
  1875.         Bool is_percent;
  1876.  
  1877.         PA_LOCK(str, char *, buff);
  1878.         val = lo_ValueOrPercent(str, &is_percent);
  1879.         if (is_percent != FALSE)
  1880.         {
  1881.             image->percent_width = val;
  1882.         }
  1883.         else
  1884.         {
  1885.             image->percent_width = 0;
  1886.             val = FEUNITS_X(val, context);
  1887.         }
  1888.         image->width = val;
  1889.         PA_UNLOCK(buff);
  1890.         PA_FREE(buff);
  1891.     }
  1892.  
  1893.  
  1894.     /* disabled because it is broken by JS threading 
  1895.      *
  1896.      * val = LO_GetWidthFromStyleSheet(context, state);
  1897.      * if(val)
  1898.      *    image->width = val;
  1899.      */
  1900.  
  1901.     /*
  1902.      * Get the height parameter, in absolute or percentage.
  1903.      * If percentage, make it absolute.
  1904.      */
  1905.     /*
  1906.     buff = lo_FetchParamValue(context, tag, PARAM_HEIGHT);
  1907.     if (buff != NULL)
  1908.     {
  1909.         Bool is_percent;
  1910.  
  1911.         PA_LOCK(str, char *, buff);
  1912.         val = lo_ValueOrPercent(str, &is_percent);
  1913.         if (is_percent != FALSE)
  1914.         {
  1915.             if (state->allow_percent_height == FALSE)
  1916.             {
  1917.                 val = 0;
  1918.             }
  1919.             else
  1920.             {
  1921.                 val = state->win_height * val / 100;
  1922.             }
  1923.         }
  1924.         else
  1925.         {
  1926.             val = FEUNITS_Y(val, context);
  1927.         }
  1928.         image->height = val;
  1929.         PA_UNLOCK(buff);
  1930.         PA_FREE(buff);
  1931.     }
  1932.     */
  1933.  
  1934.     buff = lo_FetchParamValue(context, tag, PARAM_HEIGHT);
  1935.     if (buff != NULL)
  1936.     {
  1937.         Bool is_percent;
  1938.  
  1939.         PA_LOCK(str, char *, buff);
  1940.         val = lo_ValueOrPercent(str, &is_percent);
  1941.         if (is_percent != FALSE)
  1942.         {
  1943.             image->percent_height = val;
  1944.         }
  1945.         else
  1946.         {
  1947.             image->percent_height = 0;
  1948.             val = FEUNITS_Y(val, context);
  1949.         }
  1950.         image->height = val;
  1951.         PA_UNLOCK(buff);
  1952.         PA_FREE(buff);
  1953.     }
  1954.  
  1955.     /* disabled because it is broken by JS threading 
  1956.      *
  1957.      * val = LO_GetHeightFromStyleSheet(context, state);
  1958.      * if(val)
  1959.      *    image->height = val;
  1960.      */
  1961.  
  1962.     /*
  1963.      * Get the border parameter.
  1964.      */
  1965.     buff = lo_FetchParamValue(context, tag, PARAM_BORDER);
  1966.     if (buff != NULL)
  1967.     {
  1968.         PA_LOCK(str, char *, buff);
  1969.         val = XP_ATOI(str);
  1970.         if (val < 0)
  1971.         {
  1972.             val = 0;
  1973.         }
  1974.         image->border_width = val;
  1975.         PA_UNLOCK(buff);
  1976.         PA_FREE(buff);
  1977.     }
  1978.     image->border_width = FEUNITS_X(image->border_width, context);
  1979.  
  1980.     /*
  1981.      * Get the extra vertical space parameter.
  1982.      */
  1983.     buff = lo_FetchParamValue(context, tag, PARAM_VSPACE);
  1984.     if (buff != NULL)
  1985.     {
  1986.         PA_LOCK(str, char *, buff);
  1987.         val = XP_ATOI(str);
  1988.         if (val < 0)
  1989.         {
  1990.             val = 0;
  1991.         }
  1992.         image->border_vert_space = val;
  1993.         PA_UNLOCK(buff);
  1994.         PA_FREE(buff);
  1995.     }
  1996.     image->border_vert_space = FEUNITS_Y(image->border_vert_space, context);
  1997.  
  1998.     /*
  1999.      * Get the extra horizontal space parameter.
  2000.      */
  2001.     if (image->ele_attrmask & LO_ELE_FLOATING)
  2002.     {
  2003.         image->border_horiz_space = IMAGE_DEF_FLOAT_HORIZONTAL_SPACE;
  2004.     }
  2005.     else
  2006.     {
  2007.         image->border_horiz_space = IMAGE_DEF_HORIZONTAL_SPACE;
  2008.     }
  2009.     buff = lo_FetchParamValue(context, tag, PARAM_HSPACE);
  2010.     if (buff != NULL)
  2011.     {
  2012.         PA_LOCK(str, char *, buff);
  2013.         val = XP_ATOI(str);
  2014.         if (val < 0)
  2015.         {
  2016.             val = 0;
  2017.         }
  2018.         image->border_horiz_space = val;
  2019.         PA_UNLOCK(buff);
  2020.         PA_FREE(buff);
  2021.     }
  2022.     image->border_horiz_space = FEUNITS_X(image->border_horiz_space,
  2023.                         context);
  2024.  
  2025.  
  2026.     lo_FillInImageGeometry( state, image );
  2027.  
  2028.     /*
  2029.      * Make sure we don't load insecure images inside
  2030.      * a secure document.
  2031.      */
  2032.     if (state->top_state->security_level > 0)
  2033.     {
  2034.         if (image->image_url != NULL)
  2035.         {
  2036.             PA_LOCK(str, char *, image->image_url);
  2037.             if (NET_IsURLSecure(str) == FALSE)
  2038.             {
  2039.                 PA_UNLOCK(image->image_url);
  2040.                 PA_FREE(image->image_url);
  2041.                 image->image_url = PA_ALLOC(
  2042.                     XP_STRLEN("internal-icon-insecure") + 1);
  2043.                 if (image->image_url != NULL)
  2044.                 {
  2045.                     PA_LOCK(str, char *, image->image_url);
  2046.                     XP_STRCPY(str, "internal-icon-insecure");
  2047.                     PA_UNLOCK(image->image_url);
  2048.                 }
  2049.                 else
  2050.                 {
  2051.                     state->top_state->out_of_memory = TRUE;
  2052.                 }
  2053.                 if (state->top_state->insecure_images == FALSE)
  2054.                 {
  2055.                     state->top_state->insecure_images = TRUE;
  2056.                     SECNAV_SecurityDialog(context, SD_INSECURE_DOCS_WITHIN_SECURE_DOCS_NOT_SHOWN);
  2057.                 }
  2058.             }
  2059.             else
  2060.             {
  2061.                 PA_UNLOCK(image->image_url);
  2062.             }
  2063.         }
  2064.     }
  2065.  
  2066. #ifdef MOCHA
  2067.     layer_id = lo_CurrentLayerId(state);
  2068.     image->layer_id = layer_id;
  2069.     
  2070.     /* Reflect the image into Javascript */
  2071.     lo_ReflectImage(context, state, tag, image, FALSE, layer_id);
  2072. #endif
  2073.  
  2074.     if (context->compositor) {
  2075.         image->layer = lo_CreateImageLayer(context, image, NULL);
  2076.     }
  2077.  
  2078.     /* Initiate the loading of this image. */
  2079.     image_obs_list = lo_NewImageObserverList(context, image);
  2080.     if (!image_obs_list)
  2081.         return;
  2082.     lo_GetImage(context, context->img_cx, image, image_obs_list,
  2083.                     state->top_state->force_reload);
  2084.  
  2085.     /* During relayout the editor is not allowed to block. */
  2086.     if ( (image->width == 0)||(image->height == 0))
  2087.     {
  2088.         if ( EDT_IN_RELAYOUT( context ) ){
  2089.             lo_edt_AvoidImageBlock(image);
  2090.         }
  2091.     }
  2092.  
  2093.     /*
  2094.      * We may have to block on this image until later
  2095.      * when the front end can give us the width and height.
  2096.      */
  2097.     if ((image->width == 0)||(image->height == 0))
  2098.     {
  2099.         state->top_state->layout_blocking_element = (LO_Element *)image;
  2100.     }
  2101.     else
  2102.     {
  2103.         lo_FinishImage(context, state, image);
  2104.     }
  2105. }
  2106.  
  2107.  
  2108. void
  2109. lo_FinishImage(MWContext *context, lo_DocState *state, LO_ImageStruct *image)
  2110. {
  2111.     /* PA_Block buff;
  2112.     char *str;
  2113.     Bool line_break;
  2114.     */
  2115.     int32 baseline_inc;
  2116.     int32 line_inc;
  2117.     /*
  2118.     int32 image_height, image_width;
  2119.     LO_TextStruct tmp_text;
  2120.     LO_TextInfo text_info;
  2121.     */
  2122.  
  2123.     if (context->compositor && lo_CurrentLayerState(state)) {
  2124.         CL_Layer *parent, *doc_layer, *content_layer;
  2125.             lo_LayerDocState *layer_state = lo_CurrentLayerState(state);
  2126.         
  2127.         doc_layer = CL_GetCompositorRoot(context->compositor);
  2128.         if (layer_state->layer == doc_layer) 
  2129.         parent = CL_GetLayerChildByName(doc_layer,
  2130.                                             LO_BODY_LAYER_NAME);
  2131.         else
  2132.         parent = layer_state->layer;
  2133.  
  2134.             content_layer = CL_GetLayerChildByName(parent, 
  2135.                                                    LO_CONTENT_LAYER_NAME);
  2136.             XP_ASSERT(content_layer);
  2137.             if (content_layer)
  2138.                 CL_InsertChild(parent, image->layer, content_layer, CL_ABOVE);
  2139.     }
  2140.  
  2141.     /*
  2142.      * All this work is to get the text_info filled in for the current
  2143.      * font in the font stack. Yuck, there must be a better way.
  2144.      */
  2145.     
  2146.     /*
  2147.     memset (&tmp_text, 0, sizeof (tmp_text));
  2148.     buff = PA_ALLOC(1);
  2149.     if (buff == NULL)
  2150.     {
  2151.         state->top_state->out_of_memory = TRUE;
  2152.         return;
  2153.     }
  2154.     PA_LOCK(str, char *, buff);
  2155.     str[0] = ' ';
  2156.     PA_UNLOCK(buff);
  2157.     tmp_text.text = buff;
  2158.     tmp_text.text_len = 1;
  2159.     tmp_text.text_attr =
  2160.         state->font_stack->text_attr;
  2161.     FE_GetTextInfo(context, &tmp_text, &text_info);
  2162.     PA_FREE(buff);
  2163.     */
  2164.  
  2165.     /*
  2166.      * Eventually this will never happen since we always
  2167.      * have dims here from either the image tag itself or the
  2168.      * front end.
  2169.      */
  2170.     
  2171.     /*
  2172.     if (image->width == 0)
  2173.     {
  2174.         image->width = IMAGE_DEF_DIM;
  2175.     }
  2176.     if (image->height == 0)
  2177.     {
  2178.         image->height = IMAGE_DEF_DIM;
  2179.     }
  2180.  
  2181.     image_width = image->width + (2 * image->border_width) +
  2182.         (2 * image->border_horiz_space);
  2183.     image_height = image->height + (2 * image->border_width) +
  2184.         (2 * image->border_vert_space);
  2185.  
  2186.     */
  2187.  
  2188.  
  2189.     /*
  2190.      * SEVERE FLOW BREAK!  This may be a floating image,
  2191.      * which means at this point we go do something completely
  2192.      * different.
  2193.      */
  2194.     if (image->ele_attrmask & LO_ELE_FLOATING)
  2195.     {    /*
  2196.         if (image->image_attr->alignment == LO_ALIGN_RIGHT)
  2197.         {
  2198.             if (state->right_margin_stack == NULL)
  2199.             {
  2200.                 image->x = state->right_margin - image_width;
  2201.             }
  2202.             else
  2203.             {
  2204.                 image->x = state->right_margin_stack->margin -
  2205.                     image_width;
  2206.             }
  2207.             if (image->x < 0)
  2208.             {
  2209.                 image->x = 0;
  2210.             }
  2211.         }
  2212.         else
  2213.         {
  2214.             image->x = state->left_margin;
  2215.         }
  2216.  
  2217.         image->y = -1;
  2218.         image->x_offset += (int16)image->border_horiz_space;
  2219.         image->y_offset += (int32)image->border_vert_space;
  2220.  
  2221.         lo_AddMarginStack(state, image->x, image->y,
  2222.             image->width, image->height,
  2223.             image->border_width,
  2224.             image->border_vert_space, image->border_horiz_space,
  2225.             image->image_attr->alignment);
  2226.  
  2227.         */
  2228.  
  2229.         /*
  2230.          * Insert this element into the float list.
  2231.          */
  2232.         image->next = state->float_list;
  2233.         state->float_list = (LO_Element *)image;
  2234.  
  2235.         /* Update its offsets */
  2236.         image->x_offset += (int16)image->border_horiz_space;
  2237.         image->y_offset += (int32)image->border_vert_space;    
  2238.  
  2239.         /* 
  2240.          * Append a dummy layout element in the line list.  When the relayout engine
  2241.          * will see this dummy element, it will call lo_LayoutFloatImage()
  2242.          */
  2243.         lo_AppendFloatInLineList( state, (LO_Element *) image, NULL );
  2244.         
  2245.         lo_LayoutFloatImage( context, state, image, TRUE);
  2246.         
  2247.         /*
  2248.         if (state->at_begin_line != FALSE)
  2249.         {
  2250.             lo_FindLineMargins(context, state);
  2251.             state->x = state->left_margin;
  2252.         }
  2253.         */
  2254.  
  2255.         return;
  2256.     }
  2257.  
  2258.     /*
  2259.      * Will this image make the line too wide.
  2260.      */
  2261.     /*
  2262.     if ((state->x + image_width) > state->right_margin)
  2263.     {
  2264.         line_break = TRUE;
  2265.     }
  2266.     else
  2267.     {
  2268.         line_break = FALSE;
  2269.     }
  2270.     */
  2271.  
  2272.     /*
  2273.      * We cannot break a line if we have no break positions.
  2274.      * Usually happens with a single line of unbreakable text.
  2275.      */
  2276.     /*
  2277.      * This doesn't work right now, I don't know why, seems we
  2278.      * have lost the last old_break_pos somehow.
  2279.      */
  2280. #ifdef FIX_THIS
  2281.     if ((line_break != FALSE)&&(state->break_pos == -1))
  2282.     {
  2283.         /*
  2284.          * It may be possible to break a previous
  2285.          * text element on the same line.
  2286.          */
  2287.         if (state->old_break_pos != -1)
  2288.         {
  2289.             lo_BreakOldElement(context, state);
  2290.             line_break = FALSE;
  2291.         }
  2292.         else
  2293.         {
  2294.             line_break = FALSE;
  2295.         }
  2296.     }
  2297. #endif /* FIX_THIS */
  2298.  
  2299.     /*
  2300.      * if we are at the beginning of the line.  There is
  2301.      * no point in breaking, we are just too wide.
  2302.      * Also don't break in unwrapped preformatted text.
  2303.      * Also can't break inside a NOBR section.
  2304.      */
  2305.     /*
  2306.     if ((state->at_begin_line != FALSE)||
  2307.         (state->preformatted == PRE_TEXT_YES)||
  2308.         (state->breakable == FALSE))
  2309.     {
  2310.         line_break = FALSE;
  2311.     }
  2312.     */
  2313.  
  2314.     /*
  2315.      * break on the image if we have
  2316.      * a break.
  2317.      */
  2318.     /*
  2319.     if (line_break != FALSE)
  2320.     {
  2321.     */
  2322.         /*
  2323.          * We need to make the elements sequential, linefeed
  2324.          * before image.
  2325.          */
  2326.     /*
  2327.         state->top_state->element_id = image->ele_id;
  2328.  
  2329.         lo_SoftLineBreak(context, state, TRUE);
  2330.         image->x = state->x;
  2331.         image->y = state->y;
  2332.         image->ele_id = NEXT_ELEMENT;
  2333.     }
  2334.     */
  2335.  
  2336.     /*
  2337.      * Figure out how to align this image.
  2338.      * baseline_inc is how much to increase the baseline
  2339.      * of previous element of this line.  line_inc is how
  2340.      * much to increase the line height below the baseline.
  2341.      */
  2342.     /*
  2343.     baseline_inc = 0;
  2344.     line_inc = 0;
  2345.     */
  2346.  
  2347.     /*
  2348.      * If we are at the beginning of a line, with no baseline,
  2349.      * we first set baseline and line_height based on the current
  2350.      * font, then place the image.
  2351.      */
  2352.     if (state->baseline == 0)
  2353.     {
  2354. #ifdef ALIGN_IMAGE_WITH_FAKE_TEXT
  2355.         state->baseline = text_info.ascent;
  2356.         state->line_height = text_info.ascent + text_info.descent;
  2357. #else
  2358.         state->baseline = 0;
  2359. /* Why do we need this?
  2360.         if (state->line_height < 1)
  2361.         {
  2362.             state->line_height = 1;
  2363.         }
  2364. */
  2365. #endif /* ALIGN_IMAGE_WITH_FAKE_TEXT */
  2366.     }
  2367.  
  2368.     /*
  2369.     lo_CalcAlignOffsets(state, &text_info, image->image_attr->alignment,
  2370.         image_width, image_height,
  2371.         &image->x_offset, &image->y_offset, &line_inc, &baseline_inc);
  2372.  
  2373.     image->x_offset += (int16)image->border_horiz_space;
  2374.     image->y_offset += (int32)image->border_vert_space;
  2375.     */
  2376.  
  2377.     lo_LayoutInflowImage( context, state, image, FALSE, &line_inc, &baseline_inc);
  2378.  
  2379.     lo_AppendToLineList(context, state,
  2380.         (LO_Element *)image, baseline_inc);
  2381.  
  2382.     lo_UpdateStateAfterImageLayout( state, image, line_inc, baseline_inc );
  2383.  
  2384.     /*
  2385.     state->baseline += (intn) baseline_inc;
  2386.     state->line_height += (intn) (baseline_inc + line_inc);
  2387.     */
  2388.  
  2389.     /*
  2390.      * Clean up state
  2391.      */
  2392.  
  2393.     /*
  2394.     state->x = state->x + image->x_offset +
  2395.         image_width - image->border_horiz_space;
  2396.     state->linefeed_state = 0;
  2397.     state->at_begin_line = FALSE;
  2398.     state->trailing_space = FALSE;
  2399.     state->cur_ele_type = LO_IMAGE;
  2400.     */
  2401. }
  2402.  
  2403.  
  2404. Bool
  2405. LO_BlockedOnImage(MWContext *context, LO_ImageStruct *image)
  2406. {
  2407.     int32 doc_id;
  2408.     lo_TopState *top_state;
  2409.  
  2410.     /*
  2411.      * Get the unique document ID, and retreive this
  2412.      * documents layout state.
  2413.      */
  2414.     doc_id = XP_DOCID(context);
  2415.     top_state = lo_FetchTopState(doc_id);
  2416.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  2417.     {
  2418.         return(FALSE);
  2419.     }
  2420.  
  2421.     if ((top_state->layout_blocking_element != NULL)&&
  2422.         (top_state->layout_blocking_element == (LO_Element *)image))
  2423.     {
  2424.         return(TRUE);
  2425.     }
  2426.     return(FALSE);
  2427. }
  2428.  
  2429.  
  2430. /*
  2431.  * Make sure the image library has been informed of all possible
  2432.  * image URLs that might be loaded by this document.
  2433.  */
  2434. void
  2435. lo_NoMoreImages(MWContext *context)
  2436. {
  2437.     PA_Tag *tag_ptr;
  2438.     int32 doc_id;
  2439.     lo_TopState *top_state;
  2440.     lo_DocState *state;
  2441.  
  2442.     /*
  2443.      * All blocked tags should be at the top level of state
  2444.      */
  2445.     doc_id = XP_DOCID(context);
  2446.     top_state = lo_FetchTopState(doc_id);
  2447.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  2448.     {
  2449. #ifndef M12N                    /* XXXM12N Fix me. IL_NoMoreImages was used
  2450.                                    by the image library to detect when it
  2451.                                    could install a custom colormap. */
  2452.         /*
  2453.          * No matter what, we must be done with all images now
  2454.          */
  2455.         IL_NoMoreImages(context);
  2456. #else
  2457.         /* XXXM12N Need an observer callback. */
  2458. #endif /* M12N */
  2459.         return;
  2460.     }
  2461.     state = top_state->doc_state;
  2462.     tag_ptr = top_state->tags;
  2463.  
  2464.     /*
  2465.      * Go through all the remaining blocked tags looking
  2466.      * for <INPUT TYPE=IMAGE> tags.
  2467.      */
  2468.     while (tag_ptr != NULL)
  2469.     {
  2470.         if (tag_ptr->type == P_INPUT)
  2471.         {
  2472.             PA_Block buff;
  2473.             char *str;
  2474.             int32 type;
  2475.  
  2476.             type = FORM_TYPE_TEXT;
  2477.             buff = lo_FetchParamValue(context, tag_ptr, PARAM_TYPE);
  2478.             if (buff != NULL)
  2479.             {
  2480.                 PA_LOCK(str, char *, buff);
  2481.                 type = lo_ResolveInputType(str);
  2482.                 PA_UNLOCK(buff);
  2483.                 PA_FREE(buff);
  2484.             }
  2485.  
  2486.             /*
  2487.              * Prefetch this image.
  2488.              * The ImageStruct created will get stuck into
  2489.              * tag_ptr->lo_data, and freed later in 
  2490.              * lo_ProcessInputTag().
  2491.              */
  2492.             if (type == FORM_TYPE_IMAGE)
  2493.             {
  2494.                 lo_BlockedImageLayout(context, state, tag_ptr, 
  2495.                                       top_state->base_url);
  2496.             }
  2497.         }
  2498.         tag_ptr = tag_ptr->next;
  2499.     }
  2500.  
  2501. #ifndef M12N                    /* XXXM12N Fix me. IL_NoMoreImages was used
  2502.                                    by the image library to detect when it
  2503.                                    could install a custom colormap. */
  2504.         /*
  2505.          * No matter what, we must be done with all images now
  2506.          */
  2507.         IL_NoMoreImages(context);
  2508. #else
  2509.         /* XXXM12N Need an observer callback. */
  2510. #endif /* M12N */
  2511. }
  2512.  
  2513. #ifdef EDITOR
  2514. LO_ImageStruct* LO_NewImageElement( MWContext* context ){
  2515.     int32 doc_id;
  2516.     lo_TopState *top_state;
  2517.     lo_DocState *state;
  2518.     LO_ImageStruct *image;
  2519.  
  2520.     /*
  2521.      * Get the unique document ID, and retreive this
  2522.      * documents layout state.
  2523.      */
  2524.     doc_id = XP_DOCID(context);
  2525.     top_state = lo_FetchTopState(doc_id);
  2526.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  2527.     {
  2528.         return 0;
  2529.     }
  2530.     state = top_state->doc_state;
  2531.  
  2532.     state->edit_current_element = 0;
  2533.     state->edit_current_offset = 0;
  2534.  
  2535.     /*
  2536.      * Fill in the image structure with default data
  2537.      */
  2538.     image = lo_new_image_element(context, state, NULL, NULL);
  2539.     if (!image)
  2540.         return NULL;
  2541.  
  2542.     image->border_width = -1;
  2543.     image->border_vert_space  = IMAGE_DEF_VERTICAL_SPACE;
  2544.     image->border_horiz_space = IMAGE_DEF_HORIZONTAL_SPACE;
  2545.  
  2546.     return image;
  2547. }
  2548. #endif        
  2549.  
  2550.  
  2551. /* Create a new observer list which will be passed into to IL_GetImage (via
  2552.    lo_GetImage) in order to permit an Image Library request to be
  2553.    monitored. The layout image observer is added to this new observer list
  2554.    before the function returns. */
  2555. XP_ObserverList
  2556. lo_NewImageObserverList(MWContext *context, LO_ImageStruct *lo_image)
  2557. {
  2558.     int32 doc_id;lo_TopState *top_state;
  2559.     XP_ObserverList image_obs_list; /* List of observer callbacks. */
  2560.     lo_ImageObsClosure *image_obs_closure; /* Closure data to be passed back
  2561.                                               to lo_ImageObserver. */
  2562.     NS_Error status;
  2563.  
  2564.     /* Get the unique document ID, and retrieve this document's layout
  2565.        state. */
  2566.     doc_id = XP_DOCID(context);
  2567.     top_state = lo_FetchTopState(doc_id);
  2568.     if (!top_state)    {
  2569.         return NULL;
  2570.     }
  2571.  
  2572.     /* Create an XP_ObserverList for this image.  The observable IL_ImageReq
  2573.        will be set by the Image Library. */
  2574.     status = XP_NewObserverList(NULL, &image_obs_list);
  2575.     if (status < 0) {
  2576.         if (status == MK_OUT_OF_MEMORY)
  2577.             top_state->out_of_memory = TRUE;
  2578.         return NULL;
  2579.     }
  2580.  
  2581.     /* Closure data for the image observer. */
  2582.     image_obs_closure = XP_NEW_ZAP(lo_ImageObsClosure);
  2583.     if (!image_obs_closure) {
  2584.         top_state->out_of_memory = TRUE;
  2585.         return NULL;
  2586.     }
  2587.     image_obs_closure->context = context;
  2588.     image_obs_closure->lo_image = lo_image;
  2589.     image_obs_closure->obs_list = image_obs_list;
  2590.  
  2591.     /* Add the layout image observer to the observer list. */
  2592.     status = XP_AddObserver(image_obs_list, lo_ImageObserver, image_obs_closure);
  2593.     if (status < 0) {
  2594.         if (status == MK_OUT_OF_MEMORY)
  2595.             top_state->out_of_memory = TRUE;
  2596.         return NULL;
  2597.     }
  2598.  
  2599.     return image_obs_list;
  2600. }
  2601.  
  2602.  
  2603. static void
  2604. lo_image_pixmap_update(MWContext *context, LO_ImageStruct *lo_image,
  2605.                        IL_Rect *update_rect)
  2606. {
  2607.     /* This lo_image cannot correspond to an icon since we are receiving
  2608.        pixmap update messages. */
  2609.     lo_image->is_icon = FALSE;
  2610.  
  2611.     /* Update the image layer if it is appropriate to do so. */
  2612.     if (context->compositor && lo_image && lo_image->layer &&
  2613.         lo_image->image_attr) {
  2614.         if (lo_image->image_attr->attrmask & LO_ATTR_BACKDROP) {
  2615.             /* Only update backdrops when the image has
  2616.                completed decoding, not when the pixmap is updated. */
  2617.         }
  2618.         else {
  2619.             /* Non-backdrop images only respond to pixmap update messages
  2620.                so that they can load incrementally. */
  2621.             XP_Rect rect, *valid_rect;
  2622.  
  2623.             rect.left = FEUNITS_X(update_rect->x_origin, context);
  2624.             rect.top = FEUNITS_Y(update_rect->y_origin, context);
  2625.             rect.bottom = rect.top + FEUNITS_Y(update_rect->height, context);
  2626.             rect.right = rect.left + FEUNITS_X(update_rect->width, context);
  2627.  
  2628.             valid_rect = &lo_image->valid_rect;
  2629.             XP_RectsBbox(&rect, valid_rect, valid_rect);
  2630.             CL_ResizeLayer(lo_image->layer, valid_rect->right - valid_rect->left,
  2631.                            valid_rect->bottom - valid_rect->top);
  2632.             CL_UpdateLayerRect(context->compositor, lo_image->layer, &rect,
  2633.                                PR_TRUE); /* XXX FALSE on the final update? */
  2634.         }
  2635.     }
  2636. }
  2637.  
  2638. static void
  2639. lo_frame_complete(MWContext *context, LO_ImageStruct *lo_image)
  2640. {
  2641.     PRBool is_anim, is_backdrop, is_cell_backdrop;
  2642.  
  2643.     XP_ASSERT(lo_image && lo_image->image_attr);
  2644.     if (!lo_image || !lo_image->image_attr) /* Paranoia */
  2645.         return;
  2646.  
  2647.     /* If we've already received a frame-complete message, then this
  2648.        must be an animated image. */
  2649.     is_anim = (PRBool)(lo_image->image_status == IL_FRAME_COMPLETE); 
  2650.     is_backdrop = (PRBool)(lo_image->image_attr->attrmask & LO_ATTR_BACKDROP);
  2651.     is_cell_backdrop = (PRBool)(lo_image->image_attr->attrmask & LO_ATTR_CELL_BACKDROP);
  2652.  
  2653.     if (!is_cell_backdrop)
  2654.         ET_SendImageEvent(context, lo_image, LM_IMGLOAD);
  2655.  
  2656.     if (!lo_image->layer)
  2657.         return;
  2658.  
  2659.     if (is_backdrop) {
  2660.         /* Only update cell/layer/doc backdrops when the image has completed
  2661.            loading, not when the pixmap is updated. */
  2662.         XP_Rect rect = CL_MAX_RECT;
  2663.         CL_UpdateLayerRect(context->compositor, lo_image->layer, &rect, PR_FALSE);
  2664.  
  2665.         /* Unlike ordinary images, backdrop images are assumed to be transparent
  2666.            until they are displayed.  (Ordinary images are assumed to be opaque
  2667.            until they are determined to be transparent.) */
  2668.         CL_ChangeLayerFlag(lo_image->layer, CL_OPAQUE, (PRBool)!lo_image->is_transparent);
  2669.         
  2670.         /* If this animated GIF serves as a backdrop image, force
  2671.            offscreen compositing in order to reduce flicker. */
  2672.         if (is_anim)
  2673.             CL_ChangeLayerFlag(lo_image->layer, CL_PREFER_DRAW_OFFSCREEN, PR_TRUE);
  2674.     }
  2675.     else {
  2676.         /* We may need to reset the layer transparency if the current image
  2677.            is opaque and it is replacing a previous image. */
  2678.         if (!lo_image->is_transparent) {
  2679.             CL_ChangeLayerFlag(lo_image->layer, CL_OPAQUE, PR_TRUE);
  2680.             CL_ChangeLayerFlag(lo_image->layer, CL_PREFER_DRAW_OFFSCREEN,
  2681.                                PR_FALSE);
  2682.         }
  2683.     }
  2684.  
  2685. }
  2686.  
  2687.  
  2688. static void
  2689. lo_image_dimensions(MWContext *context, LO_ImageStruct *lo_image,
  2690.                     int width, int height)
  2691. {
  2692.     if(!lo_image)    {
  2693.         return;
  2694.     }
  2695.  
  2696.     width = FEUNITS_X(width, context);
  2697.     height = FEUNITS_Y(height, context);
  2698.     lo_image->width = width;
  2699.     lo_image->height = height;
  2700.  
  2701.     /* Don't call LO_SetImageInfo() for backdrop images. */
  2702.     if (lo_image->image_attr &&
  2703.         !(lo_image->image_attr->attrmask & LO_ATTR_BACKDROP))
  2704.         {
  2705.             LO_SetImageInfo (context, lo_image->ele_id, width, height);
  2706.         }
  2707. }
  2708.  
  2709. static void
  2710. lo_icon_box( MWContext *context, LO_ImageStruct *lo_image, int icon_width, int icon_height )
  2711. {
  2712.     LO_TextStruct text;
  2713.     LO_TextAttr text_attr;
  2714.     LO_TextInfo text_info;
  2715.     int32 doc_id;
  2716.     lo_TopState *top_state;
  2717.     lo_DocState *state;
  2718.     char *image_url;
  2719.       
  2720.  /* ptn: The code that determines the area needed for the alt text
  2721.     will be put in a separate function so that it is the same
  2722.     code called for the display alttext as well as the area estimation.
  2723.     This code was for an immediate bug fix with time limits */
  2724.         
  2725.        PA_LOCK(image_url, char *, lo_image->image_url);
  2726.     /* Determine whether the icon was explicitly requested by URL
  2727.     (in which case only the icon is drawn) or whether it needs
  2728.     to be drawn as a placeholder (along with the ALT text and
  2729.     placeholder border) as a result of a failed image request. */
  2730.     if (image_url &&
  2731.         (*image_url == 'i'              ||
  2732.         !XP_STRNCMP(image_url, "/mc-", 4)  ||
  2733.         !XP_STRNCMP(image_url, "/ns-", 4))) {
  2734.             lo_image->width = FEUNITS_X(icon_width, context);
  2735.             lo_image->height = FEUNITS_Y(icon_height, context);
  2736.     }
  2737.     else {
  2738.         lo_image->width = FEUNITS_X(icon_width + (2*ICON_X_OFFSET), 
  2739.                                             context);
  2740.         lo_image->height = FEUNITS_Y(icon_height + (2*ICON_Y_OFFSET), 
  2741.                                              context);
  2742.         
  2743.         if(lo_image->alt){
  2744.                 
  2745.             /* Get the unique doc ID, and retrieve this doc's layout state. 
  2746.             */
  2747.             doc_id = XP_DOCID(context);
  2748.             top_state = lo_FetchTopState(doc_id);
  2749.             if (!top_state)    {
  2750.                 return;
  2751.             }
  2752.             state = lo_CurrentSubState(top_state->doc_state);
  2753.             memset (&text, 0, sizeof (text));
  2754.             text.text_attr = &text_attr;
  2755.             lo_SetDefaultFontAttr(state, text.text_attr, context);
  2756.             text.text = lo_image->alt;
  2757.             text.text_len = lo_image->alt_len;
  2758.  
  2759.              FE_GetTextInfo(context, &text, &text_info);
  2760.  
  2761.             text.width = text_info.max_width;
  2762.             text.height = text_info.ascent + text_info.descent;
  2763.             if( text.width && text.height ){
  2764.                 lo_image->width  = FEUNITS_X(icon_width + (4*ICON_X_OFFSET), context) + text.width;
  2765.                 lo_image->height= (icon_height > text.height) ? 
  2766.                         FEUNITS_Y(icon_height + (2*ICON_Y_OFFSET), context) : text.height + FEUNITS_Y(2*ICON_Y_OFFSET, context);
  2767.             }    
  2768.         }
  2769.     } 
  2770.     PA_UNLOCK(lo_image->image_url);
  2771. }
  2772.  
  2773. static void
  2774. lo_internal_image(MWContext *context, LO_ImageStruct *lo_image, int icon_number,
  2775.                   int icon_width, int icon_height)
  2776. {
  2777.     int bw = lo_image->border_width;
  2778.  
  2779.  
  2780.     /* Don't draw icons for mocha images. */
  2781.     if (lo_image->image_attr->attrmask & LO_ATTR_MOCHA_IMAGE)
  2782.         return;
  2783.  
  2784.     /* Mark this lo_image as an icon, so that drawing calls will use
  2785.        IL_DisplayIcon instead of IL_DisplaySubImage. */
  2786.     lo_image->is_icon = TRUE;
  2787.     lo_image->icon_number = icon_number;
  2788.     
  2789.     /* Set the lo_image->width and lo_image->height so that 
  2790.     icons and alt text are displayed, if present */
  2791.  
  2792.     if(!lo_image->width || !lo_image->height )
  2793.         lo_icon_box( context, lo_image, icon_width, icon_height );
  2794.  
  2795.     /* Tell layout the dimensions of the image. */
  2796.     LO_SetImageInfo (context, lo_image->ele_id, lo_image->width, lo_image->height);
  2797.  
  2798.     /* Refresh the area occupied by the image. */
  2799.     if (context->compositor && lo_image->layer) {
  2800.         XP_Rect update_rect, *valid_rect;
  2801.  
  2802.         update_rect.left = 0;
  2803.         update_rect.top = 0;
  2804.         update_rect.right = lo_image->width;
  2805.         update_rect.bottom = lo_image->height;
  2806.  
  2807.         valid_rect = &lo_image->valid_rect;
  2808.         XP_RectsBbox(&update_rect, valid_rect, valid_rect);
  2809.         CL_SetLayerBbox(lo_image->layer, valid_rect);
  2810.         CL_ChangeLayerFlag(lo_image->layer, CL_OPAQUE, PR_FALSE);
  2811.  
  2812.         CL_UpdateLayerRect(context->compositor, lo_image->layer, &update_rect,
  2813.                            PR_FALSE);
  2814.     }
  2815. }
  2816.  
  2817.  
  2818. static void
  2819. lo_image_incomplete(MWContext *context, LO_ImageStruct *lo_image,
  2820.                     XP_ObservableMsg message, int icon_number,
  2821.                     int icon_width, int icon_height, LM_ImageEvent mocha_event)
  2822. {
  2823.  
  2824.     if (lo_image->lowres_image_req) {
  2825.         /* If we already have a lowres image, then use that instead. */
  2826.         lo_image->image_req = lo_image->lowres_image_req;
  2827.     }
  2828.     else {
  2829.         lo_image->image_status = (uint16)message;
  2830.             
  2831.         if (lo_image->width && lo_image->height) {
  2832.             int valid_width, valid_height;
  2833.             XP_Rect *valid_rect = &lo_image->valid_rect;
  2834.  
  2835.             valid_width = valid_rect->right - valid_rect->left;
  2836.             valid_height = valid_rect->bottom - valid_rect->top;
  2837.             if (!valid_height || !valid_width)
  2838.                 lo_internal_image(context, lo_image, icon_number,
  2839.                                   icon_width, icon_height);
  2840.         }
  2841.         else {
  2842.             lo_internal_image(context, lo_image, icon_number,
  2843.                               icon_width, icon_height);
  2844.         }
  2845.  
  2846.         if (lo_image->image_attr &&
  2847.             !(lo_image->image_attr->attrmask & LO_ATTR_CELL_BACKDROP))
  2848.                 ET_SendImageEvent(context, lo_image, mocha_event);
  2849.     }
  2850. }
  2851.  
  2852.         
  2853. /* Image observer callback. */
  2854. void
  2855. lo_ImageObserver(XP_Observable observable, XP_ObservableMsg message,
  2856.                  void *message_data, void *closure)
  2857. {
  2858.     IL_MessageData *data = (IL_MessageData*)message_data;
  2859.     lo_ImageObsClosure *image_obs_closure = (lo_ImageObsClosure *)closure;
  2860.     MWContext *context;
  2861.     LO_ImageStruct *lo_image;
  2862. #ifdef MOCHA
  2863.     LM_ImageEvent mocha_event;
  2864. #endif /* MOCHA */
  2865.  
  2866.     if (image_obs_closure) {
  2867.         context = image_obs_closure->context;
  2868.         lo_image = image_obs_closure->lo_image;
  2869.     }
  2870.  
  2871.     /* The lo_image may not have a valid image handle at this point, or
  2872.        the image's URL property may have been changed in JavaScript,
  2873.        so give the lo_image the image handle passed in with the message
  2874.        data. */
  2875.     if(lo_image)    {
  2876.         lo_image->image_req = data->image_instance;
  2877.     }
  2878.  
  2879.      switch(message) {
  2880.     case IL_DIMENSIONS:
  2881.         lo_image_dimensions(context, lo_image, data->width, data->height);
  2882.         break;
  2883.  
  2884.     case IL_IS_TRANSPARENT:
  2885.         lo_image->is_transparent = TRUE;
  2886.         if (context->compositor && lo_image->layer) {
  2887.             CL_ChangeLayerFlag(lo_image->layer, CL_OPAQUE, PR_FALSE);
  2888.             CL_ChangeLayerFlag(lo_image->layer, CL_PREFER_DRAW_OFFSCREEN,
  2889.                                PR_TRUE);
  2890.         }
  2891.        break;
  2892.  
  2893.     case IL_DESCRIPTION:
  2894.         /* This must be a call to the stand alone image viewer, so
  2895.             the document title is set in the Title observer in 
  2896.            libimg/src/dummy_nc.c.*/         
  2897.         break;
  2898.  
  2899.     case IL_PIXMAP_UPDATE:
  2900.         lo_image_pixmap_update(context, lo_image, &data->update_rect);
  2901.         break;
  2902.  
  2903.     case IL_IMAGE_COMPLETE:
  2904.         lo_image->image_status = (uint16)message;
  2905.     if( (lo_image->lowres_image_url) != NULL ){
  2906.         if(!lo_image->lowres_image_req){
  2907.             XP_ObserverList tmp_obs_list;
  2908.             int32 doc_id;
  2909.             lo_TopState *top_state;
  2910.          
  2911.             /* Get the unique document ID, and retrieve this document's layout
  2912.                state. 
  2913.             */
  2914.             doc_id = XP_DOCID(context);
  2915.             top_state = lo_FetchTopState(doc_id);
  2916.             if (!top_state)    {
  2917.                 return;
  2918.             }
  2919.  
  2920.             /* Hold on to lowres image handle in case the highres image
  2921.                fails. */
  2922.             lo_image->lowres_image_req = lo_image->image_req;
  2923.  
  2924.             tmp_obs_list = lo_NewImageObserverList(context, lo_image);
  2925.             /* Lowres image request is overwritten. Destruction of
  2926.                lowres image occurs when document is destroyed.    */
  2927.             lo_GetImage(context, context->img_cx, lo_image, tmp_obs_list,
  2928.                         top_state->force_reload);
  2929.             }
  2930.         }    
  2931.         break;
  2932.         
  2933.     case IL_FRAME_COMPLETE:
  2934.         lo_frame_complete(context, lo_image);
  2935.         lo_image->image_status = (uint16)message;
  2936.         break;
  2937.  
  2938.     case IL_NOT_IN_CACHE:
  2939.         if (lo_image->lowres_image_req) {
  2940.             /* If we already have a lowres image, then use that instead. */
  2941.             lo_image->image_req = lo_image->lowres_image_req;
  2942.         }
  2943.         else {
  2944.             lo_image->image_status = (uint16)message;
  2945.             lo_internal_image(context, lo_image, data->icon_number,
  2946.                               data->icon_width, data->icon_height);
  2947.             /* As far as JavaScript events go, we treat an image that wasn't in
  2948.                the cache the same as if it was actually loaded.  That way, a
  2949.                Javascript program will run the same way with images turned on
  2950.                or off. */
  2951.              mocha_event = LM_IMGLOAD;
  2952.              if (lo_image->image_attr &&
  2953.                  !(lo_image->image_attr->attrmask & LO_ATTR_CELL_BACKDROP))
  2954.                       ET_SendImageEvent(context, lo_image, mocha_event);
  2955.         }
  2956.         break;
  2957.  
  2958.     case IL_ABORTED:
  2959.        lo_image_incomplete(context, lo_image, message, data->icon_number,
  2960.                     data->icon_width, data->icon_height, LM_IMGABORT);
  2961.        break;
  2962.  
  2963.     case IL_ERROR_NO_DATA:
  2964.     case IL_ERROR_IMAGE_DATA_CORRUPT:
  2965.     case IL_ERROR_IMAGE_DATA_TRUNCATED:
  2966.     case IL_ERROR_IMAGE_DATA_ILLEGAL:
  2967.     case IL_ERROR_INTERNAL:
  2968.         lo_image_incomplete(context, lo_image, message, data->icon_number,
  2969.                     data->icon_width, data->icon_height, LM_IMGERROR);
  2970.         break;
  2971.  
  2972.     case IL_INTERNAL_IMAGE:
  2973.         lo_internal_image(context, lo_image, data->icon_number, data->icon_width,
  2974.                           data->icon_height);
  2975.         break;
  2976.  
  2977.     case IL_IMAGE_DESTROYED:
  2978.         /* Remove ourself from the observer callback list. */
  2979.         XP_RemoveObserver(image_obs_closure->obs_list, lo_ImageObserver,
  2980.                           image_obs_closure);
  2981.         XP_FREE(image_obs_closure);
  2982.         lo_image->image_req = NULL;
  2983.         
  2984.         break;
  2985.  
  2986.     default:
  2987.         break;
  2988.     }
  2989. }
  2990.  
  2991. /* We want to write a title in the titlebar and tell all other
  2992. functions not to write over it. This is only used by il_load_image
  2993. for view streams in libimg/dummy_nc.c & external.c. */
  2994. void
  2995. lo_view_title( MWContext *context, char *title_str ){
  2996.  
  2997.     int32 doc_id;
  2998.     lo_TopState *top_state;
  2999.          
  3000.     /* Get the unique document ID and the layout state.*/
  3001.     doc_id = XP_DOCID(context);
  3002.     top_state = lo_FetchTopState(doc_id);
  3003.     if (!top_state)    
  3004.           return;
  3005.  
  3006.     FE_SetDocTitle(context, title_str);
  3007.     top_state->have_title = TRUE;
  3008.     return;
  3009. }
  3010.  
  3011. #define FORCE_LOAD_ALL_IMAGES ((char *)1)
  3012.  
  3013. static char *force_load_images = NULL;
  3014. static XP_Bool autoload_images = TRUE;
  3015. static XP_Bool pref_initialized = FALSE;
  3016.  
  3017. /* remove Mac warning about missing prototype */
  3018. MODULE_PRIVATE int PR_CALLBACK lo_AutoloadPrefChangedFunc(const char *pref,
  3019.                                                           void *data);
  3020.  
  3021. MODULE_PRIVATE int PR_CALLBACK lo_AutoloadPrefChangedFunc(const char *pref,
  3022.                                                           void *data) 
  3023. {
  3024.     int status;
  3025.  
  3026.     if (!XP_STRCASECMP(pref,"general.always_load_images")) 
  3027.         status = PREF_GetBoolPref("general.always_load_images",
  3028.                                   &autoload_images);
  3029.  
  3030.     return status;
  3031. }
  3032.  
  3033. /* Inform layout of an image URL to be force loaded.  If all_images is TRUE,
  3034.    this indicates that all images are to be force loaded.  Note that this
  3035.    function does not actually trigger the loading of images. */
  3036. void LO_SetForceLoadImage(char *url, XP_Bool all_images)
  3037. {
  3038.     if (force_load_images &&
  3039.         force_load_images != FORCE_LOAD_ALL_IMAGES) {
  3040.         XP_FREE(force_load_images);
  3041.     }
  3042.     
  3043.     if (all_images) {
  3044.         force_load_images = FORCE_LOAD_ALL_IMAGES;
  3045.     }
  3046.     else {
  3047.         if (url)
  3048.             force_load_images = XP_STRDUP(url);
  3049.         else
  3050.             force_load_images = NULL;
  3051.     }
  3052. }
  3053.  
  3054. /* Initiate the loading of an image. */
  3055. void lo_GetImage(MWContext *context, IL_GroupContext *img_cx,
  3056.                  LO_ImageStruct *lo_image, XP_ObserverList obs_list,
  3057.                  NET_ReloadMethod requested_reload_method)
  3058. {
  3059.  
  3060.     XP_Bool net_request_allowed; /* Are we willing to make a net request? */
  3061.     NET_ReloadMethod reload_method;
  3062.     IL_NetContext *net_cx = NULL;
  3063.     IL_IRGB *trans_pixel;
  3064.     char *image_url, *lowres_image_url, *url_to_fetch;
  3065.     IL_ImageReq *dummy_ireq;
  3066.  
  3067.     /* Safety checks. */
  3068.     if (!context || !lo_image)
  3069.         return;
  3070.  
  3071.     /* Handle the TextFE. */
  3072.     if (context->type == MWContextText) {
  3073.         XL_GetTextImage(lo_image);
  3074.         return;
  3075.     }
  3076.  
  3077.     /* More safety checks. */
  3078.     if (!img_cx || !obs_list)
  3079.         return;
  3080.  
  3081.     /* Initialize the autoload images pref, if necessary. */
  3082.     if (!pref_initialized) {
  3083.         int status = PREF_GetBoolPref("general.always_load_images",
  3084.                                       &autoload_images);
  3085.         if (status == PREF_NOERROR) {
  3086.             PREF_RegisterCallback("general.always_load_images",
  3087.                                   lo_AutoloadPrefChangedFunc, NULL);
  3088.             pref_initialized = TRUE;
  3089.         }
  3090.     }
  3091.  
  3092.     /* Fetch the lowres image first if there is one.  Layout will call us
  3093.        again to fetch the hires image, at which point the lowres_image_url
  3094.        will be NULL. */
  3095.     if (lo_image->lowres_image_url) {
  3096.         PA_LOCK(lowres_image_url, char *, lo_image->lowres_image_url);
  3097.     }
  3098.     PA_LOCK(image_url, char *, lo_image->image_url);
  3099.     if ((context->type == MWContextPostScript) ||
  3100.         (context->type == MWContextPrint)) {
  3101.         url_to_fetch = image_url;
  3102.     }
  3103.     else {
  3104.         if ((lo_image->lowres_image_url)&&(!lo_image->lowres_image_req))
  3105.             url_to_fetch = lowres_image_url;
  3106.         else
  3107.             url_to_fetch = image_url;
  3108.     }
  3109.     
  3110.     /* Determine whether we are willing to load the image from the Network. */
  3111.     if ((context->type == MWContextPostScript) ||
  3112.         (context->type == MWContextPrint) ||
  3113.         (context->type == MWContextDialog) ||
  3114.         autoload_images ||
  3115.         (force_load_images == FORCE_LOAD_ALL_IMAGES) ||
  3116.         (force_load_images && image_url && !XP_STRCMP(force_load_images, image_url))) {
  3117.         net_request_allowed = TRUE;
  3118.     }
  3119.     else {
  3120.         net_request_allowed = FALSE;
  3121.     }
  3122.  
  3123.     /* JavaScript-generated images can change if the document is reloaded,
  3124.        so don't request a cache-only reload, even if layout requested one. */
  3125.     if (NET_URL_Type(url_to_fetch) == MOCHA_TYPE_URL)
  3126.         requested_reload_method = NET_DONT_RELOAD;
  3127.  
  3128.     /* Create a dummy Net Context for the Image Library to use for network
  3129.        operations.  This will be replaced by a true Net Context when the
  3130.        Network Library is modularized. */
  3131.     reload_method =
  3132.         net_request_allowed ? requested_reload_method : NET_CACHE_ONLY_RELOAD;
  3133.     net_cx = IL_NewDummyNetContext(context, reload_method);
  3134.  
  3135.     /* Determine whether to request a mask if this is a transparent image.
  3136.        In the case of a document backdrop, we ask the image library to fill
  3137.        in the transparent area with a solid color.  For all other transparent
  3138.        images, we force the creation of a mask by passing in NULL. */
  3139.     if (context->type == MWContextPostScript) {
  3140.         trans_pixel = XP_NEW_ZAP(IL_IRGB);
  3141.         if (trans_pixel)
  3142.             trans_pixel->red = trans_pixel->green = trans_pixel->blue = 0xff;
  3143.     }
  3144. #ifndef XP_WIN32
  3145.     else if (context->type == MWContextPrint) {
  3146.         trans_pixel = context->transparent_pixel;
  3147.     }
  3148. #endif
  3149.     else {
  3150.         if (lo_image->image_attr &&
  3151.             (lo_image->image_attr->attrmask & LO_ATTR_BACKDROP) &&
  3152.             !(lo_image->image_attr->attrmask & LO_ATTR_CELL_BACKDROP) &&
  3153.             !(lo_image->image_attr->attrmask & LO_ATTR_LAYER_BACKDROP)
  3154.             ) {
  3155.             trans_pixel = context->transparent_pixel;
  3156.         }
  3157.         else {
  3158. #ifdef XP_WIN32
  3159.         XP_Bool backgroundPref = FALSE;
  3160.         PREF_GetBoolPref("browser.print_background",&backgroundPref);
  3161.         if (context->type == MWContextPrint && !backgroundPref)
  3162.             trans_pixel = context->transparent_pixel;
  3163.         else
  3164. #endif
  3165.             trans_pixel = NULL;
  3166.         }
  3167.     }
  3168.  
  3169.     /* Fetch the image.  We ignore the return value and only set the lo_image's
  3170.        image handle in the observer.  Any context-specific scaling of images,
  3171.        e.g. for printing, should be handled by the Front End, so we divide the
  3172.        image dimensions by the context scaling factors. */
  3173.         dummy_ireq = IL_GetImage(url_to_fetch, img_cx, obs_list,
  3174.                                       trans_pixel,
  3175.                                       lo_image->width / context->convertPixX,
  3176.                                       lo_image->height / context->convertPixY,
  3177.                                       0, net_cx);
  3178.  
  3179.         if(( dummy_ireq != lo_image->lowres_image_req ) && url_to_fetch )
  3180.             lo_image->image_req = dummy_ireq;
  3181.  
  3182.     /* Destroy the transparent pixel if this is a PostScript context. */
  3183.     if ((context->type == MWContextPostScript) && trans_pixel)
  3184.         XP_FREE(trans_pixel);
  3185.  
  3186.     /* The Image Library clones the dummy Net Context, so it safe to destroy
  3187.        it. */
  3188.     IL_DestroyDummyNetContext(net_cx);
  3189.  
  3190.     if (lo_image->lowres_image_url)
  3191.         PA_UNLOCK(lo_image->lowres_image_url);
  3192.     PA_UNLOCK(lo_image->image_url);
  3193. }
  3194.  
  3195. /* 
  3196.  * Fills in x, y, % width, % height of image
  3197.  * Does not change anything for absolute width/height images 
  3198.  */
  3199.  
  3200. void lo_FillInImageGeometry( lo_DocState *state, LO_ImageStruct *image )
  3201. {
  3202.     int32 doc_width;
  3203.  
  3204.     image->ele_id = NEXT_ELEMENT;
  3205.     image->x = state->x;
  3206.     image->y = state->y;
  3207.  
  3208.     /* Set image->width if image has a % width specified */
  3209.     doc_width = state->right_margin - state->left_margin;
  3210.     if (image->percent_width > 0) {
  3211.         int32 val = image->percent_width;
  3212.         if (state->allow_percent_width == FALSE) {
  3213.             val = 0;
  3214.         }
  3215.         else {
  3216.             val = doc_width * val / 100;
  3217.         }
  3218.         image->width = val;
  3219.     }
  3220.  
  3221.     /* Set image->height if image has a % height specified */
  3222.     if (image->percent_height > 0) {
  3223.         int32 val = image->percent_height;
  3224.         if (state->allow_percent_height == FALSE) {
  3225.             val = 0;
  3226.         }
  3227.         else {
  3228.             val = state->win_height * val / 100;
  3229.         }
  3230.         image->height = val;
  3231.     }
  3232. }
  3233.  
  3234.  
  3235. /* Look into possibility of reusing for other floating elements? */
  3236. void lo_LayoutFloatImage( MWContext *context, lo_DocState *state, LO_ImageStruct *image, Bool updateFE )
  3237. {
  3238.     int32 image_width;
  3239.  
  3240.     image_width = image->width + (2 * image->border_width) + 
  3241.         (2 * image->border_horiz_space);
  3242.  
  3243.  
  3244.     if (image->image_attr->alignment == LO_ALIGN_RIGHT)
  3245.     {
  3246.         if (state->right_margin_stack == NULL)
  3247.         {
  3248.             image->x = state->right_margin - image_width;
  3249.         }
  3250.         else
  3251.         {
  3252.             image->x = state->right_margin_stack->margin -
  3253.                 image_width;
  3254.         }
  3255.         if (image->x < 0)
  3256.         {
  3257.             image->x = 0;
  3258.         }
  3259.     }
  3260.     else
  3261.     {
  3262.         image->x = state->left_margin;
  3263.     }
  3264.  
  3265.     image->y = -1;
  3266.     /*
  3267.     image->x_offset += (int16)image->border_horiz_space;
  3268.     image->y_offset += (int32)image->border_vert_space;    
  3269.     */
  3270.     lo_AddMarginStack(state, image->x, image->y,
  3271.         image->width, image->height,
  3272.         image->border_width,
  3273.         image->border_vert_space, image->border_horiz_space,
  3274.         image->image_attr->alignment);
  3275.  
  3276.     if (state->at_begin_line != FALSE)
  3277.     {
  3278.         lo_FindLineMargins(context, state, updateFE);
  3279.         state->x = state->left_margin;
  3280.     }
  3281.  
  3282. }
  3283.  
  3284. void lo_LayoutInflowImage(MWContext *context, lo_DocState *state, LO_ImageStruct *image,
  3285.                           Bool inRelayout, int32 *line_inc, int32 *baseline_inc)
  3286. {
  3287.     PA_Block buff;
  3288.     char *str;
  3289.     LO_TextStruct tmp_text;
  3290.     LO_TextInfo text_info;
  3291.     int32 image_height, image_width;
  3292.     Bool line_break;
  3293.  
  3294.     /* 
  3295.     int32 baseline_inc;
  3296.     int32 line_inc;
  3297.     */
  3298.  
  3299.     /*
  3300.      * Eventually this will never happen since we always
  3301.      * have dims here from either the image tag itself or the
  3302.      * front end.
  3303.      */
  3304.     if (image->width == 0)
  3305.     {
  3306.         image->width = IMAGE_DEF_DIM;
  3307.     }
  3308.     if (image->height == 0)
  3309.     {
  3310.         image->height = IMAGE_DEF_DIM;
  3311.     }
  3312.  
  3313.     image_width = image->width + (2 * image->border_width) +
  3314.         (2 * image->border_horiz_space);
  3315.     image_height = image->height + (2 * image->border_width) +
  3316.         (2 * image->border_vert_space);
  3317.  
  3318.     /*
  3319.      * Will this image make the line too wide.
  3320.      */
  3321.     if ((state->x + image_width) > state->right_margin)
  3322.     {
  3323.         line_break = TRUE;
  3324.     }
  3325.     else
  3326.     {
  3327.         line_break = FALSE;
  3328.     }
  3329.  
  3330.     /*
  3331.      * if we are at the beginning of the line.  There is
  3332.      * no point in breaking, we are just too wide.
  3333.      * Also don't break in unwrapped preformatted text.
  3334.      * Also can't break inside a NOBR section.
  3335.      */
  3336.     if ((state->at_begin_line != FALSE)||
  3337.         (state->preformatted == PRE_TEXT_YES)||
  3338.         (state->breakable == FALSE))
  3339.     {
  3340.         line_break = FALSE;
  3341.     }
  3342.  
  3343.     /*
  3344.      * break on the image if we have
  3345.      * a break.
  3346.      */
  3347.     if (line_break != FALSE)
  3348.     {
  3349.         /*
  3350.          * We need to make the elements sequential, linefeed
  3351.          * before image.
  3352.          */
  3353.         state->top_state->element_id = image->ele_id;
  3354.  
  3355.         if (!inRelayout)
  3356.         {
  3357.             lo_SoftLineBreak(context, state, TRUE);
  3358.         }
  3359.         else {
  3360.             lo_rl_AddSoftBreakAndFlushLine(context, state);
  3361.         }
  3362.         image->x = state->x;
  3363.         image->y = state->y;
  3364.         image->ele_id = NEXT_ELEMENT;
  3365.     }
  3366.  
  3367.     /*
  3368.      * Figure out how to align this image.
  3369.      * baseline_inc is how much to increase the baseline
  3370.      * of previous element of this line.  line_inc is how
  3371.      * much to increase the line height below the baseline.
  3372.      */
  3373.     *baseline_inc = 0;
  3374.     *line_inc = 0;
  3375.  
  3376.     /*
  3377.      * All this work is to get the text_info filled in for the current
  3378.      * font in the font stack. Yuck, there must be a better way.
  3379.      */
  3380.     memset (&tmp_text, 0, sizeof (tmp_text));
  3381.     buff = PA_ALLOC(1);
  3382.     if (buff == NULL)
  3383.     {
  3384.         state->top_state->out_of_memory = TRUE;
  3385.         return;
  3386.     }
  3387.     PA_LOCK(str, char *, buff);
  3388.     str[0] = ' ';
  3389.     PA_UNLOCK(buff);
  3390.     tmp_text.text = buff;
  3391.     tmp_text.text_len = 1;
  3392.     tmp_text.text_attr =
  3393.         state->font_stack->text_attr;
  3394.     FE_GetTextInfo(context, &tmp_text, &text_info);
  3395.     PA_FREE(buff);
  3396.  
  3397.     lo_CalcAlignOffsets(state, &text_info, image->image_attr->alignment,
  3398.         image_width, image_height,
  3399.         &image->x_offset, &image->y_offset, line_inc, baseline_inc);
  3400.  
  3401.     image->x_offset += (int16)image->border_horiz_space;
  3402.     image->y_offset += (int32)image->border_vert_space;
  3403. }
  3404.  
  3405.  
  3406. void lo_UpdateStateAfterImageLayout( lo_DocState *state, LO_ImageStruct *image, int32 line_inc, int32 baseline_inc )
  3407. {
  3408.     int32 image_width;
  3409.     int32 x, y;
  3410.     
  3411.     image_width = image->width + (2 * image->border_width) +
  3412.         (2 * image->border_horiz_space);
  3413.  
  3414.     state->baseline += (intn) baseline_inc;
  3415.     state->line_height += (intn) (baseline_inc + line_inc);
  3416.     
  3417.     /*
  3418.      * Clean up state
  3419.      */
  3420.     state->x = state->x + image->x_offset +
  3421.         image_width - image->border_horiz_space;
  3422.     state->linefeed_state = 0;
  3423.     state->at_begin_line = FALSE;
  3424.     state->trailing_space = FALSE;
  3425.     state->cur_ele_type = LO_IMAGE;
  3426.  
  3427.     /* Determine the new position of the layer. */
  3428.     x = image->x + image->x_offset + image->border_width;
  3429.     y = image->y + image->y_offset + image->border_width;
  3430.  
  3431.     /* Move layer to new position */
  3432.     if (image->layer != NULL)
  3433.         CL_MoveLayer(image->layer,    x, y);
  3434. }
  3435.  
  3436. #ifdef PROFILE
  3437. #pragma profile off
  3438. #endif
  3439.