home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * The contents of this file are subject to the Netscape Public License
- * Version 1.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
- */
- /*
- * JS reflection of the current Navigator Window.
- *
- * Brendan Eich, 9/8/95
- */
- #include "lm.h"
- #include "xp.h"
- #include "xpgetstr.h"
- #include "structs.h"
- #include "layout.h" /* included via -I../layout */
- #include "prtime.h"
- #include "shist.h"
- #include "ssl.h"
- #include "libi18n.h"
- #include "jsdbgapi.h"
- #include "intl_csi.h"
- #include "layers.h"
- #include "base64.h"
-
- #define IL_CLIENT
- #include "libimg.h" /* Image Library public API. */
- #include "prthread.h"
-
- #ifdef JAVA
- #include "jsjava.h"
- #endif
-
- #undef FREE_AND_CLEAR /* XXX over-including Mac compiled headers */
-
- extern int XP_MSG_JS_CLOSE_WINDOW;
- extern int XP_MSG_JS_CLOSE_WINDOW_NAME;
-
- enum window_slot {
- WIN_LENGTH = -1,
- WIN_FRAMES = -2,
- WIN_PARENT = -3,
- WIN_TOP = -4,
- WIN_SELF = -5,
- WIN_NAME = -6,
- WIN_STATUS = -7,
- WIN_DEFAULT_STATUS = -8,
- WIN_OPENER = -9,
- WIN_CLOSED = -10,
- WIN_WIDTH = -11,
- WIN_HEIGHT = -12,
- WIN_OUTWIDTH = -13,
- WIN_OUTHEIGHT = -14,
- WIN_XPOS = -15,
- WIN_YPOS = -16,
- WIN_XOFFSET = -17,
- WIN_YOFFSET = -18,
- WIN_SECURE = -19,
- WIN_LOADING = -20,
- WIN_FRAMERATE = -21,
- WIN_OFFSCREEN_BUFFERING = -22
- };
-
- #define IS_INSECURE_SLOT(s) (WIN_LOADING <= (s) && (s) <= WIN_CLOSED)
-
- static JSPropertySpec window_props[] = {
- {"length", WIN_LENGTH, JSPROP_ENUMERATE|JSPROP_READONLY},
- {"frames", WIN_FRAMES, JSPROP_ENUMERATE|JSPROP_READONLY},
- {"parent", WIN_PARENT, JSPROP_ENUMERATE|JSPROP_READONLY},
- {"top", WIN_TOP, JSPROP_ENUMERATE|JSPROP_READONLY},
- {"self", WIN_SELF, JSPROP_ENUMERATE|JSPROP_READONLY},
- {"window", WIN_SELF, JSPROP_READONLY},
- {"name", WIN_NAME, JSPROP_ENUMERATE},
- {"status", WIN_STATUS, JSPROP_ENUMERATE},
- {"defaultStatus", WIN_DEFAULT_STATUS, JSPROP_ENUMERATE},
- {lm_opener_str, WIN_OPENER, JSPROP_ENUMERATE},
- {lm_closed_str, WIN_CLOSED, JSPROP_ENUMERATE|JSPROP_READONLY},
- {"innerWidth", WIN_WIDTH, JSPROP_ENUMERATE},
- {"innerHeight", WIN_HEIGHT, JSPROP_ENUMERATE},
- {"outerWidth", WIN_OUTWIDTH, JSPROP_ENUMERATE},
- {"outerHeight", WIN_OUTHEIGHT, JSPROP_ENUMERATE},
- {"screenX", WIN_XPOS, JSPROP_ENUMERATE},
- {"screenY", WIN_YPOS, JSPROP_ENUMERATE},
- {"pageXOffset", WIN_XOFFSET, JSPROP_ENUMERATE|JSPROP_READONLY},
- {"pageYOffset", WIN_YOFFSET, JSPROP_ENUMERATE|JSPROP_READONLY},
- {"secure", WIN_SECURE, JSPROP_ENUMERATE|JSPROP_READONLY},
- {"frameRate", WIN_FRAMERATE, JSPROP_ENUMERATE},
- {"offscreenBuffering",
- WIN_OFFSCREEN_BUFFERING,JSPROP_ENUMERATE},
- {0}
- };
-
- static Chrome *
- win_get_chrome(MWContext *context, Chrome *chrome)
- {
- if (!context->mocha_context)
- return NULL;
-
- /* All calls to this function must free the Chrome struct themselves!!! */
- chrome = JS_malloc(context->mocha_context, sizeof *chrome);
- if (!chrome)
- return NULL;
- XP_BZERO(chrome, sizeof *chrome);
-
- ET_PostQueryChrome(context, chrome);
-
- return chrome;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
- {
- MochaDecoder *decoder;
- MWContext *context;
- jsint count;
- Chrome *chrome = NULL;
- JSString * str;
- jsint slot;
- CL_OffscreenMode offscreen_mode;
- int status;
-
- while (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, NULL))) {
- obj = JS_GetPrototype(cx, obj);
- if (!obj)
- return JS_TRUE;
- }
-
- /*
- * Allow anyone who can address this window to refer to its "window" and
- * "self" properties, because they refer to the window already in hand by
- * the accessing script. Useful for layer scripts that 'import window.*'.
- */
- if (JSVAL_IS_INT(id) && JSVAL_TO_INT(id) == WIN_SELF) {
- *vp = OBJECT_TO_JSVAL(decoder->window_object);
- return JS_TRUE;
- }
-
- slot = JSVAL_IS_INT(id) ? JSVAL_TO_INT(id) : 0;
-
- if (!IS_INSECURE_SLOT(slot) &&
- !lm_CheckContainerAccess(cx, obj, decoder,
- JSTARGET_UNIVERSAL_BROWSER_READ)) {
- return JS_FALSE;
- }
-
- context = decoder->window_context;
- if (!context) {
- if (JSVAL_IS_INT(id) && JSVAL_TO_INT(id) == WIN_CLOSED)
- *vp = JSVAL_TRUE;
- return JS_TRUE;
- }
-
- if (!JSVAL_IS_INT(id))
- return JS_TRUE;
-
- switch (slot) {
- case WIN_LENGTH:
- *vp = INT_TO_JSVAL(XP_ListCount(context->grid_children));
- break;
-
- case WIN_FRAMES:
- *vp = OBJECT_TO_JSVAL(decoder->window_object);
- break;
-
- case WIN_PARENT:
- *vp = OBJECT_TO_JSVAL(decoder->window_object);
- if (context->grid_parent) {
- decoder = LM_GetMochaDecoder(context->grid_parent);
- if (decoder) {
- *vp = OBJECT_TO_JSVAL(decoder->window_object);
- LM_PutMochaDecoder(decoder);
- }
- }
- break;
-
- case WIN_TOP:
- while (context->grid_parent)
- context = context->grid_parent;
- decoder = LM_GetMochaDecoder(context);
- *vp = OBJECT_TO_JSVAL(decoder ? decoder->window_object : NULL);
- if (decoder)
- LM_PutMochaDecoder(decoder);
- break;
-
- case WIN_NAME:
- str = lm_LocalEncodingToStr(context, context->name);
- if (!str)
- return JS_FALSE;
- *vp = STRING_TO_JSVAL(str);
- break;
-
- case WIN_STATUS:
- return JS_TRUE; /* XXX can't get yet, return last known */
-
- case WIN_DEFAULT_STATUS:
- str = JS_NewStringCopyZ(cx, context->defaultStatus);
- if (!str)
- return JS_FALSE;
- *vp = STRING_TO_JSVAL(str);
- break;
-
- case WIN_OPENER:
- if (!JSVAL_IS_OBJECT(*vp) &&
- !JS_ConvertValue(cx, *vp, JSTYPE_OBJECT, vp)) {
- return JS_FALSE;
- }
- break;
-
- case WIN_CLOSED:
- *vp = JSVAL_FALSE;
- break;
-
- case WIN_WIDTH:
- if (!(chrome = win_get_chrome(context, chrome)))
- return JS_FALSE;
- *vp = INT_TO_JSVAL(chrome->w_hint);
- break;
-
- case WIN_HEIGHT:
- if (!(chrome = win_get_chrome(context, chrome)))
- return JS_FALSE;
- *vp = INT_TO_JSVAL(chrome->h_hint);
- break;
-
- case WIN_OUTWIDTH:
- if (!(chrome = win_get_chrome(context, chrome)))
- return JS_FALSE;
- *vp = INT_TO_JSVAL(chrome->outw_hint);
- break;
-
- case WIN_OUTHEIGHT:
- if (!(chrome = win_get_chrome(context, chrome)))
- return JS_FALSE;
- *vp = INT_TO_JSVAL(chrome->outh_hint);
- break;
-
- case WIN_XPOS:
- if (!(chrome = win_get_chrome(context, chrome)))
- return JS_FALSE;
- *vp = INT_TO_JSVAL(chrome->l_hint);
- break;
-
- case WIN_YPOS:
- if (!(chrome = win_get_chrome(context, chrome)))
- return JS_FALSE;
- *vp = INT_TO_JSVAL(chrome->t_hint);
- break;
-
- case WIN_XOFFSET:
- *vp = INT_TO_JSVAL(CL_GetCompositorXOffset(context->compositor));
- break;
-
- case WIN_YOFFSET:
- *vp = INT_TO_JSVAL(CL_GetCompositorYOffset(context->compositor));
- break;
-
- case WIN_SECURE:
- status = ET_GetSecurityStatus(context);
- if (status == SSL_SECURITY_STATUS_ON_LOW || status == SSL_SECURITY_STATUS_ON_HIGH)
- *vp = JSVAL_TRUE;
- else
- *vp = JSVAL_FALSE;
- break;
-
- case WIN_LOADING:
- decoder = LM_GetMochaDecoder(context);
- if (decoder && !decoder->load_event_sent)
- *vp = JSVAL_TRUE;
- else
- *vp = JSVAL_FALSE;
- if (decoder)
- LM_PutMochaDecoder(decoder);
- break;
-
- case WIN_FRAMERATE:
- *vp = INT_TO_JSVAL(CL_GetCompositorFrameRate(context->compositor));
- break;
-
- case WIN_OFFSCREEN_BUFFERING:
- offscreen_mode = CL_GetCompositorOffscreenDrawing(context->compositor);
-
- switch (offscreen_mode) {
- case CL_OFFSCREEN_ENABLED:
- *vp = JSVAL_TRUE;
- break;
- case CL_OFFSCREEN_DISABLED:
- *vp = JSVAL_FALSE;
- break;
- case CL_OFFSCREEN_AUTO:
- str = JS_NewStringCopyZ(cx, "auto");
- if (!str)
- return JS_FALSE;
- *vp = STRING_TO_JSVAL(str);
- break;
- }
- break;
-
- default:
- if (slot < 0) {
- /* Don't mess with user-defined or method properties. */
- return JS_TRUE;
- }
-
- /* XXX silly xp_cntxt.c puts newer contexts at the front! fix. */
- count = XP_ListCount(context->grid_children);
- context = XP_ListGetObjectNum(context->grid_children, count - slot);
- if (context) {
- decoder = LM_GetMochaDecoder(context);
- if (decoder) {
- *vp = OBJECT_TO_JSVAL(decoder->window_object);
- LM_PutMochaDecoder(decoder);
- } else {
- *vp = JSVAL_NULL;
- }
- }
- break;
- }
- if (chrome)
- JS_free(cx, chrome);
-
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
- {
- MochaDecoder *decoder, *parent_decoder;
- CL_OffscreenMode mode;
- JSBool enable_offscreen;
- jsdouble frame_rate, size;
- MWContext *context;
- Chrome *chrome = NULL;
- enum window_slot window_slot;
- const char *prop_name;
- char *str, *name, *old_name;
- jsint slot;
- int32 width, height;
-
- while (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, NULL))) {
- obj = JS_GetPrototype(cx, obj);
- if (!obj)
- return JS_TRUE;
- }
-
- if (!lm_CheckContainerAccess(cx, obj, decoder,
- JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
- return JS_FALSE;
- }
-
- context = decoder->window_context;
- if (!context)
- return JS_TRUE;
-
- if (!JSVAL_IS_INT(id)) {
- /* Due to the wonderful world of threads we need to know ahead of time if
- * someone is setting an onMouseMove event handler here or in document so
- * that we don't lose messages.*/
- if (JS_TypeOfValue(cx, *vp) == JSTYPE_FUNCTION) {
- if (JSVAL_IS_STRING(id)) {
- prop_name = JS_GetStringBytes(JSVAL_TO_STRING(id));
- /* XXX use lm_onMouseMove_str etc.*/
- if (XP_STRCMP(prop_name, "onmousemove") == 0 ||
- XP_STRCMP(prop_name, "onMouseMove") == 0) {
- decoder->window_context->js_drag_enabled = TRUE;
- }
- }
- }
- return JS_TRUE;
- }
-
- slot = JSVAL_TO_INT(id);
-
- window_slot = slot;
- switch (window_slot) {
- case WIN_NAME:
- case WIN_STATUS:
- case WIN_DEFAULT_STATUS:
- if (!JSVAL_IS_STRING(*vp) &&
- !JS_ConvertValue(cx, *vp, JSTYPE_STRING, vp)) {
- return JS_FALSE;
- }
- break;
- default:;
- }
-
- switch (window_slot) {
- case WIN_NAME:
- /* Don't let rogue JS name a mail or news window and then close it. */
- if (context->type != MWContextBrowser && context->type != MWContextPane)
- return JS_TRUE;
- name = lm_StrToLocalEncoding(context, JSVAL_TO_STRING(*vp));
- if (!name)
- return JS_FALSE;
- if (!lm_CheckWindowName(cx, name)) {
- XP_FREE(name);
- return JS_FALSE;
- }
- old_name = context->name;
- if (old_name) {
- /* If context is a frame, change its name in its parent's scope. */
- if (context->grid_parent) {
- parent_decoder = LM_GetMochaDecoder(context->grid_parent);
- if (parent_decoder) {
- JS_DeleteProperty(cx, parent_decoder->window_object,
- old_name);
- LM_PutMochaDecoder(parent_decoder);
- }
- }
- XP_FREE(old_name);
- }
- context->name = name;
- break;
-
- case WIN_STATUS:
- ET_PostProgress(context, JS_GetStringBytes(JSVAL_TO_STRING(*vp)));
- break;
-
- case WIN_DEFAULT_STATUS:
- str = JS_strdup(cx, JS_GetStringBytes(JSVAL_TO_STRING(*vp)));
- if (!str)
- return JS_FALSE;
- if (context->defaultStatus)
- XP_FREE(context->defaultStatus);
- context->defaultStatus = str;
- ET_PostProgress(context, NULL);
- break;
-
- case WIN_OPENER:
- if (decoder->opener && !JSVAL_TO_OBJECT(*vp))
- decoder->opener = NULL;
- break;
-
- case WIN_WIDTH:
- if (context->grid_parent)
- return JS_TRUE;
- if (!JS_ValueToNumber(cx, *vp, &size))
- return JS_FALSE;
- if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
- return JS_FALSE;
- chrome->w_hint = (int32)size;
- chrome->outw_hint = chrome->outh_hint = 0;
- /* Minimum window size is 100 x 100 without security */
- if (chrome->w_hint < 100) {
- if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE))
- chrome->w_hint = 100;
- }
- chrome->w_hint = (chrome->w_hint < 10) ? 10 : chrome->w_hint;
- ET_PostUpdateChrome(decoder->window_context, chrome);
- break;
-
- case WIN_HEIGHT:
- if (context->grid_parent)
- return JS_TRUE;
- if (!JS_ValueToNumber(cx, *vp, &size))
- return JS_FALSE;
- if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
- return JS_FALSE;
- chrome->h_hint = (int32)size;
- chrome->outw_hint = chrome->outh_hint = 0;
- /* Minimum window size is 100 x 100 without security */
- if (chrome->h_hint < 100) {
- if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE))
- chrome->h_hint = 100;
- }
- chrome->h_hint = (chrome->h_hint < 10) ? 10 : chrome->h_hint;
- ET_PostUpdateChrome(decoder->window_context, chrome);
- break;
-
- case WIN_OUTWIDTH:
- if (!JS_ValueToNumber(cx, *vp, &size))
- return JS_FALSE;
- if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
- return JS_FALSE;
- chrome->outw_hint = (int32)size;
- /* Minimum window size is 100 x 100 without security */
- if (chrome->outw_hint < 100) {
- if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE))
- chrome->outw_hint = 100;
- }
- chrome->outw_hint = (chrome->outw_hint < 10) ? 10 : chrome->outw_hint;
- ET_PostUpdateChrome(decoder->window_context, chrome);
- break;
-
- case WIN_OUTHEIGHT:
- if (!JS_ValueToNumber(cx, *vp, &size))
- return JS_FALSE;
- if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
- return JS_FALSE;
- chrome->outh_hint = (int32)size;
- /* Minimum window size is 100 x 100 without security */
- if (chrome->outh_hint < 100) {
- if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE))
- chrome->outh_hint = 100;
- }
- chrome->outh_hint = (chrome->outh_hint < 10) ? 10 : chrome->outh_hint;
- ET_PostUpdateChrome(decoder->window_context, chrome);
- break;
-
- case WIN_XPOS:
- if (!JS_ValueToNumber(cx, *vp, &size))
- return JS_FALSE;
- if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
- return JS_FALSE;
- chrome->l_hint = (int32)size;
- /* Windows must be positioned on screen without security */
- ET_PostGetScreenSize(decoder->window_context, &width, &height);
- if ((width < chrome->l_hint + chrome->outw_hint)||(chrome->l_hint < 0)){
- if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
- chrome->l_hint = (width < chrome->l_hint + chrome->outw_hint) ?
- width - chrome->outw_hint : chrome->l_hint;
- chrome->l_hint = (chrome->l_hint < 0) ? 0 : chrome->l_hint;
- }
- }
- ET_PostUpdateChrome(decoder->window_context, chrome);
- break;
-
- case WIN_YPOS:
- if (!JS_ValueToNumber(cx, *vp, &size))
- return JS_FALSE;
- if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
- return JS_FALSE;
- chrome->t_hint = (int32)size;
- /* Windows must be positioned on screen without security */
- ET_PostGetScreenSize(decoder->window_context, &width, &height);
- if ((height < chrome->t_hint + chrome->outh_hint)||(chrome->t_hint < 0)){
- if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
- chrome->t_hint = (height < chrome->t_hint + chrome->outh_hint) ?
- height - chrome->outh_hint : chrome->t_hint;
- chrome->t_hint = (chrome->t_hint < 0) ? 0 : chrome->t_hint;
- }
- }
- ET_PostUpdateChrome(decoder->window_context, chrome);
- break;
-
- case WIN_FRAMERATE:
- if (!JS_ValueToNumber(cx, *vp, &frame_rate))
- return JS_FALSE;
- CL_SetCompositorFrameRate(context->compositor, (uint32) frame_rate);
- break;
-
- case WIN_OFFSCREEN_BUFFERING:
- if (!JS_ValueToBoolean(cx, *vp, &enable_offscreen))
- return JS_FALSE;
- mode = enable_offscreen ? CL_OFFSCREEN_ENABLED : CL_OFFSCREEN_DISABLED;
- CL_SetCompositorOffscreenDrawing(context->compositor, mode);
- break;
-
- default:;
- }
- if (chrome)
- JS_free(cx, chrome);
-
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(JSBool)
- win_list_properties(JSContext *cx, JSObject *obj)
- {
- MochaDecoder *decoder;
- MWContext *context, *kid;
- XP_List *list;
- uint slot;
-
- decoder = JS_GetPrivate(cx, obj);
- if (!decoder)
- return JS_TRUE;
- context = decoder->window_context;
- if (!context)
- return JS_TRUE;
-
- /* xp_cntxt.c puts newer contexts at the front! deal. */
- list = context->grid_children;
- slot = XP_ListCount(list);
- while ((kid = XP_ListNextObject(list)) != NULL) {
- slot--;
- if (!JS_DefineProperty(cx, decoder->window_object, kid->name,
- JSVAL_NULL, NULL, NULL,
- JSPROP_ENUMERATE|JSPROP_READONLY))
- return JS_FALSE;
- }
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(JSBool)
- win_resolve_name(JSContext *cx, JSObject *obj, jsval id)
- {
- char * name = NULL;
- MochaDecoder *decoder;
- MWContext *context, *kid;
- XP_List *list;
- jsint slot;
- JSObject *window_obj;
- JSBool rv = JS_TRUE;
-
- /* Don't resolve any of names if id is on the left side of an = op. */
- if (JS_IsAssigning(cx))
- return JS_TRUE;
-
- if (!JSVAL_IS_STRING(id))
- return JS_TRUE;
-
- decoder = JS_GetPrivate(cx, obj);
- if (!decoder)
- return JS_TRUE;
- context = decoder->window_context;
- if (!context)
- return JS_TRUE;
-
- name = lm_StrToLocalEncoding(context, JSVAL_TO_STRING(id));
- if (!name)
- return JS_TRUE;
-
- /* xp_cntxt.c puts newer contexts at the front! deal. */
- list = context->grid_children;
- slot = XP_ListCount(list);
- while ((kid = XP_ListNextObject(list)) != NULL) {
- slot--;
- if (kid->name && XP_STRCMP(kid->name, name) == 0) {
- window_obj = decoder->window_object;
- if (!JS_DefinePropertyWithTinyId(cx, window_obj,
- kid->name, (int8)slot, JSVAL_NULL,
- NULL, NULL,
- JSPROP_ENUMERATE|JSPROP_READONLY))
- {
- rv = JS_FALSE;
- goto done;
- }
- if (!JS_AliasElement(cx, window_obj, kid->name, slot)) {
- rv = JS_FALSE;
- goto done;
- }
- goto done;
- }
- }
-
- XP_FREE(name);
- return lm_ResolveWindowProps(cx, decoder, obj, id);
-
- done:
- XP_FREE(name);
- return rv;
- }
-
- JSBool
- lm_ResolveWindowProps(JSContext *cx, MochaDecoder *decoder, JSObject *obj,
- jsval id)
- {
- const char * name;
-
- if (!JSVAL_IS_STRING(id))
- return JS_TRUE;
- name = JS_GetStringBytes(JSVAL_TO_STRING(id));
-
- if (!XP_STRCMP(name, "screen"))
- return ((JSBool) (lm_DefineScreen(decoder, obj) != NULL));
-
- if (!XP_STRCMP(name, "hardware"))
- return ((JSBool) (lm_DefineHardware(decoder, obj) != NULL));
-
- if (!XP_STRCMP(name, "loading"))
- return (JS_DefinePropertyWithTinyId(cx, obj, name, WIN_LOADING,
- JSVAL_VOID, NULL, NULL,
- JSPROP_ENUMERATE));
-
- if (!XP_STRCMP(name, lm_navigator_str)) {
- /* see if there is a global navigator object yet */
- if (!lm_crippled_decoder->navigator) {
- lm_DefinePluginClasses(lm_crippled_decoder);
- lm_crippled_decoder->navigator = lm_DefineNavigator(lm_crippled_decoder);
- if (!lm_crippled_decoder->navigator)
- return JS_FALSE;
- if (!JS_AddRoot(cx, &lm_crippled_decoder->navigator))
- return JS_FALSE;
- }
-
- /* use the global navigator */
- decoder->navigator = lm_crippled_decoder->navigator;
- if (!JS_DefineProperty(cx, obj, lm_navigator_str,
- OBJECT_TO_JSVAL(decoder->navigator),
- NULL, NULL,
- JSPROP_ENUMERATE | JSPROP_READONLY)) {
- return JS_FALSE;
- }
-
- }
-
- if (!XP_STRCMP(name, lm_components_str)) {
- /* see if there is a global components object yet */
- if (!lm_crippled_decoder->components) {
- lm_crippled_decoder->components =
- lm_DefineComponents(lm_crippled_decoder);
- if (!lm_crippled_decoder->components)
- return JS_FALSE;
- if (!JS_AddRoot(cx, &lm_crippled_decoder->components))
- return JS_FALSE;
- }
-
- /* use the global navigator */
- decoder->components = lm_crippled_decoder->components;
- if (!JS_DefineProperty(cx, obj, lm_components_str,
- OBJECT_TO_JSVAL(decoder->components),
- NULL, NULL,
- JSPROP_ENUMERATE | JSPROP_READONLY)) {
- return JS_FALSE;
- }
- }
-
- return lm_ResolveBar(cx, decoder, name);
- }
-
- PR_STATIC_CALLBACK(void)
- win_finalize(JSContext *cx, JSObject *obj)
- {
- MochaDecoder *decoder;
-
- decoder = JS_GetPrivate(cx, obj);
- if (!decoder)
- return;
- decoder->window_object = NULL;
-
- /*
- * If the decoder is going down and no one has a ref to
- * us run GC in LM_PutMochaDecoder() else destroy
- * the context here because its not being used by
- * whomever is finalizing us (i.e. a ref to a window
- * from another)
- */
- DROP_BACK_COUNT(decoder);
- }
-
- JSClass lm_window_class = {
- "Window", JSCLASS_HAS_PRIVATE,
- JS_PropertyStub, JS_PropertyStub, win_getProperty, win_setProperty,
- win_list_properties, win_resolve_name, JS_ConvertStub, win_finalize
- };
-
- /*
- * Alert and some simple dialogs.
- */
- PR_STATIC_CALLBACK(PRBool)
- win_alert(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
- MWContext *context;
- char *message, *platform_message;
- JSString * str;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
- if (!(str = JS_ValueToString(cx, argv[0])))
- return JS_FALSE;
-
- /* if there is no context let the script continue */
- context = decoder->window_context;
- if (!context)
- return JS_TRUE;
-
- message = lm_StrToLocalEncoding(context, str);
-
- if (message) {
- platform_message = lm_FixNewlines(cx, message, JS_FALSE);
- ET_PostMessageBox(context, platform_message, JS_FALSE);
- XP_FREEIF(platform_message);
- XP_FREE(message);
- }
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_confirm(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
- MWContext *context;
- JSString * str;
- char *message;
- JSBool ok;
-
- decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv);
- if (!decoder)
- return JS_FALSE;
- if (!(str = JS_ValueToString(cx, argv[0])))
- return JS_FALSE;
-
- context = decoder->window_context;
- if (context) {
- char *platform_message;
- message = lm_StrToLocalEncoding(context, str);
- if (!message) {
- *rval = JSVAL_FALSE;
- return JS_TRUE;
- }
- platform_message = lm_FixNewlines(cx, message, JS_FALSE);
- ok = ET_PostMessageBox(context, platform_message, JS_TRUE);
- XP_FREEIF(platform_message);
- XP_FREE(message);
- }
- else {
- ok = JS_FALSE;
- }
- *rval = BOOLEAN_TO_JSVAL(ok);
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_prompt(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
- MWContext *context;
- jsval arg;
- JSString *str;
- char *retval;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
- arg = argv[0];
-
- context = decoder->window_context;
- if (context) {
- char *query, *defval, *platform_query;
-
- /*
- * Build the query_string
- */
- if (!(str = JS_ValueToString(cx, argv[0])))
- return JS_FALSE;
- query = lm_StrToLocalEncoding(context, str);
- if (!query) {
- JS_ReportOutOfMemory(cx);
- return JS_FALSE;
- }
- platform_query = lm_FixNewlines(cx, query, JS_FALSE);
-
- /*
- * Build the default value
- */
- if (!(str = JS_ValueToString(cx, argv[1]))) {
- return JS_FALSE;
- }
- defval = lm_StrToLocalEncoding(context, str);
-
- retval = ET_PostPrompt(context, platform_query, defval);
- XP_FREEIF(query);
- XP_FREEIF(defval);
- XP_FREEIF(platform_query);
- }
- else {
- retval = NULL;
- }
-
- if (!retval) {
- *rval = JSVAL_NULL;
- return JS_TRUE;
- }
-
- XP_ASSERT(context);
- str = lm_LocalEncodingToStr(context, retval);
- XP_FREE(retval);
- if (!str)
- return JS_FALSE;
- *rval = STRING_TO_JSVAL(str);
- return JS_TRUE;
- }
-
- /*
- * Open and close of a named window.
- */
- JSBool
- lm_CheckWindowName(JSContext *cx, const char *window_name)
- {
- const char *cp;
-
- for (cp = window_name; *cp != '\0'; cp++) {
- if (!XP_IS_ALPHA(*cp) && !XP_IS_DIGIT(*cp) && *cp != '_') {
- JS_ReportError(cx,
- "illegal character '%c' ('\\%o') in window name %s",
- *cp, *cp, window_name);
- return JS_FALSE;
- }
- }
- return JS_TRUE;
- }
-
- static int32
- win_has_option(char *options, char *name)
- {
- char *comma, *equal;
- int32 found = 0;
-
- for (;;) {
- comma = XP_STRCHR(options, ',');
- if (comma) *comma = '\0';
- equal = XP_STRCHR(options, '=');
- if (equal) *equal = '\0';
- if (XP_STRCASECMP(options, name) == 0) {
- if (!equal || XP_STRCASECMP(equal + 1, "yes") == 0)
- found = 1;
- else
- found = XP_ATOI(equal + 1);
- }
- if (equal) *equal = '=';
- if (comma) *comma = ',';
- if (found || !comma)
- break;
- options = comma + 1;
- }
- return found;
- }
-
- /* These apply to top-level windows only, not to frames */
- static uint lm_window_count = 0;
- static uint lm_window_limit = 100;
-
- /* XXX this can't be static yet, it's called by lm_doc.c/doc_open */
- JSBool PR_CALLBACK
- win_open(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder, *new_decoder;
- URL_Struct *url_struct;
- JSString *str, *window_name_str;
- const char *url_string;
- char *window_name = NULL;
- char *options;
- Chrome *chrome = NULL;
- MWContext *old_context, *context;
- int32 width, height;
- int32 win_width, win_height;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
-
- /* Make url_string absolute based on current document's base URL. */
- url_struct = NULL;
- if (argc > 0) {
- if (!(str = JS_ValueToString(cx, argv[0])))
- return JS_FALSE;
- url_string = JS_GetStringBytes(str);
- if (*url_string != '\0') {
- url_string = lm_CheckURL(cx, url_string, JS_TRUE);
- if (url_string) {
- const char *referer;
- url_struct = NET_CreateURLStruct(url_string, NET_DONT_RELOAD);
- XP_FREE((char *)url_string);
- if (!url_struct) {
- JS_ReportOutOfMemory(cx);
- return JS_FALSE;
- }
- if (!(referer = lm_GetSubjectOriginURL(cx)) ||
- !(url_struct->referer = JS_strdup(cx, referer))) {
- NET_FreeURLStruct(url_struct);
- return JS_FALSE;
- }
- }
- }
- if (!url_string)
- return JS_FALSE;
- }
-
- /* Set this to null so we can goto fail from here onward. */
- new_decoder = NULL;
-
- /* Sanity-check the optional window_name argument. */
- if (argc > 1) {
- if (!(window_name_str = JS_ValueToString(cx, argv[1])))
- goto fail;
- if (!JS_LockGCThing(cx, window_name_str))
- goto fail;
- /* XXXunicode ? */
- window_name = lm_StrToLocalEncoding(decoder->window_context, window_name_str);
- if (!lm_CheckWindowName(cx, window_name))
- goto fail;
- } else {
- window_name_str = NULL;
- window_name = NULL;
- }
-
- /* Check for window chrome options. */
- chrome = XP_NEW_ZAP(Chrome);
- if(chrome == NULL)
- goto fail;
- if (argc > 2) {
- if (!(str = JS_ValueToString(cx, argv[2])))
- goto fail;
- options = JS_GetStringBytes(str);
-
- chrome->show_button_bar = win_has_option(options, "toolbar");
- chrome->show_url_bar = win_has_option(options, "location");
- chrome->show_directory_buttons =
- win_has_option(options, "directories") | win_has_option(options, "personalbar");
- chrome->show_bottom_status_bar = win_has_option(options, "status");
- chrome->show_menu = win_has_option(options, "menubar");
- chrome->show_security_bar = FALSE;
- chrome->w_hint =
- win_has_option(options, "innerWidth") | win_has_option(options, "width");
- chrome->h_hint =
- win_has_option(options, "innerHeight") | win_has_option(options, "height");
- chrome->outw_hint = win_has_option(options, "outerWidth");
- chrome->outh_hint = win_has_option(options, "outerHeight");
- chrome->l_hint =
- win_has_option(options, "left") | win_has_option(options, "screenX");
- chrome->t_hint =
- win_has_option(options, "top") | win_has_option(options, "screenY");
- chrome->show_scrollbar = win_has_option(options, "scrollbars");
- chrome->allow_resize = win_has_option(options, "resizable");
- chrome->allow_close = TRUE;
- chrome->dependent = win_has_option(options, "dependent");
- chrome->copy_history = FALSE; /* XXX need strong trust */
- chrome->topmost = win_has_option(options, "alwaysRaised");
- chrome->bottommost = win_has_option(options, "alwaysLowered");
- chrome->z_lock = win_has_option(options, "z-lock");
- chrome->is_modal = win_has_option(options, "modal");
- chrome->hide_title_bar = !(win_has_option(options, "titlebar"));
-
- /* Allow disabling of commands only if there is no menubar */
- if (!chrome->show_menu) {
- chrome->disable_commands = !win_has_option(options, "hotkeys");
- if (XP_STRCASESTR(options,"hotkeys")==NULL)
- chrome->disable_commands = FALSE;
- }
- /* If titlebar condition not specified, default to shown */
- if (XP_STRCASESTR(options,"titlebar")==0)
- chrome->hide_title_bar=FALSE;
-
- if (chrome->topmost || chrome->bottommost ||
- chrome->z_lock || chrome->is_modal ||
- chrome->hide_title_bar || chrome->disable_commands) {
- if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
- chrome->topmost = chrome->bottommost =
- chrome->z_lock = chrome->is_modal =
- chrome->hide_title_bar = chrome->disable_commands = 0;
- }
- }
-
- /* In order to not start Java for every single window open we
- * have to first check if we need to check, and then check.
- * Start by getting width and height to use for positioning
- * calculations. Defaults to 100 if neither are specified.
- * Then get screen size.
- */
- win_width = chrome->w_hint ? chrome->w_hint :
- (chrome->outw_hint ? chrome->outw_hint : 100);
- win_height = chrome->h_hint ? chrome->h_hint :
- (chrome->outh_hint ? chrome->outh_hint : 100);
- ET_PostGetScreenSize(decoder->window_context, &width, &height);
- if ((chrome->w_hint && chrome->w_hint < 100) ||
- (chrome->h_hint && chrome->h_hint < 100) ||
- (chrome->outw_hint && chrome->outw_hint < 100) ||
- (chrome->outh_hint && chrome->outh_hint < 100) ||
- (width < chrome->l_hint + win_width) ||
- (chrome->l_hint < 0) ||
- (height < chrome->t_hint + win_height) ||
- (chrome->t_hint < 0)) {
- /* The window is trying to put a window offscreen or make it too
- * small. We have to check the security permissions
- */
- if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
- /* Make sure windows are at least 100 by 100 pixels. */
- if (chrome->w_hint && chrome->w_hint < 100) {
- chrome->w_hint = 100;
- win_width = 100;
- }
- if (chrome->h_hint && chrome->h_hint < 100) {
- chrome->h_hint = 100;
- win_height = 100;
- }
- if (chrome->outw_hint && chrome->outw_hint < 100) {
- chrome->outw_hint = 100;
- win_width = 100;
- }
- if (chrome->outh_hint && chrome->outh_hint < 100) {
- chrome->outh_hint = 100;
- win_height = 100;
- }
- /* Windows must be positioned on screen without security */
- chrome->l_hint = (width < chrome->l_hint + win_width) ?
- width - win_width : chrome->l_hint;
- chrome->l_hint = (chrome->l_hint < 0) ? 0 : chrome->l_hint;
- chrome->t_hint = (height < chrome->t_hint + win_height) ?
- height - win_height : chrome->t_hint;
- chrome->t_hint = (chrome->t_hint < 0) ? 0 : chrome->t_hint;
- }
- }
- /* Make sure they always at least 10 x 10 regardless of security. 1 x 1
- * windows are really hard to spot */
- if (chrome->w_hint && chrome->w_hint < 10) chrome->w_hint = 10;
- if (chrome->h_hint && chrome->h_hint < 10) chrome->h_hint = 10;
- if (chrome->outw_hint && chrome->outw_hint < 10) chrome->outw_hint = 10;
- if (chrome->outh_hint && chrome->outh_hint < 10) chrome->outh_hint = 10;
-
- /* You must specify both width and height to get either */
- if (chrome->w_hint == 0 || chrome->h_hint == 0)
- chrome->w_hint = chrome->h_hint = 0;
- if (chrome->outw_hint == 0 || chrome->outh_hint == 0)
- chrome->outw_hint = chrome->outh_hint = 0;
-
- /* Needed to allow positioning of windows at 0,0 */
- if ((XP_STRCASESTR(options,"top") || XP_STRCASESTR(options,"left") ||
- XP_STRCASESTR(options,"screenX") || XP_STRCASESTR(options,"screenY")) != 0)
- chrome->location_is_chrome=TRUE;
-
- options = 0;
- } else {
- /* Make a fully chromed window, but don't copy history. */
- chrome->show_button_bar = TRUE;
- chrome->show_url_bar = TRUE;
- chrome->show_directory_buttons = TRUE;
- chrome->show_bottom_status_bar = TRUE;
- chrome->show_menu = TRUE;
- chrome->show_security_bar = FALSE;
- chrome->w_hint = chrome->h_hint = 0;
- chrome->is_modal = FALSE;
- chrome->show_scrollbar = TRUE;
- chrome->allow_resize = TRUE;
- chrome->allow_close = TRUE;
- chrome->copy_history = FALSE; /* XXX need strong trust */
- }
-
- /* Windows created by JS cannot be randomly used by Mail/News */
- chrome->restricted_target = TRUE;
-
- old_context = decoder->window_context;
- if (!old_context)
- goto fail;
- if (window_name)
- context = XP_FindNamedContextInList(old_context, (char*)window_name);
- else
- context = NULL;
-
- if (context) {
- new_decoder = LM_GetMochaDecoder(context);
- if (!new_decoder)
- goto fail;
- if (url_struct && !lm_GetURL(cx, new_decoder, url_struct)) {
- url_struct = 0;
- goto fail;
- }
- /* lm_GetURL() stashed a url_struct pointer, and owns it now. */
- url_struct = 0;
-
- /* If specific options are specified we will update the named
- * window to match those options. If not, we won't change them */
- if (argc > 2)
- ET_PostUpdateChrome(context, chrome);
- } else {
- if (lm_window_count >= lm_window_limit)
- goto fail;
- context = ET_PostNewWindow(old_context, url_struct,
- (char*)window_name,
- chrome);
- if (!context)
- goto fail;
- /* ET_PostNewWindow() stashed a url_struct pointer, and owns it now. */
- url_struct = 0;
- new_decoder = LM_GetMochaDecoder(context);
- if (!new_decoder) {
- (void) ET_PostDestroyWindow(context);
- goto fail;
- }
- }
-
- new_decoder->opener = obj;
- if (!JS_DefinePropertyWithTinyId(cx, new_decoder->window_object,
- lm_opener_str, WIN_OPENER,
- OBJECT_TO_JSVAL(obj),
- NULL, NULL, JSPROP_ENUMERATE)) {
- goto fail;
- }
- JS_UnlockGCThing(cx, window_name_str);
- new_decoder->in_window_quota = JS_TRUE;
- lm_window_count++;
- LM_PutMochaDecoder(new_decoder);
- *rval = OBJECT_TO_JSVAL(new_decoder->window_object);
- XP_FREE(chrome);
- XP_FREEIF(window_name);
- return JS_TRUE;
-
- fail:
- if (window_name_str)
- JS_UnlockGCThing(cx, window_name_str);
- if (new_decoder)
- LM_PutMochaDecoder(new_decoder);
- if (url_struct)
- NET_FreeURLStruct(url_struct);
- XP_FREEIF(chrome);
- XP_FREEIF(window_name);
- *rval = JSVAL_NULL;
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(JSBool)
- win_set_zoptions(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
- JSString *str;
- char *options;
- Chrome *chrome = NULL;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
- if (argc != 1) {
- JS_ReportError(cx, lm_argc_err_str);
- return JS_FALSE;
- }
- if (!decoder->window_context)
- return JS_TRUE;
-
- /* Check for window chrome options. */
- chrome = win_get_chrome(decoder->window_context, chrome);
- if(chrome == NULL)
- return JS_FALSE;
-
- if (!(str = JS_ValueToString(cx, argv[0])))
- return JS_TRUE;
- options = JS_GetStringBytes(str);
-
- if (lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
- chrome->topmost = win_has_option(options, "alwaysRaised");
- chrome->bottommost = win_has_option(options, "alwaysLowered");
- chrome->z_lock = win_has_option(options, "z-lock");
- }
-
- ET_PostUpdateChrome(decoder->window_context, chrome);
-
- options = 0;
- JS_free(cx, chrome);
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(JSBool)
- win_set_hotkeys(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
- Chrome *chrome = NULL;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
- if (argc != 1) {
- JS_ReportError(cx, lm_argc_err_str);
- return JS_FALSE;
- }
- if (!decoder->window_context)
- return JS_TRUE;
-
- /* Check for window chrome options. */
- chrome = win_get_chrome(decoder->window_context, chrome);
- if(chrome == NULL)
- return JS_FALSE;
-
- if(JSVAL_IS_BOOLEAN(argv[0])) {
- if (lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
- if (!chrome->show_menu) {
- chrome->disable_commands = !JSVAL_TO_BOOLEAN(argv[0]);
- }
- }
- }
-
- ET_PostUpdateChrome(decoder->window_context, chrome);
-
- JS_free(cx, chrome);
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(JSBool)
- win_set_resizable(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
- Chrome *chrome = NULL;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
- if (argc != 1) {
- JS_ReportError(cx, lm_argc_err_str);
- return JS_FALSE;
- }
- if (!decoder->window_context)
- return JS_TRUE;
-
- /* Check for window chrome options. */
- chrome = win_get_chrome(decoder->window_context, chrome);
- if(chrome == NULL)
- return JS_FALSE;
-
- if(JSVAL_IS_BOOLEAN(argv[0])) {
- chrome->allow_resize = JSVAL_TO_BOOLEAN(argv[0]);
- }
-
- ET_PostUpdateChrome(decoder->window_context, chrome);
-
- JS_free(cx, chrome);
- return JS_TRUE;
- }
-
- static void
- destroy_window(void *closure)
- {
- MWContext * context = (MWContext *)
- ((MozillaEvent_Timeout *)closure)->pClosure;
- ET_PostDestroyWindow(context);
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_close(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
- MochaDecoder *running_decoder;
- MWContext *context;
- char *message;
- JSBool ok;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
- context = decoder->window_context;
- if (!context || context->grid_parent)
- return JS_TRUE;
- running_decoder = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
- /* Bypass close window check if script is signed */
- if (context->type != MWContextBrowser && context->type != MWContextPane ||
- (!decoder->opener &&
- (XP_ListCount(SHIST_GetList(context)) > 1 ||
- decoder != running_decoder)) &&
- !lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
- /*
- * Prevent this window.close() call if this window
- * - is not a browser window, or
- * - was not opened by javascript, and
- * - has session history other than the current document, or
- * - does not contain the script that is closing this window.
- * - has no security privileges.
- */
- if (context->name)
- message = PR_smprintf(XP_GetString(XP_MSG_JS_CLOSE_WINDOW_NAME),
- context->name);
- else
- message = XP_GetString(XP_MSG_JS_CLOSE_WINDOW);
- ok = ET_PostMessageBox(context, message, JS_TRUE);
- if (context->name)
- XP_FREE(message);
- if (!ok)
- return JS_TRUE;
- }
- if(!decoder->called_win_close) {
- decoder->called_win_close = JS_TRUE;
- /*
- * If we are closing the window that the script is running in
- * wait until the script has finished running before sending
- * the close message
- */
- if (decoder == running_decoder)
- ET_PostSetTimeout(destroy_window, context, 0, XP_DOCID(context));
- else
- ET_PostDestroyWindow(context);
-
- }
-
- return JS_TRUE;
- }
-
- /*
- * Timeout support.
- */
- static uint lm_timeout_count = 0;
- static uint lm_timeout_limit = 1000;
-
- #define HOLD_TIMEOUT(cx,to) ((to)->ref_count++)
- #define DROP_TIMEOUT(decoder,to) \
- NSPR_BEGIN_MACRO \
- XP_ASSERT((to)->ref_count > 0); \
- if (--(to)->ref_count == 0) \
- free_timeout(decoder,to); \
- NSPR_END_MACRO
-
- static void
- free_timeout(MochaDecoder *decoder, JSTimeout *timeout)
- {
- MWContext *context;
- JSContext *cx;
-
- cx = decoder->js_context;
- context = decoder->window_context;
- if (context) {
- XP_ASSERT(context->js_timeouts_pending > 0);
- context->js_timeouts_pending--;
- }
-
- if (timeout->expr)
- JS_free(cx, timeout->expr);
- else if (timeout->funobj) {
- JS_RemoveRoot(cx, &timeout->funobj);
- if (timeout->argv) {
- int i;
- for (i = 0; i < timeout->argc; i++)
- JS_RemoveRoot(cx, &timeout->argv[i]);
- JS_free(cx, timeout->argv);
- }
- }
- if (timeout->principals)
- JSPRINCIPALS_DROP(cx, timeout->principals);
- XP_FREEIF(timeout->filename);
- JS_free(cx, timeout);
- lm_timeout_count--;
- }
-
- /* Re-insert timeout before the first list item with greater deadline, or at
- * the head if the list is empty, or at the tail if there is no item with
- * greater deadline.
- * Through the righteousness of double-indirection we do this without two
- * ugly if-tests.
- */
- static void
- insert_timeout_into_list(JSTimeout **listp, JSTimeout *timeout)
- {
- JSTimeout *to;
-
- while ((to = *listp) != NULL) {
- if (LL_CMP(to->when, >, timeout->when))
- break;
- listp = &to->next;
- }
- timeout->next = to;
- *listp = timeout;
- }
-
- static JSTimeout *js_timeout_running = NULL;
- static JSTimeout **js_timeout_insertion_point = NULL;
-
- static void
- win_run_timeout(void *closure)
- {
- JSTimeout *timeout, *next;
- JSTimeout *last_expired_timeout;
- JSTimeout dummy_timeout;
- MochaDecoder *decoder;
- JSContext *cx;
- int64 now;
- jsval result;
- MWContext * context = (MWContext *)((MozillaEvent_Timeout *)closure)->pClosure;
- void *timer_id;
-
- /* make sure the context hasn't disappeared out from under us */
- if (!XP_IsContextInList(context))
- return;
-
- timer_id = ((MozillaEvent_Timeout *)closure)->pTimerId;
-
- decoder = LM_GetMochaDecoder(context);
- if (!decoder)
- return;
-
- if (!decoder->timeouts) {
- LM_PutMochaDecoder(decoder);
- return;
- }
-
- cx = decoder->js_context;
-
- /*
- * A front end timer has gone off. See which of our timeouts need
- * servicing
- */
- restart:
- LL_I2L(now, PR_IntervalNow());
-
- /* The timeout list is kept in deadline order. Discover the
- latest timeout whose deadline has expired. On some platforms,
- front-end timeout events fire "early", so we need to test the
- timer_id as well as the deadline. */
- last_expired_timeout = NULL;
- for (timeout = decoder->timeouts; timeout; timeout = timeout->next) {
- if ((timer_id == timeout->toid) || !LL_CMP(timeout->when, >, now))
- last_expired_timeout = timeout;
- }
-
- /* Maybe the timeout that the event was fired for has been deleted
- and there are no others timeouts with deadlines that make them
- eligible for execution yet. Go away. */
- if (!last_expired_timeout)
- return;
-
- /* Insert a dummy timeout into the list of timeouts between the portion
- of the list that we are about to process now and those timeouts that
- will be processed in a future call to win_run_timeout(). This dummy
- timeout serves as the head of the list for any timeouts inserted as
- a result of running a timeout. */
- dummy_timeout.toid = NULL;
- dummy_timeout.public_id = 0;
- dummy_timeout.next = last_expired_timeout->next;
- last_expired_timeout->next = &dummy_timeout;
-
- /* Don't let lm_ClearWindowTimeouts throw away our stack-allocated
- dummy timeout. */
- dummy_timeout.ref_count = 2;
-
- XP_ASSERT(!js_timeout_insertion_point);
- js_timeout_insertion_point = &dummy_timeout.next;
-
- for (timeout = decoder->timeouts; timeout != &dummy_timeout; timeout = next) {
- next = timeout->next;
-
- /*
- * make sure the document that asked for this timeout is still
- * the active document
- */
- if (timeout->doc_id != XP_DOCID(decoder->window_context)) {
- #ifdef DEBUG_chouck
- XP_TRACE(("DOCID: in win_run_timeout"));
- #endif
- /* make sure this gets removed from the list */
- decoder->timeouts = next;
- DROP_TIMEOUT(decoder, timeout);
- continue;
- }
-
- /* Hold the timeout in case expr or funobj releases its doc. */
- HOLD_TIMEOUT(cx, timeout);
- js_timeout_running = timeout;
-
- if (timeout->expr) {
- /* Evaluate the timeout expression. */
- JSVersion save = JS_SetVersion(decoder->js_context,
- timeout->version);
- JS_EvaluateScriptForPrincipals(decoder->js_context,
- decoder->window_object,
- timeout->principals,
- timeout->expr,
- XP_STRLEN(timeout->expr),
- timeout->filename, timeout->lineno,
- &result);
- JS_SetVersion(decoder->js_context, save);
- } else {
- int64 lateness64;
- int32 lateness;
-
- /* Add "secret" final argument that indicates timeout
- lateness in milliseconds */
- LL_SUB(lateness64, now, timeout->when);
- LL_L2I(lateness, lateness64);
- timeout->argv[timeout->argc] = INT_TO_JSVAL((jsint)lateness);
- JS_CallFunctionValue(cx, decoder->window_object,
- OBJECT_TO_JSVAL(timeout->funobj),
- timeout->argc + 1, timeout->argv, &result);
- }
-
- /* If timeout's reference count is now 1, its doc was released
- * and we should restart this function.
- */
- js_timeout_running = NULL;
- if (timeout->ref_count == 1) {
- free_timeout(decoder, timeout);
- goto restart;
- }
- DROP_TIMEOUT(decoder, timeout);
-
- /* If we have a regular interval timer, we re-fire the
- * timeout, accounting for clock drift.
- */
- if (timeout->interval) {
- /* Compute time to next timeout for interval timer. */
- int32 delay32;
- int64 interval, delay;
- LL_I2L(interval, timeout->interval);
- LL_ADD(timeout->when, timeout->when, interval);
- LL_I2L(now, PR_IntervalNow());
- LL_SUB(delay, timeout->when, now);
- LL_L2I(delay32, delay);
-
- /* If the next interval timeout is already supposed to
- * have happened then run the timeout immediately.
- */
- if (delay32 < 0)
- delay32 = 0;
-
- /* Reschedule timeout. Account for possible error return in
- code below that checks for zero toid. */
- timeout->toid = ET_PostSetTimeout(win_run_timeout,
- decoder->window_context,
- (uint32)delay32,
- decoder->doc_id);
- }
-
- /* Running a timeout can cause another timeout to be deleted,
- so we need to reset the pointer to the following timeout. */
- next = timeout->next;
- decoder->timeouts = next;
-
- /* Free the timeout if this is not a repeating interval
- * timeout (or if it was an interval timeout, but we were
- * unsuccessful at rescheduling it.)
- */
- if (!timeout->interval || !timeout->toid) {
- DROP_TIMEOUT(decoder, timeout);
- } else {
- /* Reschedule an interval timeout */
- /* Insert interval timeout onto list sorted in deadline order. */
- insert_timeout_into_list(js_timeout_insertion_point, timeout);
- }
- }
-
- /* Take the dummy timeout off the head of the list */
- XP_ASSERT(decoder->timeouts == &dummy_timeout);
- decoder->timeouts = dummy_timeout.next;
- js_timeout_insertion_point = NULL;
-
- LM_PutMochaDecoder(decoder);
- }
-
- void
- lm_ClearWindowTimeouts(MochaDecoder *decoder)
- {
- JSTimeout *timeout, *next;
-
- for (timeout = decoder->timeouts; timeout; timeout = next) {
- /* If win_run_timeouts() is higher up on the stack for this
- decoder, e.g. as a result of document.write from a timeout,
- then we need to reset the list insertion point for
- newly-created timeouts in case the user adds a timeout,
- before we pop the stack back to win_run_timeouts(). */
- if (js_timeout_running == timeout)
- js_timeout_insertion_point = NULL;
-
- next = timeout->next;
- if (timeout->toid)
- ET_PostClearTimeout(timeout->toid);
- timeout->toid = NULL;
- DROP_TIMEOUT(decoder, timeout);
- }
-
- for (timeout = decoder->saved_timeouts; timeout; timeout = next) {
- next = timeout->next;
- DROP_TIMEOUT(decoder, timeout);
- }
-
- decoder->timeouts = NULL;
- decoder->saved_timeouts = NULL;
- }
-
- /*
- * Stop time temporarily till we restore the timeouts. The timeouts
- * are cancelled with the FE, the current time is recorded and
- * the timeout list is saved.
- */
- void
- lm_SaveWindowTimeouts(MochaDecoder *decoder)
- {
- JSTimeout *timeout;
- int64 now, time_left;
-
- if (!decoder->timeouts)
- return;
-
- LL_I2L(now, PR_IntervalNow());
-
- /*
- * Clear all the timeouts so that they don't fire till we're
- * ready to restart time.
- */
- for (timeout = decoder->timeouts; timeout; timeout = timeout->next) {
- ET_PostClearTimeout(timeout->toid);
- /* Figure out how much time was left before the timeout fired */
- LL_SUB(time_left, timeout->when, now);
- timeout->when = time_left;
- }
-
- decoder->saved_timeouts = decoder->timeouts;
- decoder->timeouts = NULL;
- }
-
- /*
- * Restore timeouts from the saved_timeouts list and restart time.
- * These are timeouts that were suspended while we were reloading
- * the document.
- */
- void
- lm_RestoreWindowTimeouts(MochaDecoder *decoder)
- {
- JSTimeout *timeout, *next;
- int64 now, when;
- int interval;
- JSBool fire_now = JS_FALSE;
-
- if (!decoder->saved_timeouts)
- return;
-
- LL_I2L(now, PR_IntervalNow());
-
- for (timeout = decoder->saved_timeouts; timeout; timeout = next) {
- next = timeout->next;
-
- LL_L2I(interval, timeout->when);
- /* Unclear if result can be one of the operands */
- LL_ADD(when, timeout->when, now);
- timeout->when = when;
-
- timeout->doc_id = decoder->doc_id;
-
- /*
- * If we don't have to fire this timeout now, we tell the
- * FE to call us back.
- */
- if (interval > 0) {
- timeout->toid = ET_PostSetTimeout(win_run_timeout,
- decoder->window_context,
- (uint32)interval,
- decoder->doc_id);
- }
- else {
- timeout->toid = NULL;
- fire_now = JS_TRUE;
- }
-
- insert_timeout_into_list(&decoder->timeouts, timeout);
- }
-
- decoder->saved_timeouts = NULL;
-
- /*
- * If there are any timeouts that are ready to go, have them fired
- * off immediately.
- */
- if (fire_now) {
- MozillaEvent_Timeout e;
-
- e.ce.doc_id = decoder->doc_id;
- e.pClosure = decoder->window_context;
- e.pTimerId = NULL;
- e.ulTime = 0;
-
- win_run_timeout((void *)&e);
- }
- }
-
- static timeout_public_id_counter = 0;
-
- static const char setTimeout_str[] = "setTimeout";
- static const char setInterval_str[] = "setInterval";
- static const char *time_methods[2] = { setTimeout_str, setInterval_str };
-
- static JSBool
- win_set_timeout_or_interval(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval,
- JSBool interval_timer)
- {
- MWContext *context;
- MochaDecoder *decoder;
- jsdouble interval;
- JSString *str;
- char *expr;
- JSTimeout *timeout, **insertion_point;
- int64 now, delta;
- JSObject *funobj;
- JSStackFrame *fp;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
-
- if (lm_timeout_count >= lm_timeout_limit) {
- JS_ReportError(cx, "too many timeouts and intervals");
- return JS_FALSE;
- }
-
- if (!JS_ValueToNumber(cx, argv[1], &interval))
- return JS_FALSE;
-
- switch (JS_TypeOfValue(cx, argv[0])) {
- case JSTYPE_FUNCTION:
- funobj = JSVAL_TO_OBJECT(argv[0]);
- expr = NULL;
- break;
- case JSTYPE_STRING:
- case JSTYPE_OBJECT:
- if (!(str = JS_ValueToString(cx, argv[0])))
- return JS_FALSE;
- expr = JS_strdup(cx, JS_GetStringBytes(str));
- if (!expr)
- return JS_FALSE;
- funobj = NULL;
- break;
- default:
- JS_ReportError(cx, "useless %s call (missing quotes around argument?)",
- time_methods[interval_timer]);
- return JS_FALSE;
- }
-
- timeout = JS_malloc(cx, sizeof *timeout);
- if (!timeout) {
- JS_free(cx, expr);
- return JS_FALSE;
- }
- XP_BZERO(timeout, sizeof *timeout);
- timeout->ref_count = 1;
- if (interval_timer)
- timeout->interval = (int32)interval;
- timeout->expr = expr;
- timeout->funobj = funobj;
- timeout->version = JS_GetVersion(cx);
- timeout->principals = lm_GetPrincipalsFromStackFrame(cx);
- if (timeout->principals == NULL) {
- /* Result of out of memory error */
- DROP_TIMEOUT(decoder, timeout);
- return JS_FALSE;
- }
- JSPRINCIPALS_HOLD(cx, timeout->principals);
-
- fp = NULL;
- while ((fp = JS_FrameIterator(cx, &fp)) != NULL) {
- JSScript *script = JS_GetFrameScript(cx, fp);
- if (script) {
- /*
- * XXX - Disable error reporter; we may get an error
- * trying to find a line number. Two cases where we
- * get an error is in evaluating an expression as part
- * of the preferences code, and evaluating a javascript:
- * typein. In both cases there are no newlines and no
- * source annotations are generated, and the initial
- * linenumber is specified as zero. We need to clean
- * up all those cases and then remove the error reporter
- * workaround.
- */
- JSErrorReporter reporter = JS_SetErrorReporter(cx, NULL);
- const char *filename = JS_GetScriptFilename(cx, script);
- timeout->filename = filename ? XP_STRDUP(filename) : NULL;
- timeout->lineno = JS_PCToLineNumber(cx, script,
- JS_GetFramePC(cx, fp));
- JS_SetErrorReporter(cx, reporter);
- break;
- }
- }
-
- /* Keep track of any pending timeouts so that FE can tell whether
- the stop button should be active. */
- context = decoder->window_context;
- if (context)
- context->js_timeouts_pending++;
-
- if (expr) {
- timeout->argv = 0;
- timeout->argc = 0;
- } else {
- int i;
- /* Leave an extra slot for a secret final argument that
- indicates to the called function how "late" the timeout is. */
- timeout->argv = JS_malloc(cx, (argc - 1) * sizeof(jsval));
- if (!timeout->argv) {
- DROP_TIMEOUT(decoder, timeout);
- return JS_FALSE;
- }
- if (!JS_AddNamedRoot(cx, &timeout->funobj, "timeout.funobj")) {
- DROP_TIMEOUT(decoder, timeout);
- return JS_FALSE;
- }
-
- timeout->argc = 0;
- for (i = 2; (uint)i < argc; i++) {
- timeout->argv[i - 2] = argv[i];
- if (!JS_AddNamedRoot(cx, &timeout->argv[i - 2], "timeout.argv[i]"))
- {
- DROP_TIMEOUT(decoder, timeout);
- return JS_FALSE;
- }
- timeout->argc++;
- }
- }
-
- LL_I2L(now, PR_IntervalNow());
- LL_D2L(delta, interval);
- LL_ADD(timeout->when, now, delta);
- timeout->doc_id = decoder->doc_id;
-
- if (interval < 0)
- interval = 0;
-
- timeout->toid = ET_PostSetTimeout(win_run_timeout,
- decoder->window_context,
- (uint32)interval,
- decoder->doc_id);
- if (!timeout->toid) {
- DROP_TIMEOUT(decoder, timeout);
- return JS_FALSE;
- }
-
- if (js_timeout_insertion_point == NULL)
- insertion_point = &decoder->timeouts;
- else
- insertion_point = js_timeout_insertion_point;
-
- /* Insert interval timeout onto list sorted in deadline order */
- insert_timeout_into_list(insertion_point, timeout);
-
- lm_timeout_count++;
-
- timeout->public_id = ++timeout_public_id_counter;
- *rval = INT_TO_JSVAL((jsint)timeout->public_id);
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_set_timeout(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- return win_set_timeout_or_interval(cx, obj, argc, argv, rval, JS_FALSE);
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_set_interval(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- return win_set_timeout_or_interval(cx, obj, argc, argv, rval, JS_TRUE);
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_clear_timeout(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
- uint32 public_id;
- JSTimeout **top, *timeout;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
- if (!JSVAL_IS_INT(argv[0]))
- return JS_TRUE;
- public_id = (uint32)JSVAL_TO_INT(argv[0]);
- if (!public_id) /* id of zero is reserved for internal use */
- return JS_TRUE;
- for (top = &decoder->timeouts; ((timeout = *top) != NULL); top = &timeout->next) {
- if (timeout->public_id == public_id) {
- if (js_timeout_running == timeout) {
- /* We're running from inside the timeout. Mark this
- timeout for deferred deletion by the code in
- win_run_timeout() */
- timeout->interval = 0;
- } else {
- /* Delete the timeout from the pending timeout list */
- *top = timeout->next;
- ET_PostClearTimeout(timeout->toid);
- DROP_TIMEOUT(decoder, timeout);
- }
- break;
- }
- }
- return JS_TRUE;
- }
-
- /* Sleep for the specified number of milliseconds */
- PR_STATIC_CALLBACK(PRBool)
- win_delay(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
-
- /* XXX - Brendan and Scott decided not to provide a delay() method
- because of untoward side-effects of its use. We might do so in the
- future, so I'm effectively reserving the name by leaving a
- do-nothing method in the Window object. */
-
- #if DELAY_METHOD_ALLOWED
-
- /* Arbitrary maximum delay to prevent near-infinit delays */
- #define JS_MAX_DELAY 1000
-
- jsdouble ms;
- int64 ms64, c;
-
- if (argc < 1) {
- JS_ReportError(cx, lm_argc_err_str);
- return JS_FALSE;
- }
-
- if (!JS_ValueToNumber(cx, argv[0], &ms))
- return JS_FALSE;
-
- if (ms < 0) {
- JS_ReportError(cx, "milliseconds argument must be non-negative");
- return JS_FALSE;
- }
-
- /* Don't let someone hang the JS thread for too long. */
- if (ms > JS_MAX_DELAY)
- ms = JS_MAX_DELAY;
-
- LL_UI2L(ms64, (uint32)ms);
- LL_I2L(c, 1000);
- LL_MUL(ms64, ms64, c);
- {
- PRIntervalTime i;
- LL_L2I(i, ms64);
- PR_Sleep(i);
- }
- #undef JS_MAX_DELAY
-
- #endif
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_escape(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- jsdouble v;
- JSString *str;
- char *bytes;
- int32 length;
- int mask;
-
- if (argc > 1) {
- if (!JS_ValueToNumber(cx, argv[1], &v))
- return JS_FALSE;
- mask = (int)v;
- if (mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH)) {
- JS_ReportError(cx, "invalid string escape mask %x", mask);
- return JS_FALSE;
- }
- } else {
- mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
- }
- if (!(str = JS_ValueToString(cx, argv[0])))
- return JS_FALSE;
- /* XXXunicode ? */
- bytes = NET_EscapeBytes(JS_GetStringBytes(str),
- (int32)JS_GetStringLength(str),
- mask,
- &length);
- if (!bytes) {
- JS_ReportOutOfMemory(cx);
- return JS_FALSE;
- }
-
- /* XXXunicode ? */
- str = JS_NewString(cx, bytes, (size_t)length);
- if (!str)
- return JS_FALSE;
- *rval = STRING_TO_JSVAL(str);
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_unescape(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- JSString *str;
- size_t length;
- char *bytes;
-
- if (!(str = JS_ValueToString(cx, argv[0])))
- return JS_FALSE;
- length = JS_GetStringLength(str);
- if (!(bytes = JS_malloc(cx, length + 1)))
- return JS_FALSE;
- /* XXXunicode ? */
- XP_MEMCPY(bytes, JS_GetStringBytes(str), length);
- bytes[length] = '\0';
- length = (size_t)NET_UnEscapeBytes(bytes, length);
- /* XXXunicode ? */
- str = JS_NewString(cx, bytes, length);
- if (!str)
- return JS_FALSE;
- *rval = STRING_TO_JSVAL(str);
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_focus(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
-
- if (!decoder->window_context)
- return JS_TRUE;
-
- ET_PostManipulateForm(decoder->window_context, 0, EVENT_FOCUS);
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_blur(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
-
- if (!decoder->window_context)
- return JS_TRUE;
-
- ET_PostManipulateForm(decoder->window_context, 0, EVENT_BLUR);
-
- return JS_TRUE;
- }
-
- /*
- * Scrolling support.
- */
- PR_STATIC_CALLBACK(PRBool)
- win_scroll_to(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
- int32 x, y;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
-
- if (argc != 2) {
- JS_ReportError(cx, lm_argc_err_str);
- return JS_FALSE;
- }
-
- if (!decoder->window_context)
- return JS_TRUE;
-
- if (!JS_ValueToInt32(cx, argv[0], &x) || !JS_ValueToInt32(cx, argv[1], &y))
- return JS_FALSE;
-
- ET_PostScrollDocTo(decoder->window_context, 0, x<0?0:x, y<0?0:y);
- return JS_TRUE;
- }
-
- /*
- * Scrolling support.
- */
- PR_STATIC_CALLBACK(PRBool)
- win_scroll_by(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
- int32 x, y;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
-
- if (argc != 2) {
- JS_ReportError(cx, lm_argc_err_str);
- return JS_FALSE;
- }
-
- if (!decoder->window_context)
- return JS_TRUE;
-
- if (!JS_ValueToInt32(cx, argv[0], &x) || !JS_ValueToInt32(cx, argv[1], &y))
- return JS_FALSE;
-
- ET_PostScrollDocBy(decoder->window_context, 0, x, y);
- return JS_TRUE;
- }
-
- /*
- * Window resizing after initial creation.
- */
- PR_STATIC_CALLBACK(PRBool)
- win_resize_to(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
- Chrome *chrome = NULL;
- int32 width, height;
- JSBool outer_size;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
-
- if (argc > 3) {
- JS_ReportError(cx, lm_argc_err_str);
- return JS_FALSE;
- }
-
- if (!decoder->window_context)
- return JS_TRUE;
-
- if (!JS_ValueToInt32(cx, argv[0], &width) || !JS_ValueToInt32(cx, argv[1], &height))
- return JS_FALSE;
-
- if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
- return JS_FALSE;
-
- if (argc==3 && JS_ValueToBoolean(cx, argv[2], &outer_size) && outer_size == JS_TRUE) {
- chrome->outw_hint = width;
- chrome->outh_hint = height;
- if (chrome->outw_hint <= 0 || chrome->outh_hint <= 0) {
- JS_free(cx, chrome);
- return JS_TRUE;
- }
- }
- else {
- chrome->w_hint = width;
- chrome->h_hint = height;
- chrome->outw_hint = 0;
- chrome->outh_hint = 0;
- if (chrome->w_hint <= 0 || chrome->h_hint <= 0 ||
- decoder->window_context->grid_parent) {
- JS_free(cx, chrome);
- return JS_TRUE;
- }
- }
- if ((chrome->w_hint && chrome->w_hint < 100) ||
- (chrome->h_hint && chrome->h_hint < 100) ||
- (chrome->outw_hint && chrome->outw_hint < 100) ||
- (chrome->outh_hint && chrome->outh_hint < 100)) {
- if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
- /* Make sure windows are at least 100 by 100 pixels. */
- if (chrome->w_hint && chrome->w_hint < 100) chrome->w_hint = 100;
- if (chrome->h_hint && chrome->h_hint < 100) chrome->h_hint = 100;
- if (chrome->outw_hint && chrome->outw_hint < 100) chrome->outw_hint = 100;
- if (chrome->outh_hint && chrome->outh_hint < 100) chrome->outh_hint = 100;
- }
- }
- /* Make sure they always at least 10 x 10 regardless of security. 1 x 1
- * windows are really hard to spot */
- if (chrome->w_hint && chrome->w_hint < 10) chrome->w_hint = 10;
- if (chrome->h_hint && chrome->h_hint < 10) chrome->h_hint = 10;
- if (chrome->outw_hint && chrome->outw_hint < 10) chrome->outw_hint = 10;
- if (chrome->outh_hint && chrome->outh_hint < 10) chrome->outh_hint = 10;
-
- ET_PostUpdateChrome(decoder->window_context, chrome);
- JS_free(cx, chrome);
- return JS_TRUE;
- }
-
- /*
- * Scrolling support.
- */
- PR_STATIC_CALLBACK(PRBool)
- win_resize_by(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
- Chrome *chrome = NULL;
- int32 width, height;
- JSBool outer_size;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
-
- if (argc > 3) {
- JS_ReportError(cx, lm_argc_err_str);
- return JS_FALSE;
- }
-
- if (!decoder->window_context)
- return JS_TRUE;
-
- if (!JS_ValueToInt32(cx, argv[0], &width) || !JS_ValueToInt32(cx, argv[1], &height))
- return JS_FALSE;
-
- if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
- return JS_FALSE;
-
- if (argc==3 && JS_ValueToBoolean(cx, argv[2], &outer_size) && outer_size == JS_TRUE) {
- chrome->outw_hint += width;
- chrome->outh_hint += height;
- if (chrome->outw_hint <= 0 || chrome->outh_hint <= 0) {
- JS_free(cx, chrome);
- return JS_TRUE;
- }
- }
- else {
- chrome->w_hint += width;
- chrome->h_hint += height;
- chrome->outw_hint = 0;
- chrome->outh_hint = 0;
- if (chrome->w_hint <= 0 || chrome->h_hint <= 0 ||
- decoder->window_context->grid_parent) {
- JS_free(cx, chrome);
- return JS_TRUE;
- }
- }
- if ((chrome->w_hint && chrome->w_hint < 100) ||
- (chrome->h_hint && chrome->h_hint < 100) ||
- (chrome->outw_hint && chrome->outw_hint < 100) ||
- (chrome->outh_hint && chrome->outh_hint < 100)) {
- if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
- /* Make sure windows are at least 100 by 100 pixels. */
- if (chrome->w_hint && chrome->w_hint < 100) chrome->w_hint = 100;
- if (chrome->h_hint && chrome->h_hint < 100) chrome->h_hint = 100;
- if (chrome->outw_hint && chrome->outw_hint < 100) chrome->outw_hint = 100;
- if (chrome->outh_hint && chrome->outh_hint < 100) chrome->outh_hint = 100;
- }
- }
- /* Make sure they always at least 10 x 10 regardless of security. 1 x 1
- * windows are really hard to spot */
- if (chrome->w_hint && chrome->w_hint < 10) chrome->w_hint = 10;
- if (chrome->h_hint && chrome->h_hint < 10) chrome->h_hint = 10;
- if (chrome->outw_hint && chrome->outw_hint < 10) chrome->outw_hint = 10;
- if (chrome->outh_hint && chrome->outh_hint < 10) chrome->outh_hint = 10;
-
- ET_PostUpdateChrome(decoder->window_context, chrome);
- JS_free(cx, chrome);
- return JS_TRUE;
- }
-
- /*
- * Scrolling support.
- */
- PR_STATIC_CALLBACK(PRBool)
- win_move_to(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
- Chrome *chrome = NULL;
- int32 width, height, x, y;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
-
- if (argc != 2) {
- JS_ReportError(cx, lm_argc_err_str);
- return JS_FALSE;
- }
-
- if (!decoder->window_context)
- return JS_TRUE;
-
- if (!JS_ValueToInt32(cx, argv[0], &x) || !JS_ValueToInt32(cx, argv[1], &y))
- return JS_FALSE;
-
- if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
- return JS_FALSE;
-
- chrome->l_hint = x;
- chrome->t_hint = y;
-
- /* Windows must be positioned on screen without security */
- ET_PostGetScreenSize(decoder->window_context, &width, &height);
- if ((width < chrome->l_hint + chrome->outw_hint) ||
- (chrome->l_hint < 0) ||
- (height < chrome->t_hint + chrome->outh_hint) ||
- (chrome->t_hint < 0)) {
- if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
- chrome->l_hint = (width < chrome->l_hint + chrome->outw_hint) ?
- width - chrome->outw_hint : chrome->l_hint;
- chrome->l_hint = (chrome->l_hint < 0) ? 0 : chrome->l_hint;
- chrome->t_hint = (height < chrome->t_hint + chrome->outh_hint) ?
- height - chrome->outh_hint : chrome->t_hint;
- chrome->t_hint = (chrome->t_hint < 0) ? 0 : chrome->t_hint;
- }
- }
-
- ET_PostUpdateChrome(decoder->window_context, chrome);
- JS_free(cx, chrome);
- return JS_TRUE;
- }
-
- /*
- * Scrolling support.
- */
- PR_STATIC_CALLBACK(PRBool)
- win_move_by(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
- Chrome *chrome = NULL;
- int32 x, y, width, height;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
-
- if (argc != 2) {
- JS_ReportError(cx, lm_argc_err_str);
- return JS_FALSE;
- }
-
- if (!decoder->window_context)
- return JS_TRUE;
-
- if (!JS_ValueToInt32(cx, argv[0], &x) || !JS_ValueToInt32(cx, argv[1], &y))
- return JS_FALSE;
-
- if (!(chrome = win_get_chrome(decoder->window_context, chrome)))
- return JS_FALSE;
-
- chrome->l_hint += x;
- chrome->t_hint += y;
-
- /* Windows must be positioned on screen without security */
- ET_PostGetScreenSize(decoder->window_context, &width, &height);
- if ((width < chrome->l_hint + chrome->outw_hint) ||
- (chrome->l_hint < 0) ||
- (height < chrome->t_hint + chrome->outh_hint) ||
- (chrome->t_hint < 0)) {
- if (!lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
- chrome->l_hint = (width < chrome->l_hint + chrome->outw_hint) ?
- width - chrome->outw_hint : chrome->l_hint;
- chrome->l_hint = (chrome->l_hint < 0) ? 0 : chrome->l_hint;
- chrome->t_hint = (height < chrome->t_hint + chrome->outh_hint) ?
- height - chrome->outh_hint : chrome->t_hint;
- chrome->t_hint = (chrome->t_hint < 0) ? 0 : chrome->t_hint;
- }
- }
-
- ET_PostUpdateChrome(decoder->window_context, chrome);
- JS_free(cx, chrome);
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_capture_events(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
- jsdouble d;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
-
- if (!decoder->window_context)
- return JS_TRUE;
-
- if (argc != 1)
- return JS_TRUE;
-
- if (!JS_ValueToNumber(cx, argv[0], &d))
- return JS_FALSE;
-
- decoder->event_bit |= (uint32)d;
- decoder->window_context->event_bit |= (uint32)d;
-
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_release_events(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
- JSEventCapturer *cap;
- jsdouble d;
- jsint layer_index;
- jsint max_layer_num;
- JSObject *cap_obj;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
-
- if (!decoder->window_context)
- return JS_TRUE;
-
- if (argc != 1)
- return JS_TRUE;
-
- if (!JS_ValueToNumber(cx, argv[0], &d))
- return JS_FALSE;
-
- decoder->event_bit &= ~(uint32)d;
- decoder->window_context->event_bit &= ~(uint32)d;
-
- /* Now we have to see if anyone else wanted that bit set. Joy!*/
- max_layer_num = LO_GetNumberOfLayers(decoder->window_context);
-
- for (layer_index=0; layer_index <= max_layer_num; layer_index++) {
- cap_obj = LO_GetLayerMochaObjectFromId(decoder->window_context, layer_index);
- if (cap_obj && (cap = JS_GetPrivate(cx, cap_obj)) != NULL)
- decoder->window_context->event_bit |= cap->event_bit;
-
- cap_obj = lm_GetDocumentFromLayerId(decoder, layer_index);
- if (cap_obj && (cap = JS_GetPrivate(cx, cap_obj)) != NULL)
- decoder->window_context->event_bit |= cap->event_bit;
- }
-
- return JS_TRUE;
- }
-
- static PRBool
- setExternalCapture(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, JSBool val)
- {
- MochaDecoder *decoder;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
-
- if (argc != 0)
- return JS_TRUE;
-
- if (lm_CanAccessTarget(cx, JSTARGET_UNIVERSAL_BROWSER_WRITE)) {
- if (decoder->principals)
- lm_SetExternalCapture(cx, decoder->principals, val);
- }
-
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_enable_external_capture(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- return setExternalCapture(cx, obj, argc, argv, JS_TRUE);
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_disable_external_capture(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- return setExternalCapture(cx, obj, argc, argv, JS_FALSE);
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_compromise_principals(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
-
- decoder->principals_compromised = JS_TRUE;
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_downgrade_principals(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
-
- if (decoder->principals)
- lm_InvalidateCertPrincipals(decoder, decoder->principals);
-
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_back(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
- if (!decoder->window_context)
- return JS_TRUE;
-
- ET_PostBackCommand(decoder->window_context);
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_forward(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
- if (!decoder->window_context)
- return JS_TRUE;
-
- ET_PostForwardCommand(decoder->window_context);
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_home(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
- if (!decoder->window_context)
- return JS_TRUE;
-
- ET_PostHomeCommand(decoder->window_context);
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_find(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
- MWContext *context;
- JSString *str;
- JSBool ret = JS_TRUE,
- matchCase = JS_FALSE,
- searchBackward = JS_FALSE;
- char * findStr;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
- context = decoder->window_context;
- if (!context)
- return JS_TRUE;
-
- /* If no find argument set, just bring up find dialog */
- if (argc == 0) {
- ET_PostFindCommand(context, NULL, JS_FALSE, JS_FALSE);
- return JS_TRUE;
- }
-
- if (argc >3 )
- return JS_FALSE;
-
- if (!(str = JS_ValueToString(cx, argv[0])))
- return JS_TRUE;
- if (!lm_CheckPermissions(cx, decoder->window_object,
- JSTARGET_UNIVERSAL_BROWSER_READ))
- return JS_FALSE;
-
- if (argc == 3) {
- if (!JS_ValueToBoolean(cx, argv[1], &matchCase))
- matchCase = JS_FALSE;
- if (!JS_ValueToBoolean(cx, argv[2], &searchBackward))
- searchBackward = JS_FALSE;
- }
-
- findStr = lm_StrToLocalEncoding(context, str);
- ret = ET_PostFindCommand(context, findStr, matchCase, searchBackward);
-
- XP_FREEIF(findStr);
- *rval = BOOLEAN_TO_JSVAL(ret);
-
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_print(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
- if (!decoder->window_context)
- return JS_TRUE;
-
- ET_PostPrintCommand(decoder->window_context);
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_open_file(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
- if (!decoder->window_context)
- return JS_TRUE;
-
- ET_PostOpenFileCommand(decoder->window_context);
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_stop(JSContext *cx, JSObject *obj,
- uint argc, jsval *argv, jsval *rval)
- {
- MochaDecoder *decoder;
-
- if (!(decoder = JS_GetInstancePrivate(cx, obj, &lm_window_class, argv)))
- return JS_FALSE;
- if (!decoder->window_context)
- return JS_TRUE;
-
- ET_moz_CallFunctionAsync((ETVoidPtrFunc) XP_InterruptContext, decoder->window_context);
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_atob(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
- {
- JSString *str;
- char *srcStr, *destStr = NULL, *tmpStr;
- unsigned int len;
-
- if (argc != 1) {
- JS_ReportError(cx, lm_argc_err_str);
- return JS_FALSE;
- }
- if (!(str = JS_ValueToString(cx, argv[0])))
- return JS_FALSE;
-
- srcStr = JS_GetStringBytes(str);
- if (JS_GetStringLength(str) == 0) {
- *rval = JS_GetEmptyStringValue(cx);
- return JS_TRUE;
- }
-
- tmpStr = (char *)ATOB_AsciiToData(srcStr, &len);
- if (tmpStr == NULL) {
- JS_ReportError(cx, "base64 decoder failure");
- return JS_FALSE;
- }
-
- destStr = JS_malloc(cx, len + 1);
- if (destStr == NULL) {
- XP_FREE(tmpStr);
- return JS_FALSE;
- }
- destStr[len] = 0;
-
- XP_MEMCPY(destStr, tmpStr, len);
- XP_FREE(tmpStr);
- str = JS_NewString(cx, destStr, len);
- if (str == NULL) {
- JS_free(cx, destStr);
- return JS_FALSE;
- }
-
- *rval= STRING_TO_JSVAL(str);
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_btoa(JSContext *cx, JSObject *obj, uint argc, jsval *argv, jsval *rval)
- {
- JSString *str;
- char *srcStr, *destStr;
- unsigned int len;
-
- if (argc != 1) {
- JS_ReportError(cx, lm_argc_err_str);
- return JS_FALSE;
- }
-
- if (!(str = JS_ValueToString(cx, argv[0])))
- return JS_FALSE;
- srcStr = JS_GetStringBytes(str);
- len = JS_GetStringLength(str);
- if (len == 0) {
- *rval = JS_GetEmptyStringValue(cx);
- return JS_TRUE;
- }
-
- destStr = BTOA_DataToAscii((unsigned char *)srcStr, len);
- if (destStr == NULL) {
- JS_ReportError(cx, "base64 encoder failure");
- return JS_FALSE;
- }
-
- len = XP_STRLEN(destStr);
- str = JS_NewString(cx, destStr, len);
- if (str == NULL)
- return JS_FALSE;
-
- *rval= STRING_TO_JSVAL(str);
- return JS_TRUE;
- }
-
- PR_STATIC_CALLBACK(PRBool)
- win_taint_stub(JSContext *cx, JSObject *obj, uint argc, jsval *argv,
- jsval *rval)
- {
- *rval = argv[0];
- return JS_TRUE;
- }
-
- static JSFunctionSpec lm_window_methods[] = {
- {"alert", win_alert, 1},
- {"clearTimeout", win_clear_timeout, 1},
- {"clearInterval", win_clear_timeout, 1},
- {"close", win_close, 0},
- {"confirm", win_confirm, 1},
- {"open", win_open, 1},
- {"setZOptions", win_set_zoptions, 1},
- {"setHotkeys", win_set_hotkeys, 1},
- {"setResizable", win_set_resizable, 1},
- {"prompt", win_prompt, 2},
- {setTimeout_str, win_set_timeout, 2},
- {setInterval_str, win_set_interval, 2},
- {"delay", win_delay, 0},
- {"escape", win_escape, 2},
- {"unescape", win_unescape, 1},
- {lm_blur_str, win_blur, 0},
- {lm_focus_str, win_focus, 0},
- {lm_scroll_str, win_scroll_to, 2},
- {"scrollTo", win_scroll_to, 2},
- {"scrollBy", win_scroll_by, 2},
- {"moveTo", win_move_to, 2},
- {"moveBy", win_move_by, 2},
- {"resizeTo", win_resize_to, 2},
- {"resizeBy", win_resize_by, 2},
- {"captureEvents", win_capture_events, 1},
- {"releaseEvents", win_release_events, 1},
- {"enableExternalCapture", win_enable_external_capture, 0 },
- {"disableExternalCapture", win_disable_external_capture, 0 },
- {"compromisePrincipals", win_compromise_principals, 0 },
- {"downgradePrincipals", win_downgrade_principals, 0 },
- {"back", win_back, 0},
- {"forward", win_forward, 0},
- {"home", win_home, 0},
- {"find", win_find, 0},
- {"print", win_print, 0},
- {"openFile", win_open_file, 0},
- {"stop", win_stop, 0},
- {"atob", win_atob, 1},
- {"btoa", win_btoa, 1},
- {"taint", win_taint_stub, 1},
- {"untaint", win_taint_stub, 1},
- {0}
- };
-
- static JSBool
- is_context_really_busy_or_loading(MWContext *context)
- {
- lo_TopState *top_state;
- int i;
- XP_List *kids;
- MWContext *kid;
-
- if (!context)
- return JS_FALSE;
-
- LO_LockLayout();
-
- if ((top_state = lo_FetchTopState(XP_DOCID(context))) != NULL &&
- (top_state->mocha_loading_applets_count ||
- top_state->mocha_loading_embeds_count)) {
- LO_UnlockLayout();
- return JS_TRUE;
- }
-
- if ((kids = context->grid_children) != NULL) {
- for (i = 1; ((kid = XP_ListGetObjectNum(kids, i)) != NULL); i++) {
-
- /* see if this frame is loading */
- if (is_context_really_busy_or_loading(kid)) {
- LO_UnlockLayout();
- return JS_TRUE;
- }
-
- /* make sure the load event has fired for this frame */
- if (kid->mocha_context) {
- MochaDecoder * decoder = LM_GetMochaDecoder(kid);
- if (!decoder->load_event_sent) {
- LM_PutMochaDecoder(decoder);
- LO_UnlockLayout();
- return JS_TRUE;
- }
- LM_PutMochaDecoder(decoder);
- }
- }
- }
-
- LO_UnlockLayout();
- return JS_FALSE;
- }
-
- static JSBool
- is_context_busy(MWContext *context)
- {
- if (XP_IsContextBusy(context))
- return JS_TRUE;
- return is_context_really_busy_or_loading(context);
- }
-
- /*
- * 3.0 ran load events from the timeout loop to avoid freeing contexts in use,
- * e.g., parent.document.write() in a frame's BODY onLoad= attribute. That
- * hack ran afoul of WinFE's failure to FIFO-schedule same-deadline timeouts.
- * Now, with threading and no way for the mozilla thread to blow away its own
- * data structures without unwinding to its event loop, an event handler can
- * use document.write or start a new load without fear of free memory usage by
- * the front end code that sent the event.
- */
- static void
- try_load_event(MWContext *context, MochaDecoder *decoder)
- {
- /*
- * Don't do anything if we are waiting for URLs to load, or if applets
- * have not been loaded and initialized.
- */
- if (is_context_busy(context))
- return;
-
- /*
- * Send a load event at most once.
- */
- if (!decoder->load_event_sent) {
- JSEvent *event;
- jsval rval;
-
- event = XP_NEW_ZAP(JSEvent);
- if (!event)
- return;
-
- event->type = decoder->resize_reload ? EVENT_RESIZE : EVENT_LOAD;
- if (context->compositor) {
- XP_Rect rect;
-
- CL_GetCompositorWindowSize(context->compositor, &rect);
- event->x = rect.right;
- event->y = rect.bottom;
- }
-
- decoder->load_event_sent = JS_TRUE;
- (void) lm_SendEvent(context, decoder->window_object, event, &rval);
-
- decoder->event_mask &= ~event->type;
-
- if (!event->saved)
- XP_FREE(event);
-
- }
-
- /*
- * Now that we may have scheduled a load event for this context, send
- * a transfer-done event to our parent frameset, in case it was
- * waiting for us to finish
- */
- if (context->grid_parent)
- lm_SendLoadEvent(context->grid_parent, EVENT_XFER_DONE, JS_FALSE);
-
- }
-
- /*
- * Entry point for the netlib to notify JS of load and unload events.
- * Note: we can only rely on the resize_reload parameter to be
- * correct in the load and unload (but not the xfer) cases.
- */
- void
- lm_SendLoadEvent(MWContext *context, int32 event, JSBool resize_reload)
- {
- MochaDecoder *decoder;
- JSEvent *pEvent;
- jsval rval;
-
- decoder = context->mocha_context ? LM_GetMochaDecoder(context) : 0;
- if (!decoder)
- return;
-
- switch (event) {
- case EVENT_LOAD:
- decoder->event_mask |= EVENT_LOAD;
- if (resize_reload) {
- decoder->resize_reload = JS_TRUE;
- /* Restore any saved timeouts that we have for this window */
- lm_RestoreWindowTimeouts(decoder);
- }
- try_load_event(context, decoder);
- break;
-
- case EVENT_UNLOAD:
- decoder->load_event_sent = JS_FALSE;
- decoder->event_mask &= ~EVENT_LOAD;
-
- /* If we're resizing, just save timeouts but don't send an event */
- if (resize_reload) {
- lm_SaveWindowTimeouts(decoder);
- } else {
- pEvent = XP_NEW_ZAP(JSEvent);
- pEvent->type = EVENT_UNLOAD;
-
- (void) lm_SendEvent(context, decoder->window_object,
- pEvent, &rval);
- if (!pEvent->saved)
- XP_FREE(pEvent);
- }
-
- break;
-
- case EVENT_XFER_DONE:
- if ((decoder->event_mask & EVENT_LOAD))
- try_load_event(context, decoder);
- if (context->grid_parent)
- lm_SendLoadEvent(context->grid_parent, EVENT_XFER_DONE, JS_FALSE);
- break;
-
- case EVENT_ABORT:
- default:
- break;
- }
-
- if (decoder)
- LM_PutMochaDecoder(decoder);
- return;
- }
-
- /*
- * Entry point for front-ends to notify JS code of help events.
- */
- void
- LM_SendOnHelp(MWContext *context)
- {
- JSEvent *pEvent;
-
- pEvent = XP_NEW_ZAP(JSEvent);
- pEvent->type = EVENT_HELP;
-
- ET_SendEvent(context, NULL, pEvent, NULL, NULL);
-
- }
-
- /*
- * Entry point for front-ends to notify JS code of scroll events.
- */
- void
- LM_SendOnScroll(MWContext *context, int32 x, int32 y)
- {
- MochaDecoder *decoder;
- JSEvent *event;
- jsval rval;
-
- XP_ASSERT(0);
-
- if (!context->mocha_context)
- return;
- decoder = LM_GetMochaDecoder(context);
- if (!(decoder->event_mask & EVENT_SCROLL)) {
- decoder->event_mask |= EVENT_SCROLL;
-
- event = XP_NEW_ZAP(JSEvent);
- event->type = EVENT_SCROLL;
-
- (void) lm_SendEvent(context, decoder->window_object, event,
- &rval);
- decoder->event_mask &= ~EVENT_SCROLL;
- }
- LM_PutMochaDecoder(decoder);
- }
-
- PRHashNumber
- lm_KeyHash(const void *key)
- {
- return (PRHashNumber)key;
- }
-
- PRHashTable *
- lm_GetIdToObjectMap(MochaDecoder *decoder)
- {
- PRHashTable *map;
-
- map = decoder->id_to_object_map;
- if (map)
- return map;
-
- map = PR_NewHashTable(LM_ID_TO_OBJ_MAP_SIZE,
- lm_KeyHash,
- PR_CompareValues,
- PR_CompareValues,
- NULL, NULL);
-
- if (!map)
- return NULL;
-
- decoder->id_to_object_map = map;
- return map;
- }
-
-
- MochaDecoder *
- lm_NewWindow(MWContext *context)
- {
- History_entry *he;
- MochaDecoder *decoder;
- JSContext *cx;
- JSObject *obj;
-
- /* make sure its a JS-able context */
- if (!LM_CanDoJS(context))
- return NULL;
-
- /*
- * If this is a (resizing) frame, get its decoder from session history.
- * Using the layout lock to protect context->hist.cur_doc_ptr (which is
- * all SHIST_GetCurrent uses) is dicey. XXXchouck
- */
- LO_LockLayout();
- he = context->is_grid_cell ? SHIST_GetCurrent(&context->hist) : NULL;
- if (he && he->savedData.Window) {
- decoder = he->savedData.Window;
- he->savedData.Window = NULL;
- cx = decoder->js_context;
- obj = decoder->window_object;
- decoder->window_context = context;
- context->mocha_context = cx;
- LO_UnlockLayout();
-
- /*
- * Allow the context to observe the decoder's image context.
- */
- ET_il_SetGroupObserver(context, decoder->image_context, context, JS_TRUE);
-
- return decoder;
- }
- LO_UnlockLayout();
-
- /* Otherwise, make a new decoder/context/object for this window. */
- decoder = XP_NEW_ZAP(MochaDecoder);
- if (!decoder)
- return NULL;
- cx = JS_NewContext(lm_runtime, LM_STACK_SIZE);
- if (!cx) {
- XP_DELETE(decoder);
- return NULL;
- }
- obj = JS_NewObject(cx, &lm_window_class, NULL, NULL);
- if (!obj || !JS_SetPrivate(cx, obj, decoder)) {
- JS_DestroyContext(cx);
- XP_DELETE(decoder);
- return NULL;
- }
-
- /* Set the backward refcount to 1 because obj now holds decoder. */
- decoder->back_count = 1;
-
- /* Add a root in decoder for obj early, in case the GC runs soon. */
- decoder->window_object = obj;
- if (!JS_AddNamedRoot(cx, &decoder->window_object, "window_object"))
- return NULL;
-
- /* Create a new image context for anonymous images. */
- if (!lm_NewImageContext(context, decoder))
- return NULL;
-
- /* Set the forward refcount to 1 because context holds decoder. */
- decoder->forw_count = 1;
- decoder->window_context = context;
- decoder->js_context = cx;
- context->mocha_context = cx;
-
- if (!lm_InitWindowContent(decoder)) {
- /* This will cause finalization and call lm_DestroyWindow(). */
- decoder->window_object = NULL;
- return NULL;
- }
-
- #define HOLD(obj) if (!JS_AddNamedRoot(cx, &(obj), #obj)) return NULL
-
- /* Drop all object prototype refs. */
- HOLD(decoder->anchor_prototype);
- HOLD(decoder->bar_prototype);
- HOLD(decoder->document_prototype);
- HOLD(decoder->event_prototype);
- HOLD(decoder->event_capturer_prototype);
- HOLD(decoder->event_receiver_prototype);
- HOLD(decoder->form_prototype);
- HOLD(decoder->image_prototype);
- HOLD(decoder->input_prototype);
- HOLD(decoder->layer_prototype);
- HOLD(decoder->option_prototype);
- HOLD(decoder->rect_prototype);
- HOLD(decoder->url_prototype);
-
- /* Drop window sub-object refs. */
- HOLD(decoder->document);
- HOLD(decoder->history);
- HOLD(decoder->location);
- HOLD(decoder->navigator);
- HOLD(decoder->components);
- HOLD(decoder->crypto);
- HOLD(decoder->screen);
- HOLD(decoder->hardware);
- HOLD(decoder->pkcs11);
- /* Drop ad-hoc GC roots. */
- HOLD(decoder->event_receiver);
- HOLD(decoder->opener);
-
- #undef HOLD
-
- JS_SetBranchCallback(cx, lm_BranchCallback);
- JS_SetErrorReporter(cx, lm_ErrorReporter);
- return decoder;
- }
-
- void
- lm_DestroyWindow(MochaDecoder *decoder)
- {
- JSContext *cx;
-
- /* All reference counts must be 0 here. */
- XP_ASSERT(decoder->forw_count == 0);
- XP_ASSERT(decoder->back_count == 0);
-
- /* We must not have an MWContext at this point. */
- XP_ASSERT(!decoder->window_context);
-
- /* Drop decoder refs to window prototypes and sub-objects. */
- lm_FreeWindowContent(decoder, JS_FALSE);
-
- /* Set cx for use by DROP. */
- cx = decoder->js_context;
-
- #define DROP(obj) JS_RemoveRoot(cx, &(obj))
-
- /* Drop all object prototype refs. */
- DROP(decoder->anchor_prototype);
- DROP(decoder->bar_prototype);
- DROP(decoder->document_prototype);
- DROP(decoder->event_prototype);
- DROP(decoder->event_capturer_prototype);
- DROP(decoder->event_receiver_prototype);
- DROP(decoder->form_prototype);
- DROP(decoder->image_prototype);
- DROP(decoder->input_prototype);
- DROP(decoder->layer_prototype);
- DROP(decoder->option_prototype);
- DROP(decoder->rect_prototype);
- DROP(decoder->url_prototype);
-
- /* Drop window sub-object refs. */
- DROP(decoder->document);
- DROP(decoder->history);
- DROP(decoder->location);
- DROP(decoder->navigator);
- DROP(decoder->components);
- DROP(decoder->crypto);
- DROP(decoder->screen);
- DROP(decoder->hardware);
- DROP(decoder->pkcs11);
- /* Drop ad-hoc GC roots. */
- DROP(decoder->event_receiver);
- DROP(decoder->opener);
-
- if (decoder->in_window_quota)
- lm_window_count--;
-
- /* Remove the root that holds up the whole window in the decoder world */
- DROP(decoder->window_object);
-
- #undef DROP
-
- /*
- * Destroy the mocha image context. All mocha images need to have been
- * finalized *before* we get here, since image destruction requires a
- * valid MWContext.
- */
- ET_PostFreeImageContext(NULL, decoder->image_context);
-
- /* Free JS context and decoder struct, window is gone. */
- JS_DestroyContext(cx);
-
- XP_DELETE(decoder);
- }
-
- #ifdef DEBUG
- extern MochaDecoder *
- lm_HoldBackCount(MochaDecoder *decoder)
- {
- if (decoder) {
- XP_ASSERT(decoder->back_count >= 0);
- decoder->back_count++;
- }
- return decoder;
- }
-
- extern void
- lm_DropBackCount(MochaDecoder *decoder)
- {
- if (!decoder)
- return;
- XP_ASSERT(decoder->back_count > 0);
- if (--decoder->back_count <= 0) {
- decoder->back_count = 0;
- XP_ASSERT(decoder->forw_count >= 0);
- if (!decoder->forw_count)
- lm_DestroyWindow(decoder);
- }
- }
- #endif /* DEBUG */
-
- JSBool
- lm_InitWindowContent(MochaDecoder *decoder)
- {
- JSContext *cx;
- JSObject *obj;
-
- cx = decoder->js_context;
- obj = decoder->window_object;
- if (!JS_InitStandardClasses(cx, obj))
- return JS_FALSE;
-
- if (!lm_AddSetParentSecurityCheck(cx, obj))
- return JS_FALSE;
-
- #ifdef JAVA
- if (JSJ_IsEnabled() && !JSJ_InitContext(cx, obj))
- return JS_FALSE;
- #endif
- if (!JS_DefineProperties(cx, obj, window_props))
- return JS_FALSE;
-
- if (decoder->opener) {
- if (!JS_DefinePropertyWithTinyId(cx, obj, lm_opener_str, WIN_OPENER,
- OBJECT_TO_JSVAL(decoder->opener),
- NULL, NULL, JSPROP_ENUMERATE)) {
- return JS_FALSE;
- }
- }
-
- return (JSBool)(lm_DefineWindowProps(cx, decoder) &&
- JS_SetPrototype(cx, obj, decoder->event_capturer_prototype));
- }
-
- JSBool
- lm_DefineWindowProps(JSContext *cx, MochaDecoder *decoder)
- {
- JSObject *obj;
-
- obj = decoder->window_object;
- return (JSBool)(JS_DefineFunctions(cx, obj, lm_window_methods) &&
- lm_InitEventClasses(decoder) &&
- lm_InitDocumentClass(decoder) &&
- lm_DefineDocument(decoder, LO_DOCUMENT_LAYER_ID) &&
- lm_DefineHistory(decoder) &&
- lm_DefineLocation(decoder) &&
- lm_DefineCrypto(decoder) &&
- lm_DefineBarClasses(decoder) &&
- lm_InitLayerClass(decoder) &&
- lm_InitRectClass(decoder) &&
- lm_InitImageClass(decoder) &&
- lm_InitAnchorClass(decoder) &&
- lm_InitInputClasses(decoder) &&
- lm_DefinePkcs11(decoder));
- }
-
- void
- lm_FreeWindowContent(MochaDecoder *decoder, JSBool fromDiscard)
- {
- JSContext *cx;
- JSObject *obj;
- JSNestingUrl * url, * next_url;
-
- /* Clear any stream that the user forgot to close. */
- lm_ClearDecoderStream(decoder, fromDiscard);
-
- /* Clear any pending timeouts and URL fetches. */
- lm_ClearWindowTimeouts(decoder);
-
- /* These flags should never be set, but if any are, we'll cope. */
- decoder->replace_location = JS_FALSE;
- decoder->resize_reload = JS_FALSE;
- decoder->load_event_sent = JS_FALSE;
- decoder->visited = JS_FALSE;
- decoder->writing_input = JS_FALSE;
-
- /* This flag may have been set by a script; clear it now. */
- decoder->principals_compromised = JS_FALSE;
-
- /* need to inline this since source_url is 'const char *' and the Mac will whine */
- if (decoder->source_url) {
- XP_FREE((char *) decoder->source_url);
- decoder->source_url = NULL;
- }
-
- for (url = decoder->nesting_url; url; url = next_url) {
- next_url = url->next;
- XP_FREE(url->str);
- XP_FREE(url);
- }
- decoder->nesting_url = NULL;
-
- /* Forgive and forget all excessive errors. */
- decoder->error_count = 0;
-
- decoder->active_form_id = 0;
- decoder->signature_ordinal = 0;
-
- /* Clear the event mask. */
- decoder->event_mask = 0;
-
- if (decoder->id_to_object_map) {
- PR_HashTableDestroy(decoder->id_to_object_map);
- decoder->id_to_object_map = NULL;
- }
-
- cx = decoder->js_context;
- decoder->firstVersion = JSVERSION_UNKNOWN;
- decoder->principals = NULL;
- if (decoder->early_access_list)
- lm_DestroyPrincipalsList(cx, decoder->early_access_list);
- decoder->early_access_list = NULL;
-
- #define CLEAR(obj) obj = NULL
-
- /* Clear all object prototype refs. */
- CLEAR(decoder->anchor_prototype);
- CLEAR(decoder->bar_prototype);
- CLEAR(decoder->document_prototype);
- CLEAR(decoder->event_prototype);
- CLEAR(decoder->event_capturer_prototype);
- CLEAR(decoder->event_receiver_prototype);
- CLEAR(decoder->form_prototype);
- CLEAR(decoder->image_prototype);
- CLEAR(decoder->input_prototype);
- CLEAR(decoder->layer_prototype);
- CLEAR(decoder->option_prototype);
- CLEAR(decoder->rect_prototype);
- CLEAR(decoder->url_prototype);
-
- /* Clear window sub-object refs. */
- if (decoder->document)
- lm_CleanUpDocumentRoots(decoder, decoder->document);
- CLEAR(decoder->document);
- CLEAR(decoder->history);
- CLEAR(decoder->location);
- CLEAR(decoder->navigator);
- CLEAR(decoder->components);
- CLEAR(decoder->crypto);
- CLEAR(decoder->screen);
- CLEAR(decoder->hardware);
- CLEAR(decoder->pkcs11);
-
- /* Drop ad-hoc GC roots, but not opener -- it survives unloads. */
- CLEAR(decoder->event_receiver);
-
- #undef CLEAR
-
- #undef DROP_AND_CLEAR
-
- obj = decoder->window_object;
- if (obj) {
- JS_ClearWatchPointsForObject(cx, obj);
- JS_ClearScope(cx, obj);
- (void) JS_DefinePropertyWithTinyId(cx, obj, lm_closed_str, WIN_CLOSED,
- JSVAL_FALSE, NULL, NULL,
- JSPROP_ENUMERATE|JSPROP_READONLY);
- }
- }
-
- void
- LM_RemoveWindowContext(MWContext *context, History_entry * he)
- {
- MochaDecoder *decoder;
- JSContext *cx;
-
- /* Do work only if this context has a JS decoder. */
- cx = context->mocha_context;
- if (!cx)
- return;
- decoder = JS_GetPrivate(cx, JS_GetGlobalObject(cx));
-
- /* Sever the bidirectional connection between context and decoder. */
- XP_ASSERT(decoder->window_context == context);
- context->mocha_context = NULL;
- decoder->window_context = NULL;
- lm_ClearDecoderStream(decoder, JS_TRUE);
-
- ET_il_SetGroupObserver(context, decoder->image_context, NULL, JS_FALSE);
-
- if (he) {
- /*
- * Set current history entry's saved window from its layout cell.
- * We need to do this rather than SHIST_SetCurrentDocWindowData()
- * because FE_FreeGridWindow (who calls us indirectly) has already
- * "stolen" session history for return to layout, who saves it in
- * parent session history in lo_InternalDiscardDocument().
- */
- he->savedData.Window = decoder;
- return;
- }
-
- /* This might call lm_DestroyWindow(decoder), so do it last. */
- LM_PutMochaDecoder(decoder);
- }
-
- extern void
- LM_DropSavedWindow(MWContext *context, void *window)
- {
- MochaDecoder *decoder = window;
- #ifdef DEBUG
- extern PRThread *mozilla_thread;
-
- /* Our caller, SHIST_FreeHistoryEntry, must run on the mozilla thread. */
- XP_ASSERT(PR_CurrentThread() == mozilla_thread);
- #endif
-
- et_PutMochaDecoder(context, decoder);
- }
-