home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libmocha / lm_layer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  90.1 KB  |  2,909 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.  * Compositor layer reflection and event notification
  20.  *
  21.  * Scott Furman, 6/20/96
  22.  *
  23.  */
  24.  
  25. #include "lm.h"  /* moved out of ifdef for pre compiled headers */
  26. #include "xp.h"
  27. #include "lo_ele.h"
  28. #include "prtypes.h"
  29. #include "pa_tags.h"
  30. #include "layout.h"
  31. #include "jsdbgapi.h"
  32.  
  33. #include "layers.h"
  34.  
  35. /* Forward declarations. Can these be static? */
  36. PR_STATIC_CALLBACK(JSBool)
  37. rect_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
  38. PR_STATIC_CALLBACK(JSBool)
  39. rect_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
  40.  
  41.  
  42. enum layer_array_slot {
  43.     LAYER_ARRAY_LENGTH = -1
  44. };
  45.  
  46. /* Native part of mocha object reflecting children layers of another layer */
  47. typedef struct JSLayerArray {
  48.     MochaDecoder        *decoder;   /* prefix must match JSObjectArray */
  49.     jsint                length;    /* # of entries in array */
  50.     int32                parent_layer_id;
  51. } JSLayerArray;
  52.  
  53. extern JSClass lm_layer_array_class;
  54.  
  55. PR_STATIC_CALLBACK(JSBool)
  56. layer_array_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  57. {
  58.     JSLayerArray *array;
  59.     MochaDecoder *decoder;
  60.     MWContext *context;
  61.     jsint count, slot;
  62.     CL_Layer *layer, *parent_layer;
  63.     int32 layer_id;
  64.  
  65.     while (!(array = JS_GetInstancePrivate(cx, obj, &lm_layer_array_class, 
  66.                                            NULL))) {
  67.         obj = JS_GetPrototype(cx, obj);
  68.         if (!obj)
  69.             return JS_TRUE;
  70.     }
  71.     decoder = array->decoder;
  72.  
  73.     if (!lm_CheckContainerAccess(cx, obj, decoder, 
  74.                                  JSTARGET_UNIVERSAL_BROWSER_READ)) {
  75.         return JS_FALSE;
  76.     }
  77.  
  78.     if (!JSVAL_IS_INT(id))
  79.         return JS_TRUE;
  80.  
  81.     slot = JSVAL_TO_INT(id);
  82.  
  83.     context = decoder->window_context;
  84.     if (!context) 
  85.         return JS_TRUE;
  86.  
  87.     LO_LockLayout();
  88.  
  89.     if(decoder->doc_id != XP_DOCID(context)) {
  90.         LO_UnlockLayout();
  91.         return JS_FALSE;
  92.     }
  93.  
  94.     parent_layer = LO_GetLayerFromId(context, array->parent_layer_id);
  95.     if (!parent_layer) {
  96.         LO_UnlockLayout();
  97.         return JS_TRUE;
  98.     }
  99.  
  100.     switch (slot) {
  101.       case LAYER_ARRAY_LENGTH:
  102.         count = CL_GetLayerChildCount(parent_layer);
  103.         if (count > array->length)
  104.             array->length = count;
  105.         *vp = INT_TO_JSVAL(count);
  106.         break;
  107.  
  108.       default:
  109.         if (slot < 0) {
  110.             /* Don't mess with user-defined or method properties. */
  111.             LO_UnlockLayout();
  112.             return JS_TRUE;
  113.         }
  114.         if (slot >= array->length)
  115.             array->length = slot + 1;
  116.         layer = CL_GetLayerChildByIndex(parent_layer, slot);
  117.         if (!layer) {
  118.             JS_ReportError(cx,
  119.                            "Attempt to access nonexistent slot %d "
  120.                            "of layers[] array", slot);
  121.             LO_UnlockLayout();
  122.             return JS_FALSE;
  123.         }
  124.         layer_id = LO_GetIdFromLayer(context, layer);
  125.         *vp = OBJECT_TO_JSVAL(LM_ReflectLayer(context, layer_id, 
  126.                                               array->parent_layer_id,
  127.                                               NULL));
  128.         break;
  129.     }
  130.  
  131.     LO_UnlockLayout();
  132.     return JS_TRUE;
  133. }
  134.  
  135. PR_STATIC_CALLBACK(JSBool)
  136. layer_array_resolve_name(JSContext *cx, JSObject *obj, jsval id)
  137. {
  138.     JSLayerArray *array;
  139.     MochaDecoder *decoder;
  140.     const char * name;
  141.     JSObject *layer_obj;
  142.  
  143.     if (!JSVAL_IS_STRING(id))
  144.         return JS_TRUE;
  145.  
  146.     name = JS_GetStringBytes(JSVAL_TO_STRING(id));
  147.     if (!name)
  148.         return JS_TRUE;
  149.  
  150.     array = JS_GetPrivate(cx, obj);
  151.     if (!array)
  152.         return JS_TRUE;
  153.     decoder = array->decoder;
  154.  
  155.     /* 
  156.      * If the layer exists, we don't have to define the property here,
  157.      * since the reflection code will define it for us.
  158.      */
  159.     layer_obj = lm_GetNamedLayer(decoder, array->parent_layer_id, name);
  160.  
  161.     return JS_TRUE;
  162. }
  163.  
  164. PR_STATIC_CALLBACK(void)
  165. layer_array_finalize(JSContext *cx, JSObject *obj)
  166. {
  167.     JSLayerArray *array;
  168.  
  169.     array = JS_GetPrivate(cx, obj);
  170.     if (!array)
  171.         return;
  172.     DROP_BACK_COUNT(array->decoder);
  173.     JS_free(cx, array);
  174. }
  175.  
  176. JSClass lm_layer_array_class = {
  177.     "LayerArray", JSCLASS_HAS_PRIVATE,
  178.     JS_PropertyStub, JS_PropertyStub,
  179.     layer_array_getProperty, layer_array_getProperty, JS_EnumerateStub,
  180.     layer_array_resolve_name, JS_ConvertStub, layer_array_finalize
  181. };
  182.  
  183. static JSPropertySpec layer_array_props[] = {
  184.     {lm_length_str, LAYER_ARRAY_LENGTH,
  185.                     JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT},
  186.     {0}
  187. };
  188.  
  189.  
  190. /* Native part of a mocha object that reflects a single compositor layer
  191.  */
  192. typedef struct JSLayer {
  193.     JSEventCapturer        capturer;
  194.     MochaDecoder           *decoder;
  195.     int32                   layer_id;
  196.     JSString               *name;
  197.     JSObject               *child_layers_array_obj;
  198.     char                   *source_url;
  199.     /* 
  200.      * Indicates which properties have been modified and should be
  201.      * saved across a resize relayout. 
  202.      */
  203.     uint32                  modification_mask; 
  204.     /* 
  205.      * The following are properties whose saved values are of a different
  206.      * type than the property itself.
  207.      */
  208.     JSString               *sibling_above;
  209.     JSString               *sibling_below;
  210.     int32                   width;
  211.     PRPackedBool            properties_locked;
  212.     PRPackedBool            principals_compromised;
  213.     JSPrincipals           *principals;
  214. } JSLayer;
  215.  
  216.  
  217. static JSObject *
  218. reflect_layer_array(MochaDecoder *decoder,
  219.                     int32 parent_layer_id)
  220. {
  221.     JSContext *cx;
  222.     JSLayer *js_layer_parent;
  223.     JSLayerArray *array;
  224.     JSObject *obj, *layer_obj, *parent_doc_obj;
  225.     JSClass *clasp;
  226.     CL_Layer *parent_layer;
  227.  
  228.     cx = decoder->js_context;
  229.     layer_obj = LO_GetLayerMochaObjectFromId(decoder->window_context, 
  230.                                              parent_layer_id);
  231.     parent_layer = LO_GetLayerFromId(decoder->window_context, parent_layer_id);
  232.     parent_doc_obj = lm_GetDocumentFromLayerId(decoder, parent_layer_id);
  233.     if (! layer_obj || !parent_layer || !parent_doc_obj) /* paranoia */
  234.         return NULL;
  235.     js_layer_parent = JS_GetPrivate(cx, layer_obj);
  236.     if (!js_layer_parent)
  237.         return NULL;
  238.     obj = js_layer_parent->child_layers_array_obj;
  239.  
  240.     if (obj)                    /* Are layer children already reflected ? */
  241.         return obj;
  242.     
  243.     clasp = &lm_layer_array_class;
  244.     
  245.     array = JS_malloc(cx, sizeof *array);
  246.     if (!array)
  247.         return NULL;
  248.     XP_BZERO(array, sizeof *array);
  249.     
  250.     obj = JS_NewObject(cx, clasp, NULL, parent_doc_obj);
  251.     if (!obj || !JS_SetPrivate(cx, obj, array)) {
  252.         JS_free(cx, array);
  253.         return NULL;
  254.     }
  255.  
  256.     if (!JS_DefineProperties(cx, obj, layer_array_props))
  257.         return NULL;
  258.  
  259.     array->decoder = HOLD_BACK_COUNT(decoder);
  260.     array->parent_layer_id = parent_layer_id;
  261.     return obj;
  262. }
  263.  
  264. /* Given the mocha object reflecting a compositor layer, return
  265.    the mocha object that reflects its child layers in an array. */
  266. PRIVATE JSObject *
  267. lm_GetLayerArray(MochaDecoder *decoder,
  268.                  JSObject  *parent_js_layer_obj)
  269. {
  270.     JSLayer *js_layer_parent;
  271.     JSObject *obj;
  272.     JSContext *cx;
  273.     
  274.     if (! parent_js_layer_obj)
  275.         return NULL;
  276.     cx = decoder->js_context;
  277.     js_layer_parent = JS_GetPrivate(cx, parent_js_layer_obj);
  278.     if (!js_layer_parent)
  279.         return NULL;
  280.     obj = js_layer_parent->child_layers_array_obj;
  281.     if (obj)
  282.         return obj;
  283.  
  284.     obj = reflect_layer_array(decoder, js_layer_parent->layer_id);
  285.  
  286.     if (obj && !JS_DefineProperty(cx, parent_js_layer_obj, "layers", 
  287.                   OBJECT_TO_JSVAL(obj), NULL, NULL,
  288.                   JSPROP_ENUMERATE|JSPROP_READONLY|
  289.                                   JSPROP_PERMANENT)) {
  290.     return NULL;
  291.     }
  292.  
  293.     js_layer_parent->child_layers_array_obj = obj;
  294.     return obj;
  295. }
  296.  
  297.  
  298. /* The top-level document object contains the distinguished _DOCUMENT
  299.    layer.  Reflect the array containing children of the _DOCUMENT layer. */
  300. JSObject *
  301. lm_GetDocumentLayerArray(MochaDecoder *decoder, JSObject *document)
  302. {
  303.     MWContext *context;
  304.     JSObject *obj;
  305.     JSLayerArray *array;
  306.     JSClass *clasp;
  307.     JSContext *cx;
  308.     JSDocument *doc;
  309.  
  310.     cx = decoder->js_context;
  311.     doc = JS_GetPrivate(cx, document);
  312.     if (!doc)
  313.         return NULL;
  314.  
  315.     obj = doc->layers;
  316.     if (obj)
  317.         return obj;
  318.     context = decoder->window_context;
  319.  
  320.     /* If this is a layer's document, return the layer's child array */
  321.     if (doc->layer_id != LO_DOCUMENT_LAYER_ID) {
  322.         JSObject *layer_obj;
  323.         
  324.         layer_obj = LO_GetLayerMochaObjectFromId(context, doc->layer_id);
  325.         if (!layer_obj)
  326.             return NULL;
  327.         doc->layers = lm_GetLayerArray(decoder, layer_obj);
  328.         
  329.         return doc->layers;
  330.     }
  331.     
  332.     clasp = &lm_layer_array_class;
  333.     
  334.     array = JS_malloc(cx, sizeof *array);
  335.     if (!array)
  336.         return NULL;
  337.     XP_BZERO(array, sizeof *array);
  338.     
  339.     obj = JS_NewObject(cx, clasp, NULL, document);
  340.     if (!obj || !JS_SetPrivate(cx, obj, array)) {
  341.         JS_free(cx, array);
  342.         return NULL;
  343.     }
  344.  
  345.     if (!JS_DefineProperties(cx, obj, layer_array_props)) {
  346.         JS_free(cx, array);
  347.         return NULL;
  348.     }
  349.  
  350.     array->decoder = HOLD_BACK_COUNT(decoder);
  351.     array->parent_layer_id = doc->layer_id;
  352.  
  353.     doc->layers = obj;
  354.     return obj;
  355. }
  356.  
  357. #define LM_SET_LAYER_MODIFICATION(layer, bit)        \
  358.           (layer)->modification_mask |= (1 << (bit))
  359. #define LM_CLEAR_LAYER_MODIFICATION(layer, bit)      \
  360.           (layer)->modification_mask &= ~(1 << (bit))
  361. #define LM_CHECK_LAYER_MODIFICATION(layer, bit)      \
  362.           (((layer)->modification_mask & (1 << (bit))) != 0)
  363.  
  364. enum layer_prop_modification_bits {
  365.     LAYER_MOD_LEFT = 0,
  366.     LAYER_MOD_TOP,
  367.     LAYER_MOD_VISIBILITY,
  368.     LAYER_MOD_SRC,
  369.     LAYER_MOD_ZINDEX,
  370.     LAYER_MOD_BGCOLOR,
  371.     LAYER_MOD_BACKGROUND,
  372.     LAYER_MOD_PARENT,
  373.     LAYER_MOD_SIB_ABOVE,
  374.     LAYER_MOD_SIB_BELOW,
  375.     LAYER_MOD_CLIP_LEFT,
  376.     LAYER_MOD_CLIP_RIGHT,
  377.     LAYER_MOD_CLIP_TOP,
  378.     LAYER_MOD_CLIP_BOTTOM,
  379.     LAYER_MOD_WIDTH
  380. };
  381.  
  382. /* Static compositor layer property slots */
  383. enum layer_slot {
  384.     LAYER_WINDOW            = -1,
  385.     LAYER_NAME              = -2,
  386.     LAYER_LEFT              = -3,
  387.     LAYER_TOP               = -4,
  388.     LAYER_X                 = -5,
  389.     LAYER_Y                 = -6,
  390.     LAYER_HIDDEN            = -7,
  391.     LAYER_SIB_ABOVE         = -8,
  392.     LAYER_SIB_BELOW         = -9,
  393.     LAYER_PARENT            = -10,
  394.     LAYER_CHILDREN          = -11,
  395.     LAYER_SRC               = -12,
  396.     LAYER_VISIBILITY        = -13,
  397.     LAYER_ABOVE             = -14,
  398.     LAYER_BELOW             = -15,
  399.     LAYER_ZINDEX            = -16,
  400.     LAYER_BGCOLOR           = -17
  401. };
  402.  
  403. char lm_left_str[] = "left";
  404. char lm_top_str[] = "top";
  405. char lm_right_str[] = "right";
  406. char lm_bottom_str[] = "bottom";
  407. char lm_src_str[] = "src";
  408. char lm_visibility_str[] = "visibility";
  409. char lm_zindex_str[] = "zIndex";
  410. char lm_bgcolor_str[] = "bgColor";
  411. char lm_background_str[] = "background";
  412. char lm_clip_str[] = "clip";
  413.  
  414. /* Static compositor layer properties */
  415. static JSPropertySpec layer_props[] = {
  416.     {"window",              LAYER_WINDOW,       JSPROP_ENUMERATE | JSPROP_READONLY},
  417.     {"id",                  LAYER_NAME,         JSPROP_ENUMERATE | JSPROP_READONLY},
  418.     {"name",                LAYER_NAME,         JSPROP_ENUMERATE},
  419.     {lm_left_str,           LAYER_LEFT,         JSPROP_ENUMERATE},
  420.     {"x",                   LAYER_LEFT,         JSPROP_ENUMERATE}, /* Synonym for left */
  421.     {lm_top_str,            LAYER_TOP,          JSPROP_ENUMERATE},
  422.     {"y",                   LAYER_TOP,          JSPROP_ENUMERATE}, /* Synonym for top */
  423.     {"pageX",               LAYER_X,            JSPROP_ENUMERATE},
  424.     {"pageY",               LAYER_Y,            JSPROP_ENUMERATE},
  425.     {"hidden",              LAYER_HIDDEN,       JSPROP_ENUMERATE},
  426.     {"layers",              LAYER_CHILDREN,     JSPROP_ENUMERATE | JSPROP_READONLY},
  427.     {"siblingAbove",        LAYER_SIB_ABOVE,    JSPROP_ENUMERATE | JSPROP_READONLY}, /* FIXME - should be writeable */
  428.     {"siblingBelow",        LAYER_SIB_BELOW,    JSPROP_ENUMERATE | JSPROP_READONLY}, /* FIXME - should be writeable */
  429.     {lm_parentLayer_str,    LAYER_PARENT,       JSPROP_ENUMERATE | JSPROP_READONLY},
  430.     {lm_src_str,            LAYER_SRC,          JSPROP_ENUMERATE},
  431.     {lm_visibility_str,     LAYER_VISIBILITY,   JSPROP_ENUMERATE},
  432.     {"above",               LAYER_ABOVE,        JSPROP_ENUMERATE | JSPROP_READONLY},
  433.     {"below",               LAYER_BELOW,        JSPROP_ENUMERATE | JSPROP_READONLY},
  434.     {lm_zindex_str,         LAYER_ZINDEX,       JSPROP_ENUMERATE},
  435.     {lm_bgcolor_str,        LAYER_BGCOLOR,      JSPROP_ENUMERATE},
  436.     {0}
  437. };
  438.  
  439. /* 
  440.  * Static compositor rect property slots. Declared here since we 
  441.  * need the ids in some of the methods.
  442.  */
  443. enum rect_slot {
  444.     RECT_LEFT              = -1,
  445.     RECT_TOP               = -2,
  446.     RECT_RIGHT             = -3,
  447.     RECT_BOTTOM            = -4,
  448.     RECT_WIDTH             = -5,
  449.     RECT_HEIGHT            = -6
  450. };
  451.  
  452. extern JSClass lm_layer_class;
  453.  
  454. PR_STATIC_CALLBACK(JSBool)
  455. layer_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  456. {
  457.     JSLayer *js_layer;
  458.     MochaDecoder *decoder;
  459.     MWContext *context;
  460.     JSString *str;
  461.     CL_Layer *layer, *layer_above, *layer_below, *layer_parent;
  462.     LO_Color *bg_color;
  463.     jsint slot;
  464.     char *visibility;
  465.     uint32 flags;
  466.  
  467.     while (!(js_layer = JS_GetInstancePrivate(cx, obj, &lm_layer_class, NULL))) {
  468.         obj = JS_GetPrototype(cx, obj);
  469.         if (!obj)
  470.             return JS_TRUE;
  471.     }
  472.  
  473.     decoder = js_layer->decoder;
  474.  
  475.     if (!lm_CheckContainerAccess(cx, obj, decoder, 
  476.                                  JSTARGET_UNIVERSAL_BROWSER_READ)) {
  477.         return JS_FALSE;
  478.     }
  479.  
  480.     if (!JSVAL_IS_INT(id))
  481.         return JS_TRUE;
  482.  
  483.     slot = JSVAL_TO_INT(id);
  484.  
  485.     context = decoder->window_context;
  486.     if (!context)
  487.         return JS_TRUE;
  488.  
  489.     /*
  490.      * Not sure if this is enough protection or not...
  491.      */
  492.     LO_LockLayout();
  493.  
  494.     if(decoder->doc_id != XP_DOCID(context)) {
  495.         LO_UnlockLayout();
  496.         return JS_FALSE;
  497.     }
  498.  
  499.     layer = LO_GetLayerFromId(context, js_layer->layer_id);
  500.     if (!layer) {
  501.         LO_UnlockLayout();
  502.         return JS_TRUE;
  503.     }
  504.     
  505.     switch (slot) {
  506.     case LAYER_WINDOW:
  507.         *vp = OBJECT_TO_JSVAL(decoder->window_object);
  508.         break;
  509.  
  510.     case LAYER_NAME:
  511.         if (js_layer->name)
  512.             *vp = STRING_TO_JSVAL(js_layer->name);
  513.         else
  514.             *vp = JSVAL_NULL;
  515.         break;
  516.  
  517.     case LAYER_HIDDEN:
  518.         *vp = BOOLEAN_TO_JSVAL(CL_GetLayerHidden(layer));
  519.         break;
  520.  
  521.     case LAYER_VISIBILITY:
  522.         flags = CL_GetLayerFlags(layer);
  523.         if (flags & CL_HIDDEN)
  524.             visibility = "hide";
  525.         else if (flags & CL_OVERRIDE_INHERIT_VISIBILITY)
  526.             visibility = "show";
  527.         else
  528.             visibility = "inherit";
  529.         
  530.         str = JS_NewStringCopyZ(cx, visibility);
  531.         if (!str) {
  532.             LO_UnlockLayout();
  533.             return JS_FALSE;
  534.         }
  535.         *vp = STRING_TO_JSVAL(str);
  536.         break;
  537.  
  538.     case LAYER_LEFT:
  539.       *vp = INT_TO_JSVAL(LO_GetLayerXOffset(layer));
  540.       break;
  541.  
  542.     case LAYER_TOP:
  543.       *vp = INT_TO_JSVAL(LO_GetLayerYOffset(layer));
  544.       break;
  545.  
  546.     case LAYER_X:
  547.       *vp = INT_TO_JSVAL(CL_GetLayerXOrigin(layer));
  548.       break;
  549.  
  550.     case LAYER_Y:
  551.       *vp = INT_TO_JSVAL(CL_GetLayerYOrigin(layer));
  552.       break;
  553.  
  554.     case LAYER_CHILDREN: 
  555.         *vp = OBJECT_TO_JSVAL(lm_GetLayerArray(js_layer->decoder, obj));
  556.         break;
  557.         
  558.     case LAYER_SIB_ABOVE:
  559.         layer_above = CL_GetLayerSiblingAbove(layer);
  560.         if (layer_above)
  561.             *vp = OBJECT_TO_JSVAL(LO_GetLayerMochaObjectFromLayer(context, 
  562.                                                                layer_above));
  563.         else
  564.             *vp = JSVAL_NULL;
  565.         break;
  566.  
  567.     case LAYER_SIB_BELOW:
  568.         layer_below = CL_GetLayerSiblingBelow(layer);
  569.         if (layer_below) 
  570.             *vp = OBJECT_TO_JSVAL(LO_GetLayerMochaObjectFromLayer(context, 
  571.                                                                layer_below));
  572.         else
  573.             *vp = JSVAL_NULL;
  574.         break;
  575.  
  576.     case LAYER_PARENT:
  577.         layer_parent = CL_GetLayerParent(layer);
  578.  
  579.         /* 
  580.          * XXX This is a bit controversial - should the parent layer of
  581.          * a top-level layer be the window??
  582.          */
  583.         if (layer_parent) {
  584.             if (CL_GetLayerFlags(layer_parent) & CL_DONT_ENUMERATE)
  585.                 *vp = OBJECT_TO_JSVAL(decoder->window_object);
  586.             else
  587.                 *vp = OBJECT_TO_JSVAL(LO_GetLayerMochaObjectFromLayer(context, 
  588.                                                                 layer_parent));
  589.         }
  590.         else
  591.             *vp = JSVAL_NULL;
  592.         break;
  593.  
  594.     case LAYER_ZINDEX:
  595.         *vp = INT_TO_JSVAL(CL_GetLayerZIndex(layer));
  596.       break;
  597.  
  598.     case LAYER_ABOVE:
  599.         layer_above = CL_GetLayerAbove(layer);
  600.         if (layer_above) 
  601.             *vp = OBJECT_TO_JSVAL(LO_GetLayerMochaObjectFromLayer(context, 
  602.                                                                layer_above));
  603.         else
  604.             *vp = JSVAL_NULL;
  605.         break;
  606.  
  607.     case LAYER_BELOW:
  608.         layer_below = CL_GetLayerBelow(layer);
  609.         if (layer_below) 
  610.             *vp = OBJECT_TO_JSVAL(LO_GetLayerMochaObjectFromLayer(context, 
  611.                                                                layer_below));
  612.         else
  613.             *vp = JSVAL_NULL;
  614.         break;
  615.  
  616.     case LAYER_BGCOLOR:
  617.         bg_color = LO_GetLayerBgColor(layer);
  618.         if (bg_color) {
  619.             uint32 packed_color =
  620.                 (bg_color->red << 16) | (bg_color->green << 8) | (bg_color->blue);
  621.             *vp = INT_TO_JSVAL(packed_color);
  622.         } else
  623.             *vp = JSVAL_NULL;
  624.         break;
  625.         
  626.     case LAYER_SRC:
  627.         if (!lm_CheckPermissions(cx, obj, JSTARGET_UNIVERSAL_BROWSER_READ))
  628.         return JS_FALSE;
  629.     if (!js_layer->source_url) {
  630.             *vp = JSVAL_NULL;
  631.         } else {
  632.             JSString *url;
  633.             
  634.             url = JS_NewStringCopyZ(cx, js_layer->source_url);
  635.             if (!url) {
  636.                 LO_UnlockLayout();
  637.                 return JS_FALSE;
  638.             }
  639.             *vp = STRING_TO_JSVAL(url);
  640.         }
  641.         break;
  642.     default:
  643.         /* Don't mess with a user-defined or method property. */
  644.         break;
  645.     }
  646.  
  647.     LO_UnlockLayout();
  648.  
  649.     return JS_TRUE;
  650. }
  651.  
  652. JSBool
  653. lm_jsval_to_rgb(JSContext *cx, jsval *vp, LO_Color **rgbp)
  654. {
  655.     LO_Color *rgb = NULL;
  656.     int32 color;
  657.  
  658.     if (JSVAL_IS_NUMBER(*vp)) {
  659.         if (!JS_ValueToInt32(cx, *vp, &color))
  660.             return JS_FALSE;
  661.         if ((color >> 24) != 0)
  662.             return JS_FALSE;
  663.  
  664.         rgb = XP_NEW(LO_Color);
  665.         if (!rgb)
  666.             return JS_FALSE;
  667.  
  668.         rgb->red = (uint8) (color >> 16);
  669.         rgb->green = (uint8) ((color >> 8) & 0xff);
  670.         rgb->blue = (uint8) (color & 0xff);
  671.     } else {
  672.         switch(JS_TypeOfValue(cx, *vp)) {
  673.  
  674.         case JSTYPE_OBJECT:
  675.             /* Check for null (transparent) bgcolor */
  676.             if (JSVAL_IS_NULL(*vp)) {
  677.                 rgb = NULL;
  678.                 break;
  679.             }
  680.             /* FALL THROUGH */
  681.             
  682.         default:
  683.             if (!JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp))
  684.                 return JS_FALSE;
  685.             /* FALL THROUGH */
  686.  
  687.         case JSTYPE_STRING:
  688.             rgb = XP_NEW(LO_Color);
  689.             if (!rgb)
  690.                 return JS_FALSE;
  691.  
  692.             if (!LO_ParseRGB((char *)JS_GetStringBytes(JSVAL_TO_STRING(*vp)),
  693.                              &rgb->red, &rgb->green, &rgb->blue)) {
  694.         JS_ReportError(cx, "Invalid color specification %s",
  695.                    (char *)JS_GetStringBytes(JSVAL_TO_STRING(*vp)));
  696.         XP_FREE(rgb);
  697.         return JS_FALSE;
  698.             }
  699.             break;
  700.         }
  701.     }
  702.     *rgbp = rgb;
  703.     return JS_TRUE;
  704.     
  705. }
  706.  
  707.  
  708. PR_STATIC_CALLBACK(JSBool)
  709. layer_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  710. {
  711.     int32 val;
  712.     int32 val32;
  713.     JSBool hidden;
  714.     PRBool properties_locked;
  715.     JSLayer *js_layer;
  716.     MochaDecoder *decoder;
  717.     MWContext *context;
  718.     CL_Layer *layer, *parent;
  719.     char *url;
  720.     LO_Color *rgb;
  721.     jsint slot;
  722.     jsval js_val;
  723.     const char *referer;
  724.     JSBool unlockp = JS_TRUE;
  725.  
  726.     while (!(js_layer = JS_GetInstancePrivate(cx, obj, &lm_layer_class, NULL))) {
  727.         obj = JS_GetPrototype(cx, obj);
  728.         if (!obj)
  729.             return JS_TRUE;
  730.     }
  731.     properties_locked = (PRBool)js_layer->properties_locked;
  732.  
  733.     decoder = js_layer->decoder;
  734.  
  735.     if (!lm_CheckContainerAccess(cx, obj, decoder, 
  736.                                  JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
  737.         return JS_FALSE;
  738.     }
  739.  
  740.     context = decoder->window_context;
  741.     if (!context) 
  742.         return JS_TRUE;
  743.  
  744.     if (!JSVAL_IS_INT(id))
  745.         return JS_TRUE;
  746.  
  747.     slot = JSVAL_TO_INT(id);
  748.  
  749.     LO_LockLayout();
  750.     if(decoder->doc_id != XP_DOCID(context)) {
  751.         LO_UnlockLayout();
  752.         return JS_FALSE;
  753.     }
  754.  
  755.     layer = LO_GetLayerFromId(context, js_layer->layer_id);
  756.     if (!layer) {
  757.         LO_UnlockLayout();
  758.         return JS_TRUE;
  759.     }
  760.  
  761.     /* If a layer is dynamically changing, it will probably look
  762.        better if it utilizes offscreen compositing. */
  763.     CL_ChangeLayerFlag(layer, CL_PREFER_DRAW_OFFSCREEN, PR_TRUE);
  764.  
  765.     switch (slot) {
  766.     case LAYER_HIDDEN:
  767.         if (!JS_ValueToBoolean(cx, *vp, &hidden))
  768.             goto error_exit;
  769.         js_val = BOOLEAN_TO_JSVAL(!hidden);
  770.         JS_SetProperty(cx, obj, lm_visibility_str, &js_val);
  771.         break;
  772.         
  773.     case LAYER_VISIBILITY:
  774.     {
  775.         JSBool hidden, inherit;
  776.  
  777.         if (JSVAL_IS_BOOLEAN(*vp)) {
  778.             hidden = (JSBool)(!JSVAL_TO_BOOLEAN(*vp));
  779.             CL_ChangeLayerFlag(layer, CL_HIDDEN, (PRBool)hidden);
  780.         } else {
  781.             JSString *str;
  782.             const char *visibility;
  783.             
  784.             if (!(str = JS_ValueToString(cx, *vp)))
  785.                 goto error_exit;
  786.             visibility = JS_GetStringBytes(str);
  787.             /* Accept "hidden" or "hide" */
  788.             hidden = (JSBool)(!XP_STRNCASECMP(visibility, "hid", 3));
  789.             inherit = (JSBool)(!XP_STRCASECMP(visibility, "inherit"));
  790.  
  791.             if (!hidden && !inherit &&
  792.                 XP_STRCASECMP(visibility, "show") &&
  793.                 XP_STRCASECMP(visibility, "visible")) {
  794.                 JS_ReportError(cx,
  795.                                "Layer visibility property must be set to "
  796.                                "one of 'hide', 'show' or 'inherit'");
  797.             }
  798.             CL_ChangeLayerFlag(layer, CL_HIDDEN, (PRBool)hidden);
  799.             CL_ChangeLayerFlag(layer, CL_OVERRIDE_INHERIT_VISIBILITY,
  800.                                (PRBool)!inherit);
  801.         }
  802.         LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_VISIBILITY);
  803.         break;
  804.     }
  805.  
  806.     case LAYER_LEFT:
  807.         /* Some layers have mostly read-only properties because we
  808.            don't want a malicious/careless JS author to modify them,
  809.            e.g.  for layers that are used to encapulate a mail
  810.            message. In such cases, we fail silently. */
  811.         if (properties_locked)
  812.             break;
  813.         if (!JS_ValueToInt32(cx, *vp, &val))
  814.             goto error_exit;
  815.         LO_MoveLayer(layer, (int32)val, LO_GetLayerYOffset(layer));
  816.         LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_LEFT);
  817.         break;
  818.             
  819.     case LAYER_TOP:
  820.         /* Some layers have mostly read-only properties because we
  821.            don't want a malicious/careless JS author to modify them,
  822.            e.g.  for layers that are used to encapulate a mail
  823.            message. In such cases, we fail silently. */
  824.         if (properties_locked)
  825.             break;
  826.         if (!JS_ValueToInt32(cx, *vp, &val))
  827.             goto error_exit;
  828.         LO_MoveLayer(layer, LO_GetLayerXOffset(layer), (int32)val);
  829.         LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_TOP);
  830.         break;
  831.  
  832.     case LAYER_X:
  833.         /* Some layers have mostly read-only properties because we
  834.            don't want a malicious/careless JS author to modify them,
  835.            e.g.  for layers that are used to encapulate a mail
  836.            message. In such cases, we fail silently. */
  837.         if (properties_locked)
  838.             break;
  839.         if (!JS_ValueToInt32(cx, *vp, &val32))
  840.             goto error_exit;
  841.         parent = CL_GetLayerParent(layer);
  842.         XP_ASSERT(parent);
  843.         if (parent)
  844.             val32 -= CL_GetLayerXOrigin(parent);
  845.         js_val = INT_TO_JSVAL(val32);
  846.         JS_SetProperty(cx, obj, lm_left_str, &js_val);
  847.         break;
  848.                            
  849.     case LAYER_Y:
  850.         /* Some layers have mostly read-only properties because we
  851.            don't want a malicious/careless JS author to modify them,
  852.            e.g.  for layers that are used to encapulate a mail
  853.            message. In such cases, we fail silently. */
  854.         if (properties_locked)
  855.             break;
  856.         if (!JS_ValueToInt32(cx, *vp, &val32))
  857.             goto error_exit;
  858.         parent = CL_GetLayerParent(layer);
  859.         XP_ASSERT(parent);
  860.         if (parent)
  861.             val32 -= CL_GetLayerYOrigin(parent);
  862.         js_val = INT_TO_JSVAL(val32);
  863.         JS_SetProperty(cx, obj, lm_top_str, &js_val);
  864.         break;
  865.  
  866.     case LAYER_SRC:
  867.         /* Some layers have mostly read-only properties because we
  868.            don't want a malicious/careless JS author to modify them,
  869.            e.g.  for layers that are used to encapulate a mail
  870.            message. In such cases, we fail silently. */
  871.         if (properties_locked)
  872.             break;
  873.         if (!JSVAL_IS_STRING(*vp) &&
  874.             !JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp)) {
  875.             goto error_exit;
  876.         }
  877.         
  878.         url = JS_GetStringBytes(JSVAL_TO_STRING(*vp));
  879.         LO_UnlockLayout();
  880.  
  881.         url = (char *)lm_CheckURL(cx, url, JS_TRUE);
  882.         if (! url)
  883.         return JS_FALSE;
  884.  
  885.     referer = lm_GetSubjectOriginURL(cx);
  886.     if (! referer) {
  887.             XP_FREE(url);
  888.         return JS_FALSE;
  889.     }
  890.  
  891.     if (ET_TweakLayer(decoder->window_context, layer, 0, 0,
  892.               (void *)url, js_layer->layer_id, 
  893.               CL_SetSrc, referer, decoder->doc_id)) {
  894.         lm_NewLayerDocument(decoder, js_layer->layer_id);
  895.         XP_FREEIF(js_layer->source_url);
  896.         js_layer->source_url = url;
  897.         if (js_layer->principals) {
  898.         JSPRINCIPALS_DROP(cx, js_layer->principals);
  899.         }
  900.         js_layer->principals = LM_NewJSPrincipals(NULL, NULL, url);
  901.         if (js_layer->principals == NULL) {
  902.         XP_FREE(url);
  903.         return JS_FALSE;
  904.         }
  905.         JSPRINCIPALS_HOLD(cx, js_layer->principals);
  906.         LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_SRC);
  907.         decoder->stream_owner = js_layer->layer_id;
  908.     }
  909.     else {
  910.             XP_FREE(url);
  911.     }
  912.  
  913.         /* Note that the name will be deallocated at the other end
  914.            of this call. */
  915.  
  916.     /* Return true here to avoid passing through the getter and 
  917.      * hitting the additional security checks there.  Return
  918.      * value has already been stringized here. */
  919.     return JS_TRUE;
  920.  
  921.         break;
  922.  
  923.     case LAYER_ZINDEX:
  924.         if (!JS_ValueToInt32(cx, *vp, &val))
  925.             goto error_exit;
  926.         parent = CL_GetLayerParent(layer);
  927.         CL_RemoveChild(parent, layer);
  928.         CL_InsertChildByZ(parent, layer, (int32)val);
  929.         LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_ZINDEX);
  930.         LM_CLEAR_LAYER_MODIFICATION(js_layer, LAYER_MOD_SIB_ABOVE);
  931.         LM_CLEAR_LAYER_MODIFICATION(js_layer, LAYER_MOD_SIB_BELOW);        
  932.         break;
  933.  
  934.     case LAYER_BGCOLOR:
  935.         LO_UnlockLayout();
  936.         unlockp = JS_FALSE;
  937.         if (!lm_jsval_to_rgb(cx, vp, &rgb))
  938.             return JS_FALSE;
  939.         ET_TweakLayer(decoder->window_context, layer, 0, 0,
  940.                       rgb, 0, CL_SetBgColor, NULL, decoder->doc_id);
  941.         LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_BGCOLOR);
  942.         break;
  943.  
  944.     case LAYER_SIB_ABOVE:
  945.     case LAYER_SIB_BELOW:
  946.         /* FIXME - these should be writeable */
  947.         break;
  948.  
  949.     /* These are immutable. */
  950.     case LAYER_NAME:
  951.     case LAYER_CHILDREN:
  952.         break;
  953.  
  954.     default:
  955.         break;
  956.     }
  957.  
  958.     if (unlockp)
  959.         LO_UnlockLayout();
  960.     return layer_getProperty(cx, obj, id, vp);
  961.  
  962.   error_exit:
  963.     LO_UnlockLayout();
  964.     return JS_FALSE;
  965. }
  966.  
  967. JSBool
  968. layer_setBgColorProperty(JSContext *cx, JSObject *obj, jsval *vp)
  969. {
  970.     return layer_setProperty(cx, obj, INT_TO_JSVAL(LAYER_BGCOLOR), vp);
  971. }
  972.  
  973. /* Lazily synthesize an Image object for the layer's 'background' property */
  974. PR_STATIC_CALLBACK(JSBool)
  975. layer_resolve_name(JSContext *cx, JSObject *obj, jsval id)
  976. {
  977.     JSLayer *js_layer;
  978.     MochaDecoder *decoder;
  979.     const char * name;
  980.  
  981.     js_layer = JS_GetPrivate(cx, obj);
  982.     if (!js_layer)
  983.         return JS_TRUE;
  984.     decoder = js_layer->decoder;
  985.  
  986.     if (!JSVAL_IS_STRING(id))
  987.         return JS_TRUE;
  988.     name = JS_GetStringBytes(JSVAL_TO_STRING(id));
  989.  
  990.     if (!XP_STRCMP(name, lm_background_str)) {
  991.         JSObject *image_obj;
  992.         CL_Layer *layer;
  993.         
  994.         layer = LO_GetLayerFromId(decoder->window_context, js_layer->layer_id);
  995.         if (!layer)
  996.             return JS_FALSE;
  997.         image_obj = lm_NewImage(cx, LO_GetLayerBackdropImage(layer));
  998.         if (!image_obj)
  999.             return JS_FALSE;
  1000.         
  1001.         return JS_DefineProperty(cx, obj, name, OBJECT_TO_JSVAL(image_obj),
  1002.                                  NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY);
  1003.     }
  1004.     return lm_ResolveWindowProps(cx, decoder, obj, id);
  1005. }
  1006.  
  1007. PR_STATIC_CALLBACK(void)
  1008. layer_finalize(JSContext *cx, JSObject *obj)
  1009. {
  1010.     JSLayer *js_layer;
  1011.     PRHashTable *map;
  1012.  
  1013.     js_layer = JS_GetPrivate(cx, obj);
  1014.     if (!js_layer)
  1015.         return;
  1016.  
  1017. /* XXX js_layer->layer is sometimes freed by the time the GC runs
  1018.     CL_SetLayerMochaObject(js_layer->layer, NULL);
  1019.  */
  1020.     DROP_BACK_COUNT(js_layer->decoder);
  1021.     JS_UnlockGCThing(cx, js_layer->name);
  1022.  
  1023.     map = lm_GetIdToObjectMap(js_layer->decoder);
  1024.     if (map)
  1025.         PR_HashTableRemove(map, LM_GET_MAPPING_KEY(LM_LAYERS, 0, js_layer->layer_id));
  1026.  
  1027.     JS_RemoveRoot(cx, &js_layer->sibling_above);
  1028.     JS_RemoveRoot(cx, &js_layer->sibling_below);
  1029.     XP_FREEIF(js_layer->source_url);
  1030.     if (js_layer->principals) {
  1031.         JSPRINCIPALS_DROP(cx, js_layer->principals);
  1032.     }
  1033.     JS_free(cx, js_layer);
  1034. }
  1035.  
  1036. JSClass lm_layer_class = {
  1037.     "Layer", JSCLASS_HAS_PRIVATE,
  1038.     JS_PropertyStub, JS_PropertyStub, layer_getProperty, layer_setProperty,
  1039.     JS_EnumerateStub, layer_resolve_name, JS_ConvertStub, layer_finalize
  1040. };
  1041.  
  1042. /* JS native method:
  1043.  
  1044.    Translate layer to given XY coordinates, e.g.
  1045.    document.layers[0].moveto(1, 3); */
  1046. static JSBool
  1047. move_layer(JSContext *cx, JSObject *obj,
  1048.            uint argc, jsval *argv, jsval *rval, PRBool is_absolute)
  1049. {
  1050.     int32 x, y;
  1051.     JSLayer *js_layer;
  1052.     MochaDecoder *decoder;
  1053.     jsval val;
  1054.     CL_Layer *layer;
  1055.     
  1056.     if (!(js_layer = JS_GetInstancePrivate(cx, obj, &lm_layer_class, argv)))
  1057.         return JS_FALSE;
  1058.  
  1059.     /* Some layers have mostly read-only properties because we
  1060.        don't want a malicious/careless JS author to modify them,
  1061.        e.g.  for layers that are used to encapulate a mail
  1062.        message. In such cases, we fail silently. */
  1063.     if (js_layer->properties_locked)
  1064.         return JS_TRUE;
  1065.     
  1066.     decoder = js_layer->decoder;
  1067.  
  1068.     LO_LockLayout();
  1069.     if(!decoder->window_context || 
  1070.     decoder->doc_id != XP_DOCID(decoder->window_context)) {
  1071.         LO_UnlockLayout();
  1072.         return JS_FALSE;
  1073.     }
  1074.     
  1075.     layer = LO_GetLayerFromId(decoder->window_context, js_layer->layer_id);
  1076.     if (!layer) 
  1077.         goto error_exit;
  1078.     if (argc != 2) {
  1079.         JS_ReportError(cx, lm_argc_err_str);
  1080.         goto error_exit;
  1081.     }
  1082.     if (!JS_ValueToInt32(cx, argv[0], &x) ||
  1083.         !JS_ValueToInt32(cx, argv[1], &y)) {
  1084.         goto error_exit;
  1085.     }
  1086.  
  1087.     if (is_absolute) {
  1088.         CL_Layer *parent_layer = CL_GetLayerParent(layer);
  1089.         x -= CL_GetLayerXOrigin(parent_layer);
  1090.         y -= CL_GetLayerYOrigin(parent_layer);
  1091.     }
  1092.  
  1093.     /* If a layer is moving, it will probably look better if it
  1094.        utilizes offscreen compositing. */
  1095.     CL_ChangeLayerFlag(layer, CL_PREFER_DRAW_OFFSCREEN, PR_TRUE);
  1096.     LO_MoveLayer(layer, x, y);
  1097.  
  1098.     /*
  1099.      * Record that we've side-effected left and top. We do a DefineProperty
  1100.      * to mutate the property and ensure that we have a unique slot per-object.
  1101.      */
  1102.     if (!LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_LEFT)) {
  1103.         JS_DefinePropertyWithTinyId(cx, obj, lm_left_str, LAYER_LEFT,
  1104.                                     INT_TO_JSVAL(x), layer_getProperty, 
  1105.                                     layer_setProperty, JSPROP_ENUMERATE);
  1106.         LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_LEFT);
  1107.     }
  1108.     else
  1109.         JS_GetProperty(cx, obj, lm_left_str, &val);
  1110.     if (!LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_TOP)) {
  1111.         LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_TOP);
  1112.         JS_DefinePropertyWithTinyId(cx, obj, lm_top_str, LAYER_TOP,
  1113.                                     INT_TO_JSVAL(y), layer_getProperty, 
  1114.                                     layer_setProperty, JSPROP_ENUMERATE);
  1115.     }
  1116.     else
  1117.         JS_GetProperty(cx, obj, lm_top_str, &val);
  1118.  
  1119.     LO_UnlockLayout();
  1120.     return JS_TRUE;
  1121.  
  1122.   error_exit:
  1123.     LO_UnlockLayout();
  1124.     return JS_FALSE;
  1125. }
  1126.  
  1127. /* JS native method:
  1128.  
  1129.    Translate layer to given XY coordinates relative to BODY document origin, e.g.
  1130.    document.layers[0].moveto(1, 3); */
  1131. PR_STATIC_CALLBACK(JSBool)
  1132. move_layer_abs(JSContext *cx, JSObject *obj,
  1133.                uint argc, jsval *argv, jsval *rval)
  1134. {
  1135.     return move_layer(cx, obj, argc, argv, rval, PR_TRUE);
  1136. }
  1137.  
  1138. /* JS native method:
  1139.  
  1140.    Translate layer to given XY coordinates relative to parent_layer, e.g.
  1141.    document.layers[0].moveto(1, 3); */
  1142. PR_STATIC_CALLBACK(JSBool)
  1143. move_layer_rel(JSContext *cx, JSObject *obj,
  1144.                uint argc, jsval *argv, jsval *rval)
  1145. {
  1146.     return move_layer(cx, obj, argc, argv, rval, PR_FALSE);
  1147. }
  1148.  
  1149. /* JS native method:
  1150.  
  1151.    Stack layer above argument layer, e.g.
  1152.    document.layers[0].moveAbove(document.layers[2]); */
  1153. static JSBool
  1154. change_layer_stacking(JSContext *cx, JSObject *obj,
  1155.                       uint argc, jsval *argv, jsval *rval,
  1156.                       CL_LayerPosition position)
  1157. {
  1158.     int32 sibling_parent_layer_id;
  1159.     JSLayer *js_layer, *sibling_js_layer;
  1160.     JSObject *sibling_obj;
  1161.     MochaDecoder *decoder;
  1162.     CL_Layer *layer, *sibling_layer, *parent, *sibling_layer_parent;
  1163.     char *new_sibling_name;
  1164.  
  1165.     if (!(js_layer = JS_GetInstancePrivate(cx, obj, &lm_layer_class, argv)))
  1166.         return JS_FALSE;
  1167.     decoder = js_layer->decoder;
  1168.  
  1169.     if (argc != 1) {
  1170.         JS_ReportError(cx, lm_argc_err_str);
  1171.         return JS_FALSE;
  1172.     }
  1173.     if (!JS_ValueToObject(cx, argv[0], &sibling_obj))
  1174.         return JS_FALSE;
  1175.  
  1176.     /* no-op */
  1177.     if (!sibling_obj)
  1178.         return JS_TRUE;
  1179.  
  1180.     /* could be an object of another class. */
  1181.     if (!JS_InstanceOf(cx, sibling_obj, &lm_layer_class, argv))
  1182.         return JS_FALSE;
  1183.  
  1184.     sibling_js_layer = JS_GetPrivate(cx, sibling_obj);
  1185.     if (!sibling_js_layer)
  1186.         return JS_TRUE;
  1187.  
  1188.     LO_LockLayout();
  1189.     if(decoder->doc_id != XP_DOCID(decoder->window_context)) {
  1190.         LO_UnlockLayout();
  1191.         return JS_FALSE;
  1192.     }
  1193.     
  1194.     layer = LO_GetLayerFromId(decoder->window_context, js_layer->layer_id);
  1195.     sibling_layer = LO_GetLayerFromId(decoder->window_context, 
  1196.                                       sibling_js_layer->layer_id);
  1197.     parent = CL_GetLayerParent(layer);
  1198.     sibling_layer_parent = CL_GetLayerParent(sibling_layer);
  1199.  
  1200.     sibling_parent_layer_id = LO_GetIdFromLayer(decoder->window_context,
  1201.                                                 sibling_layer_parent);
  1202.     if (IS_MESSAGE_WINDOW(decoder->window_context) &&
  1203.         (sibling_parent_layer_id == LO_DOCUMENT_LAYER_ID)) {
  1204.         LO_UnlockLayout();
  1205.         JS_ReportError(cx, 
  1206.                        "Disallowed attempt to manipulate top-level layer"
  1207.                        " in a message window");
  1208.         return JS_FALSE;
  1209.     }
  1210.  
  1211.     if (layer == sibling_layer) {
  1212.         LO_UnlockLayout();
  1213.         JS_ReportError(cx, "Cannot stack a Layer above or beneath itself");
  1214.         return JS_FALSE;
  1215.     }
  1216.  
  1217.     /* It shouldn't be possible to be passed the 
  1218.        compositor's root layer. */
  1219.     XP_ASSERT(parent);
  1220.     XP_ASSERT(sibling_layer_parent);
  1221.     if (!sibling_layer_parent || !parent) {
  1222.         LO_UnlockLayout();
  1223.         return JS_FALSE;
  1224.     }
  1225.             
  1226.     /* If a layer is dynamically changing, it will probably look
  1227.        better if it utilizes offscreen compositing. */
  1228.     CL_ChangeLayerFlag(layer, CL_PREFER_DRAW_OFFSCREEN, PR_TRUE);
  1229.  
  1230.     CL_RemoveChild(parent, layer);
  1231.     CL_InsertChild(sibling_layer_parent, layer, 
  1232.                    sibling_layer, position);
  1233.  
  1234.     /* 
  1235.      * Now store the sibling's name. Note that preservation of zindex,
  1236.      * sibling_above and sibling_below are mutually exclusive, so if
  1237.      * we set one, the others are cleared.
  1238.      */
  1239.     LM_CLEAR_LAYER_MODIFICATION(js_layer, LAYER_MOD_ZINDEX); 
  1240.     if (position == CL_ABOVE) {
  1241.         LM_CLEAR_LAYER_MODIFICATION(js_layer, LAYER_MOD_SIB_ABOVE);        
  1242.         new_sibling_name = CL_GetLayerName(sibling_layer);
  1243.         if (new_sibling_name) {
  1244.             LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_SIB_BELOW);
  1245.             js_layer->sibling_below = JS_NewStringCopyZ(cx, new_sibling_name);
  1246.         }
  1247.     }
  1248.  
  1249.     if (position == CL_BELOW) {
  1250.         LM_CLEAR_LAYER_MODIFICATION(js_layer, LAYER_MOD_SIB_BELOW);        
  1251.         new_sibling_name = CL_GetLayerName(sibling_layer);
  1252.         if (new_sibling_name) {
  1253.             LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_SIB_ABOVE);
  1254.             js_layer->sibling_above = JS_NewStringCopyZ(cx, new_sibling_name);
  1255.         }
  1256.     }
  1257.     
  1258.     LO_UnlockLayout();
  1259.     return JS_TRUE;
  1260. }
  1261.  
  1262. PR_STATIC_CALLBACK(JSBool)
  1263. move_above(JSContext *cx, JSObject *obj,
  1264.            uint argc, jsval *argv, jsval *rval)
  1265. {
  1266.     return change_layer_stacking(cx, obj, argc, argv, rval, CL_ABOVE);
  1267. }
  1268.  
  1269. PR_STATIC_CALLBACK(JSBool)
  1270. move_below(JSContext *cx, JSObject *obj,
  1271.            uint argc, jsval *argv, jsval *rval)
  1272. {
  1273.     return change_layer_stacking(cx, obj, argc, argv, rval, CL_BELOW);
  1274. }
  1275.  
  1276. /* JS native method:
  1277.  
  1278.    Translate layer by given XY offset, e.g.
  1279.    document.layers[0].offset(1, 3); */
  1280. PR_STATIC_CALLBACK(JSBool)
  1281. offset_layer(JSContext *cx, JSObject *obj,
  1282.            uint argc, jsval *argv, jsval *rval)
  1283. {
  1284.     int32 x, y;
  1285.     JSLayer *js_layer;
  1286.     MochaDecoder *decoder;
  1287.     CL_Layer *layer;
  1288.     jsval val;
  1289.  
  1290.     if (!(js_layer = JS_GetInstancePrivate(cx, obj, &lm_layer_class, argv)))
  1291.         return JS_FALSE;
  1292.     decoder = js_layer->decoder;
  1293.  
  1294.     /* Some layers have mostly read-only properties because we
  1295.        don't want a malicious/careless JS author to modify them,
  1296.        e.g.  for layers that are used to encapulate a mail
  1297.        message. In such cases, we fail silently. */
  1298.     if (js_layer->properties_locked)
  1299.         return JS_TRUE;
  1300.     
  1301.     LO_LockLayout();
  1302.     if(!decoder->window_context ||
  1303.     decoder->doc_id != XP_DOCID(decoder->window_context)) {
  1304.         LO_UnlockLayout();
  1305.         return JS_FALSE;
  1306.     }
  1307.     
  1308.     layer = LO_GetLayerFromId(decoder->window_context, js_layer->layer_id);
  1309.     if (!layer)
  1310.         goto error_exit;
  1311.     
  1312.     if (argc != 2) {
  1313.         JS_ReportError(cx,  lm_argc_err_str);
  1314.         goto error_exit;
  1315.     }
  1316.     if (!JS_ValueToInt32(cx, argv[0], &x) ||
  1317.         !JS_ValueToInt32(cx, argv[1], &y)) {
  1318.         goto error_exit;
  1319.     }
  1320.     
  1321.     /* If a layer is dynamically changing, it will probably look
  1322.        better if it utilizes offscreen compositing. */
  1323.     CL_ChangeLayerFlag(layer, CL_PREFER_DRAW_OFFSCREEN, PR_TRUE);
  1324.  
  1325.     CL_OffsetLayer(layer, (int32) x, (int32) y);
  1326.  
  1327.     /* We record that we've mutated left and top */
  1328.     if (!LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_LEFT)) {
  1329.         LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_LEFT);
  1330.         JS_GetProperty(cx, obj, lm_left_str, &val);
  1331.         JS_DefinePropertyWithTinyId(cx, obj, lm_left_str, LAYER_LEFT, val, 
  1332.                                     layer_getProperty, layer_setProperty, 
  1333.                                     JSPROP_ENUMERATE);
  1334.     }
  1335.     else
  1336.         JS_GetProperty(cx, obj, lm_left_str, &val);
  1337.     if (!LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_TOP)) {
  1338.         LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_TOP);
  1339.         JS_GetProperty(cx, obj, lm_top_str, &val);
  1340.         JS_DefinePropertyWithTinyId(cx, obj, lm_top_str, LAYER_TOP, val, 
  1341.                                     layer_getProperty, layer_setProperty, 
  1342.                                     JSPROP_ENUMERATE);
  1343.     }
  1344.     else
  1345.         JS_GetProperty(cx, obj, lm_top_str, &val);
  1346.  
  1347.     LO_UnlockLayout();
  1348.     return JS_TRUE;
  1349.  
  1350.   error_exit:
  1351.     LO_UnlockLayout();
  1352.     return JS_FALSE;
  1353. }
  1354.  
  1355. #define CLEAR_LAYER_EXPANSION_POLICY(layer, bits)                             \
  1356.  lo_SetLayerClipExpansionPolicy(layer,                                        \
  1357.                                 lo_GetLayerClipExpansionPolicy(layer) & ~(bits))
  1358.  
  1359. PRIVATE JSBool
  1360. resize_layer_common(JSContext *cx, JSObject *obj, CL_Layer *layer,
  1361.                     int32 width, int32 height)
  1362. {
  1363.     JSLayer *js_layer;
  1364.     MochaDecoder * decoder;
  1365.     JSObject *clip;
  1366.     jsval val;
  1367.  
  1368.     if (!(js_layer = JS_GetPrivate(cx, obj)))
  1369.         return JS_FALSE;
  1370.  
  1371.     /* Some layers have mostly read-only properties because we
  1372.        don't want a malicious/careless JS author to modify them,
  1373.        e.g.  for layers that are used to encapulate a mail
  1374.        message. In such cases, we fail silently. */
  1375.     if (js_layer->properties_locked)
  1376.         return JS_TRUE;
  1377.     
  1378.     decoder = js_layer->decoder;
  1379.  
  1380.     /* If a layer is dynamically changing, it will probably look
  1381.        better if it utilizes offscreen compositing. */
  1382.     CL_ChangeLayerFlag(layer, CL_PREFER_DRAW_OFFSCREEN, PR_TRUE);
  1383.  
  1384.     CL_ResizeLayer(layer, (int32) width, (int32) height);
  1385.  
  1386.     CLEAR_LAYER_EXPANSION_POLICY(layer, 
  1387.                   LO_AUTO_EXPAND_CLIP_BOTTOM | LO_AUTO_EXPAND_CLIP_RIGHT);
  1388.     if (JS_LookupProperty(cx, obj, lm_clip_str, &val) &&
  1389.         JSVAL_IS_OBJECT(val)) {
  1390.         clip = JSVAL_TO_OBJECT(val);
  1391.         if (!LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_RIGHT)) {
  1392.             LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_RIGHT);
  1393.             JS_DefinePropertyWithTinyId(cx, clip, lm_right_str, RECT_RIGHT,
  1394.                                         INT_TO_JSVAL(width), rect_getProperty,
  1395.                                         rect_setProperty, JSPROP_ENUMERATE);
  1396.         }
  1397.         else {
  1398.             JS_GetProperty(cx, clip, lm_right_str, &val);
  1399.         }
  1400.  
  1401.         if (!LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_BOTTOM)) {
  1402.             LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_BOTTOM);
  1403.             JS_DefinePropertyWithTinyId(cx, clip, lm_bottom_str, RECT_BOTTOM,
  1404.                                         INT_TO_JSVAL(height), rect_getProperty,
  1405.                                         rect_setProperty, JSPROP_ENUMERATE);
  1406.         }
  1407.         else {
  1408.             JS_GetProperty(cx, clip, lm_bottom_str, &val);
  1409.         }       
  1410.     }
  1411.  
  1412.     return JS_TRUE;
  1413. }
  1414.  
  1415.  
  1416. PR_STATIC_CALLBACK(JSBool)
  1417. resize_layer_to(JSContext *cx, JSObject *obj,
  1418.                 uint argc, jsval *argv, jsval *rval)
  1419. {
  1420.     int32 x, y;
  1421.     JSLayer *js_layer;
  1422.     MochaDecoder * decoder;
  1423.     CL_Layer *layer;
  1424.     JSBool ret;
  1425.  
  1426.     if (!(js_layer = JS_GetInstancePrivate(cx, obj, &lm_layer_class, argv)))
  1427.         return JS_FALSE;
  1428.     decoder = js_layer->decoder;
  1429.     
  1430.     LO_LockLayout();
  1431.     if(!decoder->window_context || 
  1432.     decoder->doc_id != XP_DOCID(decoder->window_context)) {
  1433.         LO_UnlockLayout();
  1434.         return JS_FALSE;
  1435.     }
  1436.     
  1437.     layer = LO_GetLayerFromId(decoder->window_context, js_layer->layer_id);
  1438.     if (!layer)
  1439.         goto error_exit;
  1440.  
  1441.     if (argc != 2) {
  1442.         JS_ReportError(cx, lm_argc_err_str);
  1443.         goto error_exit;
  1444.     }
  1445.     if (!JS_ValueToInt32(cx, argv[0], &x) ||
  1446.         !JS_ValueToInt32(cx, argv[1], &y)) {
  1447.         goto error_exit;
  1448.     }
  1449.     
  1450.     ret = resize_layer_common(cx, obj, layer, x, y);
  1451.     
  1452.     LO_UnlockLayout();
  1453.     return ret;
  1454.     
  1455.   error_exit:
  1456.     LO_UnlockLayout();
  1457.     return JS_FALSE;
  1458. }
  1459.  
  1460. PR_STATIC_CALLBACK(JSBool)
  1461. resize_layer_by(JSContext *cx, JSObject *obj,
  1462.                 uint argc, jsval *argv, jsval *rval)
  1463. {
  1464.     int32 x, y;
  1465.     JSLayer *js_layer;
  1466.     MochaDecoder * decoder;
  1467.     CL_Layer *layer;
  1468.     XP_Rect bbox;
  1469.     JSBool ret;
  1470.     
  1471.     if (!(js_layer = JS_GetInstancePrivate(cx, obj, &lm_layer_class, argv)))
  1472.         return JS_FALSE;
  1473.     decoder = js_layer->decoder;
  1474.     
  1475.     LO_LockLayout();
  1476.     if(!decoder->window_context ||
  1477.     decoder->doc_id != XP_DOCID(decoder->window_context)) {
  1478.         LO_UnlockLayout();
  1479.         return JS_FALSE;
  1480.     }
  1481.     
  1482.     layer = LO_GetLayerFromId(decoder->window_context, js_layer->layer_id);
  1483.     if (!layer)
  1484.         goto error_exit;
  1485.     if (argc != 2) {
  1486.         JS_ReportError(cx, lm_argc_err_str);
  1487.         goto error_exit;
  1488.     }
  1489.     if (!JS_ValueToInt32(cx, argv[0], &x) ||
  1490.         !JS_ValueToInt32(cx, argv[1], &y)) {
  1491.         goto error_exit;
  1492.     }
  1493.  
  1494.     CL_GetLayerBbox(layer, &bbox);
  1495.     
  1496.     ret = resize_layer_common(cx, obj, layer,
  1497.                               (bbox.right - bbox.left + x),
  1498.                               (bbox.bottom - bbox.top + y));
  1499.  
  1500.     LO_UnlockLayout();
  1501.     return ret;
  1502.  
  1503.   error_exit:
  1504.     LO_UnlockLayout();
  1505.     return JS_FALSE;
  1506. }
  1507.  
  1508.  
  1509. PR_STATIC_CALLBACK(JSBool)
  1510. load_layer(JSContext *cx, JSObject *obj,
  1511.            uint argc, jsval *argv, jsval *rval)
  1512. {
  1513.     jsdouble width;
  1514.     JSLayer *js_layer;
  1515.     MochaDecoder * decoder;
  1516.     char *url;
  1517.     JSBool ret;
  1518.     const char *referer;
  1519.  
  1520.     if (!(js_layer = JS_GetInstancePrivate(cx, obj, &lm_layer_class, argv)))
  1521.         return JS_FALSE;
  1522.  
  1523.     /* Some layers have mostly read-only properties because we
  1524.        don't want a malicious/careless JS author to modify them,
  1525.        e.g.  for layers that are used to encapulate a mail
  1526.        message. In such cases, we fail silently. */
  1527.     if (js_layer->properties_locked)
  1528.         return JS_TRUE;
  1529.  
  1530.     decoder = js_layer->decoder;
  1531.     if (argc != 2) {
  1532.         JS_ReportError(cx, lm_argc_err_str);
  1533.         return JS_FALSE;
  1534.     }
  1535.  
  1536.     if ((!JSVAL_IS_STRING(argv[0]) &&
  1537.         !JS_ConvertValue(cx, argv[0], JSTYPE_STRING, &argv[0])) ||
  1538.         !JS_ValueToNumber(cx, argv[1], &width))
  1539.         return JS_FALSE;
  1540.  
  1541.     url = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
  1542.     url = (char *)lm_CheckURL(cx, url, JS_TRUE);
  1543.     if (! url)
  1544.         return JS_FALSE;
  1545.  
  1546.     referer = lm_GetSubjectOriginURL(cx);
  1547.     if (! referer) {
  1548.     XP_FREE(url);
  1549.         return JS_FALSE;
  1550.     }
  1551.  
  1552.     ret = (JSBool)ET_TweakLayer(decoder->window_context, NULL, 
  1553.                                 (int32)width, 0,
  1554.                                 (void *)url, js_layer->layer_id, 
  1555.                                 CL_SetSrcWidth, referer,
  1556.                 decoder->doc_id);
  1557.  
  1558.     *rval = BOOLEAN_TO_JSVAL(ret);
  1559.  
  1560.     if (ret) {
  1561.     lm_NewLayerDocument(decoder, js_layer->layer_id);
  1562.         LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_WIDTH);
  1563.         js_layer->width = (int32)width;
  1564.         LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_SRC);
  1565.         XP_FREEIF(js_layer->source_url);
  1566.         js_layer->source_url = url;
  1567.         decoder->stream_owner = js_layer->layer_id;
  1568.         if (js_layer->principals)
  1569.             JSPRINCIPALS_DROP(cx, js_layer->principals);
  1570.         js_layer->principals = LM_NewJSPrincipals(NULL, NULL, url);
  1571.         if (js_layer->principals == NULL) {
  1572.             JS_ReportOutOfMemory(cx);
  1573.             return JS_FALSE;
  1574.         }
  1575.         JSPRINCIPALS_HOLD(cx, js_layer->principals);
  1576.     }
  1577.  
  1578.     return JS_TRUE;
  1579. }
  1580.  
  1581. PR_STATIC_CALLBACK(JSBool)
  1582. layer_capture(JSContext *cx, JSObject *obj,
  1583.               uint argc, jsval *argv, jsval *rval)
  1584. {
  1585.     JSLayer *js_layer;
  1586.     MochaDecoder * decoder;
  1587.     jsdouble d;
  1588.  
  1589.     if (!(js_layer = JS_GetInstancePrivate(cx, obj, &lm_layer_class, argv)))
  1590.         return JS_FALSE;
  1591.     decoder = js_layer->decoder;
  1592.  
  1593.     if (!decoder->window_context)
  1594.         return JS_TRUE;
  1595.  
  1596.     if (argc != 1)
  1597.         return JS_TRUE;
  1598.  
  1599.     if (!JS_ValueToNumber(cx, argv[0], &d)) 
  1600.         return JS_FALSE;
  1601.  
  1602.     js_layer->capturer.event_bit |= (uint32)d;
  1603.     decoder->window_context->event_bit |= (uint32)d;
  1604.  
  1605.     return JS_TRUE;
  1606. }
  1607.  
  1608. PR_STATIC_CALLBACK(JSBool)
  1609. layer_release(JSContext *cx, JSObject *obj,
  1610.               uint argc, jsval *argv, jsval *rval)
  1611. {
  1612.     JSLayer *js_layer;
  1613.     JSEventCapturer *cap;
  1614.     MochaDecoder *decoder;
  1615.     jsdouble d;
  1616.     jsint layer_index;
  1617.     jsint max_layer_num;
  1618.     JSObject *cap_obj;
  1619.  
  1620.     if (!(js_layer = JS_GetInstancePrivate(cx, obj, &lm_layer_class, argv)))
  1621.         return JS_FALSE;
  1622.     decoder = js_layer->decoder;
  1623.  
  1624.     if (!decoder->window_context)
  1625.         return JS_TRUE;
  1626.  
  1627.     if (argc != 1)
  1628.         return JS_TRUE;
  1629.  
  1630.     if (!JS_ValueToNumber(cx, argv[0], &d)) 
  1631.         return JS_FALSE;
  1632.  
  1633.  
  1634.     js_layer->capturer.event_bit &=  ~(uint32)d;
  1635.     decoder->window_context->event_bit &= ~(uint32)d;
  1636.     
  1637.     /*Now we have to see if anyone else wanted that bit set.  Joy!*/
  1638.     /*First we check versus window */
  1639.     decoder->window_context->event_bit |= decoder->event_bit;
  1640.  
  1641.     /*Now we check versus layers */
  1642.     max_layer_num = LO_GetNumberOfLayers(decoder->window_context);
  1643.     
  1644.     for (layer_index=0; layer_index <= max_layer_num; layer_index++) {
  1645.         cap_obj = LO_GetLayerMochaObjectFromId(decoder->window_context, layer_index);
  1646.          if (cap_obj && (cap = JS_GetPrivate(cx, cap_obj)) != NULL)
  1647.             decoder->window_context->event_bit |= cap->event_bit;
  1648.         
  1649.         cap_obj = lm_GetDocumentFromLayerId(decoder, layer_index);
  1650.         if (cap_obj && (cap = JS_GetPrivate(cx, cap_obj)) != NULL)
  1651.             decoder->window_context->event_bit |= cap->event_bit;
  1652.     }
  1653.     
  1654.     return JS_TRUE;
  1655. }
  1656.  
  1657. static PRBool
  1658. setExternalCapture(JSContext *cx, JSObject *obj, 
  1659.                    uint argc, jsval *argv, JSBool val)
  1660. {
  1661.     JSLayer *js_layer;
  1662.  
  1663.     if (!(js_layer = JS_GetInstancePrivate(cx, obj, &lm_layer_class, argv)))
  1664.         return JS_FALSE;
  1665.  
  1666.     if (argc != 0)
  1667.         return JS_TRUE;
  1668.  
  1669.     if (lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
  1670.         JSPrincipals *principals;
  1671.         
  1672.         principals = lm_GetInnermostPrincipals(cx, obj, NULL);
  1673.         if (principals == NULL)
  1674.             return JS_FALSE;
  1675.  
  1676.         lm_SetExternalCapture(cx, principals, val);
  1677.     }
  1678.  
  1679.     return JS_TRUE;
  1680. }
  1681.  
  1682. PR_STATIC_CALLBACK(PRBool)
  1683. layer_enable_external_capture(JSContext *cx, JSObject *obj,
  1684.                               uint argc, jsval *argv, jsval *rval)
  1685. {
  1686.     return setExternalCapture(cx, obj, argc, argv, JS_TRUE);
  1687. }
  1688.  
  1689. PR_STATIC_CALLBACK(PRBool)
  1690. layer_disable_external_capture(JSContext *cx, JSObject *obj,
  1691.                                uint argc, jsval *argv, jsval *rval)
  1692. {
  1693.     return setExternalCapture(cx, obj, argc, argv, JS_FALSE);
  1694. }
  1695.  
  1696. PR_STATIC_CALLBACK(PRBool)
  1697. layer_compromise_principals(JSContext *cx, JSObject *obj,
  1698.                             uint argc, jsval *argv, jsval *rval)
  1699. {
  1700.     JSLayer *js_layer;
  1701.  
  1702.     if (!(js_layer = JS_GetInstancePrivate(cx, obj, &lm_layer_class, argv)))
  1703.         return JS_FALSE;
  1704.  
  1705.     js_layer->principals_compromised = JS_TRUE;
  1706.     return JS_TRUE;
  1707. }
  1708.  
  1709. PR_STATIC_CALLBACK(PRBool)
  1710. layer_downgrade_principals(JSContext *cx, JSObject *obj,
  1711.                            uint argc, jsval *argv, jsval *rval)
  1712. {
  1713.     JSLayer *js_layer;
  1714.  
  1715.     if (!(js_layer = JS_GetInstancePrivate(cx, obj, &lm_layer_class, argv)))
  1716.         return JS_FALSE;
  1717.  
  1718.     if (js_layer->principals)
  1719.         lm_InvalidateCertPrincipals(js_layer->decoder, js_layer->principals);
  1720.  
  1721.     return JS_TRUE;
  1722. }
  1723.  
  1724. PR_STATIC_CALLBACK(JSBool)
  1725. layer_initStandardObjects(JSContext *cx, JSObject *obj, uint argc, jsval *argv,
  1726.                           jsval *rval)
  1727. {
  1728.     JSLayer *js_layer;
  1729.  
  1730.     if (!(js_layer = JS_GetInstancePrivate(cx, obj, &lm_layer_class, argv)))
  1731.         return JS_FALSE;
  1732.     return (JSBool)(JS_InitStandardClasses(cx, obj) &&
  1733.            lm_DefineWindowProps(cx, js_layer->decoder));
  1734. }
  1735.  
  1736. /* The minimum number of arguments for each of the functions in this
  1737.    table is set to zero, so that argc is the actual number of arguments
  1738.    passed by the user. */
  1739. static JSFunctionSpec layer_methods[] = {
  1740.     {"offset",         offset_layer,    0},
  1741.     {"moveBy",         offset_layer,    0},
  1742.     {"moveTo",         move_layer_rel,  0},
  1743.     {"moveToAbsolute", move_layer_abs,  0},
  1744.     {"resize",         resize_layer_to, 0},
  1745.     {"resizeTo",       resize_layer_to, 0},
  1746.     {"resizeBy",       resize_layer_by, 0},
  1747.     {"moveAbove",      move_above,      0},
  1748.     {"moveBelow",      move_below,      0},
  1749.     {"load",           load_layer,      0},
  1750.     {"captureEvents",  layer_capture,   0},
  1751.     {"releaseEvents",  layer_release,   0},
  1752.     {"enableExternalCapture",   layer_enable_external_capture,  0 },
  1753.     {"disableExternalCapture",  layer_disable_external_capture, 0 },
  1754.     {"compromisePrincipals",    layer_compromise_principals,    0 },
  1755.     {"downgradePrincipals",     layer_downgrade_principals,     0 },
  1756.     {"initStandardObjects", layer_initStandardObjects, 0},
  1757.     {0}
  1758. };
  1759.  
  1760. static JSObject *
  1761. lm_reflect_layer_using_existing_obj(MWContext *context,
  1762.                                     int32 layer_id,
  1763.                                     int32 parent_layer_id, 
  1764.                                     PA_Tag *tag,
  1765.                                     JSObject *obj);
  1766.  
  1767. PR_STATIC_CALLBACK(JSBool)
  1768. Layer(JSContext *cx, JSObject *obj,
  1769.       uint argc, jsval *argv, jsval *rval)
  1770. {
  1771.     JSObject *parent_layer_obj = NULL, *window_obj, *enclosing_obj;
  1772.     JSLayer *js_layer_parent;
  1773.     int32 wrap_width = 0;
  1774.     int32 parent_layer_id, layer_id;
  1775.     MochaDecoder *decoder;
  1776.     MWContext *context;
  1777.  
  1778.     XP_ASSERT(JS_InstanceOf(cx, obj, &lm_layer_class, NULL));
  1779.  
  1780.     /* XXX - Hack to force constructor not to allocate any layers */
  1781.     if (argc == 0)
  1782.         return JS_TRUE;
  1783.  
  1784.     if (argc < 1) {
  1785.         JS_ReportError(cx, lm_argc_err_str);
  1786.         return JS_FALSE;
  1787.     }
  1788.  
  1789.     /* Mandatory first argument is layer's wrap width. */
  1790.     if (!JS_ValueToInt32(cx, argv[0], &wrap_width))
  1791.         return JS_FALSE;
  1792.  
  1793.     /* By default, we're creating the layer for the current window. */ 
  1794.     window_obj = JS_GetGlobalObject(cx); 
  1795.  
  1796.     /* Get enclosing window or layer of the code that calls the constructor. */
  1797.     parent_layer_id = LO_DOCUMENT_LAYER_ID; /* Default */
  1798.     enclosing_obj = JS_GetScopeChain(cx);
  1799.     while (enclosing_obj) {
  1800.         if (JS_InstanceOf(cx, enclosing_obj, &lm_layer_class, 0)) {
  1801.             js_layer_parent = JS_GetPrivate(cx, enclosing_obj);
  1802.             parent_layer_id = js_layer_parent->layer_id;
  1803.             break;
  1804.         }
  1805.         if (JS_InstanceOf(cx, enclosing_obj, &lm_window_class, 0))
  1806.             break;
  1807.         enclosing_obj = JS_GetParent(cx, enclosing_obj);
  1808.     }
  1809.     /* Optional second argument is parent layer */
  1810.     if (argc >= 2) {
  1811.         /* The parent has to be an object */
  1812.         if ((JS_TypeOfValue(cx, argv[1]) == JSTYPE_OBJECT) &&
  1813.             ((parent_layer_obj = JSVAL_TO_OBJECT(argv[1])) != NULL)) { 
  1814.             /* If the parent is a layer, we get its layer_id */
  1815.             if (JS_InstanceOf(cx, parent_layer_obj, &lm_layer_class, 0)) { 
  1816.                 js_layer_parent = JS_GetPrivate(cx, parent_layer_obj); 
  1817.                 parent_layer_id = js_layer_parent->layer_id;
  1818.                 decoder = js_layer_parent->decoder;
  1819.                 window_obj = decoder->window_object;
  1820.             } 
  1821.             /* 
  1822.              * If the parent is another window, the new layer is created
  1823.              * in that window's context as a top-level layer.
  1824.              */ 
  1825.             else if (JS_InstanceOf(cx, parent_layer_obj, 
  1826.                                    &lm_window_class, 0)) { 
  1827.                 parent_layer_id = LO_DOCUMENT_LAYER_ID; 
  1828.                 window_obj = parent_layer_obj; 
  1829.             } 
  1830.             else 
  1831.                 return JS_FALSE; 
  1832.         } else {
  1833.             return JS_FALSE;
  1834.         }
  1835.     }
  1836.  
  1837.     decoder = JS_GetPrivate(cx, window_obj); 
  1838.     context = decoder->window_context;
  1839.  
  1840.     /* From a security standpoint, it's dangerous to allow new
  1841.        top-level layers to be created in a mail/news window. */
  1842.     if (IS_MESSAGE_WINDOW(context) &&
  1843.         (parent_layer_id == LO_DOCUMENT_LAYER_ID)) {
  1844.         JS_ReportError(cx,
  1845.                        "Disallowed attempt to create new top-level layer"
  1846.                        " in a message window");
  1847.         return JS_FALSE;
  1848.     }
  1849.  
  1850.     layer_id = ET_PostCreateLayer(context, wrap_width, parent_layer_id);
  1851.  
  1852.     /* Zero-valued return means layout/parser stream is busy. A -1
  1853.        return indicates error. */
  1854.     if (!layer_id || layer_id == -1)
  1855.         return JS_FALSE;
  1856.  
  1857.     /* Reflect the layer, but don't create a new object parented by
  1858.        the layers array.  Rather, use the object that we're
  1859.        constructing now. */
  1860.     obj = lm_reflect_layer_using_existing_obj(context, layer_id,
  1861.                                               parent_layer_id, NULL, obj);
  1862.     if (!obj)
  1863.         return JS_FALSE;
  1864.     return JS_TRUE;
  1865. }
  1866.  
  1867. static JSObject *
  1868. lm_init_layer_clip(MochaDecoder *decoder,
  1869.                    int32 layer_id,
  1870.                    JSObject *parent_layer_obj);
  1871.  
  1872. void
  1873. lm_RestoreLayerState(MWContext *context, int32 layer_id, 
  1874.                      LO_BlockInitializeStruct *param)
  1875. {
  1876.     PRHashTable *map;
  1877.     MochaDecoder *decoder;
  1878.     JSContext *cx;
  1879.     JSLayer *js_layer;
  1880.     JSObject *obj, *clip_obj;
  1881.     jsval val;
  1882.  
  1883.     decoder = LM_GetMochaDecoder(context);
  1884.     if (!decoder)               /* Paranoia */
  1885.         return;
  1886.     cx = decoder->js_context;
  1887.  
  1888.     /* 
  1889.      * Get the mocha object associated with this layer, since it's been
  1890.      * preserved across a resize_relayout.
  1891.      */
  1892.     map = lm_GetIdToObjectMap(decoder);
  1893.     if (map)
  1894.         obj = (JSObject *)PR_HashTableLookup(map,
  1895.                                   LM_GET_MAPPING_KEY(LM_LAYERS, 0, layer_id));
  1896.     if (!obj)
  1897.         goto out;
  1898.     
  1899.     js_layer = JS_GetPrivate(cx, obj);
  1900.     if (!js_layer)
  1901.         goto out;
  1902.  
  1903.     /* 
  1904.      * For each property that was modified, set the value for the
  1905.      * corresponding attribute in the param struct.
  1906.      */
  1907.     if (LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_LEFT) &&
  1908.         JS_LookupProperty(cx, obj, lm_left_str, &val)) {
  1909.         param->has_left = TRUE;
  1910.         param->left = JSVAL_TO_INT(val);
  1911.     }
  1912.  
  1913.     if (LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_TOP) &&
  1914.         JS_LookupProperty(cx, obj, lm_top_str, &val)) {
  1915.         param->has_top = TRUE;
  1916.         param->top = JSVAL_TO_INT(val);
  1917.     }
  1918.     
  1919.     if (LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_WIDTH)) {
  1920.         param->has_width = TRUE;
  1921.         param->width = js_layer->width;
  1922.     }
  1923.  
  1924.     if (LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_SIB_ABOVE)) {
  1925.         XP_FREEIF(param->above);
  1926.         param->above = XP_STRDUP(JS_GetStringBytes(js_layer->sibling_above));
  1927.     }
  1928.  
  1929.     if (LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_SIB_BELOW)) {
  1930.         XP_FREEIF(param->below);
  1931.         param->below = XP_STRDUP(JS_GetStringBytes(js_layer->sibling_below));
  1932.     }
  1933.     
  1934.     if (LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_ZINDEX) &&
  1935.         JS_LookupProperty(cx, obj, lm_zindex_str, &val)) {
  1936.         param->has_zindex = TRUE;
  1937.         param->zindex = JSVAL_TO_INT(val);
  1938.     }
  1939.  
  1940.     if (LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_VISIBILITY) &&
  1941.         JS_LookupProperty(cx, obj, lm_visibility_str, &val)) {
  1942.         XP_FREEIF(param->visibility);
  1943.         param->visibility = XP_STRDUP(JS_GetStringBytes(JSVAL_TO_STRING(val)));
  1944.     }
  1945.  
  1946.     if (LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_BGCOLOR) &&
  1947.         JS_LookupProperty(cx, obj, lm_bgcolor_str, &val)) {
  1948.         XP_FREEIF(param->bgcolor);
  1949.         param->is_style_bgcolor = FALSE;
  1950.         param->bgcolor = XP_ALLOC(10);
  1951.         PR_snprintf(param->bgcolor, 10, "%x", JSVAL_TO_INT(val));
  1952.     }
  1953.  
  1954.     if (JS_LookupProperty(cx, obj, lm_background_str, &val) &&
  1955.         JSVAL_IS_OBJECT(val)) {
  1956.         JSObject *background;
  1957.  
  1958.         if (JS_ValueToObject(cx, val, &background) && background &&
  1959.             JS_LookupProperty(cx, background, "src", &val) &&
  1960.             JSVAL_IS_STRING(val)) {
  1961.             XP_FREEIF(param->bgimage);
  1962.             param->bgimage = XP_STRDUP(JS_GetStringBytes(JSVAL_TO_STRING(val)));
  1963.         }
  1964.     }
  1965.  
  1966.     if (LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_SRC) &&
  1967.         js_layer->source_url) {
  1968.         XP_FREEIF(param->src);
  1969.         param->src = XP_STRDUP(js_layer->source_url);
  1970.     }
  1971.     
  1972.     if (JS_LookupProperty(cx, obj, lm_clip_str, &val) &&
  1973.         JSVAL_IS_OBJECT(val)) {
  1974.         clip_obj = JSVAL_TO_OBJECT(val);
  1975.         if (!clip_obj)
  1976.             goto out;
  1977.  
  1978.         if (!param->clip && 
  1979.             (LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_LEFT) ||
  1980.              LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_RIGHT) ||
  1981.              LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_BOTTOM) ||
  1982.              LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_TOP))) {
  1983.             param->clip = XP_NEW_ZAP(XP_Rect);
  1984.             if (!param->clip)
  1985.                 goto out;
  1986.         }
  1987.         
  1988.         if (LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_LEFT) &&
  1989.             JS_LookupProperty(cx, clip_obj, lm_left_str, &val)) {
  1990.             param->clip->left = JSVAL_TO_INT(val);
  1991.             param->clip_expansion_policy &= ~LO_AUTO_EXPAND_CLIP_LEFT;
  1992.         }
  1993.         
  1994.         if (LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_RIGHT) &&
  1995.             JS_LookupProperty(cx, clip_obj, lm_right_str, &val)) {
  1996.             param->clip->right = JSVAL_TO_INT(val);
  1997.             param->clip_expansion_policy &= ~LO_AUTO_EXPAND_CLIP_RIGHT;
  1998.         }
  1999.  
  2000.         if (LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_TOP) &&
  2001.             JS_LookupProperty(cx, clip_obj, lm_top_str, &val)) {
  2002.             param->clip->top = JSVAL_TO_INT(val);
  2003.             param->clip_expansion_policy &= ~LO_AUTO_EXPAND_CLIP_TOP;
  2004.         }
  2005.         
  2006.         if (LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_BOTTOM) &&
  2007.             JS_LookupProperty(cx, clip_obj, lm_bottom_str, &val)) {
  2008.             param->clip->bottom = JSVAL_TO_INT(val);
  2009.             param->clip_expansion_policy &= ~LO_AUTO_EXPAND_CLIP_BOTTOM;
  2010.         }
  2011.     }
  2012.  
  2013. out:
  2014.     LM_PutMochaDecoder(decoder);
  2015.     return;
  2016. }
  2017.  
  2018. static void
  2019. lm_process_layer_tag(MochaDecoder *decoder, PA_Tag *tag, JSObject *obj)
  2020. {
  2021.     MWContext *context = decoder->window_context;
  2022.     PA_Block onload, onunload, onmouseover, onmouseout, onblur, onfocus, id;
  2023.     PA_Block properties_locked;
  2024.     JSLayer *js_layer;
  2025.     JSContext *cx;
  2026.     char *source_url;
  2027.     
  2028.     cx = decoder->js_context;
  2029.     js_layer = JS_GetPrivate(cx, obj);
  2030.     if (!js_layer)
  2031.         return;
  2032.     
  2033.     if (tag) {
  2034.         onload   = lo_FetchParamValue(context, tag, PARAM_ONLOAD);
  2035.         onunload  = lo_FetchParamValue(context, tag, PARAM_ONUNLOAD);
  2036.         onmouseover  = lo_FetchParamValue(context, tag, PARAM_ONMOUSEOVER);
  2037.         onmouseout  = lo_FetchParamValue(context, tag, PARAM_ONMOUSEOUT);
  2038.         onblur  = lo_FetchParamValue(context, tag,  PARAM_ONBLUR);
  2039.         onfocus  = lo_FetchParamValue(context, tag, PARAM_ONFOCUS);
  2040.         id  = lo_FetchParamValue(context, tag, PARAM_ID);
  2041.         properties_locked = lo_FetchParamValue(context, tag, PARAM_LOCKED);
  2042.  
  2043.     /* don't hold the layout lock across compiles */
  2044.     LO_UnlockLayout();
  2045.  
  2046.         if (properties_locked) {
  2047.             js_layer->properties_locked = PR_TRUE;
  2048.             PA_FREE(properties_locked);
  2049.         }
  2050.  
  2051.         if (onload != NULL) {
  2052.             (void) lm_CompileEventHandler(decoder, id, tag->data,
  2053.                                           tag->newline_count, obj,
  2054.                                           PARAM_ONLOAD, onload);
  2055.             PA_FREE(onload);
  2056.         }
  2057.  
  2058.         if (onunload != NULL) {
  2059.             (void) lm_CompileEventHandler(decoder, id, tag->data,
  2060.                                           tag->newline_count, obj,
  2061.                                           PARAM_ONUNLOAD, onunload);
  2062.             PA_FREE(onunload);
  2063.         }
  2064.  
  2065.         if (onmouseover != NULL) {
  2066.             (void) lm_CompileEventHandler(decoder, id, tag->data,
  2067.                                           tag->newline_count, obj,
  2068.                                           PARAM_ONMOUSEOVER, onmouseover);
  2069.             PA_FREE(onmouseover);
  2070.         }
  2071.  
  2072.         if (onmouseout != NULL) {
  2073.             (void) lm_CompileEventHandler(decoder, id, tag->data,
  2074.                                           tag->newline_count, obj,
  2075.                                           PARAM_ONMOUSEOUT, onmouseout);
  2076.             PA_FREE(onmouseout);
  2077.         }
  2078.  
  2079.         if (onblur != NULL) {
  2080.             (void) lm_CompileEventHandler(decoder, id, tag->data,
  2081.                                           tag->newline_count, obj,
  2082.                                           PARAM_ONBLUR, onblur);
  2083.             PA_FREE(onblur);
  2084.         }
  2085.  
  2086.         if (onfocus != NULL) {
  2087.             (void) lm_CompileEventHandler(decoder, id, tag->data,
  2088.                                           tag->newline_count, obj,
  2089.                                           PARAM_ONFOCUS, onfocus);
  2090.             PA_FREE(onfocus);
  2091.         }
  2092.  
  2093.         if (id)
  2094.             PA_FREE(id);
  2095.  
  2096.     LO_LockLayout();
  2097.  
  2098.         source_url = (char*)lo_FetchParamValue(context, tag, 
  2099.                                                PARAM_SRC);
  2100.  
  2101.         if (source_url) {
  2102.         /*
  2103.          * Temporarily unlock layout so that we don't hold the lock
  2104.          * across a call (lm_CheckURL) that may result in 
  2105.          * synchronous event handling.
  2106.          */
  2107.         LO_UnlockLayout();
  2108.             js_layer->source_url = (char *)lm_CheckURL(cx, source_url, 
  2109.                                                        JS_TRUE);
  2110.             if (js_layer->principals)
  2111.                 JSPRINCIPALS_DROP(cx, js_layer->principals);
  2112.             js_layer->principals = LM_NewJSPrincipals(NULL, NULL, 
  2113.                                                       js_layer->source_url);
  2114.             if (js_layer->principals)
  2115.                 JSPRINCIPALS_HOLD(cx, js_layer->principals);
  2116.         LO_LockLayout();
  2117.     }
  2118.     }
  2119. }
  2120.  
  2121.  
  2122. static JSObject *
  2123. lm_reflect_layer_using_existing_obj(MWContext *context,
  2124.                                     int32 layer_id,
  2125.                                     int32 parent_layer_id, 
  2126.                                     PA_Tag *tag,
  2127.                                     JSObject *obj)
  2128. {
  2129.     JSObject *array_obj, *clip_obj, *doc_obj;
  2130.     MochaDecoder *decoder;
  2131.     JSContext *cx;
  2132.     JSLayer *js_layer;
  2133.     char *name = NULL;    
  2134.     uint flags = JSPROP_READONLY;
  2135.     JSBool bFreeName = JS_FALSE;
  2136.     static fake_layer_count = 0;
  2137.     CL_Layer *layer;
  2138.     lo_TopState *top_state;
  2139.     PRHashTable *map;
  2140.  
  2141.     decoder = LM_GetMochaDecoder(context);
  2142.     if (!decoder)
  2143.         return NULL;
  2144.  
  2145.     if (!obj) {
  2146.         obj = LO_GetLayerMochaObjectFromId(context, layer_id);
  2147.         if (obj) {                    /* Already reflected ? */
  2148.             /* 
  2149.              * We might already have been reflected by someone other than the
  2150.              * layer tag processing code (e.g. as a result of entity 
  2151.              * processing). In that case, we just process the tag if it 
  2152.              * exists.
  2153.              */
  2154.             if (tag)
  2155.                 lm_process_layer_tag(decoder, tag, obj);
  2156.             LM_PutMochaDecoder(decoder);
  2157.             return obj;
  2158.         }
  2159.     }
  2160.  
  2161.     cx = decoder->js_context;
  2162.  
  2163.     top_state = lo_GetMochaTopState(context);
  2164.     if (!obj && top_state->resize_reload && !decoder->load_event_sent) {
  2165.         map = lm_GetIdToObjectMap(decoder);
  2166.         
  2167.         if (map)
  2168.             obj = (JSObject *)PR_HashTableLookup(map,
  2169.                                   LM_GET_MAPPING_KEY(LM_LAYERS, 0, layer_id));
  2170.         if (obj) {
  2171.             LO_SetLayerMochaObject(context, layer_id, obj);
  2172.             LM_PutMochaDecoder(decoder);
  2173.             return obj;
  2174.         }
  2175.     }
  2176.  
  2177.     /* Layer is accessible by name in child array of parent layer.
  2178.        For example a layer named "Fred" could be accessed as
  2179.        document.layers["Fred"] if it is a child of the distinguished
  2180.        _DOCUMENT layer. */
  2181.     if (parent_layer_id == LO_DOCUMENT_LAYER_ID)
  2182.         array_obj = lm_GetDocumentLayerArray(decoder, decoder->document);
  2183.     else
  2184.         array_obj =
  2185.             lm_GetLayerArray(decoder, 
  2186.                              LO_GetLayerMochaObjectFromId(context, 
  2187.                                                           parent_layer_id));
  2188.     if (!array_obj) {
  2189.         LM_PutMochaDecoder(decoder);
  2190.         return NULL;
  2191.     }
  2192.  
  2193.     js_layer = JS_malloc(cx, sizeof *js_layer);
  2194.     if (!js_layer) {
  2195.         LM_PutMochaDecoder(decoder);
  2196.         return NULL;
  2197.     }
  2198.     XP_BZERO(js_layer, sizeof *js_layer);
  2199.  
  2200.     if (!obj) {
  2201.         obj = JS_NewObject(cx, &lm_layer_class, decoder->layer_prototype, 
  2202.                            array_obj);
  2203.     } else {
  2204.         /* Anonymous layers, created with the "new" operator, are
  2205.            scoped by their parent layer's document */
  2206.         JS_SetParent(cx, obj, array_obj);
  2207.     }
  2208.     
  2209.     LO_SetLayerMochaObject(context, layer_id, obj);
  2210.  
  2211.     /* Put it in the index to object hash table */
  2212.     map = lm_GetIdToObjectMap(decoder);
  2213.     if (map)
  2214.         PR_HashTableAdd(map,
  2215.                         LM_GET_MAPPING_KEY(LM_LAYERS, 0, layer_id),
  2216.                         obj);
  2217.  
  2218.     if (obj) 
  2219.         clip_obj = lm_init_layer_clip(decoder, layer_id, obj);
  2220.  
  2221.     if (obj && clip_obj)
  2222.         doc_obj = lm_DefineDocument(decoder, layer_id);
  2223.  
  2224.     if (!obj || !clip_obj || !doc_obj ||  !JS_SetPrivate(cx, obj, js_layer)) {
  2225.         JS_free(cx, js_layer);
  2226.         LM_PutMochaDecoder(decoder);
  2227.         return NULL;
  2228.     }
  2229.  
  2230.     JS_AddNamedRoot(cx, &js_layer->sibling_above, "layer.sibling_above");
  2231.     JS_AddNamedRoot(cx, &js_layer->sibling_below, "layer.sibling_below");
  2232.  
  2233.     layer = LO_GetLayerFromId(context, layer_id);
  2234.     if (layer)
  2235.         name = CL_GetLayerName(layer);
  2236.     if (name) {
  2237.         flags |= JSPROP_ENUMERATE;
  2238.     } else {
  2239.         name = PR_smprintf("_js_layer_%d", fake_layer_count++);
  2240.         bFreeName = JS_TRUE;
  2241.         if (!name) {
  2242.             LM_PutMochaDecoder(decoder);
  2243.             return NULL;
  2244.         }
  2245.     }
  2246.  
  2247.     if (name && 
  2248.         !JS_DefineProperty(cx, array_obj, name, OBJECT_TO_JSVAL(obj),
  2249.                            NULL, NULL, flags)) {
  2250.         LM_PutMochaDecoder(decoder);
  2251.         if (bFreeName) 
  2252.             XP_FREE(name);
  2253.         return NULL;
  2254.     }
  2255.  
  2256.     js_layer->decoder = HOLD_BACK_COUNT(decoder);
  2257.     js_layer->layer_id = layer_id;
  2258.     js_layer->name = JS_NewStringCopyZ(cx, name);
  2259.     js_layer->source_url = NULL;
  2260.     if (!JS_LockGCThing(cx, js_layer->name)) {
  2261.         LM_PutMochaDecoder(decoder);
  2262.         if (bFreeName)
  2263.             XP_FREE(name);
  2264.         return NULL;
  2265.     }
  2266.  
  2267.     if(tag)
  2268.         lm_process_layer_tag(decoder, tag, obj);
  2269.  
  2270.     LM_PutMochaDecoder(decoder);
  2271.  
  2272.     if (bFreeName)
  2273.         XP_FREE(name);
  2274.  
  2275.     return obj;
  2276. }
  2277.  
  2278. JSObject *
  2279. LM_ReflectLayer(MWContext *context, int32 layer_id, int32 parent_layer_id, 
  2280.                 PA_Tag *tag)
  2281. {
  2282.     return lm_reflect_layer_using_existing_obj(context, layer_id,
  2283.                                                parent_layer_id, tag, NULL);
  2284. }
  2285.  
  2286. JSObject *
  2287. lm_GetNamedLayer(MochaDecoder *decoder, int32 parent_layer_id, 
  2288.                  const char *name)
  2289. {
  2290.     MWContext *context = decoder->window_context;
  2291.     lo_TopState *top_state;    
  2292.     CL_Layer *layer, *parent_layer;
  2293.     int32 layer_id; 
  2294.     JSObject *layer_obj = NULL;
  2295.  
  2296.     LO_LockLayout();
  2297.  
  2298.     top_state = lo_GetMochaTopState(context);
  2299.     if (top_state == NULL)
  2300.         goto done;
  2301.     
  2302.     if(!context || decoder->doc_id != XP_DOCID(context))
  2303.         goto done;
  2304.  
  2305.     /* Get the parent layer (the owner of this array) */
  2306.     parent_layer = LO_GetLayerFromId(context, parent_layer_id);
  2307.     if (!parent_layer) 
  2308.         goto done;
  2309.  
  2310.     /* Search for the child layer by name */
  2311.     layer = CL_GetLayerChildByName(parent_layer, (char *)name);
  2312.     if (!layer) 
  2313.         goto done;
  2314.     
  2315.     /* Reflect the child layer if it hasn't been reflected yet */
  2316.     layer_id = LO_GetIdFromLayer(context, layer);
  2317.     layer_obj = LM_ReflectLayer(context, layer_id, 
  2318.                                 parent_layer_id,
  2319.                                 NULL);
  2320.   done:
  2321.     LO_UnlockLayout();
  2322.     return layer_obj;
  2323. }
  2324.  
  2325. void
  2326. lm_NewLayerDocument(MochaDecoder *decoder, int32 layer_id)
  2327. {
  2328.     JSObject *layer_obj, *doc_obj, *layer_array_obj;
  2329.     JSLayer *js_layer;
  2330.     JSContext *cx;
  2331.     jsval layer_array_jsval;
  2332.     
  2333.     cx = decoder->js_context;
  2334.  
  2335.     LO_LockLayout();
  2336.     
  2337.     layer_obj = LO_GetLayerMochaObjectFromId(decoder->window_context,
  2338.                                              layer_id);
  2339.     if (!layer_obj) {
  2340.         LO_UnlockLayout();
  2341.         return;
  2342.     }
  2343.  
  2344.     js_layer = JS_GetPrivate(cx, layer_obj);
  2345.     if (!js_layer) {
  2346.         LO_UnlockLayout();
  2347.         return;
  2348.     }
  2349.  
  2350.     /* Throw away the child_layers_array */
  2351.     js_layer->child_layers_array_obj = NULL;
  2352.  
  2353.     /* Reset security status, clear watchpoints to close security holes. */
  2354.     /* XXX must clear scope or evil.org's functions/vars persist into signed
  2355.        script doc loaded from victim.com! */
  2356.     js_layer->principals_compromised = JS_FALSE;
  2357.     JS_ClearWatchPointsForObject(cx, layer_obj);
  2358.  
  2359.     /* 
  2360.      * Clean out a document i.e. clean out the arrays associated with
  2361.      * the document, but not all its properties.
  2362.      */
  2363.     doc_obj = lm_GetDocumentFromLayerId(decoder, layer_id);
  2364.     lm_CleanUpDocument(decoder, doc_obj);
  2365.  
  2366.     /* We're about to replace the contents of this layer, so sever
  2367.        all the references to the layer's children, so that they
  2368.        can be GC'ed. */
  2369.     if (JS_LookupProperty(cx, layer_obj, "layers", &layer_array_jsval) &&
  2370.     JSVAL_IS_OBJECT(layer_array_jsval)) {
  2371.         layer_array_obj = JSVAL_TO_OBJECT(layer_array_jsval);
  2372.     JS_ClearScope(cx, layer_array_obj);
  2373.     JS_DefineProperties(cx, layer_array_obj, layer_array_props);
  2374.     }
  2375.     LO_UnlockLayout();
  2376. }
  2377.  
  2378. void
  2379. lm_SendLayerLoadEvent(MWContext *context, int32 event, int32 layer_id, 
  2380.                       JSBool resize_reload)
  2381. {
  2382.     MochaDecoder *decoder;
  2383.     JSObject *obj;
  2384.     JSEvent *pEvent;
  2385.     jsval rval;
  2386.     
  2387.     decoder = context->mocha_context ? LM_GetMochaDecoder(context) : 0;
  2388.     if (resize_reload)
  2389.         goto out;
  2390.  
  2391.     LO_LockLayout();
  2392.     obj = LO_GetLayerMochaObjectFromId(context, layer_id);
  2393.     LO_UnlockLayout();
  2394.     if (!obj)
  2395.         goto out;
  2396.  
  2397.     /* 
  2398.      * XXX Right now, we send the load event when the layer is finished
  2399.      * laying out, not when all the streams associated with a layer
  2400.      * are completed. 
  2401.      */
  2402.     switch (event) {
  2403.       case EVENT_LOAD:
  2404.       case EVENT_UNLOAD:
  2405.           pEvent = XP_NEW_ZAP(JSEvent);
  2406.           if (!pEvent)
  2407.               goto out;
  2408.           
  2409.           pEvent->type = event;
  2410.           
  2411.           (void) lm_SendEvent(context, obj, pEvent, &rval);
  2412.  
  2413.           if (!pEvent->saved)
  2414.               XP_FREE(pEvent);
  2415.           break;
  2416.       case EVENT_ABORT:
  2417.           break;
  2418.       default: ;
  2419.     }
  2420.  
  2421. out:
  2422.     if (decoder)
  2423.         LM_PutMochaDecoder(decoder);
  2424.     return;
  2425. }
  2426.  
  2427. void
  2428. lm_DestroyLayer(MWContext *context, JSObject *obj)
  2429. {
  2430.     jsval val;
  2431.     JSObject *child_doc_obj, *parent_doc_obj, *layer_array_obj;
  2432.     JSLayer *js_layer;
  2433.     JSBool ok;
  2434.     MochaDecoder *decoder;
  2435.     JSContext *cx;
  2436.     char *layer_name;
  2437.  
  2438.     decoder = LM_GetMochaDecoder(context);
  2439.     if (!decoder)
  2440.         return;
  2441.     
  2442.     cx = decoder->js_context;
  2443.     
  2444.     if (!JS_GetProperty(cx, obj, lm_document_str, &val) ||
  2445.         !JSVAL_IS_OBJECT(val)) {
  2446.         goto end;
  2447.     }
  2448.  
  2449.     child_doc_obj = JSVAL_TO_OBJECT(val);
  2450.     if (!child_doc_obj)
  2451.         goto end;
  2452.  
  2453.     /* If we had a layer called "foo", then there was a "document.foo"
  2454.        property created in the parent document at the time this layer
  2455.        was reflected.  Get rid of it, so that we can GC the layer
  2456.        object. */
  2457.     layer_array_obj = JS_GetParent(cx, obj);
  2458.     if (!layer_array_obj)
  2459.         goto end;
  2460.     
  2461.     parent_doc_obj = JS_GetParent(cx, layer_array_obj);
  2462.     if (!parent_doc_obj)
  2463.         goto end;
  2464.     
  2465.     js_layer = JS_GetPrivate(cx, obj);    
  2466.     layer_name = (char *)JS_GetStringBytes(js_layer->name);
  2467.     ok = JS_DeleteProperty(cx, parent_doc_obj, layer_name);
  2468.     XP_ASSERT(ok);
  2469.  
  2470.     lm_CleanUpDocumentRoots(decoder, child_doc_obj);
  2471.  
  2472.   end:
  2473.     LM_PutMochaDecoder(decoder);
  2474. }
  2475.  
  2476.  
  2477. /* 
  2478.  * Called to set the source URL as a result of a document.open() on the
  2479.  * layer's document.
  2480.  */
  2481. JSBool
  2482. lm_SetLayerSourceURL(MochaDecoder *decoder, int32 layer_id, char *url)
  2483. {
  2484.     MWContext *context;
  2485.     JSObject *layer_obj;
  2486.     JSLayer *js_layer;
  2487.  
  2488.     context = decoder->window_context;
  2489.     if (!context)
  2490.         return JS_FALSE;
  2491.     
  2492.     LO_LockLayout();
  2493.     layer_obj = LO_GetLayerMochaObjectFromId(context, layer_id);
  2494.     LO_UnlockLayout();
  2495.     if (!layer_obj)
  2496.         return JS_FALSE;
  2497.     
  2498.     js_layer = JS_GetPrivate(decoder->js_context, layer_obj);
  2499.     if (!js_layer)
  2500.         return JS_FALSE;
  2501.  
  2502.     XP_FREEIF(js_layer->source_url);
  2503.     js_layer->source_url = XP_STRDUP(url);
  2504.     LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_SRC);
  2505.     decoder->stream_owner = layer_id;
  2506.  
  2507.     return JS_TRUE;
  2508. }
  2509.  
  2510. const char *
  2511. lm_GetLayerOriginURL(JSContext *cx, JSObject *obj) {
  2512.     JSLayer *js_layer = JS_GetPrivate(cx, obj);
  2513.     if (js_layer == NULL || js_layer->source_url == NULL) {
  2514.         return NULL;
  2515.     }
  2516.     return js_layer->source_url;
  2517.     
  2518. }
  2519.  
  2520. JSBool
  2521. lm_InitLayerClass(MochaDecoder *decoder)
  2522. {
  2523.     JSContext *cx;
  2524.     JSObject *prototype;
  2525.  
  2526.     cx = decoder->js_context;
  2527.     prototype = JS_InitClass(cx, decoder->window_object,
  2528.                  decoder->event_capturer_prototype, &lm_layer_class,
  2529.                              Layer, 1, layer_props, layer_methods, NULL, NULL);
  2530.     if (!prototype)
  2531.         return JS_FALSE;
  2532.     decoder->layer_prototype = prototype;
  2533.     return JS_TRUE;
  2534. }
  2535.  
  2536. /* ======================== Rect Class definition ======================= */
  2537.  
  2538. typedef struct JSRect {
  2539.     MochaDecoder           *decoder;
  2540.     int32                   layer_id;
  2541. } JSRect;
  2542.  
  2543.  
  2544. /* Static compositor rect properties */
  2545. static JSPropertySpec rect_props[] = {
  2546.     {lm_left_str,           RECT_LEFT,         JSPROP_ENUMERATE},
  2547.     {lm_top_str,            RECT_TOP,          JSPROP_ENUMERATE},
  2548.     {lm_right_str,          RECT_RIGHT,        JSPROP_ENUMERATE},
  2549.     {lm_bottom_str,         RECT_BOTTOM,       JSPROP_ENUMERATE},
  2550.     {"height",              RECT_HEIGHT,       JSPROP_ENUMERATE},
  2551.     {"width",               RECT_WIDTH,        JSPROP_ENUMERATE},
  2552.     {0}
  2553. };
  2554.  
  2555. PR_STATIC_CALLBACK(JSBool)
  2556. rect_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  2557. {
  2558.     MochaDecoder *decoder;
  2559.     MWContext *context;
  2560.     JSRect *js_rect;
  2561.     XP_Rect bbox;
  2562.     jsint slot;
  2563.     CL_Layer *layer;
  2564.  
  2565.     if (!JSVAL_IS_INT(id))
  2566.         return JS_TRUE;
  2567.  
  2568.     slot = JSVAL_TO_INT(id);
  2569.  
  2570.     js_rect = JS_GetPrivate(cx, obj);
  2571.     if (!js_rect)
  2572.         return JS_TRUE;
  2573.  
  2574.     decoder = js_rect->decoder;
  2575.     context = decoder->window_context;
  2576.  
  2577.     LO_LockLayout();
  2578.     if(!context || decoder->doc_id != XP_DOCID(context)) {
  2579.         LO_UnlockLayout();
  2580.         return JS_FALSE;
  2581.     }
  2582.  
  2583.     layer = LO_GetLayerFromId(context, js_rect->layer_id);
  2584.     if (!layer) {
  2585.         LO_UnlockLayout();
  2586.         return JS_TRUE;
  2587.     }
  2588.  
  2589.     CL_GetLayerBbox(layer, &bbox);
  2590.  
  2591.     switch (slot) {
  2592.     case RECT_LEFT:
  2593.         *vp = INT_TO_JSVAL(bbox.left);
  2594.         break;
  2595.  
  2596.     case RECT_RIGHT:
  2597.         *vp = INT_TO_JSVAL(bbox.right);
  2598.         break;
  2599.  
  2600.     case RECT_TOP:
  2601.         *vp = INT_TO_JSVAL(bbox.top);
  2602.         break;
  2603.  
  2604.     case RECT_BOTTOM:
  2605.         *vp = INT_TO_JSVAL(bbox.bottom);
  2606.         break;
  2607.  
  2608.     case RECT_WIDTH:
  2609.         *vp = INT_TO_JSVAL(bbox.right - bbox.left);
  2610.         break;
  2611.  
  2612.     case RECT_HEIGHT:
  2613.         *vp = INT_TO_JSVAL(bbox.bottom - bbox.top);
  2614.         break;
  2615.  
  2616.     default:
  2617.         break;
  2618.     }
  2619.  
  2620.     LO_UnlockLayout();
  2621.     return JS_TRUE;
  2622. }
  2623.  
  2624. PR_STATIC_CALLBACK(JSBool)
  2625. rect_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  2626. {
  2627.     JSRect *js_rect;
  2628.     MochaDecoder *decoder;
  2629.     MWContext *context;
  2630.     CL_Layer *layer;
  2631.     int32 val;
  2632.     enum rect_slot rect_slot;
  2633.     jsint slot;
  2634.     JSObject *layer_obj;
  2635.     JSLayer *js_layer;
  2636.     jsval js_val;
  2637.  
  2638.     if (!JSVAL_IS_INT(id))
  2639.         return JS_TRUE;
  2640.  
  2641.     rect_slot = slot = JSVAL_TO_INT(id);
  2642.  
  2643.     js_rect = JS_GetPrivate(cx, obj);
  2644.     if (!js_rect)
  2645.         return JS_TRUE;
  2646.  
  2647.     decoder = js_rect->decoder;
  2648.     layer = LO_GetLayerFromId(decoder->window_context, js_rect->layer_id);
  2649.     if (!layer)
  2650.         return JS_TRUE;
  2651.     layer_obj = LO_GetLayerMochaObjectFromId(decoder->window_context,
  2652.                                              js_rect->layer_id);
  2653.     if (!layer_obj)
  2654.         return JS_TRUE;
  2655.     js_layer = JS_GetPrivate(cx, layer_obj);
  2656.     if (!js_layer)
  2657.         return JS_TRUE;
  2658.     /* Some layers have mostly read-only properties because we
  2659.        don't want a malicious/careless JS author to modify them,
  2660.        e.g.  for layers that are used to encapulate a mail
  2661.        message. In such cases, we fail silently. */
  2662.     if (js_layer->properties_locked)
  2663.         return JS_TRUE;
  2664.     
  2665.     context = decoder->window_context;
  2666.  
  2667.     if (rect_slot == RECT_LEFT   ||
  2668.         rect_slot == RECT_RIGHT  ||
  2669.         rect_slot == RECT_TOP    ||
  2670.         rect_slot == RECT_BOTTOM ||
  2671.         rect_slot == RECT_WIDTH  ||
  2672.         rect_slot == RECT_HEIGHT) {
  2673.  
  2674.         XP_Rect bbox;
  2675.  
  2676.         if (!JS_ValueToInt32(cx, *vp, &val))
  2677.             return JS_FALSE;
  2678.  
  2679.         LO_LockLayout();
  2680.         if(!context || decoder->doc_id != XP_DOCID(context)) {
  2681.             LO_UnlockLayout();
  2682.             return JS_FALSE;
  2683.         }
  2684.  
  2685.         CL_GetLayerBbox(layer, &bbox);
  2686.  
  2687.         /* If a layer is dynamically changing, it will probably look
  2688.            better if it utilizes offscreen compositing. */
  2689.         CL_ChangeLayerFlag(layer, CL_PREFER_DRAW_OFFSCREEN, PR_TRUE);
  2690.  
  2691.         switch (rect_slot) {
  2692.         case RECT_LEFT:
  2693.             bbox.left = (int32)val;
  2694.             LO_SetLayerBbox(layer, &bbox);
  2695.             CLEAR_LAYER_EXPANSION_POLICY(layer, LO_AUTO_EXPAND_CLIP_LEFT);
  2696.             LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_LEFT);
  2697.             break;
  2698.  
  2699.         case RECT_RIGHT:
  2700.             bbox.right = (int32)val;
  2701.             LO_SetLayerBbox(layer, &bbox);
  2702.             CLEAR_LAYER_EXPANSION_POLICY(layer, LO_AUTO_EXPAND_CLIP_RIGHT);
  2703.             LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_RIGHT);
  2704.             break;
  2705.  
  2706.         case RECT_TOP:
  2707.             bbox.top = (int32)val;
  2708.             LO_SetLayerBbox(layer, &bbox);
  2709.             CLEAR_LAYER_EXPANSION_POLICY(layer, LO_AUTO_EXPAND_CLIP_TOP);
  2710.             LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_TOP);
  2711.             break;
  2712.  
  2713.         case RECT_BOTTOM:
  2714.             bbox.bottom = (int32)val;
  2715.             LO_SetLayerBbox(layer, &bbox);
  2716.             CLEAR_LAYER_EXPANSION_POLICY(layer, LO_AUTO_EXPAND_CLIP_BOTTOM);
  2717.             LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_BOTTOM);
  2718.             break;
  2719.  
  2720.         case RECT_WIDTH:
  2721.             bbox.right = bbox.left + (int32)val;
  2722.             LO_SetLayerBbox(layer, &bbox);
  2723.             CLEAR_LAYER_EXPANSION_POLICY(layer, LO_AUTO_EXPAND_CLIP_RIGHT);
  2724.             if (!LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_RIGHT)) {
  2725.                 LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_RIGHT);
  2726.                 JS_DefinePropertyWithTinyId(cx, obj, lm_right_str, RECT_RIGHT,
  2727.                                             INT_TO_JSVAL(bbox.right), 
  2728.                                             rect_getProperty, 
  2729.                                             rect_setProperty, 
  2730.                                             JSPROP_ENUMERATE);
  2731.             }
  2732.             else
  2733.                 JS_GetProperty(cx, obj, lm_right_str, &js_val);
  2734.             break;
  2735.  
  2736.         case RECT_HEIGHT:
  2737.             bbox.bottom = bbox.top + (int32)val;
  2738.             LO_SetLayerBbox(layer, &bbox);
  2739.             CLEAR_LAYER_EXPANSION_POLICY(layer, LO_AUTO_EXPAND_CLIP_BOTTOM);
  2740.             if (!LM_CHECK_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_BOTTOM)) {
  2741.                 LM_SET_LAYER_MODIFICATION(js_layer, LAYER_MOD_CLIP_BOTTOM);
  2742.                 JS_DefinePropertyWithTinyId(cx, obj, lm_bottom_str,
  2743.                                             RECT_BOTTOM, 
  2744.                                             INT_TO_JSVAL(bbox.bottom),
  2745.                                             rect_getProperty, 
  2746.                                             rect_setProperty, 
  2747.                                             JSPROP_ENUMERATE);
  2748.             }
  2749.             else
  2750.                 JS_GetProperty(cx, obj, lm_bottom_str, &js_val);
  2751.             break;
  2752.         }
  2753.     }
  2754.             
  2755.     LO_UnlockLayout();
  2756.     return rect_getProperty(cx, obj, id, vp);
  2757. }
  2758.  
  2759. PR_STATIC_CALLBACK(void)
  2760. rect_finalize(JSContext *cx, JSObject *obj)
  2761. {
  2762.     JSRect *js_rect;
  2763.  
  2764.     js_rect = JS_GetPrivate(cx, obj);
  2765.     if (!js_rect)
  2766.         return;
  2767.     DROP_BACK_COUNT(js_rect->decoder);
  2768.     JS_free(cx, js_rect);
  2769. }
  2770.  
  2771. static JSClass rect_class = {
  2772.     "Rect", JSCLASS_HAS_PRIVATE,
  2773.     JS_PropertyStub, JS_PropertyStub, rect_getProperty, rect_setProperty,
  2774.     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, rect_finalize
  2775. };
  2776.  
  2777. PR_STATIC_CALLBACK(JSBool)
  2778. RectConstructor(JSContext *cx, JSObject *obj,
  2779.      uint argc, jsval *argv, jsval *rval)
  2780. {
  2781.     return JS_TRUE;
  2782. }
  2783.  
  2784. /* Initialize the 'clip' property of a layer to be a Rect object */
  2785. static JSObject *
  2786. lm_init_layer_clip(MochaDecoder *decoder,
  2787.                    int32 layer_id,
  2788.                    JSObject *parent_layer_obj)
  2789. {
  2790.     JSObject *obj;
  2791.     JSContext *cx;
  2792.     JSRect *js_rect;
  2793.  
  2794.     cx = decoder->js_context;
  2795.  
  2796.     js_rect = JS_malloc(cx, sizeof *js_rect);
  2797.     if (!js_rect)
  2798.         return NULL;
  2799.     js_rect->decoder = NULL;    /* in case of error below */
  2800.  
  2801.     obj = JS_NewObject(cx, &rect_class, decoder->rect_prototype, 
  2802.                        parent_layer_obj);
  2803.     if (!obj || !JS_SetPrivate(cx, obj, js_rect)) {
  2804.         JS_free(cx, js_rect);
  2805.         return NULL;
  2806.     }
  2807.     if (!JS_DefineProperty(cx, parent_layer_obj, lm_clip_str, 
  2808.                            OBJECT_TO_JSVAL(obj),
  2809.                            NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY)) {
  2810.         return NULL;
  2811.     }
  2812.  
  2813.     js_rect->decoder = HOLD_BACK_COUNT(decoder);
  2814.     js_rect->layer_id = layer_id;
  2815.     return obj;
  2816. }
  2817.  
  2818. JSBool
  2819. lm_InitRectClass(MochaDecoder *decoder)
  2820. {
  2821.     JSContext *cx;
  2822.     JSObject *prototype;
  2823.  
  2824.     cx = decoder->js_context;
  2825.     prototype = JS_InitClass(cx, decoder->window_object, NULL, &rect_class,
  2826.                              RectConstructor, 0, rect_props, NULL, NULL, NULL);
  2827.     if (!prototype)
  2828.         return JS_FALSE;
  2829.     decoder->rect_prototype = prototype;
  2830.     return JS_TRUE;
  2831. }
  2832.  
  2833.  
  2834. static JSPrincipals **
  2835. getContainerPrincipalsAddress(JSContext *cx, JSObject *container)
  2836. {
  2837.     JSClass *classp = JS_GetClass(container);
  2838.  
  2839.     if (classp == &lm_window_class) {
  2840.         MochaDecoder *decoder = JS_GetPrivate(cx, container);
  2841.         return decoder ? &decoder->principals : NULL;
  2842.     } else if (classp == &lm_layer_class) {
  2843.         JSLayer *layer = JS_GetPrivate(cx, container);
  2844.         return layer ? &layer->principals : NULL;
  2845.     } else {
  2846.         return NULL;
  2847.     }
  2848. }
  2849.  
  2850. extern JSPrincipals *
  2851. lm_GetContainerPrincipals(JSContext *cx, JSObject *container)
  2852. {
  2853.     JSPrincipals **p = getContainerPrincipalsAddress(cx, container);
  2854.     return p ? *p : NULL;
  2855. }
  2856.  
  2857. extern void
  2858. lm_SetContainerPrincipals(JSContext *cx, JSObject *container, 
  2859.                           JSPrincipals *principals)
  2860. {
  2861.     JSPrincipals **p = getContainerPrincipalsAddress(cx, container);
  2862.     if (p && *p != principals) {
  2863.         if (*p) {
  2864.             JSPRINCIPALS_DROP(cx, *p);
  2865.         }
  2866.         *p = principals;
  2867.         JSPRINCIPALS_HOLD(cx, *p);
  2868.     }
  2869. }
  2870.  
  2871.  
  2872. extern JSObject *
  2873. lm_GetActiveContainer(MochaDecoder *decoder)
  2874. {
  2875.     if (decoder->active_layer_id == LO_DOCUMENT_LAYER_ID) {
  2876.         /* immediate container is the window */
  2877.         return decoder->window_object;
  2878.     } else {
  2879.         /* immediate container is a layer */
  2880.         JSObject *result;
  2881.         LO_LockLayout();
  2882.         result = LO_GetLayerMochaObjectFromId(decoder->window_context, 
  2883.                                               decoder->active_layer_id);
  2884.         LO_UnlockLayout();
  2885.         return result;
  2886.     }
  2887. }
  2888.  
  2889. extern JSBool
  2890. lm_GetPrincipalsCompromise(JSContext *cx, JSObject *obj)
  2891. {
  2892.     JSClass *clasp;
  2893.     MochaDecoder *decoder;
  2894.     JSLayer *js_layer;
  2895.     JSBool flag;
  2896.  
  2897.     clasp = JS_GetClass(obj);
  2898.     if (clasp == &lm_window_class) {
  2899.     decoder = JS_GetPrivate(cx, obj);
  2900.     flag = (JSBool)decoder->principals_compromised;
  2901.     } else if (clasp == &lm_layer_class) {
  2902.     js_layer = JS_GetPrivate(cx, obj);
  2903.     flag = (JSBool)js_layer->principals_compromised;
  2904.     } else {
  2905.     flag = JS_FALSE;
  2906.     }
  2907.     return flag;
  2908. }
  2909.