home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libmocha / lm_win.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  109.5 KB  |  3,479 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.  * JS reflection of the current Navigator Window.
  20.  *
  21.  * Brendan Eich, 9/8/95
  22.  */
  23. #include "lm.h"
  24. #include "xp.h"
  25. #include "xpgetstr.h"
  26. #include "structs.h"
  27. #include "layout.h"             /* included via -I../layout */
  28. #include "prtime.h"
  29. #include "shist.h"
  30. #include "ssl.h"
  31. #include "libi18n.h"
  32. #include "jsdbgapi.h"
  33. #include "intl_csi.h"
  34. #include "layers.h"
  35. #include "base64.h"
  36.  
  37. #define IL_CLIENT
  38. #include "libimg.h"             /* Image Library public API. */
  39. #include "prthread.h"
  40.  
  41. #ifdef JAVA
  42. #include "jsjava.h"
  43. #endif
  44.  
  45. #undef FREE_AND_CLEAR           /* XXX over-including Mac compiled headers */
  46.  
  47. extern int XP_MSG_JS_CLOSE_WINDOW;
  48. extern int XP_MSG_JS_CLOSE_WINDOW_NAME;
  49.  
  50. enum window_slot {
  51.     WIN_LENGTH              = -1,
  52.     WIN_FRAMES              = -2,
  53.     WIN_PARENT              = -3,
  54.     WIN_TOP                 = -4,
  55.     WIN_SELF                = -5,
  56.     WIN_NAME                = -6,
  57.     WIN_STATUS              = -7,
  58.     WIN_DEFAULT_STATUS      = -8,
  59.     WIN_OPENER              = -9,
  60.     WIN_CLOSED              = -10,
  61.     WIN_WIDTH               = -11,
  62.     WIN_HEIGHT              = -12,
  63.     WIN_OUTWIDTH            = -13,
  64.     WIN_OUTHEIGHT           = -14,
  65.     WIN_XPOS                = -15,
  66.     WIN_YPOS                = -16,
  67.     WIN_XOFFSET             = -17,
  68.     WIN_YOFFSET             = -18,
  69.     WIN_SECURE              = -19,
  70.     WIN_LOADING             = -20,
  71.     WIN_FRAMERATE           = -21,
  72.     WIN_OFFSCREEN_BUFFERING = -22
  73. };
  74.  
  75. #define IS_INSECURE_SLOT(s) (WIN_LOADING <= (s) && (s) <= WIN_CLOSED)
  76.  
  77. static JSPropertySpec window_props[] = {
  78.     {"length",        WIN_LENGTH,     JSPROP_ENUMERATE|JSPROP_READONLY},
  79.     {"frames",        WIN_FRAMES,     JSPROP_ENUMERATE|JSPROP_READONLY},
  80.     {"parent",        WIN_PARENT,     JSPROP_ENUMERATE|JSPROP_READONLY},
  81.     {"top",           WIN_TOP,        JSPROP_ENUMERATE|JSPROP_READONLY},
  82.     {"self",          WIN_SELF,       JSPROP_ENUMERATE|JSPROP_READONLY},
  83.     {"window",        WIN_SELF,       JSPROP_READONLY},
  84.     {"name",          WIN_NAME,       JSPROP_ENUMERATE},
  85.     {"status",        WIN_STATUS,     JSPROP_ENUMERATE},
  86.     {"defaultStatus", WIN_DEFAULT_STATUS, JSPROP_ENUMERATE},
  87.     {lm_opener_str,   WIN_OPENER,     JSPROP_ENUMERATE},
  88.     {lm_closed_str,   WIN_CLOSED,     JSPROP_ENUMERATE|JSPROP_READONLY},
  89.     {"innerWidth",    WIN_WIDTH,      JSPROP_ENUMERATE},
  90.     {"innerHeight",   WIN_HEIGHT,     JSPROP_ENUMERATE},
  91.     {"outerWidth",    WIN_OUTWIDTH,   JSPROP_ENUMERATE},
  92.     {"outerHeight",   WIN_OUTHEIGHT,  JSPROP_ENUMERATE},
  93.     {"screenX",       WIN_XPOS,       JSPROP_ENUMERATE},
  94.     {"screenY",       WIN_YPOS,       JSPROP_ENUMERATE},
  95.     {"pageXOffset",   WIN_XOFFSET,    JSPROP_ENUMERATE|JSPROP_READONLY},
  96.     {"pageYOffset",   WIN_YOFFSET,    JSPROP_ENUMERATE|JSPROP_READONLY},
  97.     {"secure",        WIN_SECURE,     JSPROP_ENUMERATE|JSPROP_READONLY},
  98.     {"frameRate",     WIN_FRAMERATE,  JSPROP_ENUMERATE},
  99.     {"offscreenBuffering",
  100.                       WIN_OFFSCREEN_BUFFERING,JSPROP_ENUMERATE},
  101.     {0}
  102. };
  103.  
  104. static Chrome *
  105. win_get_chrome(MWContext *context, Chrome *chrome)
  106. {
  107.     if (!context->mocha_context)
  108.         return NULL;
  109.  
  110.     /* All calls to this function must free the Chrome struct themselves!!! */
  111.     chrome = JS_malloc(context->mocha_context, sizeof *chrome);
  112.     if (!chrome)
  113.         return NULL;
  114.     XP_BZERO(chrome, sizeof *chrome);
  115.  
  116.     ET_PostQueryChrome(context, chrome);
  117.  
  118.     return chrome;
  119. }
  120.  
  121. PR_STATIC_CALLBACK(PRBool)
  122. win_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  123. {
  124.     MochaDecoder *decoder;
  125.     MWContext *context;
  126.     jsint count;
  127.     Chrome *chrome = NULL;
  128.     JSString * str;
  129.     jsint slot;
  130.     CL_OffscreenMode offscreen_mode;
  131.     int status;
  132.  
  133.     while (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, NULL))) {
  134.         obj = JS_GetPrototype(cx, obj);
  135.         if (!obj)
  136.             return JS_TRUE;
  137.     }
  138.  
  139.     /*
  140.      * Allow anyone who can address this window to refer to its "window" and
  141.      * "self" properties, because they refer to the window already in hand by
  142.      * the accessing script.  Useful for layer scripts that 'import window.*'.
  143.      */
  144.     if (JSVAL_IS_INT(id) && JSVAL_TO_INT(id) == WIN_SELF) {
  145.         *vp = OBJECT_TO_JSVAL(decoder->window_object);
  146.         return JS_TRUE;
  147.     }
  148.  
  149.     slot = JSVAL_IS_INT(id) ? JSVAL_TO_INT(id) : 0;
  150.  
  151.     if (!IS_INSECURE_SLOT(slot) &&
  152.         !lm_CheckContainerAccess(cx, obj, decoder,
  153.                                  JSTARGET_UNIVERSAL_BROWSER_READ)) {
  154.         return JS_FALSE;
  155.     }
  156.  
  157.     context = decoder->window_context;
  158.     if (!context) {
  159.         if (JSVAL_IS_INT(id) && JSVAL_TO_INT(id) == WIN_CLOSED)
  160.             *vp = JSVAL_TRUE;
  161.         return JS_TRUE;
  162.     }
  163.  
  164.     if (!JSVAL_IS_INT(id))
  165.         return JS_TRUE;
  166.  
  167.     switch (slot) {
  168.       case WIN_LENGTH:
  169.         *vp = INT_TO_JSVAL(XP_ListCount(context->grid_children));
  170.         break;
  171.  
  172.       case WIN_FRAMES:
  173.         *vp = OBJECT_TO_JSVAL(decoder->window_object);
  174.         break;
  175.  
  176.       case WIN_PARENT:
  177.         *vp = OBJECT_TO_JSVAL(decoder->window_object);
  178.         if (context->grid_parent) {
  179.             decoder = LM_GetMochaDecoder(context->grid_parent);
  180.             if (decoder) {
  181.                 *vp = OBJECT_TO_JSVAL(decoder->window_object);
  182.                 LM_PutMochaDecoder(decoder);
  183.             }
  184.         }
  185.         break;
  186.  
  187.       case WIN_TOP:
  188.         while (context->grid_parent)
  189.             context = context->grid_parent;
  190.         decoder = LM_GetMochaDecoder(context);
  191.         *vp = OBJECT_TO_JSVAL(decoder ? decoder->window_object : NULL);
  192.         if (decoder)
  193.             LM_PutMochaDecoder(decoder);
  194.         break;
  195.  
  196.       case WIN_NAME:
  197.         str = lm_LocalEncodingToStr(context, context->name);
  198.         if (!str)
  199.             return JS_FALSE;
  200.         *vp = STRING_TO_JSVAL(str);
  201.         break;
  202.  
  203.       case WIN_STATUS:
  204.         return JS_TRUE; /* XXX can't get yet, return last known */
  205.  
  206.       case WIN_DEFAULT_STATUS:
  207.         str = JS_NewStringCopyZ(cx, context->defaultStatus);
  208.         if (!str)
  209.             return JS_FALSE;
  210.         *vp = STRING_TO_JSVAL(str);
  211.         break;
  212.  
  213.       case WIN_OPENER:
  214.         if (!JSVAL_IS_OBJECT(*vp) &&
  215.             !JS_ConvertValue(cx, *vp, JSTYPE_OBJECT, vp)) {
  216.             return JS_FALSE;
  217.         }
  218.         break;
  219.  
  220.       case WIN_CLOSED:
  221.         *vp = JSVAL_FALSE;
  222.         break;
  223.  
  224.       case WIN_WIDTH:
  225.         if (!(chrome = win_get_chrome(context, chrome)))
  226.             return JS_FALSE;
  227.         *vp = INT_TO_JSVAL(chrome->w_hint);
  228.         break;
  229.  
  230.       case WIN_HEIGHT:
  231.         if (!(chrome = win_get_chrome(context, chrome)))
  232.             return JS_FALSE;
  233.         *vp = INT_TO_JSVAL(chrome->h_hint);
  234.         break;
  235.  
  236.       case WIN_OUTWIDTH:
  237.         if (!(chrome = win_get_chrome(context, chrome)))
  238.             return JS_FALSE;
  239.         *vp = INT_TO_JSVAL(chrome->outw_hint);
  240.         break;
  241.  
  242.       case WIN_OUTHEIGHT:
  243.         if (!(chrome = win_get_chrome(context, chrome)))
  244.             return JS_FALSE;
  245.         *vp = INT_TO_JSVAL(chrome->outh_hint);
  246.         break;
  247.  
  248.       case WIN_XPOS:
  249.         if (!(chrome = win_get_chrome(context, chrome)))
  250.             return JS_FALSE;
  251.         *vp = INT_TO_JSVAL(chrome->l_hint);
  252.         break;
  253.  
  254.       case WIN_YPOS:
  255.         if (!(chrome = win_get_chrome(context, chrome)))
  256.             return JS_FALSE;
  257.         *vp = INT_TO_JSVAL(chrome->t_hint);
  258.         break;
  259.  
  260.       case WIN_XOFFSET:
  261.         *vp = INT_TO_JSVAL(CL_GetCompositorXOffset(context->compositor));
  262.         break;
  263.  
  264.       case WIN_YOFFSET:
  265.         *vp = INT_TO_JSVAL(CL_GetCompositorYOffset(context->compositor));
  266.         break;
  267.  
  268.       case WIN_SECURE:
  269.         status = ET_GetSecurityStatus(context);
  270.         if (status == SSL_SECURITY_STATUS_ON_LOW || status == SSL_SECURITY_STATUS_ON_HIGH)
  271.             *vp = JSVAL_TRUE;
  272.         else
  273.             *vp = JSVAL_FALSE;
  274.         break;
  275.  
  276.       case WIN_LOADING:
  277.         decoder = LM_GetMochaDecoder(context);
  278.         if (decoder && !decoder->load_event_sent)
  279.             *vp = JSVAL_TRUE;
  280.         else
  281.             *vp = JSVAL_FALSE;
  282.         if (decoder)
  283.             LM_PutMochaDecoder(decoder);
  284.         break;
  285.  
  286.       case WIN_FRAMERATE:
  287.         *vp = INT_TO_JSVAL(CL_GetCompositorFrameRate(context->compositor));
  288.         break;
  289.  
  290.       case WIN_OFFSCREEN_BUFFERING:
  291.         offscreen_mode = CL_GetCompositorOffscreenDrawing(context->compositor);
  292.  
  293.         switch (offscreen_mode) {
  294.           case CL_OFFSCREEN_ENABLED:
  295.             *vp = JSVAL_TRUE;
  296.             break;
  297.           case CL_OFFSCREEN_DISABLED:
  298.             *vp = JSVAL_FALSE;
  299.             break;
  300.           case CL_OFFSCREEN_AUTO:
  301.             str = JS_NewStringCopyZ(cx, "auto");
  302.             if (!str)
  303.                 return JS_FALSE;
  304.             *vp = STRING_TO_JSVAL(str);
  305.             break;
  306.         }
  307.         break;
  308.  
  309.       default:
  310.         if (slot < 0) {
  311.             /* Don't mess with user-defined or method properties. */
  312.             return JS_TRUE;
  313.         }
  314.  
  315.         /* XXX silly xp_cntxt.c puts newer contexts at the front! fix. */
  316.         count = XP_ListCount(context->grid_children);
  317.         context = XP_ListGetObjectNum(context->grid_children, count - slot);
  318.         if (context) {
  319.             decoder = LM_GetMochaDecoder(context);
  320.             if (decoder) {
  321.                 *vp = OBJECT_TO_JSVAL(decoder->window_object);
  322.                 LM_PutMochaDecoder(decoder);
  323.             } else {
  324.                 *vp = JSVAL_NULL;
  325.             }
  326.         }
  327.         break;
  328.     }
  329.     if (chrome)
  330.         JS_free(cx, chrome);
  331.  
  332.     return JS_TRUE;
  333. }
  334.  
  335. PR_STATIC_CALLBACK(PRBool)
  336. win_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
  337. {
  338.     MochaDecoder *decoder, *parent_decoder;
  339.     CL_OffscreenMode mode;
  340.     JSBool enable_offscreen;
  341.     jsdouble frame_rate, size;
  342.     MWContext *context;
  343.     Chrome *chrome = NULL;
  344.     enum window_slot window_slot;
  345.     const char *prop_name;
  346.     char *str, *name, *old_name;
  347.     jsint slot;
  348.     int32 width, height;
  349.  
  350.     while (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, NULL))) {
  351.         obj = JS_GetPrototype(cx, obj);
  352.         if (!obj)
  353.             return JS_TRUE;
  354.     }
  355.  
  356.     if (!lm_CheckContainerAccess(cx, obj, decoder,
  357.                                  JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
  358.         return JS_FALSE;
  359.     }
  360.  
  361.     context = decoder->window_context;
  362.     if (!context)
  363.         return JS_TRUE;
  364.  
  365.     if (!JSVAL_IS_INT(id)) {
  366.         /* Due to the wonderful world of threads we need to know ahead of time if
  367.          * someone is setting an onMouseMove event handler here or in document so
  368.          * that we don't lose messages.*/
  369.         if (JS_TypeOfValue(cx, *vp) == JSTYPE_FUNCTION) {
  370.             if (JSVAL_IS_STRING(id)) {
  371.                 prop_name = JS_GetStringBytes(JSVAL_TO_STRING(id));
  372.                 /* XXX use lm_onMouseMove_str etc.*/
  373.                 if (XP_STRCMP(prop_name, "onmousemove") == 0 ||
  374.                     XP_STRCMP(prop_name, "onMouseMove") == 0) {
  375.                     decoder->window_context->js_drag_enabled = TRUE;
  376.                 }
  377.             }
  378.         }
  379.         return JS_TRUE;
  380.     }
  381.  
  382.     slot = JSVAL_TO_INT(id);
  383.  
  384.     window_slot = slot;
  385.     switch (window_slot) {
  386.       case WIN_NAME:
  387.       case WIN_STATUS:
  388.       case WIN_DEFAULT_STATUS:
  389.         if (!JSVAL_IS_STRING(*vp) &&
  390.             !JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp)) {
  391.             return JS_FALSE;
  392.         }
  393.         break;
  394.       default:;
  395.     }
  396.  
  397.     switch (window_slot) {
  398.       case WIN_NAME:
  399.         /* Don't let rogue JS name a mail or news window and then close it. */
  400.         if (context->type != MWContextBrowser && context->type != MWContextPane)
  401.             return JS_TRUE;
  402.         name = lm_StrToLocalEncoding(context,  JSVAL_TO_STRING(*vp));
  403.     if (!name)
  404.         return JS_FALSE;
  405.         if (!lm_CheckWindowName(cx, name)) {
  406.         XP_FREE(name);
  407.             return JS_FALSE;
  408.     }
  409.         old_name = context->name;
  410.         if (old_name) {
  411.             /* If context is a frame, change its name in its parent's scope. */
  412.             if (context->grid_parent) {
  413.                 parent_decoder = LM_GetMochaDecoder(context->grid_parent);
  414.                 if (parent_decoder) {
  415.                     JS_DeleteProperty(cx, parent_decoder->window_object,
  416.                                          old_name);
  417.                     LM_PutMochaDecoder(parent_decoder);
  418.                 }
  419.             }
  420.             XP_FREE(old_name);
  421.         }
  422.         context->name = name;
  423.         break;
  424.  
  425.       case WIN_STATUS:
  426.         ET_PostProgress(context, JS_GetStringBytes(JSVAL_TO_STRING(*vp)));
  427.         break;
  428.  
  429.       case WIN_DEFAULT_STATUS:
  430.         str = JS_strdup(cx, JS_GetStringBytes(JSVAL_TO_STRING(*vp)));
  431.         if (!str)
  432.             return JS_FALSE;
  433.         if (context->defaultStatus)
  434.             XP_FREE(context->defaultStatus);
  435.         context->defaultStatus = str;
  436.         ET_PostProgress(context, NULL);
  437.         break;
  438.  
  439.       case WIN_OPENER:
  440.         if (decoder->opener && !JSVAL_TO_OBJECT(*vp))
  441.             decoder->opener = NULL;
  442.         break;
  443.  
  444.       case WIN_WIDTH:
  445.         if (context->grid_parent)   
  446.             return JS_TRUE;
  447.         if (!JS_ValueToNumber(cx, *vp, &size))
  448.             return JS_FALSE;
  449.         if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
  450.             return JS_FALSE;
  451.         chrome->w_hint = (int32)size;
  452.         chrome->outw_hint = chrome->outh_hint = 0;
  453.         /* Minimum window size is 100 x 100 without security */
  454.         if (chrome->w_hint < 100) {
  455.             if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE))
  456.                 chrome->w_hint = 100;
  457.         }
  458.         chrome->w_hint = (chrome->w_hint < 10) ? 10 : chrome->w_hint;
  459.         ET_PostUpdateChrome(decoder->window_context, chrome);
  460.         break;
  461.  
  462.       case WIN_HEIGHT:
  463.         if (context->grid_parent)   
  464.             return JS_TRUE;
  465.         if (!JS_ValueToNumber(cx, *vp, &size))
  466.             return JS_FALSE;
  467.         if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
  468.             return JS_FALSE;
  469.         chrome->h_hint = (int32)size;
  470.         chrome->outw_hint = chrome->outh_hint = 0;
  471.         /* Minimum window size is 100 x 100 without security */
  472.         if (chrome->h_hint < 100) {
  473.             if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE))
  474.                 chrome->h_hint = 100;
  475.         }
  476.         chrome->h_hint = (chrome->h_hint < 10) ? 10 : chrome->h_hint;
  477.         ET_PostUpdateChrome(decoder->window_context, chrome);
  478.         break;
  479.  
  480.       case WIN_OUTWIDTH:
  481.         if (!JS_ValueToNumber(cx, *vp, &size))
  482.             return JS_FALSE;
  483.         if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
  484.             return JS_FALSE;
  485.         chrome->outw_hint = (int32)size;
  486.         /* Minimum window size is 100 x 100 without security */
  487.         if (chrome->outw_hint < 100) {
  488.             if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE))
  489.                 chrome->outw_hint = 100;
  490.         }
  491.         chrome->outw_hint = (chrome->outw_hint < 10) ? 10 : chrome->outw_hint;
  492.         ET_PostUpdateChrome(decoder->window_context, chrome);
  493.         break;
  494.  
  495.       case WIN_OUTHEIGHT:
  496.         if (!JS_ValueToNumber(cx, *vp, &size))
  497.             return JS_FALSE;
  498.         if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
  499.             return JS_FALSE;
  500.         chrome->outh_hint = (int32)size;
  501.         /* Minimum window size is 100 x 100 without security */
  502.         if (chrome->outh_hint < 100) { 
  503.             if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE))
  504.                 chrome->outh_hint = 100;
  505.         }
  506.         chrome->outh_hint = (chrome->outh_hint < 10) ? 10 : chrome->outh_hint;
  507.         ET_PostUpdateChrome(decoder->window_context, chrome);
  508.         break;
  509.  
  510.       case WIN_XPOS:
  511.         if (!JS_ValueToNumber(cx, *vp, &size))
  512.             return JS_FALSE;
  513.         if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
  514.             return JS_FALSE;
  515.         chrome->l_hint = (int32)size;
  516.         /* Windows must be positioned on screen without security */
  517.         ET_PostGetScreenSize(decoder->window_context, &width, &height);
  518.         if ((width < chrome->l_hint + chrome->outw_hint)||(chrome->l_hint < 0)){
  519.             if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
  520.                 chrome->l_hint = (width < chrome->l_hint + chrome->outw_hint) ?
  521.                                     width - chrome->outw_hint : chrome->l_hint;
  522.                 chrome->l_hint = (chrome->l_hint < 0) ? 0 : chrome->l_hint;
  523.             }
  524.         }
  525.         ET_PostUpdateChrome(decoder->window_context, chrome);
  526.         break;
  527.  
  528.       case WIN_YPOS:
  529.         if (!JS_ValueToNumber(cx, *vp, &size))
  530.             return JS_FALSE;
  531.         if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
  532.             return JS_FALSE;
  533.         chrome->t_hint = (int32)size;
  534.         /* Windows must be positioned on screen without security */
  535.         ET_PostGetScreenSize(decoder->window_context, &width, &height);
  536.         if ((height < chrome->t_hint + chrome->outh_hint)||(chrome->t_hint < 0)){
  537.             if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
  538.                 chrome->t_hint = (height < chrome->t_hint + chrome->outh_hint) ?
  539.                                     height - chrome->outh_hint : chrome->t_hint;
  540.                 chrome->t_hint = (chrome->t_hint < 0) ? 0 : chrome->t_hint;
  541.             }
  542.         }
  543.         ET_PostUpdateChrome(decoder->window_context, chrome);
  544.         break;
  545.  
  546.       case WIN_FRAMERATE:
  547.         if (!JS_ValueToNumber(cx, *vp, &frame_rate))
  548.             return JS_FALSE;
  549.         CL_SetCompositorFrameRate(context->compositor, (uint32) frame_rate);
  550.         break;
  551.  
  552.       case WIN_OFFSCREEN_BUFFERING:
  553.         if (!JS_ValueToBoolean(cx, *vp, &enable_offscreen))
  554.             return JS_FALSE;
  555.         mode = enable_offscreen ? CL_OFFSCREEN_ENABLED : CL_OFFSCREEN_DISABLED;
  556.         CL_SetCompositorOffscreenDrawing(context->compositor, mode);
  557.         break;
  558.  
  559.       default:;
  560.     }
  561.     if (chrome)
  562.         JS_free(cx, chrome);
  563.  
  564.     return JS_TRUE;
  565. }
  566.  
  567. PR_STATIC_CALLBACK(JSBool)
  568. win_list_properties(JSContext *cx, JSObject *obj)
  569. {
  570.     MochaDecoder *decoder;
  571.     MWContext *context, *kid;
  572.     XP_List *list;
  573.     uint slot;
  574.  
  575.     decoder = JS_GetPrivate(cx, obj);
  576.     if (!decoder)
  577.         return JS_TRUE;
  578.     context = decoder->window_context;
  579.     if (!context)
  580.         return JS_TRUE;
  581.  
  582.     /* xp_cntxt.c puts newer contexts at the front! deal. */
  583.     list = context->grid_children;
  584.     slot = XP_ListCount(list);
  585.     while ((kid = XP_ListNextObject(list)) != NULL) {
  586.         slot--;
  587.         if (!JS_DefineProperty(cx, decoder->window_object, kid->name,
  588.                                JSVAL_NULL, NULL, NULL,
  589.                                JSPROP_ENUMERATE|JSPROP_READONLY))
  590.             return JS_FALSE;
  591.     }
  592.     return JS_TRUE;
  593. }
  594.  
  595. PR_STATIC_CALLBACK(JSBool)
  596. win_resolve_name(JSContext *cx, JSObject *obj, jsval id)
  597. {
  598.     char * name = NULL;
  599.     MochaDecoder *decoder;
  600.     MWContext *context, *kid;
  601.     XP_List *list;
  602.     jsint slot;
  603.     JSObject *window_obj;
  604.     JSBool rv = JS_TRUE;
  605.  
  606.     /* Don't resolve any of names if id is on the left side of an = op. */
  607.     if (JS_IsAssigning(cx))
  608.         return JS_TRUE;
  609.  
  610.     if (!JSVAL_IS_STRING(id))
  611.         return JS_TRUE;
  612.  
  613.     decoder = JS_GetPrivate(cx, obj);
  614.     if (!decoder)
  615.         return JS_TRUE;
  616.     context = decoder->window_context;
  617.     if (!context)
  618.         return JS_TRUE;
  619.  
  620.     name = lm_StrToLocalEncoding(context, JSVAL_TO_STRING(id));
  621.     if (!name)
  622.     return JS_TRUE;
  623.  
  624.     /* xp_cntxt.c puts newer contexts at the front! deal. */
  625.     list = context->grid_children;
  626.     slot = XP_ListCount(list);
  627.     while ((kid = XP_ListNextObject(list)) != NULL) {
  628.         slot--;
  629.         if (kid->name && XP_STRCMP(kid->name, name) == 0) {
  630.             window_obj = decoder->window_object;
  631.             if (!JS_DefinePropertyWithTinyId(cx, window_obj,
  632.                                              kid->name, (int8)slot, JSVAL_NULL,
  633.                                              NULL, NULL,
  634.                                              JSPROP_ENUMERATE|JSPROP_READONLY))
  635.         {
  636.             rv = JS_FALSE;
  637.             goto done;
  638.         }
  639.             if (!JS_AliasElement(cx, window_obj, kid->name, slot)) {
  640.         rv = JS_FALSE;
  641.         goto done;
  642.         }
  643.             goto done;
  644.         }
  645.     }
  646.  
  647.     XP_FREE(name);
  648.     return lm_ResolveWindowProps(cx, decoder, obj, id);
  649.  
  650. done:
  651.     XP_FREE(name);
  652.     return rv;
  653. }
  654.  
  655. JSBool
  656. lm_ResolveWindowProps(JSContext *cx, MochaDecoder *decoder, JSObject *obj,
  657.                       jsval id)
  658. {
  659.     const char * name;
  660.  
  661.     if (!JSVAL_IS_STRING(id))
  662.         return JS_TRUE;
  663.     name = JS_GetStringBytes(JSVAL_TO_STRING(id));
  664.  
  665.     if (!XP_STRCMP(name, "screen"))
  666.         return ((JSBool) (lm_DefineScreen(decoder, obj) != NULL));
  667.  
  668.     if (!XP_STRCMP(name, "hardware"))
  669.         return ((JSBool) (lm_DefineHardware(decoder, obj) != NULL));
  670.  
  671.     if (!XP_STRCMP(name, "loading"))
  672.         return (JS_DefinePropertyWithTinyId(cx, obj, name, WIN_LOADING, 
  673.                                             JSVAL_VOID, NULL, NULL, 
  674.                                             JSPROP_ENUMERATE));
  675.  
  676.     if (!XP_STRCMP(name, lm_navigator_str)) {
  677.         /* see if there is a global navigator object yet */
  678.         if (!lm_crippled_decoder->navigator) {
  679.             lm_DefinePluginClasses(lm_crippled_decoder);
  680.             lm_crippled_decoder->navigator = lm_DefineNavigator(lm_crippled_decoder);
  681.             if (!lm_crippled_decoder->navigator)
  682.                 return JS_FALSE;
  683.             if (!JS_AddRoot(cx, &lm_crippled_decoder->navigator))
  684.                 return JS_FALSE;
  685.         }
  686.  
  687.         /* use the global navigator */
  688.         decoder->navigator = lm_crippled_decoder->navigator;
  689.         if (!JS_DefineProperty(cx, obj, lm_navigator_str,
  690.                                OBJECT_TO_JSVAL(decoder->navigator),
  691.                                NULL, NULL,
  692.                                JSPROP_ENUMERATE | JSPROP_READONLY)) {
  693.             return JS_FALSE;
  694.         }
  695.  
  696.     }
  697.  
  698.     if (!XP_STRCMP(name, lm_components_str)) {
  699.         /* see if there is a global components object yet */
  700.         if (!lm_crippled_decoder->components) {
  701.             lm_crippled_decoder->components =
  702.                 lm_DefineComponents(lm_crippled_decoder);
  703.             if (!lm_crippled_decoder->components)
  704.                 return JS_FALSE;
  705.             if (!JS_AddRoot(cx, &lm_crippled_decoder->components))
  706.                 return JS_FALSE;
  707.         }
  708.  
  709.         /* use the global navigator */
  710.         decoder->components = lm_crippled_decoder->components;
  711.         if (!JS_DefineProperty(cx, obj, lm_components_str,
  712.                                OBJECT_TO_JSVAL(decoder->components),
  713.                                NULL, NULL,
  714.                                JSPROP_ENUMERATE | JSPROP_READONLY)) {
  715.             return JS_FALSE;
  716.         }
  717.     }
  718.  
  719.     return lm_ResolveBar(cx, decoder, name);
  720. }
  721.  
  722. PR_STATIC_CALLBACK(void)
  723. win_finalize(JSContext *cx, JSObject *obj)
  724. {
  725.     MochaDecoder *decoder;
  726.  
  727.     decoder = JS_GetPrivate(cx, obj);
  728.     if (!decoder)
  729.         return;
  730.     decoder->window_object = NULL;
  731.  
  732.     /*
  733.      * If the decoder is going down and no one has a ref to
  734.      *   us run GC in LM_PutMochaDecoder() else destroy
  735.      *   the context here because its not being used by
  736.      *   whomever is finalizing us (i.e. a ref to a window
  737.      *   from another)
  738.      */
  739.     DROP_BACK_COUNT(decoder);
  740. }
  741.  
  742. JSClass lm_window_class = {
  743.     "Window", JSCLASS_HAS_PRIVATE,
  744.     JS_PropertyStub, JS_PropertyStub, win_getProperty, win_setProperty,
  745.     win_list_properties, win_resolve_name, JS_ConvertStub, win_finalize
  746. };
  747.  
  748. /*
  749.  * Alert and some simple dialogs.
  750.  */
  751. PR_STATIC_CALLBACK(PRBool)
  752. win_alert(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
  753. {
  754.     MochaDecoder *decoder;
  755.     MWContext *context;
  756.     char *message, *platform_message;
  757.     JSString * str;
  758.  
  759.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  760.         return JS_FALSE;
  761.     if (!(str = JS_ValueToString(cx, argv[0])))
  762.         return JS_FALSE;
  763.  
  764.     /* if there is no context let the script continue */
  765.     context = decoder->window_context;
  766.     if (!context)
  767.     return JS_TRUE;
  768.  
  769.     message = lm_StrToLocalEncoding(context, str);
  770.     
  771.     if (message) {
  772.         platform_message = lm_FixNewlines(cx, message, JS_FALSE); 
  773.         ET_PostMessageBox(context, platform_message, JS_FALSE);
  774.         XP_FREEIF(platform_message);
  775.     XP_FREE(message);
  776.     }
  777.     return JS_TRUE;
  778. }
  779.  
  780. PR_STATIC_CALLBACK(PRBool)
  781. win_confirm(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
  782. {
  783.     MochaDecoder *decoder;
  784.     MWContext *context;
  785.     JSString * str;
  786.     char *message;
  787.     JSBool ok;
  788.  
  789.     decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv);
  790.     if (!decoder)
  791.         return JS_FALSE;
  792.     if (!(str = JS_ValueToString(cx, argv[0])))
  793.         return JS_FALSE;
  794.  
  795.     context = decoder->window_context;
  796.     if (context) {
  797.     char *platform_message;
  798.     message = lm_StrToLocalEncoding(context, str);
  799.     if (!message) {
  800.         *rval = JSVAL_FALSE;
  801.         return JS_TRUE;
  802.     }
  803.         platform_message = lm_FixNewlines(cx, message, JS_FALSE);
  804.         ok = ET_PostMessageBox(context, platform_message, JS_TRUE);
  805.         XP_FREEIF(platform_message);
  806.     XP_FREE(message);
  807.     }
  808.     else {
  809.         ok = JS_FALSE;
  810.     }
  811.     *rval = BOOLEAN_TO_JSVAL(ok);
  812.     return JS_TRUE;
  813. }
  814.  
  815. PR_STATIC_CALLBACK(PRBool)
  816. win_prompt(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
  817. {
  818.     MochaDecoder *decoder;
  819.     MWContext *context;
  820.     jsval arg;
  821.     JSString *str;
  822.     char *retval;
  823.  
  824.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  825.         return JS_FALSE;
  826.     arg = argv[0];
  827.  
  828.     context = decoder->window_context;
  829.     if (context) {
  830.     char *query, *defval, *platform_query;
  831.  
  832.     /*
  833.      * Build the query_string
  834.      */
  835.     if (!(str = JS_ValueToString(cx, argv[0])))
  836.         return JS_FALSE;
  837.     query = lm_StrToLocalEncoding(context, str);
  838.     if (!query) {
  839.         JS_ReportOutOfMemory(cx);
  840.         return JS_FALSE;
  841.     }
  842.         platform_query = lm_FixNewlines(cx, query, JS_FALSE);
  843.  
  844.         /*
  845.      * Build the default value
  846.      */
  847.     if (!(str = JS_ValueToString(cx, argv[1]))) {
  848.             return JS_FALSE;
  849.         }
  850.     defval = lm_StrToLocalEncoding(context, str);
  851.  
  852.         retval = ET_PostPrompt(context, platform_query, defval);
  853.     XP_FREEIF(query);
  854.     XP_FREEIF(defval);
  855.         XP_FREEIF(platform_query);
  856.     } 
  857.     else {
  858.         retval = NULL;
  859.     }
  860.  
  861.     if (!retval) {
  862.         *rval = JSVAL_NULL;
  863.         return JS_TRUE;
  864.     }
  865.  
  866.     XP_ASSERT(context);
  867.     str = lm_LocalEncodingToStr(context, retval);
  868.     XP_FREE(retval);
  869.     if (!str)
  870.         return JS_FALSE;
  871.     *rval = STRING_TO_JSVAL(str);
  872.     return JS_TRUE;
  873. }
  874.  
  875. /*
  876.  * Open and close of a named window.
  877.  */
  878. JSBool
  879. lm_CheckWindowName(JSContext *cx, const char *window_name)
  880. {
  881.     const char *cp;
  882.  
  883.     for (cp = window_name; *cp != '\0'; cp++) {
  884.         if (!XP_IS_ALPHA(*cp) && !XP_IS_DIGIT(*cp) && *cp != '_') {
  885.             JS_ReportError(cx,
  886.                 "illegal character '%c' ('\\%o') in window name %s",
  887.                 *cp, *cp, window_name);
  888.             return JS_FALSE;
  889.         }
  890.     }
  891.     return JS_TRUE;
  892. }
  893.  
  894. static int32
  895. win_has_option(char *options, char *name)
  896. {
  897.     char *comma, *equal;
  898.     int32 found = 0;
  899.  
  900.     for (;;) {
  901.         comma = XP_STRCHR(options, ',');
  902.         if (comma) *comma = '\0';
  903.         equal = XP_STRCHR(options, '=');
  904.         if (equal) *equal = '\0';
  905.         if (XP_STRCASECMP(options, name) == 0) {
  906.             if (!equal || XP_STRCASECMP(equal + 1, "yes") == 0)
  907.                 found = 1;
  908.             else
  909.                 found = XP_ATOI(equal + 1);
  910.         }
  911.         if (equal) *equal = '=';
  912.         if (comma) *comma = ',';
  913.         if (found || !comma)
  914.             break;
  915.         options = comma + 1;
  916.     }
  917.     return found;
  918. }
  919.  
  920. /* These apply to top-level windows only, not to frames */
  921. static uint lm_window_count = 0;
  922. static uint lm_window_limit = 100;
  923.  
  924. /* XXX this can't be static yet, it's called by lm_doc.c/doc_open */
  925. JSBool PR_CALLBACK
  926. win_open(JSContext *cx, JSObject *obj,
  927.          uint argc, jsval *argv, jsval *rval)
  928. {
  929.     MochaDecoder *decoder, *new_decoder;
  930.     URL_Struct *url_struct;
  931.     JSString *str, *window_name_str;
  932.     const char *url_string;
  933.     char *window_name = NULL;
  934.     char *options;
  935.     Chrome *chrome = NULL;
  936.     MWContext *old_context, *context;
  937.     int32 width, height;
  938.     int32 win_width, win_height;
  939.  
  940.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  941.         return JS_FALSE;
  942.  
  943.     /* Make url_string absolute based on current document's base URL. */
  944.     url_struct = NULL;
  945.     if (argc > 0) {
  946.         if (!(str = JS_ValueToString(cx, argv[0])))
  947.             return JS_FALSE;
  948.         url_string = JS_GetStringBytes(str);
  949.         if (*url_string != '\0') {
  950.             url_string = lm_CheckURL(cx, url_string, JS_TRUE);
  951.             if (url_string) {
  952.                 const char *referer;
  953.                 url_struct = NET_CreateURLStruct(url_string, NET_DONT_RELOAD);
  954.                 XP_FREE((char *)url_string);
  955.                 if (!url_struct) {
  956.                     JS_ReportOutOfMemory(cx);
  957.                     return JS_FALSE;
  958.                 }
  959.                 if (!(referer = lm_GetSubjectOriginURL(cx)) ||
  960.             !(url_struct->referer = JS_strdup(cx, referer))) {
  961.             NET_FreeURLStruct(url_struct);
  962.             return JS_FALSE;
  963.         }
  964.             }
  965.         }
  966.         if (!url_string)
  967.             return JS_FALSE;
  968.     }
  969.  
  970.     /* Set this to null so we can goto fail from here onward. */
  971.     new_decoder = NULL;
  972.  
  973.     /* Sanity-check the optional window_name argument. */
  974.     if (argc > 1) {
  975.         if (!(window_name_str = JS_ValueToString(cx, argv[1])))
  976.             goto fail;
  977.         if (!JS_LockGCThing(cx, window_name_str))
  978.             goto fail;
  979.     /* XXXunicode ? */
  980.         window_name = lm_StrToLocalEncoding(decoder->window_context, window_name_str);
  981.         if (!lm_CheckWindowName(cx, window_name))
  982.             goto fail;
  983.     } else {
  984.         window_name_str = NULL;
  985.         window_name = NULL;
  986.     }
  987.  
  988.     /* Check for window chrome options. */
  989.     chrome = XP_NEW_ZAP(Chrome);
  990.     if(chrome == NULL)
  991.         goto fail;
  992.     if (argc > 2) {
  993.         if (!(str = JS_ValueToString(cx, argv[2])))
  994.             goto fail;
  995.         options = JS_GetStringBytes(str);
  996.  
  997.         chrome->show_button_bar        = win_has_option(options, "toolbar");
  998.         chrome->show_url_bar           = win_has_option(options, "location");
  999.         chrome->show_directory_buttons =
  1000.             win_has_option(options, "directories") | win_has_option(options, "personalbar");
  1001.         chrome->show_bottom_status_bar = win_has_option(options, "status");
  1002.         chrome->show_menu              = win_has_option(options, "menubar");
  1003.         chrome->show_security_bar      = FALSE;
  1004.         chrome->w_hint                 =
  1005.             win_has_option(options, "innerWidth") | win_has_option(options, "width");
  1006.         chrome->h_hint                 =
  1007.             win_has_option(options, "innerHeight") | win_has_option(options, "height");
  1008.         chrome->outw_hint              = win_has_option(options, "outerWidth");
  1009.         chrome->outh_hint              = win_has_option(options, "outerHeight");
  1010.         chrome->l_hint                 =
  1011.             win_has_option(options, "left") | win_has_option(options, "screenX");
  1012.         chrome->t_hint                 =
  1013.             win_has_option(options, "top") | win_has_option(options, "screenY");
  1014.         chrome->show_scrollbar         = win_has_option(options, "scrollbars");
  1015.         chrome->allow_resize           = win_has_option(options, "resizable");
  1016.         chrome->allow_close            = TRUE;
  1017.         chrome->dependent              = win_has_option(options, "dependent");
  1018.         chrome->copy_history           = FALSE; /* XXX need strong trust */
  1019.         chrome->topmost         = win_has_option(options, "alwaysRaised");
  1020.         chrome->bottommost              = win_has_option(options, "alwaysLowered");
  1021.         chrome->z_lock          = win_has_option(options, "z-lock");
  1022.         chrome->is_modal            = win_has_option(options, "modal");
  1023.         chrome->hide_title_bar  = !(win_has_option(options, "titlebar"));
  1024.  
  1025.         /* Allow disabling of commands only if there is no menubar */
  1026.         if (!chrome->show_menu) {
  1027.             chrome->disable_commands = !win_has_option(options, "hotkeys");
  1028.             if (XP_STRCASESTR(options,"hotkeys")==NULL)
  1029.                 chrome->disable_commands = FALSE;
  1030.         }
  1031.         /* If titlebar condition not specified, default to shown */
  1032.         if (XP_STRCASESTR(options,"titlebar")==0)
  1033.             chrome->hide_title_bar=FALSE;
  1034.  
  1035.         if (chrome->topmost || chrome->bottommost || 
  1036.             chrome->z_lock || chrome->is_modal || 
  1037.             chrome->hide_title_bar || chrome->disable_commands) {
  1038.             if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
  1039.                 chrome->topmost = chrome->bottommost =
  1040.                 chrome->z_lock = chrome->is_modal =
  1041.                 chrome->hide_title_bar = chrome->disable_commands = 0;
  1042.             }
  1043.         }
  1044.  
  1045.         /* In order to not start Java for every single window open we 
  1046.      * have to first check if we need to check, and then check.  
  1047.          * Start by getting width and height to use for positioning 
  1048.      * calculations. Defaults to 100 if neither are specified.
  1049.      * Then get screen size.
  1050.      */
  1051.     win_width = chrome->w_hint ? chrome->w_hint : 
  1052.             (chrome->outw_hint ? chrome->outw_hint : 100);
  1053.     win_height = chrome->h_hint ? chrome->h_hint : 
  1054.             (chrome->outh_hint ? chrome->outh_hint : 100);
  1055.         ET_PostGetScreenSize(decoder->window_context, &width, &height);
  1056.         if ((chrome->w_hint && chrome->w_hint < 100) ||
  1057.             (chrome->h_hint && chrome->h_hint < 100) ||
  1058.             (chrome->outw_hint && chrome->outw_hint < 100) ||
  1059.             (chrome->outh_hint && chrome->outh_hint < 100) ||
  1060.             (width < chrome->l_hint + win_width) ||
  1061.             (chrome->l_hint < 0) ||
  1062.             (height < chrome->t_hint + win_height) ||
  1063.             (chrome->t_hint < 0)) {
  1064.             /* The window is trying to put a window offscreen or make it too
  1065.              * small.  We have to check the security permissions 
  1066.              */
  1067.             if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
  1068.                 /* Make sure windows are at least 100 by 100 pixels. */
  1069.                 if (chrome->w_hint && chrome->w_hint < 100) {
  1070.             chrome->w_hint = 100;
  1071.             win_width = 100;
  1072.         }
  1073.                 if (chrome->h_hint && chrome->h_hint < 100) {
  1074.             chrome->h_hint = 100;
  1075.             win_height = 100;
  1076.         }
  1077.                 if (chrome->outw_hint && chrome->outw_hint < 100) {
  1078.             chrome->outw_hint = 100;
  1079.             win_width = 100;
  1080.         }
  1081.                 if (chrome->outh_hint && chrome->outh_hint < 100) {
  1082.             chrome->outh_hint = 100;
  1083.             win_height = 100;
  1084.         }
  1085.                 /* Windows must be positioned on screen without security */
  1086.                 chrome->l_hint = (width < chrome->l_hint + win_width) ?
  1087.                                     width - win_width : chrome->l_hint;
  1088.                 chrome->l_hint = (chrome->l_hint < 0) ? 0 : chrome->l_hint;
  1089.                 chrome->t_hint = (height < chrome->t_hint + win_height) ?
  1090.                                     height - win_height : chrome->t_hint;
  1091.                 chrome->t_hint = (chrome->t_hint < 0) ? 0 : chrome->t_hint;
  1092.             }
  1093.         } 
  1094.         /* Make sure they always at least 10 x 10 regardless of security. 1 x 1
  1095.          * windows are really hard to spot */
  1096.         if (chrome->w_hint && chrome->w_hint < 10) chrome->w_hint = 10;
  1097.         if (chrome->h_hint && chrome->h_hint < 10) chrome->h_hint = 10;
  1098.         if (chrome->outw_hint && chrome->outw_hint < 10) chrome->outw_hint = 10;
  1099.         if (chrome->outh_hint && chrome->outh_hint < 10) chrome->outh_hint = 10;
  1100.  
  1101.         /* You must specify both width and height to get either */
  1102.         if (chrome->w_hint == 0 || chrome->h_hint == 0)
  1103.             chrome->w_hint = chrome->h_hint = 0;
  1104.         if (chrome->outw_hint == 0 || chrome->outh_hint == 0)
  1105.             chrome->outw_hint = chrome->outh_hint = 0;
  1106.  
  1107.         /* Needed to allow positioning of windows at 0,0 */
  1108.         if ((XP_STRCASESTR(options,"top") || XP_STRCASESTR(options,"left") ||
  1109.                     XP_STRCASESTR(options,"screenX") || XP_STRCASESTR(options,"screenY")) != 0)
  1110.             chrome->location_is_chrome=TRUE;
  1111.  
  1112.         options = 0;
  1113.     } else {
  1114.         /* Make a fully chromed window, but don't copy history. */
  1115.         chrome->show_button_bar        = TRUE;
  1116.         chrome->show_url_bar           = TRUE;
  1117.         chrome->show_directory_buttons = TRUE;
  1118.         chrome->show_bottom_status_bar = TRUE;
  1119.         chrome->show_menu              = TRUE;
  1120.         chrome->show_security_bar      = FALSE;
  1121.         chrome->w_hint = chrome->h_hint = 0;
  1122.         chrome->is_modal               = FALSE;
  1123.         chrome->show_scrollbar         = TRUE;
  1124.         chrome->allow_resize           = TRUE;
  1125.         chrome->allow_close            = TRUE;
  1126.         chrome->copy_history           = FALSE; /* XXX need strong trust */
  1127.     }
  1128.  
  1129.     /* Windows created by JS cannot be randomly used by Mail/News */
  1130.     chrome->restricted_target = TRUE;
  1131.         
  1132.     old_context = decoder->window_context;
  1133.     if (!old_context)
  1134.         goto fail;
  1135.     if (window_name)
  1136.         context = XP_FindNamedContextInList(old_context, (char*)window_name);
  1137.     else
  1138.         context = NULL;
  1139.  
  1140.     if (context) {
  1141.         new_decoder = LM_GetMochaDecoder(context);
  1142.         if (!new_decoder)
  1143.             goto fail;
  1144.         if (url_struct && !lm_GetURL(cx, new_decoder, url_struct)) {
  1145.             url_struct = 0;
  1146.             goto fail;
  1147.         }
  1148.         /* lm_GetURL() stashed a url_struct pointer, and owns it now. */
  1149.         url_struct = 0;
  1150.  
  1151.     /* If specific options are specified we will update the named
  1152.      * window to match those options.  If not, we won't change them */
  1153.     if (argc > 2)
  1154.         ET_PostUpdateChrome(context, chrome);
  1155.     } else {
  1156.         if (lm_window_count >= lm_window_limit)
  1157.             goto fail;
  1158.         context = ET_PostNewWindow(old_context, url_struct,
  1159.                                    (char*)window_name,
  1160.                                    chrome);
  1161.         if (!context)
  1162.             goto fail;
  1163.         /* ET_PostNewWindow() stashed a url_struct pointer, and owns it now. */
  1164.         url_struct = 0;
  1165.         new_decoder = LM_GetMochaDecoder(context);
  1166.         if (!new_decoder) {
  1167.             (void) ET_PostDestroyWindow(context);
  1168.             goto fail;
  1169.         }
  1170.     }
  1171.  
  1172.     new_decoder->opener = obj;
  1173.     if (!JS_DefinePropertyWithTinyId(cx, new_decoder->window_object, 
  1174.                                      lm_opener_str, WIN_OPENER, 
  1175.                                      OBJECT_TO_JSVAL(obj),
  1176.                                      NULL, NULL, JSPROP_ENUMERATE)) {
  1177.         goto fail;
  1178.     }
  1179.     JS_UnlockGCThing(cx, window_name_str);
  1180.     new_decoder->in_window_quota = JS_TRUE;
  1181.     lm_window_count++;
  1182.     LM_PutMochaDecoder(new_decoder);
  1183.     *rval = OBJECT_TO_JSVAL(new_decoder->window_object);
  1184.     XP_FREE(chrome);
  1185.     XP_FREEIF(window_name);
  1186.     return JS_TRUE;
  1187.  
  1188. fail:
  1189.     if (window_name_str)
  1190.         JS_UnlockGCThing(cx, window_name_str);
  1191.     if (new_decoder)
  1192.         LM_PutMochaDecoder(new_decoder);
  1193.     if (url_struct)
  1194.         NET_FreeURLStruct(url_struct);
  1195.     XP_FREEIF(chrome);
  1196.     XP_FREEIF(window_name);
  1197.     *rval = JSVAL_NULL;
  1198.     return JS_TRUE;
  1199. }
  1200.  
  1201. PR_STATIC_CALLBACK(JSBool)
  1202. win_set_zoptions(JSContext *cx, JSObject *obj,
  1203.          uint argc, jsval *argv, jsval *rval)
  1204. {
  1205.     MochaDecoder *decoder;
  1206.     JSString *str;
  1207.     char *options;
  1208.     Chrome *chrome = NULL;
  1209.  
  1210.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  1211.         return JS_FALSE;
  1212.     if (argc != 1) {
  1213.         JS_ReportError(cx, lm_argc_err_str);
  1214.         return JS_FALSE;
  1215.     }
  1216.     if (!decoder->window_context)
  1217.         return JS_TRUE;
  1218.  
  1219.     /* Check for window chrome options. */
  1220.     chrome = win_get_chrome(decoder->window_context, chrome);
  1221.     if(chrome == NULL)
  1222.         return JS_FALSE;
  1223.  
  1224.     if (!(str = JS_ValueToString(cx, argv[0])))
  1225.         return JS_TRUE;
  1226.     options = JS_GetStringBytes(str);
  1227.  
  1228.     if (lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
  1229.         chrome->topmost         = win_has_option(options, "alwaysRaised");
  1230.         chrome->bottommost      = win_has_option(options, "alwaysLowered");
  1231.         chrome->z_lock          = win_has_option(options, "z-lock");
  1232.     }
  1233.  
  1234.     ET_PostUpdateChrome(decoder->window_context, chrome);
  1235.  
  1236.     options = 0;
  1237.     JS_free(cx, chrome);
  1238.     return JS_TRUE;
  1239. }
  1240.  
  1241. PR_STATIC_CALLBACK(JSBool)
  1242. win_set_hotkeys(JSContext *cx, JSObject *obj,
  1243.          uint argc, jsval *argv, jsval *rval)
  1244. {
  1245.     MochaDecoder *decoder;
  1246.     Chrome *chrome = NULL;
  1247.  
  1248.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  1249.         return JS_FALSE;
  1250.     if (argc != 1) {
  1251.         JS_ReportError(cx, lm_argc_err_str);
  1252.         return JS_FALSE;
  1253.     }
  1254.     if (!decoder->window_context)
  1255.         return JS_TRUE;
  1256.  
  1257.     /* Check for window chrome options. */
  1258.     chrome = win_get_chrome(decoder->window_context, chrome);
  1259.     if(chrome == NULL)
  1260.         return JS_FALSE;
  1261.  
  1262.     if(JSVAL_IS_BOOLEAN(argv[0])) {
  1263.         if (lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
  1264.             if (!chrome->show_menu) {
  1265.                 chrome->disable_commands = !JSVAL_TO_BOOLEAN(argv[0]);
  1266.             }
  1267.         }
  1268.     }
  1269.  
  1270.     ET_PostUpdateChrome(decoder->window_context, chrome);
  1271.  
  1272.     JS_free(cx, chrome);
  1273.     return JS_TRUE;
  1274. }
  1275.  
  1276. PR_STATIC_CALLBACK(JSBool)
  1277. win_set_resizable(JSContext *cx, JSObject *obj,
  1278.          uint argc, jsval *argv, jsval *rval)
  1279. {
  1280.     MochaDecoder *decoder;
  1281.     Chrome *chrome = NULL;
  1282.  
  1283.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  1284.         return JS_FALSE;
  1285.     if (argc != 1) {
  1286.         JS_ReportError(cx, lm_argc_err_str);
  1287.         return JS_FALSE;
  1288.     }
  1289.     if (!decoder->window_context)
  1290.         return JS_TRUE;
  1291.  
  1292.     /* Check for window chrome options. */
  1293.     chrome = win_get_chrome(decoder->window_context, chrome);
  1294.     if(chrome == NULL)
  1295.         return JS_FALSE;
  1296.  
  1297.     if(JSVAL_IS_BOOLEAN(argv[0])) {
  1298.         chrome->allow_resize = JSVAL_TO_BOOLEAN(argv[0]);
  1299.     }
  1300.  
  1301.     ET_PostUpdateChrome(decoder->window_context, chrome);
  1302.  
  1303.     JS_free(cx, chrome);
  1304.     return JS_TRUE;
  1305. }
  1306.  
  1307. static void
  1308. destroy_window(void *closure)
  1309. {
  1310.     MWContext * context = (MWContext *)
  1311.             ((MozillaEvent_Timeout *)closure)->pClosure;
  1312.     ET_PostDestroyWindow(context);
  1313. }
  1314.  
  1315. PR_STATIC_CALLBACK(PRBool)
  1316. win_close(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
  1317. {
  1318.     MochaDecoder *decoder;
  1319.     MochaDecoder *running_decoder;
  1320.     MWContext *context;
  1321.     char *message;
  1322.     JSBool ok;
  1323.  
  1324.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  1325.         return JS_FALSE;
  1326.     context = decoder->window_context;
  1327.     if (!context || context->grid_parent)
  1328.         return JS_TRUE;
  1329.     running_decoder = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
  1330.     /* Bypass close window check if script is signed */
  1331.     if (context->type != MWContextBrowser && context->type != MWContextPane ||
  1332.         (!decoder->opener &&
  1333.          (XP_ListCount(SHIST_GetList(context)) > 1 ||
  1334.           decoder != running_decoder)) &&
  1335.           !lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
  1336.         /*
  1337.          * Prevent this window.close() call if this window
  1338.          * - is not a browser window, or
  1339.          * - was not opened by javascript, and
  1340.          * - has session history other than the current document, or
  1341.          * - does not contain the script that is closing this window.
  1342.          * - has no security privileges.
  1343.          */
  1344.         if (context->name)
  1345.             message = PR_smprintf(XP_GetString(XP_MSG_JS_CLOSE_WINDOW_NAME),
  1346.                                   context->name);
  1347.         else
  1348.             message = XP_GetString(XP_MSG_JS_CLOSE_WINDOW);
  1349.         ok = ET_PostMessageBox(context, message, JS_TRUE);
  1350.         if (context->name)
  1351.             XP_FREE(message);
  1352.         if (!ok)
  1353.             return JS_TRUE;
  1354.     }
  1355.     if(!decoder->called_win_close) {
  1356.         decoder->called_win_close = JS_TRUE;
  1357.     /* 
  1358.      * If we are closing the window that the script is running in
  1359.      *   wait until the script has finished running before sending
  1360.      *   the close message
  1361.      */
  1362.     if (decoder == running_decoder)
  1363.         ET_PostSetTimeout(destroy_window, context, 0, XP_DOCID(context));
  1364.     else
  1365.             ET_PostDestroyWindow(context);
  1366.  
  1367.     }
  1368.  
  1369.     return JS_TRUE;
  1370. }
  1371.  
  1372. /*
  1373.  * Timeout support.
  1374.  */
  1375. static uint  lm_timeout_count = 0;
  1376. static uint  lm_timeout_limit = 1000;
  1377.  
  1378. #define HOLD_TIMEOUT(cx,to) ((to)->ref_count++)
  1379. #define DROP_TIMEOUT(decoder,to)                                             \
  1380.     NSPR_BEGIN_MACRO                                                         \
  1381.         XP_ASSERT((to)->ref_count > 0);                                      \
  1382.         if (--(to)->ref_count == 0)                                          \
  1383.             free_timeout(decoder,to);                                        \
  1384.     NSPR_END_MACRO
  1385.  
  1386. static void
  1387. free_timeout(MochaDecoder *decoder, JSTimeout *timeout)
  1388. {
  1389.     MWContext *context;
  1390.     JSContext *cx;
  1391.  
  1392.     cx = decoder->js_context;
  1393.     context = decoder->window_context;
  1394.     if (context) {
  1395.         XP_ASSERT(context->js_timeouts_pending > 0);
  1396.         context->js_timeouts_pending--;
  1397.     }
  1398.  
  1399.     if (timeout->expr)
  1400.         JS_free(cx, timeout->expr);
  1401.     else if (timeout->funobj) {
  1402.         JS_RemoveRoot(cx, &timeout->funobj);
  1403.         if (timeout->argv) {
  1404.             int i;
  1405.             for (i = 0; i < timeout->argc; i++)
  1406.                 JS_RemoveRoot(cx, &timeout->argv[i]);
  1407.             JS_free(cx, timeout->argv);
  1408.         }
  1409.     }
  1410.     if (timeout->principals)
  1411.         JSPRINCIPALS_DROP(cx, timeout->principals);
  1412.     XP_FREEIF(timeout->filename);
  1413.     JS_free(cx, timeout);
  1414.     lm_timeout_count--;
  1415. }
  1416.  
  1417. /* Re-insert timeout before the first list item with greater deadline, or at
  1418.  * the head if the list is empty, or at the tail if there is no item with
  1419.  * greater deadline.
  1420.  * Through the righteousness of double-indirection we do this without two
  1421.  * ugly if-tests.
  1422.  */
  1423. static void
  1424. insert_timeout_into_list(JSTimeout **listp, JSTimeout *timeout)
  1425. {
  1426.     JSTimeout *to;
  1427.  
  1428.     while ((to = *listp) != NULL) {
  1429.         if (LL_CMP(to->when, >, timeout->when))
  1430.             break;
  1431.         listp = &to->next;
  1432.     }
  1433.     timeout->next = to;
  1434.     *listp = timeout;
  1435. }
  1436.  
  1437. static JSTimeout *js_timeout_running = NULL;
  1438. static JSTimeout **js_timeout_insertion_point = NULL;
  1439.  
  1440. static void
  1441. win_run_timeout(void *closure)
  1442. {
  1443.     JSTimeout *timeout, *next;
  1444.     JSTimeout *last_expired_timeout;
  1445.     JSTimeout dummy_timeout;
  1446.     MochaDecoder *decoder;
  1447.     JSContext *cx;
  1448.     int64 now;
  1449.     jsval result;
  1450.     MWContext * context = (MWContext *)((MozillaEvent_Timeout *)closure)->pClosure;
  1451.     void *timer_id;
  1452.  
  1453.     /* make sure the context hasn't disappeared out from under us */
  1454.     if (!XP_IsContextInList(context))
  1455.         return;
  1456.  
  1457.     timer_id = ((MozillaEvent_Timeout *)closure)->pTimerId;
  1458.  
  1459.     decoder = LM_GetMochaDecoder(context);
  1460.     if (!decoder)
  1461.         return;
  1462.  
  1463.     if (!decoder->timeouts) {
  1464.         LM_PutMochaDecoder(decoder);
  1465.         return;
  1466.     }
  1467.  
  1468.     cx = decoder->js_context;
  1469.  
  1470.     /*
  1471.      * A front end timer has gone off.  See which of our timeouts need
  1472.      *   servicing
  1473.      */
  1474. restart:
  1475.     LL_I2L(now, PR_IntervalNow());
  1476.  
  1477.     /* The timeout list is kept in deadline order.  Discover the
  1478.        latest timeout whose deadline has expired. On some platforms,
  1479.        front-end timeout events fire "early", so we need to test the
  1480.        timer_id as well as the deadline. */
  1481.     last_expired_timeout = NULL;
  1482.     for (timeout = decoder->timeouts; timeout; timeout = timeout->next) {
  1483.         if ((timer_id == timeout->toid) || !LL_CMP(timeout->when, >, now))
  1484.             last_expired_timeout = timeout;
  1485.     }
  1486.  
  1487.     /* Maybe the timeout that the event was fired for has been deleted
  1488.        and there are no others timeouts with deadlines that make them
  1489.        eligible for execution yet.  Go away. */
  1490.     if (!last_expired_timeout)
  1491.         return;
  1492.  
  1493.     /* Insert a dummy timeout into the list of timeouts between the portion
  1494.        of the list that we are about to process now and those timeouts that
  1495.        will be processed in a future call to win_run_timeout().  This dummy
  1496.        timeout serves as the head of the list for any timeouts inserted as
  1497.        a result of running a timeout. */
  1498.     dummy_timeout.toid = NULL;
  1499.     dummy_timeout.public_id = 0;
  1500.     dummy_timeout.next = last_expired_timeout->next;
  1501.     last_expired_timeout->next = &dummy_timeout;
  1502.  
  1503.     /* Don't let lm_ClearWindowTimeouts throw away our stack-allocated
  1504.        dummy timeout. */
  1505.     dummy_timeout.ref_count = 2;
  1506.    
  1507.     XP_ASSERT(!js_timeout_insertion_point);
  1508.     js_timeout_insertion_point = &dummy_timeout.next;
  1509.     
  1510.     for (timeout = decoder->timeouts; timeout != &dummy_timeout; timeout = next) {
  1511.         next = timeout->next;
  1512.  
  1513.         /*
  1514.          * make sure the document that asked for this timeout is still
  1515.          *   the active document
  1516.          */
  1517.         if (timeout->doc_id != XP_DOCID(decoder->window_context)) {
  1518. #ifdef DEBUG_chouck
  1519.             XP_TRACE(("DOCID: in win_run_timeout"));
  1520. #endif
  1521.             /* make sure this gets removed from the list */
  1522.             decoder->timeouts = next;
  1523.             DROP_TIMEOUT(decoder, timeout);
  1524.             continue;
  1525.         }
  1526.  
  1527.         /* Hold the timeout in case expr or funobj releases its doc. */
  1528.         HOLD_TIMEOUT(cx, timeout);
  1529.         js_timeout_running = timeout;
  1530.  
  1531.         if (timeout->expr) {
  1532.             /* Evaluate the timeout expression. */
  1533.             JSVersion save = JS_SetVersion(decoder->js_context, 
  1534.                                            timeout->version);
  1535.             JS_EvaluateScriptForPrincipals(decoder->js_context, 
  1536.                                            decoder->window_object,
  1537.                                            timeout->principals, 
  1538.                                            timeout->expr, 
  1539.                                            XP_STRLEN(timeout->expr),
  1540.                                            timeout->filename, timeout->lineno, 
  1541.                                            &result);
  1542.             JS_SetVersion(decoder->js_context, save);
  1543.         } else {
  1544.             int64 lateness64;
  1545.             int32 lateness;
  1546.  
  1547.             /* Add "secret" final argument that indicates timeout
  1548.                lateness in milliseconds */
  1549.             LL_SUB(lateness64, now, timeout->when);
  1550.             LL_L2I(lateness, lateness64);
  1551.             timeout->argv[timeout->argc] = INT_TO_JSVAL((jsint)lateness);
  1552.             JS_CallFunctionValue(cx, decoder->window_object,
  1553.                                  OBJECT_TO_JSVAL(timeout->funobj),
  1554.                                  timeout->argc + 1, timeout->argv, &result);
  1555.         }
  1556.  
  1557.         /* If timeout's reference count is now 1, its doc was released
  1558.          * and we should restart this function.
  1559.          */
  1560.         js_timeout_running = NULL;
  1561.         if (timeout->ref_count == 1) {
  1562.             free_timeout(decoder, timeout);
  1563.             goto restart;
  1564.         }
  1565.         DROP_TIMEOUT(decoder, timeout);
  1566.  
  1567.         /* If we have a regular interval timer, we re-fire the
  1568.          *  timeout, accounting for clock drift.
  1569.          */
  1570.         if (timeout->interval) {
  1571.             /* Compute time to next timeout for interval timer. */
  1572.             int32 delay32;
  1573.             int64 interval, delay;
  1574.             LL_I2L(interval, timeout->interval);
  1575.             LL_ADD(timeout->when, timeout->when, interval);
  1576.             LL_I2L(now, PR_IntervalNow());
  1577.             LL_SUB(delay, timeout->when, now);
  1578.             LL_L2I(delay32, delay);
  1579.  
  1580.             /* If the next interval timeout is already supposed to
  1581.              *  have happened then run the timeout immediately.
  1582.              */
  1583.             if (delay32 < 0)
  1584.                 delay32 = 0;
  1585.  
  1586.             /* Reschedule timeout.  Account for possible error return in
  1587.                code below that checks for zero toid. */
  1588.             timeout->toid = ET_PostSetTimeout(win_run_timeout,
  1589.                                               decoder->window_context,
  1590.                                               (uint32)delay32,
  1591.                                               decoder->doc_id);
  1592.         }
  1593.  
  1594.         /* Running a timeout can cause another timeout to be deleted,
  1595.            so we need to reset the pointer to the following timeout. */
  1596.         next = timeout->next;
  1597.         decoder->timeouts = next;
  1598.  
  1599.         /* Free the timeout if this is not a repeating interval
  1600.          *  timeout (or if it was an interval timeout, but we were
  1601.          *  unsuccessful at rescheduling it.)
  1602.          */
  1603.         if (!timeout->interval || !timeout->toid) {
  1604.             DROP_TIMEOUT(decoder, timeout);
  1605.         } else {
  1606.             /* Reschedule an interval timeout */
  1607.             /* Insert interval timeout onto list sorted in deadline order. */
  1608.             insert_timeout_into_list(js_timeout_insertion_point, timeout);
  1609.         }
  1610.     }
  1611.  
  1612.     /* Take the dummy timeout off the head of the list */
  1613.     XP_ASSERT(decoder->timeouts == &dummy_timeout);
  1614.     decoder->timeouts = dummy_timeout.next;
  1615.     js_timeout_insertion_point = NULL;
  1616.  
  1617.     LM_PutMochaDecoder(decoder);
  1618. }
  1619.  
  1620. void
  1621. lm_ClearWindowTimeouts(MochaDecoder *decoder)
  1622. {
  1623.     JSTimeout *timeout, *next;
  1624.  
  1625.     for (timeout = decoder->timeouts; timeout; timeout = next) {
  1626.         /* If win_run_timeouts() is higher up on the stack for this
  1627.            decoder, e.g. as a result of document.write from a timeout,
  1628.            then we need to reset the list insertion point for
  1629.            newly-created timeouts in case the user adds a timeout,
  1630.            before we pop the stack back to win_run_timeouts(). */
  1631.         if (js_timeout_running == timeout)
  1632.             js_timeout_insertion_point = NULL;
  1633.         
  1634.         next = timeout->next;
  1635.         if (timeout->toid)
  1636.             ET_PostClearTimeout(timeout->toid);
  1637.         timeout->toid = NULL;
  1638.         DROP_TIMEOUT(decoder, timeout);
  1639.     }
  1640.  
  1641.     for (timeout = decoder->saved_timeouts; timeout; timeout = next) {
  1642.         next = timeout->next;
  1643.         DROP_TIMEOUT(decoder, timeout);
  1644.     }
  1645.  
  1646.     decoder->timeouts = NULL;
  1647.     decoder->saved_timeouts = NULL;
  1648. }
  1649.  
  1650. /*
  1651.  * Stop time temporarily till we restore the timeouts. The timeouts
  1652.  * are cancelled with the FE, the current time is recorded and
  1653.  * the timeout list is saved.
  1654.  */
  1655. void
  1656. lm_SaveWindowTimeouts(MochaDecoder *decoder)
  1657. {
  1658.     JSTimeout *timeout;
  1659.     int64 now, time_left;
  1660.  
  1661.     if (!decoder->timeouts)
  1662.         return;
  1663.     
  1664.     LL_I2L(now, PR_IntervalNow());
  1665.  
  1666.     /* 
  1667.      * Clear all the timeouts so that they don't fire till we're
  1668.      * ready to restart time.
  1669.      */
  1670.     for (timeout = decoder->timeouts; timeout; timeout = timeout->next) {
  1671.         ET_PostClearTimeout(timeout->toid);
  1672.         /* Figure out how much time was left before the timeout fired */
  1673.         LL_SUB(time_left, timeout->when, now);
  1674.         timeout->when = time_left;
  1675.     }
  1676.  
  1677.     decoder->saved_timeouts = decoder->timeouts;
  1678.     decoder->timeouts = NULL;
  1679. }
  1680.  
  1681. /*
  1682.  * Restore timeouts from the saved_timeouts list and restart time. 
  1683.  * These are timeouts that were suspended while we were reloading
  1684.  * the document.
  1685.  */
  1686. void
  1687. lm_RestoreWindowTimeouts(MochaDecoder *decoder)
  1688. {
  1689.     JSTimeout *timeout, *next;
  1690.     int64 now, when;
  1691.     int interval;
  1692.     JSBool fire_now = JS_FALSE;
  1693.  
  1694.     if (!decoder->saved_timeouts)
  1695.         return;
  1696.     
  1697.     LL_I2L(now, PR_IntervalNow());
  1698.  
  1699.     for (timeout = decoder->saved_timeouts; timeout; timeout = next) {
  1700.         next = timeout->next;
  1701.         
  1702.         LL_L2I(interval, timeout->when);
  1703.         /* Unclear if result can be one of the operands */
  1704.         LL_ADD(when, timeout->when, now);
  1705.         timeout->when = when;
  1706.  
  1707.         timeout->doc_id = decoder->doc_id;
  1708.  
  1709.         /* 
  1710.          * If we don't have to fire this timeout now, we tell the
  1711.          * FE to call us back.
  1712.          */
  1713.         if (interval > 0) {
  1714.             timeout->toid = ET_PostSetTimeout(win_run_timeout,
  1715.                                               decoder->window_context,
  1716.                                               (uint32)interval,
  1717.                                               decoder->doc_id);
  1718.         }
  1719.         else {
  1720.             timeout->toid = NULL;
  1721.             fire_now = JS_TRUE;
  1722.         }
  1723.  
  1724.         insert_timeout_into_list(&decoder->timeouts, timeout);
  1725.     }
  1726.  
  1727.     decoder->saved_timeouts = NULL;
  1728.     
  1729.     /*
  1730.      * If there are any timeouts that are ready to go, have them fired
  1731.      * off immediately.
  1732.      */
  1733.     if (fire_now) {
  1734.         MozillaEvent_Timeout e;
  1735.         
  1736.         e.ce.doc_id = decoder->doc_id;
  1737.         e.pClosure = decoder->window_context;
  1738.         e.pTimerId = NULL;
  1739.         e.ulTime = 0;
  1740.         
  1741.         win_run_timeout((void *)&e);
  1742.     }
  1743. }
  1744.  
  1745. static timeout_public_id_counter = 0;
  1746.  
  1747. static const char setTimeout_str[]  = "setTimeout";
  1748. static const char setInterval_str[] = "setInterval";
  1749. static const char *time_methods[2]  = { setTimeout_str, setInterval_str };
  1750.  
  1751. static JSBool
  1752. win_set_timeout_or_interval(JSContext *cx, JSObject *obj,
  1753.                             uint argc, jsval *argv, jsval *rval,
  1754.                             JSBool interval_timer)
  1755. {
  1756.     MWContext *context;
  1757.     MochaDecoder *decoder;
  1758.     jsdouble interval;
  1759.     JSString *str;
  1760.     char *expr;
  1761.     JSTimeout *timeout, **insertion_point;
  1762.     int64 now, delta;
  1763.     JSObject *funobj;
  1764.     JSStackFrame *fp;
  1765.  
  1766.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  1767.         return JS_FALSE;
  1768.  
  1769.     if (lm_timeout_count >= lm_timeout_limit) {
  1770.         JS_ReportError(cx, "too many timeouts and intervals");
  1771.         return JS_FALSE;
  1772.     }
  1773.  
  1774.     if (!JS_ValueToNumber(cx, argv[1], &interval))
  1775.         return JS_FALSE;
  1776.  
  1777.     switch (JS_TypeOfValue(cx, argv[0])) {
  1778.       case JSTYPE_FUNCTION:
  1779.         funobj = JSVAL_TO_OBJECT(argv[0]);
  1780.         expr = NULL;
  1781.         break;
  1782.       case JSTYPE_STRING:
  1783.       case JSTYPE_OBJECT:
  1784.         if (!(str = JS_ValueToString(cx, argv[0])))
  1785.             return JS_FALSE;
  1786.         expr = JS_strdup(cx, JS_GetStringBytes(str));
  1787.         if (!expr)
  1788.             return JS_FALSE;
  1789.         funobj = NULL;
  1790.         break;
  1791.       default:
  1792.         JS_ReportError(cx, "useless %s call (missing quotes around argument?)",
  1793.                        time_methods[interval_timer]);
  1794.         return JS_FALSE;
  1795.     }
  1796.  
  1797.     timeout = JS_malloc(cx, sizeof *timeout);
  1798.     if (!timeout) {
  1799.         JS_free(cx, expr);
  1800.         return JS_FALSE;
  1801.     }
  1802.     XP_BZERO(timeout, sizeof *timeout);
  1803.     timeout->ref_count = 1;
  1804.     if (interval_timer)
  1805.         timeout->interval = (int32)interval;
  1806.     timeout->expr = expr;
  1807.     timeout->funobj = funobj;
  1808.     timeout->version = JS_GetVersion(cx);
  1809.     timeout->principals = lm_GetPrincipalsFromStackFrame(cx);
  1810.     if (timeout->principals == NULL) {
  1811.         /* Result of out of memory error */
  1812.         DROP_TIMEOUT(decoder, timeout);
  1813.         return JS_FALSE;
  1814.     }
  1815.     JSPRINCIPALS_HOLD(cx, timeout->principals);
  1816.  
  1817.     fp = NULL;
  1818.     while ((fp = JS_FrameIterator(cx, &fp)) != NULL) {
  1819.         JSScript *script = JS_GetFrameScript(cx, fp);
  1820.         if (script) {
  1821.             /*
  1822.              * XXX - Disable error reporter; we may get an error
  1823.              * trying to find a line number. Two cases where we
  1824.              * get an error is in evaluating an expression as part
  1825.              * of the preferences code, and evaluating a javascript:
  1826.              * typein. In both cases there are no newlines and no
  1827.              * source annotations are generated, and the initial
  1828.              * linenumber is specified as zero. We need to clean
  1829.              * up all those cases and then remove the error reporter
  1830.              * workaround.
  1831.              */
  1832.             JSErrorReporter reporter = JS_SetErrorReporter(cx, NULL);
  1833.             const char *filename = JS_GetScriptFilename(cx, script);
  1834.             timeout->filename = filename ? XP_STRDUP(filename) : NULL;
  1835.             timeout->lineno = JS_PCToLineNumber(cx, script, 
  1836.                                                 JS_GetFramePC(cx, fp));
  1837.             JS_SetErrorReporter(cx, reporter);
  1838.             break;
  1839.         }
  1840.     }
  1841.  
  1842.     /* Keep track of any pending timeouts so that FE can tell whether
  1843.        the stop button should be active. */
  1844.     context = decoder->window_context;
  1845.     if (context)
  1846.         context->js_timeouts_pending++;
  1847.  
  1848.     if (expr) {
  1849.         timeout->argv = 0;
  1850.         timeout->argc = 0;
  1851.     } else {
  1852.         int i;
  1853.         /* Leave an extra slot for a secret final argument that
  1854.            indicates to the called function how "late" the timeout is. */
  1855.         timeout->argv = JS_malloc(cx, (argc - 1) * sizeof(jsval));
  1856.         if (!timeout->argv) {
  1857.             DROP_TIMEOUT(decoder, timeout);
  1858.             return JS_FALSE;
  1859.         }
  1860.         if (!JS_AddNamedRoot(cx, &timeout->funobj, "timeout.funobj")) {
  1861.             DROP_TIMEOUT(decoder, timeout);
  1862.             return JS_FALSE;
  1863.         }
  1864.  
  1865.         timeout->argc = 0;
  1866.         for (i = 2; (uint)i < argc; i++) {
  1867.             timeout->argv[i - 2] = argv[i];
  1868.             if (!JS_AddNamedRoot(cx, &timeout->argv[i - 2], "timeout.argv[i]"))
  1869.         {
  1870.                 DROP_TIMEOUT(decoder, timeout);
  1871.                 return JS_FALSE;
  1872.             }
  1873.             timeout->argc++;
  1874.         }
  1875.     }
  1876.  
  1877.     LL_I2L(now, PR_IntervalNow());
  1878.     LL_D2L(delta, interval);
  1879.     LL_ADD(timeout->when, now, delta);
  1880.     timeout->doc_id = decoder->doc_id;
  1881.  
  1882.     if (interval < 0)
  1883.     interval = 0;
  1884.  
  1885.     timeout->toid = ET_PostSetTimeout(win_run_timeout,
  1886.                                       decoder->window_context,
  1887.                                       (uint32)interval,
  1888.                                       decoder->doc_id);
  1889.     if (!timeout->toid) {
  1890.         DROP_TIMEOUT(decoder, timeout);
  1891.         return JS_FALSE;
  1892.     }
  1893.  
  1894.     if (js_timeout_insertion_point == NULL)
  1895.         insertion_point = &decoder->timeouts;
  1896.     else
  1897.         insertion_point = js_timeout_insertion_point;
  1898.  
  1899.     /* Insert interval timeout onto list sorted in deadline order */
  1900.     insert_timeout_into_list(insertion_point, timeout);
  1901.  
  1902.     lm_timeout_count++;
  1903.  
  1904.     timeout->public_id = ++timeout_public_id_counter;
  1905.     *rval = INT_TO_JSVAL((jsint)timeout->public_id);
  1906.     return JS_TRUE;
  1907. }
  1908.  
  1909. PR_STATIC_CALLBACK(PRBool)
  1910. win_set_timeout(JSContext *cx, JSObject *obj,
  1911.                 uint argc, jsval *argv, jsval *rval)
  1912. {
  1913.     return win_set_timeout_or_interval(cx, obj, argc, argv, rval, JS_FALSE);
  1914. }
  1915.  
  1916. PR_STATIC_CALLBACK(PRBool)
  1917. win_set_interval(JSContext *cx, JSObject *obj,
  1918.                  uint argc, jsval *argv, jsval *rval)
  1919. {
  1920.     return win_set_timeout_or_interval(cx, obj, argc, argv, rval, JS_TRUE);
  1921. }
  1922.  
  1923. PR_STATIC_CALLBACK(PRBool)
  1924. win_clear_timeout(JSContext *cx, JSObject *obj,
  1925.                   uint argc, jsval *argv, jsval *rval)
  1926. {
  1927.     MochaDecoder *decoder;
  1928.     uint32 public_id;
  1929.     JSTimeout **top, *timeout;
  1930.  
  1931.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  1932.         return JS_FALSE;
  1933.     if (!JSVAL_IS_INT(argv[0]))
  1934.     return JS_TRUE;
  1935.     public_id = (uint32)JSVAL_TO_INT(argv[0]);
  1936.     if (!public_id)    /* id of zero is reserved for internal use */
  1937.     return JS_TRUE;
  1938.     for (top = &decoder->timeouts; ((timeout = *top) != NULL); top = &timeout->next) {
  1939.         if (timeout->public_id == public_id) {
  1940.             if (js_timeout_running == timeout) {
  1941.                 /* We're running from inside the timeout.  Mark this
  1942.                    timeout for deferred deletion by the code in
  1943.                    win_run_timeout() */
  1944.                 timeout->interval = 0;
  1945.             } else {
  1946.                 /* Delete the timeout from the pending timeout list */
  1947.                 *top = timeout->next;
  1948.                 ET_PostClearTimeout(timeout->toid);
  1949.                 DROP_TIMEOUT(decoder, timeout);
  1950.             }
  1951.             break;
  1952.         }
  1953.     }
  1954.     return JS_TRUE;
  1955. }
  1956.  
  1957. /* Sleep for the specified number of milliseconds */
  1958. PR_STATIC_CALLBACK(PRBool)
  1959. win_delay(JSContext *cx, JSObject *obj,
  1960.           uint argc, jsval *argv, jsval *rval)
  1961. {
  1962.  
  1963. /* XXX - Brendan and Scott decided not to provide a delay() method
  1964.    because of untoward side-effects of its use.  We might do so in the
  1965.    future, so I'm effectively reserving the name by leaving a
  1966.    do-nothing method in the Window object. */
  1967.  
  1968. #if DELAY_METHOD_ALLOWED
  1969.  
  1970. /* Arbitrary maximum delay to prevent near-infinit delays */
  1971. #define JS_MAX_DELAY 1000
  1972.  
  1973.     jsdouble ms;
  1974.     int64 ms64, c;
  1975.  
  1976.     if (argc < 1) {
  1977.         JS_ReportError(cx, lm_argc_err_str);
  1978.         return JS_FALSE;
  1979.     }
  1980.  
  1981.     if (!JS_ValueToNumber(cx, argv[0], &ms))
  1982.         return JS_FALSE;
  1983.  
  1984.     if (ms < 0) {
  1985.         JS_ReportError(cx, "milliseconds argument must be non-negative");
  1986.         return JS_FALSE;
  1987.     }
  1988.  
  1989.     /* Don't let someone hang the JS thread for too long. */
  1990.     if (ms > JS_MAX_DELAY)
  1991.         ms = JS_MAX_DELAY;
  1992.  
  1993.     LL_UI2L(ms64, (uint32)ms);
  1994.     LL_I2L(c, 1000);
  1995.     LL_MUL(ms64, ms64, c);
  1996.     {
  1997.         PRIntervalTime i;
  1998.         LL_L2I(i, ms64);
  1999.         PR_Sleep(i);
  2000.     }
  2001. #undef JS_MAX_DELAY
  2002.  
  2003. #endif
  2004.     return JS_TRUE;
  2005. }
  2006.  
  2007. PR_STATIC_CALLBACK(PRBool)
  2008. win_escape(JSContext *cx, JSObject *obj,
  2009.            uint argc, jsval *argv, jsval *rval)
  2010. {
  2011.     jsdouble v;
  2012.     JSString *str;
  2013.     char *bytes;
  2014.     int32 length;
  2015.     int mask;
  2016.  
  2017.     if (argc > 1) {
  2018.         if (!JS_ValueToNumber(cx, argv[1], &v))
  2019.             return JS_FALSE;
  2020.         mask = (int)v;
  2021.         if (mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH)) {
  2022.             JS_ReportError(cx, "invalid string escape mask %x", mask);
  2023.             return JS_FALSE;
  2024.         }
  2025.     } else {
  2026.         mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
  2027.     }
  2028.     if (!(str = JS_ValueToString(cx, argv[0])))
  2029.         return JS_FALSE;
  2030.     /* XXXunicode ? */
  2031.     bytes = NET_EscapeBytes(JS_GetStringBytes(str),
  2032.                             (int32)JS_GetStringLength(str),
  2033.                             mask,
  2034.                             &length);
  2035.     if (!bytes) {
  2036.         JS_ReportOutOfMemory(cx);
  2037.         return JS_FALSE;
  2038.     }
  2039.  
  2040.     /* XXXunicode ? */
  2041.     str = JS_NewString(cx, bytes, (size_t)length);
  2042.     if (!str)
  2043.         return JS_FALSE;
  2044.     *rval = STRING_TO_JSVAL(str);
  2045.     return JS_TRUE;
  2046. }
  2047.  
  2048. PR_STATIC_CALLBACK(PRBool)
  2049. win_unescape(JSContext *cx, JSObject *obj,
  2050.              uint argc, jsval *argv, jsval *rval)
  2051. {
  2052.     JSString *str;
  2053.     size_t length;
  2054.     char *bytes;
  2055.  
  2056.     if (!(str = JS_ValueToString(cx, argv[0])))
  2057.         return JS_FALSE;
  2058.     length = JS_GetStringLength(str);
  2059.     if (!(bytes = JS_malloc(cx, length + 1)))
  2060.         return JS_FALSE;
  2061.     /* XXXunicode ? */
  2062.     XP_MEMCPY(bytes, JS_GetStringBytes(str), length);
  2063.     bytes[length] = '\0';
  2064.     length = (size_t)NET_UnEscapeBytes(bytes, length);
  2065.     /* XXXunicode ? */
  2066.     str = JS_NewString(cx, bytes, length);
  2067.     if (!str)
  2068.         return JS_FALSE;
  2069.     *rval = STRING_TO_JSVAL(str);
  2070.     return JS_TRUE;
  2071. }
  2072.  
  2073. PR_STATIC_CALLBACK(PRBool)
  2074. win_focus(JSContext *cx, JSObject *obj,
  2075.           uint argc, jsval *argv, jsval *rval)
  2076. {
  2077.     MochaDecoder *decoder;
  2078.  
  2079.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2080.         return JS_FALSE;
  2081.     
  2082.     if (!decoder->window_context)
  2083.         return JS_TRUE;
  2084.  
  2085.     ET_PostManipulateForm(decoder->window_context, 0, EVENT_FOCUS);
  2086.     return JS_TRUE;
  2087. }
  2088.  
  2089. PR_STATIC_CALLBACK(PRBool)
  2090. win_blur(JSContext *cx, JSObject *obj,
  2091.          uint argc, jsval *argv, jsval *rval)
  2092. {
  2093.     MochaDecoder *decoder;
  2094.  
  2095.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2096.         return JS_FALSE;
  2097.     
  2098.     if (!decoder->window_context)
  2099.         return JS_TRUE;
  2100.  
  2101.     ET_PostManipulateForm(decoder->window_context, 0, EVENT_BLUR);
  2102.  
  2103.     return JS_TRUE;
  2104. }
  2105.  
  2106. /*
  2107.  * Scrolling support.
  2108.  */
  2109. PR_STATIC_CALLBACK(PRBool)
  2110. win_scroll_to(JSContext *cx, JSObject *obj,
  2111.            uint argc, jsval *argv, jsval *rval)
  2112. {
  2113.     MochaDecoder *decoder;
  2114.     int32 x, y;
  2115.  
  2116.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2117.         return JS_FALSE;
  2118.  
  2119.     if (argc != 2) {
  2120.         JS_ReportError(cx, lm_argc_err_str);
  2121.         return JS_FALSE;
  2122.     }
  2123.  
  2124.     if (!decoder->window_context)
  2125.         return JS_TRUE;
  2126.  
  2127.     if (!JS_ValueToInt32(cx, argv[0], &x) || !JS_ValueToInt32(cx, argv[1], &y))
  2128.         return JS_FALSE;    
  2129.  
  2130.     ET_PostScrollDocTo(decoder->window_context, 0, x<0?0:x, y<0?0:y);
  2131.     return JS_TRUE;
  2132. }
  2133.  
  2134. /*
  2135.  * Scrolling support.
  2136.  */
  2137. PR_STATIC_CALLBACK(PRBool)
  2138. win_scroll_by(JSContext *cx, JSObject *obj,
  2139.            uint argc, jsval *argv, jsval *rval)
  2140. {
  2141.     MochaDecoder *decoder;
  2142.     int32 x, y;
  2143.  
  2144.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2145.         return JS_FALSE;
  2146.  
  2147.     if (argc != 2) {
  2148.         JS_ReportError(cx, lm_argc_err_str);
  2149.         return JS_FALSE;
  2150.     }
  2151.  
  2152.     if (!decoder->window_context)
  2153.         return JS_TRUE;
  2154.  
  2155.     if (!JS_ValueToInt32(cx, argv[0], &x) || !JS_ValueToInt32(cx, argv[1], &y))
  2156.         return JS_FALSE;    
  2157.  
  2158.     ET_PostScrollDocBy(decoder->window_context, 0, x, y);
  2159.     return JS_TRUE;
  2160. }
  2161.  
  2162. /*
  2163.  * Window resizing after initial creation.
  2164.  */
  2165. PR_STATIC_CALLBACK(PRBool)
  2166. win_resize_to(JSContext *cx, JSObject *obj,
  2167.            uint argc, jsval *argv, jsval *rval)
  2168. {
  2169.     MochaDecoder *decoder;
  2170.     Chrome *chrome = NULL;
  2171.     int32 width, height;
  2172.     JSBool outer_size;
  2173.  
  2174.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2175.         return JS_FALSE;
  2176.  
  2177.     if (argc > 3) {
  2178.         JS_ReportError(cx, lm_argc_err_str);
  2179.         return JS_FALSE;
  2180.     }
  2181.  
  2182.     if (!decoder->window_context)
  2183.         return JS_TRUE;
  2184.  
  2185.     if (!JS_ValueToInt32(cx, argv[0], &width) || !JS_ValueToInt32(cx, argv[1], &height))
  2186.         return JS_FALSE;    
  2187.  
  2188.     if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
  2189.         return JS_FALSE;
  2190.  
  2191.     if (argc==3 && JS_ValueToBoolean(cx, argv[2], &outer_size) && outer_size == JS_TRUE) {
  2192.         chrome->outw_hint = width;
  2193.         chrome->outh_hint = height;
  2194.         if (chrome->outw_hint <= 0 || chrome->outh_hint <= 0) {
  2195.             JS_free(cx, chrome);
  2196.             return JS_TRUE;
  2197.         }
  2198.     }
  2199.     else {
  2200.         chrome->w_hint = width;
  2201.         chrome->h_hint = height;
  2202.         chrome->outw_hint = 0;
  2203.         chrome->outh_hint = 0;
  2204.         if (chrome->w_hint <= 0 || chrome->h_hint <= 0 || 
  2205.                                     decoder->window_context->grid_parent) {
  2206.             JS_free(cx, chrome);
  2207.             return JS_TRUE;
  2208.         }
  2209.     }
  2210.     if ((chrome->w_hint && chrome->w_hint < 100) ||
  2211.         (chrome->h_hint && chrome->h_hint < 100) ||
  2212.         (chrome->outw_hint && chrome->outw_hint < 100) ||
  2213.         (chrome->outh_hint && chrome->outh_hint < 100)) {
  2214.         if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
  2215.             /* Make sure windows are at least 100 by 100 pixels. */
  2216.             if (chrome->w_hint && chrome->w_hint < 100) chrome->w_hint = 100;
  2217.             if (chrome->h_hint && chrome->h_hint < 100) chrome->h_hint = 100;
  2218.             if (chrome->outw_hint && chrome->outw_hint < 100) chrome->outw_hint = 100;
  2219.             if (chrome->outh_hint && chrome->outh_hint < 100) chrome->outh_hint = 100;
  2220.         }
  2221.     } 
  2222.     /* Make sure they always at least 10 x 10 regardless of security. 1 x 1
  2223.      * windows are really hard to spot */
  2224.     if (chrome->w_hint && chrome->w_hint < 10) chrome->w_hint = 10;
  2225.     if (chrome->h_hint && chrome->h_hint < 10) chrome->h_hint = 10;
  2226.     if (chrome->outw_hint && chrome->outw_hint < 10) chrome->outw_hint = 10;
  2227.     if (chrome->outh_hint && chrome->outh_hint < 10) chrome->outh_hint = 10;
  2228.  
  2229.     ET_PostUpdateChrome(decoder->window_context, chrome);
  2230.     JS_free(cx, chrome);
  2231.     return JS_TRUE;
  2232. }
  2233.  
  2234. /*
  2235.  * Scrolling support.
  2236.  */
  2237. PR_STATIC_CALLBACK(PRBool)
  2238. win_resize_by(JSContext *cx, JSObject *obj,
  2239.            uint argc, jsval *argv, jsval *rval)
  2240. {
  2241.     MochaDecoder *decoder;
  2242.     Chrome *chrome = NULL;
  2243.     int32 width, height;
  2244.     JSBool outer_size;
  2245.  
  2246.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2247.         return JS_FALSE;
  2248.  
  2249.     if (argc > 3) {
  2250.         JS_ReportError(cx, lm_argc_err_str);
  2251.         return JS_FALSE;
  2252.     }
  2253.  
  2254.     if (!decoder->window_context)
  2255.         return JS_TRUE;
  2256.  
  2257.     if (!JS_ValueToInt32(cx, argv[0], &width) || !JS_ValueToInt32(cx, argv[1], &height))
  2258.         return JS_FALSE;    
  2259.  
  2260.     if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
  2261.         return JS_FALSE;
  2262.  
  2263.     if (argc==3 && JS_ValueToBoolean(cx, argv[2], &outer_size) && outer_size == JS_TRUE) {
  2264.         chrome->outw_hint += width;
  2265.         chrome->outh_hint += height;
  2266.         if (chrome->outw_hint <= 0 || chrome->outh_hint <= 0) {
  2267.             JS_free(cx, chrome);
  2268.             return JS_TRUE;
  2269.         }
  2270.     }
  2271.     else {
  2272.         chrome->w_hint += width;
  2273.         chrome->h_hint += height;
  2274.         chrome->outw_hint = 0;
  2275.         chrome->outh_hint = 0;
  2276.         if (chrome->w_hint <= 0 || chrome->h_hint <= 0 || 
  2277.                                     decoder->window_context->grid_parent) {
  2278.             JS_free(cx, chrome);
  2279.             return JS_TRUE;
  2280.         }
  2281.     }
  2282.     if ((chrome->w_hint && chrome->w_hint < 100) ||
  2283.         (chrome->h_hint && chrome->h_hint < 100) ||
  2284.         (chrome->outw_hint && chrome->outw_hint < 100) ||
  2285.         (chrome->outh_hint && chrome->outh_hint < 100)) {
  2286.         if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
  2287.             /* Make sure windows are at least 100 by 100 pixels. */
  2288.             if (chrome->w_hint && chrome->w_hint < 100) chrome->w_hint = 100;
  2289.             if (chrome->h_hint && chrome->h_hint < 100) chrome->h_hint = 100;
  2290.             if (chrome->outw_hint && chrome->outw_hint < 100) chrome->outw_hint = 100;
  2291.             if (chrome->outh_hint && chrome->outh_hint < 100) chrome->outh_hint = 100;
  2292.         }
  2293.     }
  2294.     /* Make sure they always at least 10 x 10 regardless of security. 1 x 1
  2295.      * windows are really hard to spot */
  2296.     if (chrome->w_hint && chrome->w_hint < 10) chrome->w_hint = 10;
  2297.     if (chrome->h_hint && chrome->h_hint < 10) chrome->h_hint = 10;
  2298.     if (chrome->outw_hint && chrome->outw_hint < 10) chrome->outw_hint = 10;
  2299.     if (chrome->outh_hint && chrome->outh_hint < 10) chrome->outh_hint = 10;
  2300.  
  2301.     ET_PostUpdateChrome(decoder->window_context, chrome);
  2302.     JS_free(cx, chrome);
  2303.     return JS_TRUE;
  2304. }
  2305.  
  2306. /*
  2307.  * Scrolling support.
  2308.  */
  2309. PR_STATIC_CALLBACK(PRBool)
  2310. win_move_to(JSContext *cx, JSObject *obj,
  2311.            uint argc, jsval *argv, jsval *rval)
  2312. {
  2313.     MochaDecoder *decoder;
  2314.     Chrome *chrome = NULL;
  2315.     int32 width, height, x, y;
  2316.  
  2317.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2318.         return JS_FALSE;
  2319.  
  2320.     if (argc != 2) {
  2321.         JS_ReportError(cx, lm_argc_err_str);
  2322.         return JS_FALSE;
  2323.     }
  2324.  
  2325.     if (!decoder->window_context)
  2326.         return JS_TRUE;
  2327.  
  2328.     if (!JS_ValueToInt32(cx, argv[0], &x) || !JS_ValueToInt32(cx, argv[1], &y))
  2329.         return JS_FALSE;    
  2330.  
  2331.     if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
  2332.         return JS_FALSE;
  2333.  
  2334.     chrome->l_hint = x;
  2335.     chrome->t_hint = y;
  2336.  
  2337.     /* Windows must be positioned on screen without security */
  2338.     ET_PostGetScreenSize(decoder->window_context, &width, &height);
  2339.     if ((width < chrome->l_hint + chrome->outw_hint) ||
  2340.         (chrome->l_hint < 0) ||
  2341.         (height < chrome->t_hint + chrome->outh_hint) ||
  2342.         (chrome->t_hint < 0)) {
  2343.         if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
  2344.             chrome->l_hint = (width < chrome->l_hint + chrome->outw_hint) ?
  2345.                                 width - chrome->outw_hint : chrome->l_hint;
  2346.             chrome->l_hint = (chrome->l_hint < 0) ? 0 : chrome->l_hint;
  2347.             chrome->t_hint = (height < chrome->t_hint + chrome->outh_hint) ?
  2348.                                 height - chrome->outh_hint : chrome->t_hint;
  2349.             chrome->t_hint = (chrome->t_hint < 0) ? 0 : chrome->t_hint;
  2350.         }
  2351.     }
  2352.  
  2353.     ET_PostUpdateChrome(decoder->window_context, chrome);
  2354.     JS_free(cx, chrome);
  2355.     return JS_TRUE;
  2356. }
  2357.  
  2358. /*
  2359.  * Scrolling support.
  2360.  */
  2361. PR_STATIC_CALLBACK(PRBool)
  2362. win_move_by(JSContext *cx, JSObject *obj,
  2363.            uint argc, jsval *argv, jsval *rval)
  2364. {
  2365.     MochaDecoder *decoder;
  2366.     Chrome *chrome = NULL;
  2367.     int32 x, y, width, height;
  2368.  
  2369.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2370.         return JS_FALSE;
  2371.  
  2372.     if (argc != 2) {
  2373.         JS_ReportError(cx, lm_argc_err_str);
  2374.         return JS_FALSE;
  2375.     }
  2376.  
  2377.     if (!decoder->window_context)
  2378.         return JS_TRUE;
  2379.  
  2380.     if (!JS_ValueToInt32(cx, argv[0], &x) || !JS_ValueToInt32(cx, argv[1], &y))
  2381.         return JS_FALSE;    
  2382.  
  2383.     if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
  2384.         return JS_FALSE;
  2385.  
  2386.     chrome->l_hint += x;
  2387.     chrome->t_hint += y;
  2388.  
  2389.     /* Windows must be positioned on screen without security */
  2390.     ET_PostGetScreenSize(decoder->window_context, &width, &height);
  2391.     if ((width < chrome->l_hint + chrome->outw_hint) ||
  2392.         (chrome->l_hint < 0) ||
  2393.         (height < chrome->t_hint + chrome->outh_hint) ||
  2394.         (chrome->t_hint < 0)) {
  2395.         if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
  2396.             chrome->l_hint = (width < chrome->l_hint + chrome->outw_hint) ?
  2397.                                 width - chrome->outw_hint : chrome->l_hint;
  2398.             chrome->l_hint = (chrome->l_hint < 0) ? 0 : chrome->l_hint;
  2399.             chrome->t_hint = (height < chrome->t_hint + chrome->outh_hint) ?
  2400.                                 height - chrome->outh_hint : chrome->t_hint;
  2401.             chrome->t_hint = (chrome->t_hint < 0) ? 0 : chrome->t_hint;
  2402.         }
  2403.     }
  2404.  
  2405.     ET_PostUpdateChrome(decoder->window_context, chrome);
  2406.     JS_free(cx, chrome);
  2407.     return JS_TRUE;
  2408. }
  2409.  
  2410. PR_STATIC_CALLBACK(PRBool)
  2411. win_capture_events(JSContext *cx, JSObject *obj,
  2412.            uint argc, jsval *argv, jsval *rval)
  2413. {
  2414.     MochaDecoder *decoder;
  2415.     jsdouble d;
  2416.  
  2417.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2418.         return JS_FALSE;
  2419.  
  2420.     if (!decoder->window_context)
  2421.         return JS_TRUE;
  2422.  
  2423.     if (argc != 1)
  2424.         return JS_TRUE;
  2425.  
  2426.     if (!JS_ValueToNumber(cx, argv[0], &d))
  2427.         return JS_FALSE;
  2428.  
  2429.     decoder->event_bit |= (uint32)d;
  2430.     decoder->window_context->event_bit |= (uint32)d;
  2431.  
  2432.     return JS_TRUE;
  2433. }
  2434.  
  2435. PR_STATIC_CALLBACK(PRBool)
  2436. win_release_events(JSContext *cx, JSObject *obj,
  2437.            uint argc, jsval *argv, jsval *rval)
  2438. {
  2439.     MochaDecoder *decoder;
  2440.     JSEventCapturer *cap;
  2441.     jsdouble d;
  2442.     jsint layer_index;
  2443.     jsint max_layer_num;
  2444.     JSObject *cap_obj;
  2445.  
  2446.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2447.         return JS_FALSE;
  2448.  
  2449.     if (!decoder->window_context)
  2450.         return JS_TRUE;
  2451.  
  2452.     if (argc != 1)
  2453.         return JS_TRUE;
  2454.  
  2455.     if (!JS_ValueToNumber(cx, argv[0], &d))
  2456.         return JS_FALSE;
  2457.  
  2458.     decoder->event_bit &= ~(uint32)d;
  2459.     decoder->window_context->event_bit &= ~(uint32)d;
  2460.  
  2461.     /* Now we have to see if anyone else wanted that bit set.  Joy!*/
  2462.     max_layer_num = LO_GetNumberOfLayers(decoder->window_context);
  2463.  
  2464.     for (layer_index=0; layer_index <= max_layer_num; layer_index++) {
  2465.         cap_obj = LO_GetLayerMochaObjectFromId(decoder->window_context, layer_index);
  2466.         if (cap_obj && (cap = JS_GetPrivate(cx, cap_obj)) != NULL)
  2467.             decoder->window_context->event_bit |= cap->event_bit;
  2468.         
  2469.         cap_obj = lm_GetDocumentFromLayerId(decoder, layer_index);
  2470.         if (cap_obj && (cap = JS_GetPrivate(cx, cap_obj)) != NULL)
  2471.             decoder->window_context->event_bit |= cap->event_bit;
  2472.     }
  2473.  
  2474.     return JS_TRUE;
  2475. }
  2476.  
  2477. static PRBool
  2478. setExternalCapture(JSContext *cx, JSObject *obj, 
  2479.                    uint argc, jsval *argv, JSBool val)
  2480. {
  2481.     MochaDecoder *decoder;
  2482.  
  2483.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2484.         return JS_FALSE;
  2485.  
  2486.     if (argc != 0)
  2487.         return JS_TRUE;
  2488.  
  2489.     if (lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
  2490.         if (decoder->principals)
  2491.             lm_SetExternalCapture(cx, decoder->principals, val);
  2492.     }
  2493.  
  2494.     return JS_TRUE;
  2495. }
  2496.  
  2497. PR_STATIC_CALLBACK(PRBool)
  2498. win_enable_external_capture(JSContext *cx, JSObject *obj,
  2499.                             uint argc, jsval *argv, jsval *rval)
  2500. {
  2501.     return setExternalCapture(cx, obj, argc, argv, JS_TRUE);
  2502. }
  2503.  
  2504. PR_STATIC_CALLBACK(PRBool)
  2505. win_disable_external_capture(JSContext *cx, JSObject *obj,
  2506.                              uint argc, jsval *argv, jsval *rval)
  2507. {
  2508.     return setExternalCapture(cx, obj, argc, argv, JS_FALSE);
  2509. }
  2510.  
  2511. PR_STATIC_CALLBACK(PRBool)
  2512. win_compromise_principals(JSContext *cx, JSObject *obj,
  2513.                           uint argc, jsval *argv, jsval *rval)
  2514. {
  2515.     MochaDecoder *decoder;
  2516.  
  2517.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2518.         return JS_FALSE;
  2519.  
  2520.     decoder->principals_compromised = JS_TRUE;
  2521.     return JS_TRUE;
  2522. }
  2523.  
  2524. PR_STATIC_CALLBACK(PRBool)
  2525. win_downgrade_principals(JSContext *cx, JSObject *obj,
  2526.                          uint argc, jsval *argv, jsval *rval)
  2527. {
  2528.     MochaDecoder *decoder;
  2529.  
  2530.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2531.         return JS_FALSE;
  2532.  
  2533.     if (decoder->principals)
  2534.         lm_InvalidateCertPrincipals(decoder, decoder->principals);
  2535.  
  2536.     return JS_TRUE;
  2537. }
  2538.  
  2539. PR_STATIC_CALLBACK(PRBool)
  2540. win_back(JSContext *cx, JSObject *obj,
  2541.            uint argc, jsval *argv, jsval *rval)
  2542. {
  2543.     MochaDecoder *decoder;
  2544.  
  2545.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2546.         return JS_FALSE;
  2547.     if (!decoder->window_context)
  2548.         return JS_TRUE;
  2549.  
  2550.     ET_PostBackCommand(decoder->window_context);
  2551.     return JS_TRUE;
  2552. }
  2553.  
  2554. PR_STATIC_CALLBACK(PRBool)
  2555. win_forward(JSContext *cx, JSObject *obj,
  2556.            uint argc, jsval *argv, jsval *rval)
  2557. {
  2558.     MochaDecoder *decoder;
  2559.  
  2560.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2561.         return JS_FALSE;
  2562.     if (!decoder->window_context)
  2563.         return JS_TRUE;
  2564.  
  2565.     ET_PostForwardCommand(decoder->window_context);
  2566.     return JS_TRUE;
  2567. }
  2568.  
  2569. PR_STATIC_CALLBACK(PRBool)
  2570. win_home(JSContext *cx, JSObject *obj,
  2571.            uint argc, jsval *argv, jsval *rval)
  2572. {
  2573.     MochaDecoder *decoder;
  2574.  
  2575.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2576.         return JS_FALSE;
  2577.     if (!decoder->window_context)
  2578.         return JS_TRUE;
  2579.  
  2580.     ET_PostHomeCommand(decoder->window_context);
  2581.     return JS_TRUE;
  2582. }
  2583.  
  2584. PR_STATIC_CALLBACK(PRBool)
  2585. win_find(JSContext *cx, JSObject *obj,
  2586.            uint argc, jsval *argv, jsval *rval)
  2587. {
  2588.     MochaDecoder *decoder;
  2589.     MWContext *context;
  2590.     JSString *str;
  2591.     JSBool ret = JS_TRUE,
  2592.            matchCase = JS_FALSE,
  2593.            searchBackward = JS_FALSE;
  2594.     char * findStr;
  2595.  
  2596.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2597.         return JS_FALSE;
  2598.     context = decoder->window_context;
  2599.     if (!context)
  2600.         return JS_TRUE;
  2601.  
  2602.     /* If no find argument set, just bring up find dialog */
  2603.     if (argc == 0) {
  2604.         ET_PostFindCommand(context, NULL, JS_FALSE, JS_FALSE);
  2605.         return JS_TRUE;
  2606.     }
  2607.  
  2608.     if (argc >3 )
  2609.         return JS_FALSE;
  2610.  
  2611.     if (!(str = JS_ValueToString(cx, argv[0])))
  2612.         return JS_TRUE;
  2613.     if (!lm_CheckPermissions(cx, decoder->window_object, 
  2614.                              JSTARGET_UNIVERSAL_BROWSER_READ))
  2615.         return JS_FALSE;
  2616.  
  2617.     if (argc == 3) {
  2618.         if (!JS_ValueToBoolean(cx, argv[1], &matchCase))
  2619.             matchCase = JS_FALSE;
  2620.         if (!JS_ValueToBoolean(cx, argv[2], &searchBackward))
  2621.             searchBackward = JS_FALSE;
  2622.     }
  2623.  
  2624.     findStr = lm_StrToLocalEncoding(context, str);
  2625.     ret = ET_PostFindCommand(context, findStr, matchCase, searchBackward);
  2626.  
  2627.     XP_FREEIF(findStr);
  2628.     *rval = BOOLEAN_TO_JSVAL(ret);
  2629.  
  2630.     return JS_TRUE;
  2631. }
  2632.  
  2633. PR_STATIC_CALLBACK(PRBool)
  2634. win_print(JSContext *cx, JSObject *obj,
  2635.            uint argc, jsval *argv, jsval *rval)
  2636. {
  2637.     MochaDecoder *decoder;
  2638.  
  2639.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2640.         return JS_FALSE;
  2641.     if (!decoder->window_context)
  2642.         return JS_TRUE;
  2643.  
  2644.     ET_PostPrintCommand(decoder->window_context);
  2645.     return JS_TRUE;
  2646. }
  2647.  
  2648. PR_STATIC_CALLBACK(PRBool)
  2649. win_open_file(JSContext *cx, JSObject *obj,
  2650.            uint argc, jsval *argv, jsval *rval)
  2651. {
  2652.     MochaDecoder *decoder;
  2653.  
  2654.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2655.         return JS_FALSE;
  2656.     if (!decoder->window_context)
  2657.         return JS_TRUE;
  2658.  
  2659.     ET_PostOpenFileCommand(decoder->window_context);
  2660.     return JS_TRUE;
  2661. }
  2662.  
  2663. PR_STATIC_CALLBACK(PRBool)
  2664. win_stop(JSContext *cx, JSObject *obj,
  2665.            uint argc, jsval *argv, jsval *rval)
  2666. {
  2667.     MochaDecoder *decoder;
  2668.  
  2669.     if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
  2670.         return JS_FALSE;
  2671.     if (!decoder->window_context)
  2672.         return JS_TRUE;
  2673.  
  2674.     ET_moz_CallFunctionAsync((ETVoidPtrFunc) XP_InterruptContext, decoder->window_context);
  2675.     return JS_TRUE;
  2676. }
  2677.  
  2678. PR_STATIC_CALLBACK(PRBool)
  2679. win_atob(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
  2680. {
  2681.     JSString *str;
  2682.     char *srcStr, *destStr = NULL, *tmpStr;
  2683.     unsigned int len;
  2684.  
  2685.     if (argc != 1) {
  2686.         JS_ReportError(cx, lm_argc_err_str);
  2687.         return JS_FALSE;
  2688.     }
  2689.     if (!(str = JS_ValueToString(cx, argv[0])))
  2690.         return JS_FALSE;
  2691.  
  2692.     srcStr = JS_GetStringBytes(str);
  2693.     if (JS_GetStringLength(str) == 0) {
  2694.         *rval = JS_GetEmptyStringValue(cx);
  2695.         return JS_TRUE;
  2696.     }
  2697.  
  2698.     tmpStr = (char *)ATOB_AsciiToData(srcStr, &len);
  2699.     if (tmpStr == NULL) {
  2700.         JS_ReportError(cx, "base64 decoder failure");
  2701.         return JS_FALSE;
  2702.     }
  2703.  
  2704.     destStr = JS_malloc(cx, len + 1);
  2705.     if (destStr == NULL) {
  2706.         XP_FREE(tmpStr);
  2707.         return JS_FALSE;
  2708.     }
  2709.     destStr[len] = 0;
  2710.  
  2711.     XP_MEMCPY(destStr, tmpStr, len);
  2712.     XP_FREE(tmpStr);
  2713.     str = JS_NewString(cx, destStr, len);
  2714.     if (str == NULL) {
  2715.         JS_free(cx, destStr);
  2716.         return JS_FALSE;
  2717.     }
  2718.  
  2719.     *rval= STRING_TO_JSVAL(str);
  2720.     return JS_TRUE;
  2721. }
  2722.  
  2723. PR_STATIC_CALLBACK(PRBool)
  2724. win_btoa(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
  2725. {
  2726.     JSString *str;
  2727.     char *srcStr, *destStr;
  2728.     unsigned int len;
  2729.  
  2730.     if (argc != 1) {
  2731.         JS_ReportError(cx, lm_argc_err_str);
  2732.         return JS_FALSE;
  2733.     }
  2734.  
  2735.     if (!(str = JS_ValueToString(cx, argv[0])))
  2736.         return JS_FALSE;
  2737.     srcStr = JS_GetStringBytes(str);
  2738.     len = JS_GetStringLength(str);
  2739.     if (len == 0) {
  2740.         *rval = JS_GetEmptyStringValue(cx);
  2741.         return JS_TRUE;
  2742.     }
  2743.  
  2744.     destStr = BTOA_DataToAscii((unsigned char *)srcStr, len);
  2745.     if (destStr == NULL) {
  2746.         JS_ReportError(cx, "base64 encoder failure");
  2747.         return JS_FALSE;
  2748.     }
  2749.  
  2750.     len = XP_STRLEN(destStr);
  2751.     str = JS_NewString(cx, destStr, len);
  2752.     if (str == NULL)
  2753.         return JS_FALSE;
  2754.  
  2755.     *rval= STRING_TO_JSVAL(str);
  2756.     return JS_TRUE;
  2757. }
  2758.  
  2759. PR_STATIC_CALLBACK(PRBool)
  2760. win_taint_stub(JSContext *cx, JSObject *obj, uint argc, jsval *argv,
  2761.                jsval *rval)
  2762. {
  2763.     *rval = argv[0];
  2764.     return JS_TRUE;
  2765. }
  2766.  
  2767. static JSFunctionSpec lm_window_methods[] = {
  2768.     {"alert",           win_alert,              1},
  2769.     {"clearTimeout",    win_clear_timeout,      1},
  2770.     {"clearInterval",   win_clear_timeout,      1},
  2771.     {"close",           win_close,              0},
  2772.     {"confirm",         win_confirm,            1},
  2773.     {"open",            win_open,               1},
  2774.     {"setZOptions",     win_set_zoptions,       1},
  2775.     {"setHotkeys",      win_set_hotkeys,        1},
  2776.     {"setResizable",    win_set_resizable,      1},
  2777.     {"prompt",          win_prompt,             2},
  2778.     {setTimeout_str,    win_set_timeout,        2},
  2779.     {setInterval_str,   win_set_interval,       2},
  2780.     {"delay",           win_delay,              0},
  2781.     {"escape",          win_escape,             2},
  2782.     {"unescape",        win_unescape,           1},
  2783.     {lm_blur_str,       win_blur,               0},
  2784.     {lm_focus_str,      win_focus,              0},
  2785.     {lm_scroll_str,     win_scroll_to,          2},
  2786.     {"scrollTo",        win_scroll_to,          2},
  2787.     {"scrollBy",        win_scroll_by,          2},
  2788.     {"moveTo",          win_move_to,            2},
  2789.     {"moveBy",          win_move_by,            2},
  2790.     {"resizeTo",        win_resize_to,          2},
  2791.     {"resizeBy",        win_resize_by,          2},
  2792.     {"captureEvents",   win_capture_events,     1},
  2793.     {"releaseEvents",   win_release_events,     1},
  2794.     {"enableExternalCapture",   win_enable_external_capture,    0 },
  2795.     {"disableExternalCapture",  win_disable_external_capture,   0 },
  2796.     {"compromisePrincipals",    win_compromise_principals,      0 },
  2797.     {"downgradePrincipals",     win_downgrade_principals,       0 },
  2798.     {"back",            win_back,               0},
  2799.     {"forward",         win_forward,            0},
  2800.     {"home",            win_home,               0},
  2801.     {"find",            win_find,               0},
  2802.     {"print",           win_print,              0},
  2803.     {"openFile",        win_open_file,          0},
  2804.     {"stop",            win_stop,               0},
  2805.     {"atob",            win_atob,               1},
  2806.     {"btoa",            win_btoa,               1},
  2807.     {"taint",           win_taint_stub,         1},
  2808.     {"untaint",         win_taint_stub,         1},
  2809.     {0}
  2810. };
  2811.  
  2812. static JSBool
  2813. is_context_really_busy_or_loading(MWContext *context)
  2814. {
  2815.     lo_TopState *top_state;
  2816.     int i;
  2817.     XP_List *kids;
  2818.     MWContext *kid;
  2819.  
  2820.     if (!context)
  2821.         return JS_FALSE;
  2822.  
  2823.     LO_LockLayout();
  2824.  
  2825.     if ((top_state = lo_FetchTopState(XP_DOCID(context))) != NULL &&
  2826.         (top_state->mocha_loading_applets_count ||
  2827.          top_state->mocha_loading_embeds_count)) {
  2828.         LO_UnlockLayout();
  2829.         return JS_TRUE;
  2830.     }
  2831.  
  2832.     if ((kids = context->grid_children) != NULL) {
  2833.         for (i = 1; ((kid = XP_ListGetObjectNum(kids, i)) != NULL); i++) {
  2834.  
  2835.             /* see if this frame is loading */
  2836.             if (is_context_really_busy_or_loading(kid)) {
  2837.                 LO_UnlockLayout();
  2838.                 return JS_TRUE;
  2839.             }
  2840.  
  2841.             /* make sure the load event has fired for this frame */
  2842.             if (kid->mocha_context) {
  2843.                 MochaDecoder * decoder = LM_GetMochaDecoder(kid);
  2844.                 if (!decoder->load_event_sent) {
  2845.                     LM_PutMochaDecoder(decoder);
  2846.                     LO_UnlockLayout();
  2847.                     return JS_TRUE;
  2848.                 }
  2849.                 LM_PutMochaDecoder(decoder);
  2850.             }
  2851.         }
  2852.     }
  2853.  
  2854.     LO_UnlockLayout();
  2855.     return JS_FALSE;
  2856. }
  2857.  
  2858. static JSBool
  2859. is_context_busy(MWContext *context)
  2860. {
  2861.     if (XP_IsContextBusy(context))
  2862.         return JS_TRUE;
  2863.     return is_context_really_busy_or_loading(context);
  2864. }
  2865.  
  2866. /*
  2867.  * 3.0 ran load events from the timeout loop to avoid freeing contexts in use,
  2868.  * e.g., parent.document.write() in a frame's BODY onLoad= attribute.  That
  2869.  * hack ran afoul of WinFE's failure to FIFO-schedule same-deadline timeouts.
  2870.  * Now, with threading and no way for the mozilla thread to blow away its own
  2871.  * data structures without unwinding to its event loop, an event handler can
  2872.  * use document.write or start a new load without fear of free memory usage by
  2873.  * the front end code that sent the event.
  2874.  */
  2875. static void
  2876. try_load_event(MWContext *context, MochaDecoder *decoder)
  2877. {
  2878.     /*
  2879.      * Don't do anything if we are waiting for URLs to load, or if applets
  2880.      * have not been loaded and initialized.
  2881.      */
  2882.     if (is_context_busy(context))
  2883.         return;
  2884.  
  2885.     /*
  2886.      * Send a load event at most once.
  2887.      */
  2888.     if (!decoder->load_event_sent) {
  2889.         JSEvent *event;
  2890.         jsval rval;
  2891.  
  2892.         event = XP_NEW_ZAP(JSEvent);
  2893.         if (!event)
  2894.             return;
  2895.  
  2896.         event->type = decoder->resize_reload ? EVENT_RESIZE : EVENT_LOAD;
  2897.     if (context->compositor) {
  2898.         XP_Rect rect;
  2899.  
  2900.         CL_GetCompositorWindowSize(context->compositor, &rect);
  2901.         event->x = rect.right;
  2902.         event->y = rect.bottom;
  2903.     }
  2904.  
  2905.         decoder->load_event_sent = JS_TRUE;
  2906.         (void) lm_SendEvent(context, decoder->window_object, event, &rval);
  2907.  
  2908.         decoder->event_mask &= ~event->type;
  2909.  
  2910.         if (!event->saved)
  2911.             XP_FREE(event);
  2912.  
  2913.     }
  2914.  
  2915.     /*
  2916.      * Now that we may have scheduled a load event for this context, send
  2917.      *   a transfer-done event to our parent frameset, in case it was
  2918.      *   waiting for us to finish
  2919.      */
  2920.     if (context->grid_parent)
  2921.         lm_SendLoadEvent(context->grid_parent, EVENT_XFER_DONE, JS_FALSE);
  2922.  
  2923. }
  2924.  
  2925. /*
  2926.  * Entry point for the netlib to notify JS of load and unload events.
  2927.  * Note: we can only rely on the resize_reload parameter to be
  2928.  * correct in the load and unload (but not the xfer) cases.
  2929.  */
  2930. void
  2931. lm_SendLoadEvent(MWContext *context, int32 event, JSBool resize_reload)
  2932. {
  2933.     MochaDecoder *decoder;
  2934.     JSEvent *pEvent;
  2935.     jsval rval;
  2936.  
  2937.     decoder = context->mocha_context ? LM_GetMochaDecoder(context) : 0;
  2938.     if (!decoder)
  2939.         return;
  2940.  
  2941.     switch (event) {
  2942.       case EVENT_LOAD:
  2943.         decoder->event_mask |= EVENT_LOAD;
  2944.         if (resize_reload) {
  2945.             decoder->resize_reload = JS_TRUE;
  2946.             /* Restore any saved timeouts that we have for this window */
  2947.             lm_RestoreWindowTimeouts(decoder);
  2948.     }
  2949.     try_load_event(context, decoder);
  2950.         break;
  2951.  
  2952.       case EVENT_UNLOAD:
  2953.         decoder->load_event_sent = JS_FALSE;
  2954.         decoder->event_mask &= ~EVENT_LOAD;
  2955.  
  2956.         /* If we're resizing, just save timeouts but don't send an event */
  2957.         if (resize_reload) {
  2958.             lm_SaveWindowTimeouts(decoder);
  2959.         } else {
  2960.             pEvent = XP_NEW_ZAP(JSEvent);
  2961.             pEvent->type = EVENT_UNLOAD;
  2962.  
  2963.             (void) lm_SendEvent(context, decoder->window_object,
  2964.                                 pEvent, &rval);
  2965.             if (!pEvent->saved)
  2966.                 XP_FREE(pEvent);
  2967.         }
  2968.  
  2969.       break;
  2970.  
  2971.       case EVENT_XFER_DONE:
  2972.         if ((decoder->event_mask & EVENT_LOAD))
  2973.             try_load_event(context, decoder);
  2974.         if (context->grid_parent)
  2975.             lm_SendLoadEvent(context->grid_parent, EVENT_XFER_DONE, JS_FALSE);
  2976.         break;
  2977.  
  2978.       case EVENT_ABORT:
  2979.       default:
  2980.           break;
  2981.     }
  2982.  
  2983.     if (decoder)
  2984.         LM_PutMochaDecoder(decoder);
  2985.     return;
  2986. }
  2987.  
  2988. /*
  2989.  * Entry point for front-ends to notify JS code of help events.
  2990.  */
  2991. void
  2992. LM_SendOnHelp(MWContext *context)
  2993. {
  2994.     JSEvent                     *pEvent;
  2995.  
  2996.     pEvent = XP_NEW_ZAP(JSEvent);
  2997.     pEvent->type = EVENT_HELP;
  2998.  
  2999.     ET_SendEvent(context, NULL, pEvent, NULL, NULL);
  3000.  
  3001. }
  3002.  
  3003. /*
  3004.  * Entry point for front-ends to notify JS code of scroll events.
  3005.  */
  3006. void
  3007. LM_SendOnScroll(MWContext *context, int32 x, int32 y)
  3008. {
  3009.     MochaDecoder *decoder;
  3010.     JSEvent *event;
  3011.     jsval rval;
  3012.  
  3013. XP_ASSERT(0);
  3014.  
  3015.     if (!context->mocha_context)
  3016.                 return;
  3017.     decoder = LM_GetMochaDecoder(context);
  3018.     if (!(decoder->event_mask & EVENT_SCROLL)) {
  3019.                 decoder->event_mask |= EVENT_SCROLL;
  3020.  
  3021.                 event = XP_NEW_ZAP(JSEvent);
  3022.                 event->type = EVENT_SCROLL;
  3023.  
  3024.                 (void) lm_SendEvent(context, decoder->window_object, event,
  3025.                                         &rval);
  3026.                 decoder->event_mask &= ~EVENT_SCROLL;
  3027.     }
  3028.     LM_PutMochaDecoder(decoder);
  3029. }
  3030.  
  3031. PRHashNumber
  3032. lm_KeyHash(const void *key)
  3033. {
  3034.     return (PRHashNumber)key;
  3035. }
  3036.  
  3037. PRHashTable *
  3038. lm_GetIdToObjectMap(MochaDecoder *decoder)
  3039. {
  3040.     PRHashTable *map;
  3041.  
  3042.     map = decoder->id_to_object_map;
  3043.     if (map)
  3044.         return map;
  3045.  
  3046.     map = PR_NewHashTable(LM_ID_TO_OBJ_MAP_SIZE,
  3047.                           lm_KeyHash,
  3048.                           PR_CompareValues,
  3049.                           PR_CompareValues,
  3050.                           NULL, NULL);
  3051.  
  3052.     if (!map)
  3053.         return NULL;
  3054.  
  3055.     decoder->id_to_object_map = map;
  3056.     return map;
  3057. }
  3058.  
  3059.  
  3060. MochaDecoder *
  3061. lm_NewWindow(MWContext *context)
  3062. {
  3063.     History_entry *he;
  3064.     MochaDecoder *decoder;
  3065.     JSContext *cx;
  3066.     JSObject *obj;
  3067.  
  3068.     /* make sure its a JS-able context */
  3069.     if (!LM_CanDoJS(context))
  3070.         return NULL;
  3071.  
  3072.     /*
  3073.      * If this is a (resizing) frame, get its decoder from session history.
  3074.      * Using the layout lock to protect context->hist.cur_doc_ptr (which is
  3075.      * all SHIST_GetCurrent uses) is dicey.  XXXchouck
  3076.      */
  3077.     LO_LockLayout();
  3078.     he = context->is_grid_cell ? SHIST_GetCurrent(&context->hist) : NULL;
  3079.     if (he && he->savedData.Window) {
  3080.         decoder = he->savedData.Window;
  3081.         he->savedData.Window = NULL;
  3082.         cx = decoder->js_context;
  3083.         obj = decoder->window_object;
  3084.         decoder->window_context = context;
  3085.         context->mocha_context = cx;
  3086.         LO_UnlockLayout();
  3087.         
  3088.         /*
  3089.          * Allow the context to observe the decoder's image context.
  3090.          */
  3091.         ET_il_SetGroupObserver(context, decoder->image_context, context, JS_TRUE);
  3092.  
  3093.         return decoder;
  3094.     }
  3095.     LO_UnlockLayout();
  3096.  
  3097.     /* Otherwise, make a new decoder/context/object for this window. */
  3098.     decoder = XP_NEW_ZAP(MochaDecoder);
  3099.     if (!decoder)
  3100.         return NULL;
  3101.     cx = JS_NewContext(lm_runtime, LM_STACK_SIZE);
  3102.     if (!cx) {
  3103.         XP_DELETE(decoder);
  3104.         return NULL;
  3105.     }
  3106.     obj = JS_NewObject(cx, &lm_window_class, NULL, NULL);
  3107.     if (!obj || !JS_SetPrivate(cx, obj, decoder)) {
  3108.         JS_DestroyContext(cx);
  3109.         XP_DELETE(decoder);
  3110.         return NULL;
  3111.     }
  3112.  
  3113.     /* Set the backward refcount to 1 because obj now holds decoder. */
  3114.     decoder->back_count = 1;
  3115.  
  3116.     /* Add a root in decoder for obj early, in case the GC runs soon. */
  3117.     decoder->window_object = obj;
  3118.     if (!JS_AddNamedRoot(cx, &decoder->window_object, "window_object"))
  3119.         return NULL;
  3120.  
  3121.     /* Create a new image context for anonymous images. */
  3122.     if (!lm_NewImageContext(context, decoder))
  3123.         return NULL;
  3124.  
  3125.     /* Set the forward refcount to 1 because context holds decoder. */
  3126.     decoder->forw_count = 1;
  3127.     decoder->window_context = context;
  3128.     decoder->js_context = cx;
  3129.     context->mocha_context = cx;
  3130.  
  3131.     if (!lm_InitWindowContent(decoder)) {
  3132.         /* This will cause finalization and call lm_DestroyWindow(). */
  3133.         decoder->window_object = NULL;
  3134.         return NULL;
  3135.     }
  3136.  
  3137. #define HOLD(obj)       if (!JS_AddNamedRoot(cx, &(obj), #obj)) return NULL
  3138.  
  3139.     /* Drop all object prototype refs. */
  3140.     HOLD(decoder->anchor_prototype);
  3141.     HOLD(decoder->bar_prototype);
  3142.     HOLD(decoder->document_prototype);
  3143.     HOLD(decoder->event_prototype);
  3144.     HOLD(decoder->event_capturer_prototype);
  3145.     HOLD(decoder->event_receiver_prototype);
  3146.     HOLD(decoder->form_prototype);
  3147.     HOLD(decoder->image_prototype);
  3148.     HOLD(decoder->input_prototype);
  3149.     HOLD(decoder->layer_prototype);
  3150.     HOLD(decoder->option_prototype);
  3151.     HOLD(decoder->rect_prototype);
  3152.     HOLD(decoder->url_prototype);
  3153.  
  3154.     /* Drop window sub-object refs. */
  3155.     HOLD(decoder->document);
  3156.     HOLD(decoder->history);
  3157.     HOLD(decoder->location);
  3158.     HOLD(decoder->navigator);
  3159.     HOLD(decoder->components);
  3160.     HOLD(decoder->crypto);
  3161.     HOLD(decoder->screen);
  3162.     HOLD(decoder->hardware);
  3163.     HOLD(decoder->pkcs11);
  3164.     /* Drop ad-hoc GC roots. */
  3165.     HOLD(decoder->event_receiver);
  3166.     HOLD(decoder->opener);
  3167.  
  3168. #undef HOLD
  3169.  
  3170.     JS_SetBranchCallback(cx, lm_BranchCallback);
  3171.     JS_SetErrorReporter(cx, lm_ErrorReporter);
  3172.     return decoder;
  3173. }
  3174.  
  3175. void
  3176. lm_DestroyWindow(MochaDecoder *decoder)
  3177. {
  3178.     JSContext *cx;
  3179.  
  3180.     /* All reference counts must be 0 here. */
  3181.     XP_ASSERT(decoder->forw_count == 0);
  3182.     XP_ASSERT(decoder->back_count == 0);
  3183.  
  3184.     /* We must not have an MWContext at this point. */
  3185.     XP_ASSERT(!decoder->window_context);
  3186.  
  3187.     /* Drop decoder refs to window prototypes and sub-objects. */
  3188.     lm_FreeWindowContent(decoder, JS_FALSE);
  3189.  
  3190.     /* Set cx for use by DROP. */
  3191.     cx = decoder->js_context;
  3192.  
  3193. #define DROP(obj)       JS_RemoveRoot(cx, &(obj))
  3194.  
  3195.     /* Drop all object prototype refs. */
  3196.     DROP(decoder->anchor_prototype);
  3197.     DROP(decoder->bar_prototype);
  3198.     DROP(decoder->document_prototype);
  3199.     DROP(decoder->event_prototype);
  3200.     DROP(decoder->event_capturer_prototype);
  3201.     DROP(decoder->event_receiver_prototype);
  3202.     DROP(decoder->form_prototype);
  3203.     DROP(decoder->image_prototype);
  3204.     DROP(decoder->input_prototype);
  3205.     DROP(decoder->layer_prototype);
  3206.     DROP(decoder->option_prototype);
  3207.     DROP(decoder->rect_prototype);
  3208.     DROP(decoder->url_prototype);
  3209.  
  3210.     /* Drop window sub-object refs. */
  3211.     DROP(decoder->document);
  3212.     DROP(decoder->history);
  3213.     DROP(decoder->location);
  3214.     DROP(decoder->navigator);
  3215.     DROP(decoder->components);
  3216.     DROP(decoder->crypto);
  3217.     DROP(decoder->screen);
  3218.     DROP(decoder->hardware);
  3219.     DROP(decoder->pkcs11);
  3220.     /* Drop ad-hoc GC roots. */
  3221.     DROP(decoder->event_receiver);
  3222.     DROP(decoder->opener);
  3223.  
  3224.     if (decoder->in_window_quota)
  3225.         lm_window_count--;
  3226.  
  3227.     /* Remove the root that holds up the whole window in the decoder world */
  3228.     DROP(decoder->window_object);
  3229.  
  3230. #undef DROP
  3231.  
  3232.     /*
  3233.      * Destroy the mocha image context.  All mocha images need to have been
  3234.      * finalized *before* we get here, since image destruction requires a
  3235.      * valid MWContext.
  3236.      */
  3237.     ET_PostFreeImageContext(NULL, decoder->image_context);
  3238.  
  3239.     /* Free JS context and decoder struct, window is gone. */
  3240.     JS_DestroyContext(cx);
  3241.  
  3242.     XP_DELETE(decoder);
  3243. }
  3244.  
  3245. #ifdef DEBUG
  3246. extern MochaDecoder *
  3247. lm_HoldBackCount(MochaDecoder *decoder)
  3248. {
  3249.     if (decoder) {
  3250.         XP_ASSERT(decoder->back_count >= 0);
  3251.         decoder->back_count++;
  3252.     }
  3253.     return decoder;
  3254. }
  3255.  
  3256. extern void
  3257. lm_DropBackCount(MochaDecoder *decoder)
  3258. {
  3259.     if (!decoder)
  3260.         return;
  3261.     XP_ASSERT(decoder->back_count > 0);
  3262.     if (--decoder->back_count <= 0) {
  3263.         decoder->back_count = 0;
  3264.         XP_ASSERT(decoder->forw_count >= 0);
  3265.         if (!decoder->forw_count)
  3266.             lm_DestroyWindow(decoder);
  3267.     }
  3268. }
  3269. #endif /* DEBUG */
  3270.  
  3271. JSBool
  3272. lm_InitWindowContent(MochaDecoder *decoder)
  3273. {
  3274.     JSContext *cx;
  3275.     JSObject *obj;
  3276.  
  3277.     cx = decoder->js_context;
  3278.     obj = decoder->window_object;
  3279.     if (!JS_InitStandardClasses(cx, obj))
  3280.         return JS_FALSE;
  3281.  
  3282.     if (!lm_AddSetParentSecurityCheck(cx, obj))
  3283.         return JS_FALSE;
  3284.  
  3285. #ifdef JAVA
  3286.     if (JSJ_IsEnabled() && !JSJ_InitContext(cx, obj))
  3287.         return JS_FALSE;
  3288. #endif
  3289.     if (!JS_DefineProperties(cx, obj, window_props))
  3290.         return JS_FALSE;
  3291.  
  3292.     if (decoder->opener) {
  3293.         if (!JS_DefinePropertyWithTinyId(cx, obj, lm_opener_str, WIN_OPENER,
  3294.                                          OBJECT_TO_JSVAL(decoder->opener),
  3295.                                          NULL, NULL, JSPROP_ENUMERATE)) {
  3296.             return JS_FALSE;
  3297.         }
  3298.     }
  3299.  
  3300.     return (JSBool)(lm_DefineWindowProps(cx, decoder) &&
  3301.            JS_SetPrototype(cx, obj, decoder->event_capturer_prototype));
  3302. }
  3303.  
  3304. JSBool
  3305. lm_DefineWindowProps(JSContext *cx, MochaDecoder *decoder)
  3306. {
  3307.     JSObject *obj;
  3308.  
  3309.     obj = decoder->window_object;
  3310.     return (JSBool)(JS_DefineFunctions(cx, obj, lm_window_methods) &&
  3311.            lm_InitEventClasses(decoder) &&
  3312.            lm_InitDocumentClass(decoder) &&
  3313.            lm_DefineDocument(decoder, LO_DOCUMENT_LAYER_ID) &&
  3314.            lm_DefineHistory(decoder) &&
  3315.            lm_DefineLocation(decoder) &&
  3316.            lm_DefineCrypto(decoder) &&
  3317.            lm_DefineBarClasses(decoder) &&
  3318.            lm_InitLayerClass(decoder) &&
  3319.            lm_InitRectClass(decoder) &&
  3320.            lm_InitImageClass(decoder) &&
  3321.            lm_InitAnchorClass(decoder) &&
  3322.            lm_InitInputClasses(decoder) &&
  3323.            lm_DefinePkcs11(decoder));
  3324. }
  3325.  
  3326. void
  3327. lm_FreeWindowContent(MochaDecoder *decoder, JSBool fromDiscard)
  3328. {
  3329.     JSContext *cx;
  3330.     JSObject *obj;
  3331.     JSNestingUrl * url, * next_url;
  3332.  
  3333.     /* Clear any stream that the user forgot to close. */
  3334.     lm_ClearDecoderStream(decoder, fromDiscard);
  3335.  
  3336.     /* Clear any pending timeouts and URL fetches. */
  3337.     lm_ClearWindowTimeouts(decoder);
  3338.  
  3339.     /* These flags should never be set, but if any are, we'll cope. */
  3340.     decoder->replace_location = JS_FALSE;
  3341.     decoder->resize_reload    = JS_FALSE;
  3342.     decoder->load_event_sent  = JS_FALSE;
  3343.     decoder->visited          = JS_FALSE;
  3344.     decoder->writing_input    = JS_FALSE;
  3345.  
  3346.     /* This flag may have been set by a script; clear it now. */
  3347.     decoder->principals_compromised = JS_FALSE;
  3348.  
  3349.     /* need to inline this since source_url is 'const char *' and the Mac will whine */
  3350.     if (decoder->source_url) {
  3351.     XP_FREE((char *) decoder->source_url);
  3352.     decoder->source_url = NULL;
  3353.     }
  3354.  
  3355.     for (url = decoder->nesting_url; url; url = next_url) {
  3356.     next_url = url->next;
  3357.     XP_FREE(url->str);
  3358.     XP_FREE(url);
  3359.     }
  3360.     decoder->nesting_url = NULL;
  3361.  
  3362.     /* Forgive and forget all excessive errors. */
  3363.     decoder->error_count = 0;
  3364.  
  3365.     decoder->active_form_id = 0;
  3366.     decoder->signature_ordinal = 0;
  3367.  
  3368.     /* Clear the event mask. */
  3369.     decoder->event_mask = 0;
  3370.  
  3371.     if (decoder->id_to_object_map) {
  3372.         PR_HashTableDestroy(decoder->id_to_object_map);
  3373.         decoder->id_to_object_map = NULL;
  3374.     }
  3375.  
  3376.     cx = decoder->js_context;
  3377.     decoder->firstVersion = JSVERSION_UNKNOWN;
  3378.     decoder->principals = NULL;
  3379.     if (decoder->early_access_list)
  3380.         lm_DestroyPrincipalsList(cx, decoder->early_access_list);
  3381.     decoder->early_access_list = NULL;
  3382.  
  3383. #define CLEAR(obj)      obj = NULL
  3384.  
  3385.     /* Clear all object prototype refs. */
  3386.     CLEAR(decoder->anchor_prototype);
  3387.     CLEAR(decoder->bar_prototype);
  3388.     CLEAR(decoder->document_prototype);
  3389.     CLEAR(decoder->event_prototype);
  3390.     CLEAR(decoder->event_capturer_prototype);
  3391.     CLEAR(decoder->event_receiver_prototype);
  3392.     CLEAR(decoder->form_prototype);
  3393.     CLEAR(decoder->image_prototype);
  3394.     CLEAR(decoder->input_prototype);
  3395.     CLEAR(decoder->layer_prototype);
  3396.     CLEAR(decoder->option_prototype);
  3397.     CLEAR(decoder->rect_prototype);
  3398.     CLEAR(decoder->url_prototype);
  3399.  
  3400.     /* Clear window sub-object refs. */
  3401.     if (decoder->document)
  3402.         lm_CleanUpDocumentRoots(decoder, decoder->document);
  3403.     CLEAR(decoder->document);
  3404.     CLEAR(decoder->history);
  3405.     CLEAR(decoder->location);
  3406.     CLEAR(decoder->navigator);
  3407.     CLEAR(decoder->components);
  3408.     CLEAR(decoder->crypto);
  3409.     CLEAR(decoder->screen);
  3410.     CLEAR(decoder->hardware);
  3411.     CLEAR(decoder->pkcs11);
  3412.  
  3413.     /* Drop ad-hoc GC roots, but not opener -- it survives unloads. */
  3414.     CLEAR(decoder->event_receiver);
  3415.  
  3416. #undef CLEAR
  3417.  
  3418. #undef DROP_AND_CLEAR
  3419.  
  3420.     obj = decoder->window_object;
  3421.     if (obj) {
  3422.     JS_ClearWatchPointsForObject(cx, obj);
  3423.         JS_ClearScope(cx, obj);
  3424.         (void) JS_DefinePropertyWithTinyId(cx, obj, lm_closed_str, WIN_CLOSED,
  3425.                                            JSVAL_FALSE, NULL, NULL,
  3426.                                            JSPROP_ENUMERATE|JSPROP_READONLY);
  3427.     }
  3428. }
  3429.  
  3430. void
  3431. LM_RemoveWindowContext(MWContext *context, History_entry * he)
  3432. {
  3433.     MochaDecoder *decoder;
  3434.     JSContext *cx;
  3435.  
  3436.     /* Do work only if this context has a JS decoder. */
  3437.     cx = context->mocha_context;
  3438.     if (!cx)
  3439.         return;
  3440.     decoder = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
  3441.  
  3442.     /* Sever the bidirectional connection between context and decoder. */
  3443.     XP_ASSERT(decoder->window_context == context);
  3444.     context->mocha_context = NULL;
  3445.     decoder->window_context = NULL;
  3446.     lm_ClearDecoderStream(decoder, JS_TRUE);
  3447.  
  3448.     ET_il_SetGroupObserver(context, decoder->image_context, NULL, JS_FALSE);
  3449.         
  3450.     if (he) {
  3451.         /*
  3452.          * Set current history entry's saved window from its layout cell.
  3453.          * We need to do this rather than SHIST_SetCurrentDocWindowData()
  3454.          * because FE_FreeGridWindow (who calls us indirectly) has already
  3455.          * "stolen" session history for return to layout, who saves it in
  3456.          * parent session history in lo_InternalDiscardDocument().
  3457.          */
  3458.         he->savedData.Window = decoder;
  3459.         return;
  3460.     }
  3461.  
  3462.     /* This might call lm_DestroyWindow(decoder), so do it last. */
  3463.     LM_PutMochaDecoder(decoder);
  3464. }
  3465.  
  3466. extern void
  3467. LM_DropSavedWindow(MWContext *context, void *window)
  3468. {
  3469.     MochaDecoder *decoder = window;
  3470. #ifdef DEBUG
  3471.     extern PRThread *mozilla_thread;
  3472.  
  3473.     /* Our caller, SHIST_FreeHistoryEntry, must run on the mozilla thread. */
  3474.     XP_ASSERT(PR_CurrentThread() == mozilla_thread);
  3475. #endif
  3476.  
  3477.     et_PutMochaDecoder(context, decoder);
  3478. }
  3479.