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

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /*
  19.  * Image reflection and event notification
  20.  *
  21.  * Scott Furman, 3/30/96
  22.  */
  23.  
  24. #include "lm.h"
  25.  
  26. #include "lo_ele.h"
  27. #include "prtypes.h"
  28. #include "pa_tags.h"
  29. #include "layout.h"
  30.  
  31. #define IL_CLIENT
  32. #include "libimg.h"             /* Image Library public API. */
  33.  
  34. enum image_array_slot {
  35.     IMAGE_ARRAY_LENGTH = -1
  36. };
  37.  
  38. static JSPropertySpec image_array_props[] = {
  39.     {lm_length_str, IMAGE_ARRAY_LENGTH,
  40.             JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT},
  41.     {0}
  42. };
  43.  
  44. extern JSClass lm_image_array_class;
  45.  
  46. PR_STATIC_CALLBACK(JSBool)
  47. image_array_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  48. {
  49.     JSObjectArray *array;
  50.     MochaDecoder *decoder;
  51.     MWContext *context;
  52.     jsint count, slot;
  53.     LO_ImageStruct *image;
  54.     int32 active_layer_id;
  55.  
  56.     if (!JSVAL_IS_INT(id))
  57.     return JS_TRUE;
  58.  
  59.     slot = JSVAL_TO_INT(id);
  60.  
  61.     array = JS_GetInstancePrivate(cx, obj, &lm_image_array_class, NULL);
  62.     if (!array)
  63.     return JS_TRUE;
  64.     decoder = array->decoder;
  65.     context = decoder->window_context;
  66.     if (!context)
  67.     return JS_TRUE;
  68.  
  69.     LO_LockLayout();
  70.     switch (slot) {
  71.       case IMAGE_ARRAY_LENGTH:
  72.     active_layer_id = LM_GetActiveLayer(context);
  73.     LM_SetActiveLayer(context, array->layer_id);
  74.     count = LO_EnumerateImages(context, array->layer_id);
  75.     LM_SetActiveLayer(context, active_layer_id);
  76.     if (count > array->length)
  77.         array->length = count;
  78.     *vp = INT_TO_JSVAL(count);
  79.     break;
  80.  
  81.       default:
  82.     if (slot < 0) {
  83.         /* Don't mess with user-defined or method properties. */
  84.         LO_UnlockLayout();
  85.         return JS_TRUE;
  86.     }
  87.     if (slot >= array->length)
  88.         array->length = slot + 1;
  89.     image = LO_GetImageByIndex(context, array->layer_id, (uint)slot);
  90.     if (image) {
  91.         *vp = OBJECT_TO_JSVAL(LM_ReflectImage(context, image, NULL,
  92.                           array->layer_id, 
  93.                                                   (uint)slot));
  94.     }
  95.     break;
  96.     }
  97.     LO_UnlockLayout();
  98.     return JS_TRUE;
  99. }
  100.  
  101. PR_STATIC_CALLBACK(void)
  102. image_array_finalize(JSContext *cx, JSObject *obj)
  103. {
  104.     JSObjectArray *array;
  105.  
  106.     array = JS_GetPrivate(cx, obj);
  107.     if (!array)
  108.         return;
  109.     DROP_BACK_COUNT(array->decoder);
  110.     JS_free(cx, array);
  111. }
  112.  
  113. JSClass lm_image_array_class = {
  114.     "ImageArray", JSCLASS_HAS_PRIVATE,
  115.     JS_PropertyStub, JS_PropertyStub,
  116.     image_array_getProperty, image_array_getProperty, JS_EnumerateStub,
  117.     JS_ResolveStub, JS_ConvertStub, image_array_finalize
  118. };
  119.  
  120. enum image_slot {
  121.     IMAGE_NAME              = -2,
  122.     IMAGE_SRC               = -3,
  123.     IMAGE_LOWSRC            = -4,
  124.     IMAGE_X                 = -5,
  125.     IMAGE_Y                 = -6,
  126.     IMAGE_HEIGHT            = -7,
  127.     IMAGE_WIDTH             = -8,
  128.     IMAGE_BORDER            = -9,
  129.     IMAGE_VSPACE            = -10,
  130.     IMAGE_HSPACE            = -11,
  131.     IMAGE_COMPLETE          = -12
  132. };
  133.  
  134. static JSPropertySpec image_props[] = {
  135.     {"name",                IMAGE_NAME,         JSPROP_ENUMERATE | JSPROP_READONLY},
  136.     {"src",                 IMAGE_SRC,          JSPROP_ENUMERATE},
  137.     {"lowsrc",              IMAGE_LOWSRC,       JSPROP_ENUMERATE},
  138.     {"x",                   IMAGE_X,            JSPROP_ENUMERATE | JSPROP_READONLY},
  139.     {"y",                   IMAGE_Y,            JSPROP_ENUMERATE | JSPROP_READONLY},
  140.     {"height",              IMAGE_HEIGHT,       JSPROP_ENUMERATE | JSPROP_READONLY},
  141.     {"width",               IMAGE_WIDTH,        JSPROP_ENUMERATE | JSPROP_READONLY},
  142.     {"border",              IMAGE_BORDER,       JSPROP_ENUMERATE | JSPROP_READONLY},
  143.     {"vspace",              IMAGE_VSPACE,       JSPROP_ENUMERATE | JSPROP_READONLY},
  144.     {"hspace",              IMAGE_HSPACE,       JSPROP_ENUMERATE | JSPROP_READONLY},
  145.     {"complete",            IMAGE_COMPLETE,     JSPROP_ENUMERATE | JSPROP_READONLY},
  146.     {0}
  147. };
  148.  
  149. /*
  150.  * Base image element type.
  151.  */
  152. typedef struct JSImage {
  153.     JSEventReceiver        receiver;
  154.     MochaDecoder           *decoder;
  155.     LO_ImageStruct         *image_data;     /* 0 unless made by new Image() */
  156.     uint8                   pending_events;
  157.     int32                   layer_id;
  158.     uint                    index;
  159.     JSBool            complete;       /* Finished loading or aborted */
  160.     JSString        *name;
  161. } JSImage;
  162.  
  163. #define GET_IMAGE_DATA(context, image)                                        \
  164.     ((image)->image_data ? (image)->image_data                                \
  165.      : LO_GetImageByIndex((context), (image)->layer_id, (image)->index))
  166.  
  167. extern JSClass lm_image_class;
  168.  
  169. /*
  170.  * Force the mozilla event queue to flush to make sure any image-set-src
  171.  *   events have been processed
  172.  */
  173. PR_STATIC_CALLBACK(void)
  174. lm_img_src_sync(void * data)
  175. {
  176. }
  177.  
  178.  
  179. PR_STATIC_CALLBACK(JSBool)
  180. image_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  181. {
  182.     JSImage *image;
  183.     LO_ImageStruct *image_data;
  184.     enum image_slot image_slot;
  185.     JSString *str;
  186.     jsint slot;
  187.  
  188.     if (!JSVAL_IS_INT(id))
  189.     return JS_TRUE;
  190.  
  191.     slot = JSVAL_TO_INT(id);
  192.  
  193.     image = JS_GetInstancePrivate(cx, obj, &lm_image_class, NULL);
  194.     if (!image)
  195.     return JS_TRUE;
  196.     image_data = GET_IMAGE_DATA(image->decoder->window_context, image);
  197.     if (!image_data)
  198.         return JS_TRUE;      /* Try to handle this case gracefully. */
  199.  
  200.     image_slot = slot;
  201.     if (image_slot == IMAGE_SRC || image_slot == IMAGE_LOWSRC) {
  202.         if (!lm_CheckPermissions(cx, obj, JSTARGET_UNIVERSAL_BROWSER_READ))
  203.             return JS_FALSE;
  204.     }
  205.  
  206.     switch (image_slot) {
  207.     case IMAGE_NAME:
  208.     if (image->name)
  209.         *vp = STRING_TO_JSVAL(image->name);
  210.     else
  211.         *vp = JSVAL_NULL;
  212.         break;
  213.  
  214.     case IMAGE_SRC:
  215.     if (image_data->pending_mocha_event) {
  216.         ET_moz_CallFunction(lm_img_src_sync, NULL);
  217.         image_data->pending_mocha_event = PR_FALSE;
  218.     }
  219.     str = JS_NewStringCopyZ(cx, (char*)image_data->image_url);
  220.     if (!str)
  221.         return JS_FALSE;
  222.     *vp = STRING_TO_JSVAL(str);
  223.     break;
  224.  
  225.     case IMAGE_LOWSRC:
  226.     if (image_data->pending_mocha_event) {
  227.         ET_moz_CallFunction(lm_img_src_sync, NULL);
  228.         image_data->pending_mocha_event = PR_FALSE;
  229.     }
  230.     str = JS_NewStringCopyZ(cx, (char*)image_data->lowres_image_url);
  231.     if (!str)
  232.         return JS_FALSE;
  233.     *vp = STRING_TO_JSVAL(str);
  234.     break;
  235.  
  236.     case IMAGE_X:
  237.         *vp = INT_TO_JSVAL(image_data->x + image_data->x_offset);
  238.         break;
  239.  
  240.     case IMAGE_Y:
  241.         *vp = INT_TO_JSVAL(image_data->y + image_data->y_offset);
  242.         break;
  243.  
  244.     case IMAGE_HEIGHT:
  245.         *vp = INT_TO_JSVAL(image_data->height);
  246.         break;
  247.  
  248.     case IMAGE_WIDTH:
  249.         *vp = INT_TO_JSVAL(image_data->width);
  250.         break;
  251.  
  252.     case IMAGE_BORDER:
  253.         *vp = INT_TO_JSVAL(image_data->border_width);
  254.         break;
  255.  
  256.     case IMAGE_HSPACE:
  257.         *vp = INT_TO_JSVAL(image_data->border_horiz_space);
  258.         break;
  259.  
  260.     case IMAGE_VSPACE:
  261.         *vp = INT_TO_JSVAL(image_data->border_vert_space);
  262.         break;
  263.  
  264.     case IMAGE_COMPLETE:
  265.         *vp = BOOLEAN_TO_JSVAL(image->complete);
  266.         break;
  267.  
  268.     default:
  269.         /* Don't mess with a user-defined or method property. */
  270.         return JS_TRUE;
  271.     }
  272.  
  273.     return JS_TRUE;
  274. }
  275.  
  276. static JSBool
  277. image_set_src(JSImage *image, const char *str, LO_ImageStruct *image_data)
  278. {
  279.     MochaDecoder *decoder;
  280.     MWContext *context;
  281.     IL_GroupContext *img_cx;
  282.     
  283.     decoder = image->decoder;
  284.     context = decoder->window_context;
  285.     img_cx = decoder->image_context;
  286.  
  287.     if (!context) return JS_TRUE;
  288.  
  289.     image_data->pending_mocha_event = PR_TRUE;
  290.     image_data->image_attr->attrmask |= LO_ATTR_MOCHA_IMAGE;
  291.     
  292.     ET_il_GetImage(str, context, img_cx, image_data, NET_DONT_RELOAD);
  293.  
  294.     return JS_TRUE;
  295. }
  296.  
  297. PR_STATIC_CALLBACK(JSBool)
  298. image_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  299. {
  300.     JSBool ok;
  301.     JSImage *image;
  302.     MochaDecoder *decoder;
  303.     MWContext *context;
  304.     LO_ImageStruct *image_data;
  305.     enum image_slot image_slot;
  306.     const char *url;
  307.     jsint slot;
  308.  
  309.     image = JS_GetInstancePrivate(cx, obj, &lm_image_class, NULL);
  310.     if (!image)
  311.     return JS_TRUE;
  312.     decoder = image->decoder;
  313.     context = decoder->window_context;
  314.     if (!context) 
  315.     return JS_TRUE;
  316.     
  317.     if (!JSVAL_IS_INT(id))
  318.     return JS_TRUE;
  319.  
  320.     slot = JSVAL_TO_INT(id);
  321.  
  322.     image_data = GET_IMAGE_DATA(context, image);
  323.     if (!image_data)
  324.         return JS_TRUE;      /* Try to handle this case gracefully. */
  325.  
  326.     image_slot = slot;
  327.     switch (image_slot) {
  328.     case IMAGE_SRC:
  329.     case IMAGE_LOWSRC:
  330.         if (!lm_CheckPermissions(cx, obj, JSTARGET_UNIVERSAL_BROWSER_WRITE))
  331.             return JS_FALSE;
  332.  
  333.         if (JSVAL_IS_NULL(*vp)) {
  334.             url = NULL;
  335.         } else {
  336.             if (!JSVAL_IS_STRING(*vp) &&
  337.                 !JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp))
  338.                 return JS_FALSE;
  339.                 
  340.             url = JS_GetStringBytes(JSVAL_TO_STRING(*vp));
  341.             url = lm_CheckURL(cx, url, JS_TRUE);  /* will allocate new string */
  342.             if (!url)
  343.                 return JS_FALSE;
  344.         }
  345.  
  346.         if (image_slot == IMAGE_SRC) {
  347.             ok = image_set_src(image, url, image_data);
  348.         } else if (url) {
  349.         ok = lm_SaveParamString(cx, &image_data->lowres_image_url, url);
  350.         }
  351.  
  352.     if (url)
  353.         XP_FREE((void *) url);
  354.  
  355.         if (!ok)
  356.             return JS_FALSE;
  357.  
  358.     /*
  359.      * don't call image_getProperty so that we don't immediately
  360.      *   turn around and block
  361.      */
  362.     return JS_TRUE;
  363.         break;
  364.  
  365.     case IMAGE_NAME:
  366.     case IMAGE_X:
  367.     case IMAGE_Y:
  368.     case IMAGE_HEIGHT:
  369.     case IMAGE_WIDTH:
  370.     case IMAGE_BORDER:
  371.     case IMAGE_VSPACE:
  372.     case IMAGE_HSPACE:
  373.     case IMAGE_COMPLETE:
  374.     /* These are immutable. */
  375.     break;
  376.     }
  377.  
  378.     return image_getProperty(cx, obj, id, vp);
  379. }
  380.  
  381. PR_STATIC_CALLBACK(void)
  382. image_finalize(JSContext *cx, JSObject *obj)
  383. {
  384.     JSImage *image;
  385.     LO_ImageStruct *image_data;
  386.     MochaDecoder *decoder;
  387.     MWContext *context;
  388.  
  389.     image = JS_GetPrivate(cx, obj);
  390.     if (!image)
  391.     return;
  392.  
  393.     image_data = image->image_data;
  394.     decoder = image->decoder;
  395.     context = decoder->window_context;
  396.     if (image_data) {
  397.         /* If this is a layer background image or a reflection of an
  398.            existing layout image, then layout will take care of
  399.            destroying the image.  For anonymous images, however, 
  400.            we need to handle destruction here. */
  401.         if (!image_data->layer) {
  402.             ET_PostFreeImageElement(context, image_data);
  403.             XP_FREE(image_data->image_attr);
  404.             XP_FREE(image_data);
  405.         }
  406.     } else {
  407.     if (context) {
  408.         LO_LockLayout();
  409.         image_data = LO_GetImageByIndex(context, image->layer_id,
  410.                                             image->index);
  411.         if (image_data && image_data->mocha_object == obj)
  412.         image_data->mocha_object = NULL;
  413.         LO_UnlockLayout();
  414.     }
  415.     }
  416.     DROP_BACK_COUNT(decoder);
  417.  
  418.     JS_UnlockGCThing(cx, image->name);
  419.     JS_free(cx, image);
  420. }
  421.  
  422. JSClass lm_image_class = {
  423.     "Image", JSCLASS_HAS_PRIVATE,
  424.     JS_PropertyStub, JS_PropertyStub, image_getProperty, image_setProperty,
  425.     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, image_finalize
  426. };
  427.  
  428. /* Fill in native, private part of JS image */
  429. static JSImage *
  430. init_image_object(JSContext *cx, JSObject *obj, LO_ImageStruct *image_data)
  431. {
  432.     JSImage *image;
  433.     MochaDecoder *decoder;
  434.     
  435.     image = JS_malloc(cx, sizeof *image);
  436.     if (!image)
  437.         return NULL;
  438.     XP_BZERO(image, sizeof *image);
  439.  
  440.     image->image_data = image_data;
  441.     decoder = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
  442.     image->decoder = HOLD_BACK_COUNT(decoder);
  443.     image_data->mocha_object = obj;
  444.  
  445.     /* Events are never blocked for anonymous images
  446.        since there is no associated layout. */
  447.     image->pending_events = PR_BIT(LM_IMGUNBLOCK);
  448.     if (!JS_SetPrivate(cx, obj, image))
  449.     return NULL;
  450.  
  451.     return image;
  452. }
  453.  
  454. JSObject *
  455. lm_NewImage(JSContext *cx,
  456.             LO_ImageStruct *image_data)
  457. {
  458.     JSObject *obj, *outer_obj;
  459.     MochaDecoder *decoder;
  460.     decoder = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
  461.     outer_obj = lm_GetOuterObject(decoder);
  462.  
  463.     obj = JS_NewObject(cx, &lm_image_class, decoder->image_prototype, 
  464.                outer_obj);
  465.     if (!init_image_object(cx, obj, image_data))
  466.         return NULL;
  467.     
  468.     return obj;
  469. }
  470.  
  471. PR_STATIC_CALLBACK(JSBool)
  472. Image(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
  473. {
  474.     jsint width, height;
  475.     LO_ImageStruct *image_data;
  476.  
  477.     XP_ASSERT(JS_InstanceOf(cx, obj, &lm_image_class, NULL));
  478.  
  479.     height = width = 0;
  480.  
  481.     if (argc > 0) {
  482.     if (argc != 2) {
  483.         JS_ReportError(cx, lm_argc_err_str);
  484.         return JS_FALSE;
  485.     }
  486.         if (!JSVAL_IS_INT(argv[0]) ||
  487.             !JSVAL_IS_INT(argv[1])) {
  488.             return JS_FALSE;
  489.         }
  490.     width = JSVAL_TO_INT(argv[0]);
  491.     height = JSVAL_TO_INT(argv[1]);
  492.     }
  493.  
  494.     /* Allocate dummy layout structure.  This is not really
  495.        used by layout, but the front-ends and the imagelib
  496.        need it as a handle on an image instance. */
  497.     image_data = XP_NEW_ZAP(LO_ImageStruct);
  498.     if (!image_data) {
  499.     JS_ReportOutOfMemory(cx);
  500.         return JS_FALSE;
  501.     }
  502.     image_data->image_attr = XP_NEW_ZAP(LO_ImageAttr);
  503.     if (!image_data->image_attr) {
  504.         XP_FREE(image_data);
  505.     JS_ReportOutOfMemory(cx);
  506.         return JS_FALSE;
  507.     }
  508.  
  509.     image_data->type = LO_IMAGE;
  510.  
  511.     /* Fake layout ID, guaranteed not to match any real layout element */
  512.     image_data->ele_id = -1;
  513.  
  514.     if (!init_image_object(cx, obj, image_data)) {
  515.     XP_FREE(image_data->image_attr);
  516.     XP_FREE(image_data);
  517.         return JS_FALSE;
  518.     }
  519.  
  520.     /* Process arguments */
  521.  
  522.     /* Width & Height */
  523.     if (argc == 2) {
  524.         image_data->width  = (int)width;
  525.         image_data->height = (int)height;
  526.     }
  527.  
  528.     return JS_TRUE;
  529. }
  530.  
  531. static JSObject *
  532. reflect_image_array(MochaDecoder *decoder, JSObject *document)
  533. {
  534.     JSContext *cx;
  535.     JSObjectArray *array;
  536.     JSObject *obj;
  537.     JSDocument *doc;
  538.  
  539.     cx = decoder->js_context;
  540.     doc = JS_GetPrivate(cx, document);
  541.     if (!doc)
  542.     return NULL;
  543.  
  544.     array = JS_malloc(cx, sizeof *array);
  545.     if (!array)
  546.     return NULL;
  547.     XP_BZERO(array, sizeof *array);
  548.  
  549.     obj = JS_NewObject(cx, &lm_image_array_class, NULL, document);
  550.     if (!obj || !JS_SetPrivate(cx, obj, array)) {
  551.         LM_PutMochaDecoder(decoder);
  552.         return NULL;
  553.     }
  554.  
  555.     if (!JS_DefineProperties(cx, obj, image_array_props))
  556.     return NULL;
  557.  
  558.     array->decoder = HOLD_BACK_COUNT(decoder);
  559.     array->layer_id = doc->layer_id;
  560.     return obj;
  561. }
  562.  
  563. JSObject *
  564. lm_GetImageArray(MochaDecoder *decoder, JSObject *document)
  565. {
  566.     JSObject *obj;
  567.     JSDocument *doc;
  568.  
  569.     doc = JS_GetPrivate(decoder->js_context, document);
  570.     if (!doc)
  571.     return NULL;
  572.  
  573.     obj = doc->images;
  574.     if (obj)
  575.     return obj;
  576.     obj = reflect_image_array(decoder, document);
  577.     doc->images = obj;
  578.     return obj;
  579. }
  580.  
  581. JSObject *
  582. LM_ReflectImage(MWContext *context, LO_ImageStruct *image_data, 
  583.                 PA_Tag * tag, int32 layer_id, uint index)
  584. {
  585.     JSObject *obj, *array_obj, *outer_obj, *document;
  586.     MochaDecoder *decoder;
  587.     JSContext *cx;
  588.     JSImage *image;
  589.     PA_Block name = NULL;
  590.     lo_TopState *top_state;
  591.     PRHashTable *map;
  592.  
  593.     image_data = LO_GetImageByIndex(context, layer_id, index);
  594.     XP_ASSERT(image_data);
  595.     if (! image_data)
  596.       return NULL;
  597.  
  598.     obj = image_data->mocha_object;
  599.     if (obj)
  600.     return obj;
  601.  
  602.     decoder = LM_GetMochaDecoder(context);
  603.     if (!decoder)
  604.     return NULL;
  605.     cx = decoder->js_context;
  606.  
  607.     top_state = lo_GetMochaTopState(context);
  608.     if (top_state->resize_reload) {
  609.         map = lm_GetIdToObjectMap(decoder);
  610.         
  611.         if (map)
  612.             obj = (JSObject *)PR_HashTableLookup(map,
  613.                              LM_GET_MAPPING_KEY(LM_IMAGES, layer_id, index));
  614.         if (obj) {
  615.             image_data->mocha_object = obj;
  616.             goto done;
  617.         }
  618.     }
  619.  
  620.     /* Get the document object that will hold this link */
  621.     document = lm_GetDocumentFromLayerId(decoder, layer_id);
  622.     if (!document)
  623.         goto done;
  624.  
  625.     array_obj = lm_GetImageArray(decoder, document);
  626.     if (!array_obj)
  627.     goto done;
  628.  
  629.     image = JS_malloc(cx, sizeof *image);
  630.     if (!image)
  631.     goto done;
  632.  
  633.     XP_BZERO(image, sizeof *image);
  634.  
  635.     /* if we got a tag passed in try to get the name out of there */
  636.     name = lo_FetchParamValue(context, tag, PARAM_NAME);
  637.  
  638.     outer_obj = lm_GetOuterObject(decoder);
  639.  
  640.     obj = JS_NewObject(cx, &lm_image_class, decoder->image_prototype,
  641.                outer_obj);
  642.     if (!obj || !JS_SetPrivate(cx, obj, image)) {
  643.     JS_free(cx, image);
  644.     goto done;
  645.     }
  646.  
  647.     if (name) {
  648.     JSObject *doc_obj;
  649.     extern JSClass lm_form_class;
  650.  
  651.     if (!JS_DefineProperty(cx, outer_obj, (const char *) name, 
  652.                    OBJECT_TO_JSVAL(obj), NULL, NULL,
  653.                    JSPROP_ENUMERATE|JSPROP_READONLY)) {
  654.         obj = NULL;
  655.         goto done;
  656.     }
  657.     /* XXX backward compatibility with 3.0 bug: lo_BlockedImageLayout
  658.            would eagerly reflect images outside of any active form, so
  659.            they'd end up in document scope. */
  660.     if (JS_GetClass(outer_obj) == &lm_form_class &&
  661.         (doc_obj = JS_GetParent(cx, outer_obj)) != NULL &&
  662.         !JS_DefineProperty(cx, doc_obj, (const char *) name, 
  663.                    OBJECT_TO_JSVAL(obj), NULL, NULL,
  664.                    JSPROP_ENUMERATE|JSPROP_READONLY)) {
  665.         obj = NULL;
  666.         goto done;
  667.     }
  668.     }
  669.  
  670.     image->decoder = HOLD_BACK_COUNT(decoder);
  671.     image->index = index;
  672.     image->layer_id = layer_id;
  673.     image->name = JS_NewStringCopyZ(cx, (const char *) name);
  674.     if (!JS_LockGCThing(cx, image->name)) {
  675.     obj = NULL;
  676.     goto done;
  677.     }
  678.     image_data->mocha_object = obj;
  679.  
  680.     if (!lm_AddObjectToArray(cx, array_obj, (const char *) name, 
  681.                  index, obj)) {
  682.     obj = NULL;
  683.     goto done;
  684.     }
  685.  
  686.     /* Put it in the index to object hash table */
  687.     map = lm_GetIdToObjectMap(decoder);
  688.     if (map)
  689.         PR_HashTableAdd(map,
  690.                         LM_GET_MAPPING_KEY(LM_IMAGES, layer_id, index),
  691.                         obj);
  692.  
  693.     /* OK, we've got our image, see if there are any event handlers
  694.      *   defined with it
  695.      */
  696.     if(tag) {
  697.     PA_Block onload   = lo_FetchParamValue(context, tag, PARAM_ONLOAD);
  698.     PA_Block onabort  = lo_FetchParamValue(context, tag, PARAM_ONABORT);
  699.     PA_Block onerror  = lo_FetchParamValue(context, tag, PARAM_ONERROR);
  700.     PA_Block onmousedown = lo_FetchParamValue(context, tag, PARAM_ONMOUSEDOWN);
  701.     PA_Block onmouseup = lo_FetchParamValue(context, tag, PARAM_ONMOUSEUP);
  702.     PA_Block id      = lo_FetchParamValue(context, tag, PARAM_ID);
  703.  
  704.     /* don't hold the layout lock across compiles */
  705.     LO_UnlockLayout();
  706.  
  707.     if (onload != NULL) {
  708.         (void) lm_CompileEventHandler(decoder, id, tag->data,
  709.                       tag->newline_count, obj,
  710.                       PARAM_ONLOAD, onload);
  711.         PA_FREE(onload);
  712.     }
  713.  
  714.     if (onabort != NULL) {
  715.         (void) lm_CompileEventHandler(decoder, id, tag->data,
  716.                       tag->newline_count, obj,
  717.                           PARAM_ONABORT, onabort);
  718.         PA_FREE(onabort);
  719.     }
  720.  
  721.     if (onerror != NULL) {
  722.         (void) lm_CompileEventHandler(decoder, id, tag->data,
  723.                       tag->newline_count, obj,
  724.                       PARAM_ONERROR, onerror);
  725.         PA_FREE(onerror);
  726.     }
  727.     if (onmousedown != NULL) {
  728.         (void) lm_CompileEventHandler(decoder, id, tag->data,
  729.                       tag->newline_count, obj,
  730.                       PARAM_ONMOUSEDOWN, onmousedown);
  731.         PA_FREE(onmousedown);
  732.     }
  733.     if (onmouseup != NULL) {
  734.         (void) lm_CompileEventHandler(decoder, id, tag->data,
  735.                       tag->newline_count, obj,
  736.                       PARAM_ONMOUSEUP, onmouseup);
  737.         PA_FREE(onmouseup);
  738.     }
  739.  
  740.     if (id)
  741.         PA_FREE(id);
  742.  
  743.     LO_LockLayout();
  744.     }
  745.  
  746. done:
  747.  
  748.     if(name)
  749.     PA_FREE(name);
  750.     LM_PutMochaDecoder(decoder);
  751.  
  752.     return obj;
  753. }
  754.  
  755. void
  756. lm_ProcessImageEvent(MWContext *context, JSObject *obj,
  757.                   LM_ImageEvent event)
  758. {
  759.     uint event_mask;
  760.     jsval result;
  761.     JSImage *image;
  762.  
  763.     image = JS_GetPrivate(context->mocha_context, obj);
  764.     if (!image)
  765.         return;
  766.  
  767.     image->pending_events |= PR_BIT(event);
  768.  
  769.     /* Special event used to trigger deferred events */
  770.     if (! (image->pending_events & PR_BIT(LM_IMGUNBLOCK)))
  771.         return;
  772.  
  773.     for (event = LM_IMGLOAD; event <= LM_LASTEVENT; event++) {
  774.         event_mask = PR_BIT(event);
  775.         if (image->pending_events & event_mask) {
  776.  
  777.         JSEvent *pEvent;
  778.         pEvent=XP_NEW_ZAP(JSEvent);
  779.  
  780.             image->pending_events &= ~event_mask;
  781.             switch (event) {
  782.             case LM_IMGLOAD:
  783.                 pEvent->type = EVENT_LOAD;
  784.                 image->complete = JS_TRUE;
  785.                 break;
  786.             case LM_IMGABORT:
  787.                 pEvent->type = EVENT_ABORT;
  788.                 image->complete = JS_TRUE;
  789.                 break;
  790.             case LM_IMGERROR:
  791.                 pEvent->type = EVENT_ERROR;
  792.                 image->complete = JS_TRUE;
  793.                 break;
  794.             default:
  795.                 XP_ABORT(("Unknown image event"));
  796.             }
  797.  
  798.             lm_SendEvent(context, obj, pEvent, &result);
  799.         }
  800.     }
  801. }
  802.  
  803. JSBool
  804. lm_InitImageClass(MochaDecoder *decoder)
  805. {
  806.     JSContext *cx;
  807.     JSObject *prototype;
  808.  
  809.     cx = decoder->js_context;
  810.     prototype = JS_InitClass(cx, decoder->window_object, 
  811.                  decoder->event_receiver_prototype, &lm_image_class,
  812.                  Image, 0, image_props, NULL, NULL, NULL);
  813.     if (!prototype)
  814.     return JS_FALSE;
  815.     decoder->image_prototype = prototype;
  816.     return JS_TRUE;
  817. }
  818.  
  819. /* Create an image context for anonymous images and attach it to the specified
  820.    mocha decoder. */
  821. JSBool
  822. lm_NewImageContext(MWContext *context, MochaDecoder *decoder)
  823. {
  824.     IL_GroupContext *img_cx;
  825.     IMGCB* img_cb;
  826.     JMCException *exc = NULL;
  827.     
  828.     if (!decoder->image_context) {
  829.         img_cb = IMGCBFactory_Create(&exc); /* JMC Module */
  830.         if (exc) {
  831.             JMC_DELETE_EXCEPTION(&exc); /* XXX Should really return
  832.                                            exception */
  833.             JS_ReportOutOfMemory(decoder->js_context);
  834.             return JS_FALSE;
  835.         }
  836.  
  837.         /* Create an Image Group Context.  IL_NewGroupContext augments the
  838.            reference count for the JMC callback interface.  The opaque argument
  839.            to IL_NewGroupContext is the Front End's display context, which will
  840.            be passed back to all the Image Library's FE callbacks. */
  841.         img_cx = IL_NewGroupContext((void*)context, (IMGCBIF *)img_cb);
  842.         if (!img_cx) {
  843.             JS_ReportOutOfMemory(decoder->js_context);
  844.             return JS_FALSE;
  845.         }
  846.  
  847.         /* Attach the IL_GroupContext to the mocha decoder. */
  848.         decoder->image_context = img_cx;
  849.  
  850.         /* Allow the context to observe the decoder's image context. */
  851.         ET_il_SetGroupObserver(context, decoder->image_context, context, JS_TRUE);
  852.     }
  853.     return JS_TRUE;
  854. }
  855.