mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-14 15:37:55 +00:00
64e462e071
- Add multiple window groups to allow windows to execute JS on different threads. - Add new context parameters to JS and libmocha functions for thread safety.
423 lines
11 KiB
C
423 lines
11 KiB
C
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
*
|
|
* 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 applets in the current document
|
|
*/
|
|
|
|
/* Please leave outside of ifdef for windows precompiled headers */
|
|
#include "lm.h"
|
|
|
|
#if defined(JAVA) || defined(OJI)
|
|
|
|
#include "xp.h"
|
|
#include "layout.h"
|
|
#if defined(JAVA)
|
|
#include "java.h"
|
|
#include "lj.h" /* for LJ_InvokeMethod */
|
|
#define IMPLEMENT_netscape_applet_MozillaAppletContext
|
|
#define IMPLEMENT_netscape_applet_EmbeddedObjectNatives
|
|
#ifdef XP_MAC
|
|
#include "n_applet_MozillaAppletContext.h"
|
|
#include "n_a_EmbeddedObjectNatives.h"
|
|
#else
|
|
#include "netscape_applet_MozillaAppletContext.h"
|
|
#include "netscape_applet_EmbeddedObjectNatives.h"
|
|
#endif
|
|
#elif defined(OJI)
|
|
#include "np2.h"
|
|
#include "jni.h"
|
|
#endif /* OJI */
|
|
#include "jsjava.h"
|
|
#include "jsobj.h"
|
|
#include "prlog.h"
|
|
|
|
extern PRLogModuleInfo* Moja;
|
|
#define debug PR_LOG_DEBUG
|
|
#define warn PR_LOG_WARN
|
|
|
|
JSClass *lm_java_clasp = NULL;
|
|
|
|
enum applet_array_slot {
|
|
APPLET_ARRAY_LENGTH = -1
|
|
};
|
|
|
|
static JSPropertySpec applet_array_props[] = {
|
|
{lm_length_str, APPLET_ARRAY_LENGTH,
|
|
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT},
|
|
{0}
|
|
};
|
|
|
|
extern JSClass lm_applet_array_class;
|
|
|
|
PR_STATIC_CALLBACK(JSBool)
|
|
applet_array_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|
{
|
|
JSObjectArray *array;
|
|
MochaDecoder *decoder;
|
|
MWContext *context;
|
|
jsint count, slot;
|
|
LO_JavaAppStruct *applet_data;
|
|
int32 active_layer_id;
|
|
|
|
if (!JSVAL_IS_INT(id))
|
|
return JS_TRUE;
|
|
|
|
slot = JSVAL_TO_INT(id);
|
|
|
|
array = JS_GetInstancePrivate(cx, obj, &lm_applet_array_class, NULL);
|
|
if (!array)
|
|
return JS_TRUE;
|
|
decoder = array->decoder;
|
|
context = decoder->window_context;
|
|
|
|
if (!context)
|
|
return JS_TRUE;
|
|
|
|
if (LM_MOJA_OK != ET_InitMoja(context))
|
|
return JS_FALSE;
|
|
|
|
LO_LockLayout();
|
|
|
|
switch (slot) {
|
|
case APPLET_ARRAY_LENGTH:
|
|
active_layer_id = LM_GetActiveLayer(context);
|
|
LM_SetActiveLayer(context, array->layer_id);
|
|
count = LO_EnumerateApplets(context, array->layer_id);
|
|
LM_SetActiveLayer(context, active_layer_id);
|
|
if (count > array->length)
|
|
array->length = count;
|
|
*vp = INT_TO_JSVAL(array->length);
|
|
break;
|
|
|
|
default:
|
|
if (slot < 0) {
|
|
/* Don't mess with user-defined or method properties. */
|
|
LO_UnlockLayout();
|
|
return JS_TRUE;
|
|
}
|
|
applet_data = LO_GetAppletByIndex(context, array->layer_id,
|
|
(uint)slot);
|
|
if (applet_data) {
|
|
JSObject *mo = LM_ReflectApplet(context, applet_data, NULL,
|
|
array->layer_id, (uint)slot);
|
|
|
|
if (!mo) {
|
|
JS_ReportError(cx,
|
|
"unable to reflect applet \"%s\", index %d - not loaded yet?",
|
|
applet_data->attr_name, (uint) slot);
|
|
goto err;
|
|
}
|
|
*vp = OBJECT_TO_JSVAL(mo);
|
|
|
|
if (slot >= array->length)
|
|
array->length = slot + 1;
|
|
} else {
|
|
JS_ReportError(cx, "no applet with index %d\n");
|
|
goto err;
|
|
}
|
|
break;
|
|
}
|
|
LO_UnlockLayout();
|
|
return JS_TRUE;
|
|
err:
|
|
LO_UnlockLayout();
|
|
return JS_FALSE;
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(void)
|
|
applet_array_finalize(JSContext *cx, JSObject *obj)
|
|
{
|
|
JSObjectArray *array;
|
|
|
|
array = JS_GetPrivate(cx, obj);
|
|
if (!array)
|
|
return;
|
|
DROP_BACK_COUNT(array->decoder);
|
|
JS_free(cx, array);
|
|
}
|
|
|
|
JSClass lm_applet_array_class = {
|
|
"AppletArray", JSCLASS_HAS_PRIVATE,
|
|
JS_PropertyStub, JS_PropertyStub,
|
|
applet_array_getProperty, applet_array_getProperty, JS_EnumerateStub,
|
|
JS_ResolveStub, JS_ConvertStub, applet_array_finalize
|
|
};
|
|
|
|
JSObject *
|
|
lm_GetAppletArray(MochaDecoder *decoder, JSObject *document)
|
|
{
|
|
JSContext *cx = decoder->js_context;
|
|
JSObject *obj;
|
|
JSObjectArray *array;
|
|
JSDocument *doc;
|
|
|
|
doc = JS_GetPrivate(cx, document);
|
|
if (!doc)
|
|
return NULL;
|
|
|
|
obj = doc->applets;
|
|
if (obj)
|
|
return obj;
|
|
|
|
array = JS_malloc(cx, sizeof *array);
|
|
if (!array)
|
|
return NULL;
|
|
array->decoder = NULL; /* in case of error below */
|
|
|
|
obj = JS_NewObject(cx, &lm_applet_array_class, NULL, document);
|
|
if (!obj || !JS_SetPrivate(cx, obj, array)) {
|
|
JS_free(cx, array);
|
|
return NULL;
|
|
}
|
|
|
|
if (!JS_DefineProperties(cx, obj, applet_array_props))
|
|
return NULL;
|
|
|
|
array->decoder = HOLD_BACK_COUNT(decoder);
|
|
array->length = 0;
|
|
array->layer_id = doc->layer_id;
|
|
doc->applets = obj;
|
|
|
|
return obj;
|
|
}
|
|
|
|
|
|
static JSObject *
|
|
lm_ReallyReflectApplet(MWContext *context, LO_JavaAppStruct *lo_applet,
|
|
int32 layer_id, uint32 index)
|
|
{
|
|
JSObject *obj;
|
|
MochaDecoder *decoder;
|
|
JSContext *cx;
|
|
#ifdef JAVA
|
|
LJAppletData *ad;
|
|
jref javaobject;
|
|
#endif
|
|
lo_TopState *top_state;
|
|
PRHashTable *map;
|
|
#ifdef OJI
|
|
NPEmbeddedApp* embed;
|
|
LO_CommonPluginStruct *lo_embed = (LO_CommonPluginStruct *)lo_applet;
|
|
jobject javaobject;
|
|
#endif /* OJI */
|
|
|
|
PR_LOG(Moja, debug, ("really reflect applet 0x%x\n", lo_applet));
|
|
|
|
obj = lo_applet->objTag.mocha_object;
|
|
if (obj)
|
|
return obj;
|
|
|
|
decoder = LM_GetMochaDecoder(context);
|
|
if (!decoder)
|
|
return NULL;
|
|
cx = decoder->js_context;
|
|
|
|
top_state = lo_GetMochaTopState(context);
|
|
if (top_state->resize_reload) {
|
|
map = lm_GetIdToObjectMap(decoder);
|
|
if (map)
|
|
obj = (JSObject *)PR_HashTableLookup(map,
|
|
LM_GET_MAPPING_KEY(LM_APPLETS, layer_id, index));
|
|
|
|
if (obj) {
|
|
lo_applet->objTag.mocha_object = obj;
|
|
return obj;
|
|
}
|
|
}
|
|
|
|
#ifdef OJI
|
|
{
|
|
jsval val;
|
|
if (!JVM_IsLiveConnectEnabled()) {
|
|
return lo_embed->mocha_object = lm_DummyObject;
|
|
}
|
|
|
|
javaobject = NPL_GetJavaObject(lo_embed);
|
|
|
|
if (JSJ_ConvertJavaObjectToJSValue(decoder->js_context, javaobject, &val))
|
|
obj = JSVAL_TO_OBJECT(val);
|
|
}
|
|
#else
|
|
/* set the element to something bad if we can't get the java obj */
|
|
if (!JSJ_IsEnabled()) {
|
|
PR_LOG(Moja, debug, ("reflected applet 0x%x as null\n",
|
|
lo_applet));
|
|
return lo_applet->objTag.mocha_object = lm_DummyObject;
|
|
}
|
|
|
|
ad = (LJAppletData *) lo_applet->objTag.session_data;
|
|
|
|
if (ad) {
|
|
/* MozillaAppletContext.reflectApplet gets the java applet
|
|
* object out of a hash table given the AppletData pointer
|
|
* as an integer */
|
|
if (ad->selector_type != LO_JAVA_SELECTOR_APPLET)
|
|
javaobject = LJ_InvokeMethod(classEmbeddedObjectNatives,
|
|
methodID_netscape_applet_EmbeddedObjectNatives_reflectObject,
|
|
ad->docID, ad);
|
|
else
|
|
javaobject = LJ_InvokeMethod(classMozillaAppletContext,
|
|
methodID_netscape_applet_MozillaAppletContext_reflectApplet_1,
|
|
ad->docID, ad);
|
|
obj = js_ReflectJObjectToJSObject(decoder->js_context,
|
|
(HObject *)javaobject);
|
|
}
|
|
#endif /* !OJI */
|
|
|
|
if( obj == NULL )
|
|
{
|
|
PR_LOG(Moja, warn, ("failed to reflect applet 0x%x\n", lo_applet));
|
|
return NULL;
|
|
}
|
|
map = lm_GetIdToObjectMap(decoder);
|
|
if (map)
|
|
PR_HashTableAdd(map,
|
|
LM_GET_MAPPING_KEY(LM_APPLETS, layer_id, index),
|
|
obj);
|
|
|
|
/*
|
|
lj_mozilla_ee->js_context = saved_context;
|
|
*/
|
|
|
|
PR_LOG(Moja, debug, ("reflected applet 0x%x (java 0x%x) to 0x%x ok\n",
|
|
lo_applet, javaobject, obj));
|
|
|
|
if (obj)
|
|
lm_java_clasp = JS_GetClass(cx, obj);
|
|
return lo_applet->objTag.mocha_object = obj;
|
|
}
|
|
|
|
|
|
/* XXX what happens if this is called before java starts up?
|
|
* or if java is disabled? */
|
|
|
|
#if defined(OJI)
|
|
|
|
static char* getValue(struct lo_NVList* nvlist, const char* name)
|
|
{
|
|
int i;
|
|
char** names = nvlist->names;
|
|
char** values = nvlist->values;
|
|
|
|
for (i = nvlist->n - 1; i >= 0; --i)
|
|
if (XP_STRCASECMP(names[i], name) == 0)
|
|
return values[i];
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#endif
|
|
|
|
JSObject *
|
|
LM_ReflectApplet(MWContext *context, LO_JavaAppStruct *applet_data,
|
|
PA_Tag * tag, int32 layer_id, uint index)
|
|
{
|
|
JSObject *obj, *array_obj, *outer_obj, *document;
|
|
MochaDecoder *decoder;
|
|
JSContext *cx;
|
|
char *name;
|
|
#ifdef OJI
|
|
LO_EmbedStruct *embed = (LO_EmbedStruct *)applet_data;
|
|
#endif
|
|
|
|
obj = applet_data->objTag.mocha_object;
|
|
if (obj)
|
|
return obj;
|
|
|
|
decoder = LM_GetMochaDecoder(context);
|
|
if (!decoder)
|
|
return NULL;
|
|
cx = decoder->js_context;
|
|
|
|
#ifdef OJI
|
|
/* this is really skanky, but we don't really have a LO_JavaAppStruct, but instead a LO_EmbedStruct. */
|
|
name = getValue(&embed->attributes, "NAME");
|
|
if (name != NULL)
|
|
name = JS_strdup(cx, name);
|
|
#else
|
|
/* get the name */
|
|
if (applet_data->attr_name) {
|
|
name = JS_strdup(cx, (char *) applet_data->attr_name);
|
|
} else {
|
|
name = 0;
|
|
}
|
|
#endif
|
|
|
|
/* Get the document object that will hold this applet */
|
|
document = lm_GetDocumentFromLayerId(decoder, layer_id);
|
|
if (!document)
|
|
goto out;
|
|
|
|
array_obj = lm_GetAppletArray(decoder, document);
|
|
if (!array_obj) {
|
|
obj = 0;
|
|
goto out;
|
|
}
|
|
|
|
/* XXX should pass thru ReallyReflectApplet to whatever calls NewObject */
|
|
outer_obj = lm_GetOuterObject(decoder);
|
|
|
|
/* this function does the real work */
|
|
obj = lm_ReallyReflectApplet(context, applet_data, layer_id, index);
|
|
|
|
if (!obj)
|
|
/* reflection failed. this usually means that javascript tried
|
|
* to talk to the applet before it was ready. there's not much
|
|
* we can do about it */
|
|
goto out;
|
|
|
|
/* put it in the applet array */
|
|
if (!lm_AddObjectToArray(cx, array_obj, name, index, obj)) {
|
|
obj = NULL;
|
|
goto out;
|
|
}
|
|
|
|
/* put it in the document scope */
|
|
if (name) {
|
|
if (!JS_DefineProperty(cx, outer_obj, name, OBJECT_TO_JSVAL(obj),
|
|
NULL, NULL,
|
|
JSPROP_ENUMERATE | JSPROP_READONLY)) {
|
|
PR_LOG(Moja, warn, ("failed to define applet 0x%x as %s\n",
|
|
applet_data, name));
|
|
/* XXX remove it altogether? */
|
|
}
|
|
JS_free(cx, name);
|
|
}
|
|
|
|
/* cache it in layout data structure XXX lm_ReallyReflectApplet did this */
|
|
XP_ASSERT(applet_data->objTag.mocha_object == obj);
|
|
|
|
out:
|
|
LM_PutMochaDecoder(decoder);
|
|
return obj;
|
|
}
|
|
|
|
PRIVATE JSObject *
|
|
LM_ReflectNamedApplet(MWContext *context, lo_NameList *name_rec,
|
|
int32 layer_id, uint index)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
#else
|
|
|
|
void *lm_java_clasp = NULL;
|
|
|
|
#endif /* !JAVA && !OJI */
|