2004-07-12 15:53:22 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
2004-07-16 18:48:35 +00:00
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
2004-07-12 15:53:22 +00:00
|
|
|
*
|
2004-07-16 18:48:35 +00:00
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
2004-07-12 15:53:22 +00:00
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
2004-07-16 18:48:35 +00:00
|
|
|
* The Initial Developer of the Original Code is
|
2004-07-12 15:53:22 +00:00
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
2004-07-16 18:48:35 +00:00
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
2004-07-12 15:53:22 +00:00
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
2004-07-16 18:48:35 +00:00
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
2004-07-12 15:53:22 +00:00
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
2004-07-16 18:48:35 +00:00
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
2004-07-12 15:53:22 +00:00
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#include "nsJSNPRuntime.h"
|
|
|
|
#include "ns4xPlugin.h"
|
|
|
|
#include "ns4xPluginInstance.h"
|
|
|
|
#include "nsIPluginInstancePeer2.h"
|
|
|
|
#include "nsPIPluginInstancePeer.h"
|
|
|
|
#include "nsIScriptGlobalObject.h"
|
|
|
|
#include "nsIScriptContext.h"
|
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsIJSRuntimeService.h"
|
|
|
|
#include "nsIJSContextStack.h"
|
2005-11-04 01:01:08 +00:00
|
|
|
#include "nsIXPConnect.h"
|
|
|
|
#include "nsIDOMElement.h"
|
2004-07-12 15:53:22 +00:00
|
|
|
#include "prmem.h"
|
2005-11-22 15:51:41 +00:00
|
|
|
#include "nsIContent.h"
|
2004-07-12 15:53:22 +00:00
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
// Hash of JSObject wrappers that wraps JSObjects as NPObjects. There
|
|
|
|
// will be one wrapper per JSObject per plugin instance, i.e. if two
|
|
|
|
// plugins access the JSObject x, two wrappers for x will be
|
|
|
|
// created. This is needed to be able to properly drop the wrappers
|
|
|
|
// when a plugin is torn down in case there's a leak in the plugin (we
|
|
|
|
// don't want to leak the world just because a plugin leaks an
|
|
|
|
// NPObject).
|
2004-07-12 15:53:22 +00:00
|
|
|
static PLDHashTable sJSObjWrappers;
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
// Hash of NPObject wrappers that wrap NPObjects as JSObjects.
|
2004-07-12 15:53:22 +00:00
|
|
|
static PLDHashTable sNPObjWrappers;
|
|
|
|
|
|
|
|
// Global wrapper count. This includes JSObject wrappers *and*
|
|
|
|
// NPObject wrappers. When this count goes to zero, there are no more
|
|
|
|
// wrappers and we can kill off hash tables etc.
|
|
|
|
static PRInt32 sWrapperCount;
|
|
|
|
|
|
|
|
// The JSRuntime. Used to unroot JSObjects when no JSContext is
|
|
|
|
// reachable.
|
|
|
|
static JSRuntime *sJSRuntime;
|
|
|
|
|
|
|
|
// The JS context stack, we use this to push a plugin's JSContext onto
|
|
|
|
// while executing JS on the context.
|
|
|
|
static nsIJSContextStack *sContextStack;
|
|
|
|
|
|
|
|
class AutoCXPusher
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
AutoCXPusher(JSContext *cx)
|
|
|
|
{
|
|
|
|
if (sContextStack)
|
|
|
|
sContextStack->Push(cx);
|
|
|
|
}
|
|
|
|
|
|
|
|
~AutoCXPusher()
|
|
|
|
{
|
|
|
|
if (sContextStack)
|
|
|
|
sContextStack->Pop(nsnull);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
NPClass nsJSObjWrapper::sJSObjWrapperNPClass =
|
|
|
|
{
|
|
|
|
NP_CLASS_STRUCT_VERSION,
|
|
|
|
nsJSObjWrapper::NP_Allocate,
|
|
|
|
nsJSObjWrapper::NP_Deallocate,
|
|
|
|
nsJSObjWrapper::NP_Invalidate,
|
|
|
|
nsJSObjWrapper::NP_HasMethod,
|
|
|
|
nsJSObjWrapper::NP_Invoke,
|
2004-08-30 04:31:16 +00:00
|
|
|
nsJSObjWrapper::NP_InvokeDefault,
|
2004-07-12 15:53:22 +00:00
|
|
|
nsJSObjWrapper::NP_HasProperty,
|
|
|
|
nsJSObjWrapper::NP_GetProperty,
|
|
|
|
nsJSObjWrapper::NP_SetProperty,
|
2006-03-01 00:13:38 +00:00
|
|
|
nsJSObjWrapper::NP_RemoveProperty,
|
|
|
|
nsJSObjWrapper::NP_Enumerate
|
2004-07-12 15:53:22 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
NPObjWrapper_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
NPObjWrapper_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
NPObjWrapper_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
NPObjWrapper_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
|
|
|
|
|
2006-03-01 00:13:38 +00:00
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
NPObjWrapper_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
|
|
|
jsval *statep, jsid *idp);
|
|
|
|
|
2004-07-12 15:53:22 +00:00
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
NPObjWrapper_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
|
|
|
|
JSObject **objp);
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(void)
|
|
|
|
NPObjWrapper_Finalize(JSContext *cx, JSObject *obj);
|
|
|
|
|
2004-08-30 04:31:16 +00:00
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
NPObjWrapper_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|
|
|
jsval *rval);
|
|
|
|
|
2006-02-25 00:32:03 +00:00
|
|
|
static bool
|
|
|
|
CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj,
|
|
|
|
NPObject *npobj, jsval id, jsval *vp);
|
|
|
|
|
2004-07-12 15:53:22 +00:00
|
|
|
static JSClass sNPObjectJSWrapperClass =
|
|
|
|
{
|
2006-03-01 00:13:38 +00:00
|
|
|
"NPObject JS wrapper class", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE,
|
2004-07-12 15:53:22 +00:00
|
|
|
NPObjWrapper_AddProperty, NPObjWrapper_DelProperty,
|
2006-03-01 00:13:38 +00:00
|
|
|
NPObjWrapper_GetProperty, NPObjWrapper_SetProperty, (JSEnumerateOp)NPObjWrapper_newEnumerate,
|
2004-07-12 15:53:22 +00:00
|
|
|
(JSResolveOp)NPObjWrapper_NewResolve, JS_ConvertStub,
|
2004-08-30 04:31:16 +00:00
|
|
|
NPObjWrapper_Finalize, nsnull, nsnull, NPObjWrapper_Call, nsnull, nsnull,
|
|
|
|
nsnull
|
2004-07-12 15:53:22 +00:00
|
|
|
};
|
|
|
|
|
2005-07-14 02:36:41 +00:00
|
|
|
typedef struct NPObjectMemberPrivate {
|
2006-02-25 00:32:03 +00:00
|
|
|
JSObject *npobjWrapper;
|
2005-07-14 02:36:41 +00:00
|
|
|
jsval fieldValue;
|
|
|
|
jsval methodName;
|
|
|
|
NPP npp;
|
|
|
|
} NPObjectMemberPrivate;
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
NPObjectMember_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp);
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(void)
|
|
|
|
NPObjectMember_Finalize(JSContext *cx, JSObject *obj);
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
NPObjectMember_Call(JSContext *cx, JSObject *obj, uintN argc,
|
|
|
|
jsval *argv, jsval *rval);
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(uint32)
|
|
|
|
NPObjectMember_Mark(JSContext *cx, JSObject *obj, void *arg);
|
|
|
|
|
|
|
|
static JSClass sNPObjectMemberClass =
|
|
|
|
{
|
|
|
|
"NPObject Ambiguous Member class", JSCLASS_HAS_PRIVATE,
|
|
|
|
JS_PropertyStub, JS_PropertyStub,
|
|
|
|
JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub,
|
|
|
|
JS_ResolveStub, NPObjectMember_Convert,
|
|
|
|
NPObjectMember_Finalize, nsnull, nsnull, NPObjectMember_Call,
|
|
|
|
nsnull, nsnull, nsnull, NPObjectMember_Mark, nsnull
|
|
|
|
};
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
OnWrapperCreated()
|
|
|
|
{
|
|
|
|
if (sWrapperCount++ == 0) {
|
|
|
|
static const char rtsvc_id[] = "@mozilla.org/js/xpc/RuntimeService;1";
|
|
|
|
nsCOMPtr<nsIJSRuntimeService> rtsvc(do_GetService(rtsvc_id));
|
|
|
|
if (!rtsvc)
|
|
|
|
return;
|
|
|
|
|
|
|
|
rtsvc->GetRuntime(&sJSRuntime);
|
|
|
|
NS_ASSERTION(sJSRuntime != nsnull, "no JSRuntime?!");
|
|
|
|
|
|
|
|
CallGetService("@mozilla.org/js/xpc/ContextStack;1", &sContextStack);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
OnWrapperDestroyed()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(sWrapperCount, "Whaaa, unbalanced created/destroyed calls!");
|
|
|
|
|
|
|
|
if (--sWrapperCount == 0) {
|
|
|
|
if (sJSObjWrappers.ops) {
|
|
|
|
NS_ASSERTION(sJSObjWrappers.entryCount == 0, "Uh, hash not empty?");
|
|
|
|
|
2006-02-23 09:36:43 +00:00
|
|
|
// No more wrappers, and our hash was initialized. Finish the
|
2004-07-12 15:53:22 +00:00
|
|
|
// hash to prevent leaking it.
|
|
|
|
PL_DHashTableFinish(&sJSObjWrappers);
|
|
|
|
|
|
|
|
sJSObjWrappers.ops = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sNPObjWrappers.ops) {
|
|
|
|
NS_ASSERTION(sNPObjWrappers.entryCount == 0, "Uh, hash not empty?");
|
|
|
|
|
2006-02-23 09:36:43 +00:00
|
|
|
// No more wrappers, and our hash was initialized. Finish the
|
2004-07-12 15:53:22 +00:00
|
|
|
// hash to prevent leaking it.
|
|
|
|
PL_DHashTableFinish(&sNPObjWrappers);
|
|
|
|
|
|
|
|
sNPObjWrappers.ops = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// No more need for this.
|
|
|
|
sJSRuntime = nsnull;
|
|
|
|
|
|
|
|
NS_IF_RELEASE(sContextStack);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSContext *
|
|
|
|
GetJSContext(NPP npp)
|
|
|
|
{
|
2004-07-30 04:00:05 +00:00
|
|
|
NS_ENSURE_TRUE(npp, nsnull);
|
|
|
|
|
2004-07-12 15:53:22 +00:00
|
|
|
ns4xPluginInstance *inst = (ns4xPluginInstance *)npp->ndata;
|
|
|
|
NS_ENSURE_TRUE(inst, nsnull);
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
nsCOMPtr<nsPIPluginInstancePeer> pp(do_QueryInterface(inst->Peer()));
|
2004-07-12 15:53:22 +00:00
|
|
|
NS_ENSURE_TRUE(pp, nsnull);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIPluginInstanceOwner> owner;
|
|
|
|
pp->GetOwner(getter_AddRefs(owner));
|
|
|
|
NS_ENSURE_TRUE(owner, nsnull);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocument> doc;
|
|
|
|
owner->GetDocument(getter_AddRefs(doc));
|
|
|
|
NS_ENSURE_TRUE(doc, nsnull);
|
|
|
|
|
2005-09-17 03:40:08 +00:00
|
|
|
nsCOMPtr<nsISupports> documentContainer = doc->GetContainer();
|
|
|
|
nsCOMPtr<nsIScriptGlobalObject> sgo(do_GetInterface(documentContainer));
|
2004-07-12 15:53:22 +00:00
|
|
|
NS_ENSURE_TRUE(sgo, nsnull);
|
|
|
|
|
|
|
|
nsIScriptContext *scx = sgo->GetContext();
|
|
|
|
NS_ENSURE_TRUE(scx, nsnull);
|
|
|
|
|
|
|
|
return (JSContext *)scx->GetNativeContext();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static NPP
|
2004-07-30 04:00:05 +00:00
|
|
|
LookupNPP(NPObject *npobj);
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
static jsval
|
|
|
|
NPVariantToJSVal(NPP npp, JSContext *cx, const NPVariant *variant)
|
|
|
|
{
|
|
|
|
switch (variant->type) {
|
|
|
|
case NPVariantType_Void :
|
|
|
|
return JSVAL_VOID;
|
|
|
|
case NPVariantType_Null :
|
|
|
|
return JSVAL_NULL;
|
|
|
|
case NPVariantType_Bool :
|
|
|
|
return BOOLEAN_TO_JSVAL(NPVARIANT_TO_BOOLEAN(*variant));
|
|
|
|
case NPVariantType_Int32 :
|
|
|
|
return INT_TO_JSVAL(NPVARIANT_TO_INT32(*variant));
|
|
|
|
case NPVariantType_Double :
|
|
|
|
{
|
|
|
|
jsval val;
|
|
|
|
if (::JS_NewNumberValue(cx, NPVARIANT_TO_DOUBLE(*variant), &val)) {
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NPVariantType_String :
|
|
|
|
{
|
|
|
|
const NPString *s = &NPVARIANT_TO_STRING(*variant);
|
|
|
|
PRUint32 len;
|
|
|
|
PRUnichar *p =
|
|
|
|
UTF8ToNewUnicode(nsDependentCString(s->utf8characters, s->utf8length),
|
|
|
|
&len);
|
|
|
|
|
|
|
|
JSString *str = ::JS_NewUCString(cx, (jschar *)p, len);
|
|
|
|
|
|
|
|
if (str) {
|
|
|
|
return STRING_TO_JSVAL(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NPVariantType_Object:
|
|
|
|
{
|
|
|
|
if (npp) {
|
|
|
|
JSObject *obj =
|
|
|
|
nsNPObjWrapper::GetNewOrUsed(npp, cx, NPVARIANT_TO_OBJECT(*variant));
|
|
|
|
|
|
|
|
if (obj) {
|
|
|
|
return OBJECT_TO_JSVAL(obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ERROR("Error wrapping NPObject!");
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
NS_ERROR("Unknown NPVariant type!");
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ERROR("Unable to convert NPVariant to jsval!");
|
|
|
|
|
|
|
|
return JSVAL_VOID;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
JSValToNPVariant(NPP npp, JSContext *cx, jsval val, NPVariant *variant)
|
|
|
|
{
|
2004-07-30 04:00:05 +00:00
|
|
|
NS_ASSERTION(npp, "Must have an NPP to wrap a jsval!");
|
|
|
|
|
2004-07-12 15:53:22 +00:00
|
|
|
if (JSVAL_IS_PRIMITIVE(val)) {
|
|
|
|
if (val == JSVAL_VOID) {
|
|
|
|
VOID_TO_NPVARIANT(*variant);
|
|
|
|
} else if (JSVAL_IS_NULL(val)) {
|
|
|
|
NULL_TO_NPVARIANT(*variant);
|
|
|
|
} else if (JSVAL_IS_BOOLEAN(val)) {
|
|
|
|
BOOLEAN_TO_NPVARIANT(JSVAL_TO_BOOLEAN(val), *variant);
|
|
|
|
} else if (JSVAL_IS_INT(val)) {
|
|
|
|
INT32_TO_NPVARIANT(JSVAL_TO_INT(val), *variant);
|
|
|
|
} else if (JSVAL_IS_DOUBLE(val)) {
|
|
|
|
DOUBLE_TO_NPVARIANT(*JSVAL_TO_DOUBLE(val), *variant);
|
|
|
|
} else if (JSVAL_IS_STRING(val)) {
|
|
|
|
JSString *jsstr = JSVAL_TO_STRING(val);
|
|
|
|
nsDependentString str((PRUnichar *)::JS_GetStringChars(jsstr),
|
|
|
|
::JS_GetStringLength(jsstr));
|
|
|
|
|
|
|
|
PRUint32 len;
|
|
|
|
char *p = ToNewUTF8String(str, &len);
|
|
|
|
|
|
|
|
if (!p) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
STRINGN_TO_NPVARIANT(p, len, *variant);
|
|
|
|
} else {
|
|
|
|
NS_ERROR("Unknown primitive type!");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
NPObject *npobj =
|
|
|
|
nsJSObjWrapper::GetNewOrUsed(npp, cx, JSVAL_TO_OBJECT(val));
|
2004-07-12 15:53:22 +00:00
|
|
|
if (!npobj) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pass over ownership of npobj to *variant
|
|
|
|
OBJECT_TO_NPVARIANT(npobj, *variant);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ThrowJSException(JSContext *cx, const char *message)
|
|
|
|
{
|
2004-07-30 04:00:05 +00:00
|
|
|
const char *ex = PeekException();
|
|
|
|
|
|
|
|
if (ex) {
|
|
|
|
nsAutoString ucex;
|
|
|
|
|
|
|
|
if (message) {
|
|
|
|
AppendASCIItoUTF16(message, ucex);
|
2004-07-12 15:53:22 +00:00
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
AppendASCIItoUTF16(" [plugin exception: ", ucex);
|
|
|
|
}
|
|
|
|
|
|
|
|
AppendUTF8toUTF16(ex, ucex);
|
|
|
|
|
|
|
|
if (message) {
|
|
|
|
AppendASCIItoUTF16("].", ucex);
|
|
|
|
}
|
|
|
|
|
|
|
|
JSString *str = ::JS_NewUCStringCopyN(cx, (jschar *)ucex.get(),
|
|
|
|
ucex.Length());
|
|
|
|
|
|
|
|
if (str) {
|
|
|
|
::JS_SetPendingException(cx, STRING_TO_JSVAL(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
PopException();
|
|
|
|
} else {
|
|
|
|
::JS_ReportError(cx, message);
|
|
|
|
}
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
static JSBool
|
|
|
|
ReportExceptionIfPending(JSContext *cx)
|
|
|
|
{
|
|
|
|
const char *ex = PeekException();
|
|
|
|
|
|
|
|
if (!ex) {
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ThrowJSException(cx, nsnull);
|
2004-07-12 15:53:22 +00:00
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsJSObjWrapper::nsJSObjWrapper(NPP npp)
|
|
|
|
: nsJSObjWrapperKey(nsnull, npp)
|
2004-07-12 15:53:22 +00:00
|
|
|
{
|
|
|
|
OnWrapperCreated();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsJSObjWrapper::~nsJSObjWrapper()
|
|
|
|
{
|
|
|
|
// Invalidate first, since it relies on sJSRuntime and sJSObjWrappers.
|
|
|
|
NP_Invalidate(this);
|
|
|
|
|
|
|
|
OnWrapperDestroyed();
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
NPObject *
|
2004-08-27 00:58:44 +00:00
|
|
|
nsJSObjWrapper::NP_Allocate(NPP npp, NPClass *aClass)
|
2004-07-12 15:53:22 +00:00
|
|
|
{
|
2004-08-27 00:58:44 +00:00
|
|
|
NS_ASSERTION(aClass == &sJSObjWrapperNPClass,
|
|
|
|
"Huh, wrong class passed to NP_Allocate()!!!");
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
return new nsJSObjWrapper(npp);
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
void
|
|
|
|
nsJSObjWrapper::NP_Deallocate(NPObject *npobj)
|
|
|
|
{
|
|
|
|
// nsJSObjWrapper::~nsJSObjWrapper() will call NP_Invalidate().
|
|
|
|
delete (nsJSObjWrapper *)npobj;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
void
|
|
|
|
nsJSObjWrapper::NP_Invalidate(NPObject *npobj)
|
|
|
|
{
|
|
|
|
nsJSObjWrapper *jsnpobj = (nsJSObjWrapper *)npobj;
|
|
|
|
|
|
|
|
if (jsnpobj && jsnpobj->mJSObj) {
|
|
|
|
// Unroot the object's JSObject
|
|
|
|
::JS_RemoveRootRT(sJSRuntime, &jsnpobj->mJSObj);
|
|
|
|
|
|
|
|
if (sJSObjWrappers.ops) {
|
|
|
|
// Remove the wrapper from the hash
|
2004-07-30 04:00:05 +00:00
|
|
|
|
|
|
|
nsJSObjWrapperKey key(jsnpobj->mJSObj, jsnpobj->mNpp);
|
|
|
|
PL_DHashTableOperate(&sJSObjWrappers, &key, PL_DHASH_REMOVE);
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
// Forget our reference to the JSObject.
|
2004-07-12 15:53:22 +00:00
|
|
|
jsnpobj->mJSObj = nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
|
|
|
GetProperty(JSContext *cx, JSObject *obj, NPIdentifier identifier, jsval *rval)
|
|
|
|
{
|
|
|
|
jsval id = (jsval)identifier;
|
|
|
|
|
|
|
|
AutoCXPusher pusher(cx);
|
|
|
|
|
|
|
|
if (JSVAL_IS_STRING(id)) {
|
|
|
|
JSString *str = JSVAL_TO_STRING(id);
|
|
|
|
|
|
|
|
return ::JS_GetUCProperty(cx, obj, ::JS_GetStringChars(str),
|
|
|
|
::JS_GetStringLength(str), rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ASSERTION(JSVAL_IS_INT(id), "id must be either string or int!\n");
|
|
|
|
|
|
|
|
return ::JS_GetElement(cx, obj, JSVAL_TO_INT(id), rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool
|
|
|
|
nsJSObjWrapper::NP_HasMethod(NPObject *npobj, NPIdentifier identifier)
|
|
|
|
{
|
2004-07-30 04:00:05 +00:00
|
|
|
NPP npp = NPPStack::Peek();
|
|
|
|
JSContext *cx = GetJSContext(npp);
|
|
|
|
|
|
|
|
if (!cx || !npobj) {
|
2006-03-01 00:13:38 +00:00
|
|
|
ThrowJSException(cx,
|
|
|
|
"Null npobj or cx in nsJSObjWrapper::NP_HasMethod!");
|
|
|
|
|
2004-07-12 15:53:22 +00:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
|
|
|
jsval v;
|
2004-07-30 04:00:05 +00:00
|
|
|
JSBool ok = GetProperty(cx, npjsobj->mJSObj, identifier, &v);
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
return ok && !JSVAL_IS_PRIMITIVE(v) &&
|
2004-07-30 04:00:05 +00:00
|
|
|
::JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(v));
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
2004-08-30 04:31:16 +00:00
|
|
|
static bool
|
|
|
|
doInvoke(NPObject *npobj, NPIdentifier method, const NPVariant *args,
|
|
|
|
uint32_t argCount, NPVariant *result)
|
2004-07-12 15:53:22 +00:00
|
|
|
{
|
2004-07-30 04:00:05 +00:00
|
|
|
NPP npp = NPPStack::Peek();
|
|
|
|
JSContext *cx = GetJSContext(npp);
|
|
|
|
|
|
|
|
if (!cx || !npobj || !result) {
|
2006-03-01 00:13:38 +00:00
|
|
|
ThrowJSException(cx, "Null npobj, cx, or result in doInvoke!");
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize *result
|
|
|
|
VOID_TO_NPVARIANT(*result);
|
|
|
|
|
|
|
|
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
|
|
|
jsval fv;
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
AutoCXPusher pusher(cx);
|
2004-07-12 15:53:22 +00:00
|
|
|
|
2004-08-30 04:31:16 +00:00
|
|
|
if ((jsval)method != JSVAL_VOID) {
|
|
|
|
if (!GetProperty(cx, npjsobj->mJSObj, method, &fv) ||
|
|
|
|
::JS_TypeOfValue(cx, fv) != JSTYPE_FUNCTION) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fv = OBJECT_TO_JSVAL(npjsobj->mJSObj);
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
jsval jsargs_buf[8];
|
|
|
|
jsval *jsargs = jsargs_buf;
|
|
|
|
|
|
|
|
if (argCount > (sizeof(jsargs_buf) / sizeof(jsval))) {
|
|
|
|
// Our stack buffer isn't large enough to hold all arguments,
|
|
|
|
// malloc a buffer.
|
|
|
|
jsargs = (jsval *)PR_Malloc(argCount * sizeof(jsval));
|
|
|
|
if (!jsargs) {
|
2006-03-01 00:13:38 +00:00
|
|
|
::JS_ReportOutOfMemory(cx);
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert args
|
|
|
|
for (PRUint32 i = 0; i < argCount; ++i) {
|
2004-07-30 04:00:05 +00:00
|
|
|
jsargs[i] = NPVariantToJSVal(npp, cx, args + i);
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
jsval v;
|
2004-07-30 04:00:05 +00:00
|
|
|
JSBool ok = ::JS_CallFunctionValue(cx, npjsobj->mJSObj, fv, argCount, jsargs,
|
|
|
|
&v);
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
if (jsargs != jsargs_buf)
|
|
|
|
PR_Free(jsargs);
|
|
|
|
|
|
|
|
if (ok)
|
2004-07-30 04:00:05 +00:00
|
|
|
ok = JSValToNPVariant(npp, cx, v, result);
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
// return ok == JS_TRUE to quiet down compiler warning, even if
|
|
|
|
// return ok is what we really want.
|
|
|
|
return ok == JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2004-08-30 04:31:16 +00:00
|
|
|
// static
|
|
|
|
bool
|
|
|
|
nsJSObjWrapper::NP_Invoke(NPObject *npobj, NPIdentifier method,
|
|
|
|
const NPVariant *args, uint32_t argCount,
|
|
|
|
NPVariant *result)
|
|
|
|
{
|
|
|
|
if ((jsval)method == JSVAL_VOID) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return doInvoke(npobj, method, args, argCount, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool
|
|
|
|
nsJSObjWrapper::NP_InvokeDefault(NPObject *npobj, const NPVariant *args,
|
|
|
|
uint32_t argCount, NPVariant *result)
|
|
|
|
{
|
|
|
|
return doInvoke(npobj, (NPIdentifier)JSVAL_VOID, args, argCount, result);
|
|
|
|
}
|
|
|
|
|
2004-07-12 15:53:22 +00:00
|
|
|
// static
|
|
|
|
bool
|
|
|
|
nsJSObjWrapper::NP_HasProperty(NPObject *npobj, NPIdentifier identifier)
|
|
|
|
{
|
2004-07-30 04:00:05 +00:00
|
|
|
NPP npp = NPPStack::Peek();
|
|
|
|
JSContext *cx = GetJSContext(npp);
|
|
|
|
|
|
|
|
if (!cx || !npobj) {
|
2006-03-01 00:13:38 +00:00
|
|
|
ThrowJSException(cx,
|
|
|
|
"Null cx or npobj in nsJSObjWrapper::NP_HasProperty!");
|
2004-07-30 04:00:05 +00:00
|
|
|
|
2004-07-12 15:53:22 +00:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
|
|
|
jsval id = (jsval)identifier;
|
2004-07-30 04:00:05 +00:00
|
|
|
JSBool found, ok = JS_FALSE;
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
if (JSVAL_IS_STRING(id)) {
|
|
|
|
JSString *str = JSVAL_TO_STRING(id);
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
ok = ::JS_HasUCProperty(cx, npjsobj->mJSObj, ::JS_GetStringChars(str),
|
|
|
|
::JS_GetStringLength(str), &found);
|
2004-07-12 15:53:22 +00:00
|
|
|
} else {
|
|
|
|
NS_ASSERTION(JSVAL_IS_INT(id), "id must be either string or int!\n");
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
ok = ::JS_HasElement(cx, npjsobj->mJSObj, JSVAL_TO_INT(id), &found);
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
return ok && found;
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool
|
|
|
|
nsJSObjWrapper::NP_GetProperty(NPObject *npobj, NPIdentifier identifier,
|
|
|
|
NPVariant *result)
|
|
|
|
{
|
2004-07-30 04:00:05 +00:00
|
|
|
NPP npp = NPPStack::Peek();
|
|
|
|
JSContext *cx = GetJSContext(npp);
|
|
|
|
|
2006-03-01 00:13:38 +00:00
|
|
|
if (!cx || !npobj) {
|
|
|
|
ThrowJSException(cx,
|
|
|
|
"Null cx or npobj in nsJSObjWrapper::NP_GetProperty!");
|
|
|
|
|
2004-07-12 15:53:22 +00:00
|
|
|
return PR_FALSE;
|
2006-03-01 00:13:38 +00:00
|
|
|
}
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
AutoCXPusher pusher(cx);
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
jsval v;
|
2004-07-30 04:00:05 +00:00
|
|
|
return (GetProperty(cx, npjsobj->mJSObj, identifier, &v) &&
|
|
|
|
JSValToNPVariant(npp, cx, v, result));
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool
|
|
|
|
nsJSObjWrapper::NP_SetProperty(NPObject *npobj, NPIdentifier identifier,
|
|
|
|
const NPVariant *value)
|
|
|
|
{
|
2004-07-30 04:00:05 +00:00
|
|
|
NPP npp = NPPStack::Peek();
|
|
|
|
JSContext *cx = GetJSContext(npp);
|
|
|
|
|
2006-03-01 00:13:38 +00:00
|
|
|
if (!cx || !npobj) {
|
|
|
|
ThrowJSException(cx,
|
|
|
|
"Null cx or npobj in nsJSObjWrapper::NP_SetProperty!");
|
|
|
|
|
2004-07-12 15:53:22 +00:00
|
|
|
return PR_FALSE;
|
2006-03-01 00:13:38 +00:00
|
|
|
}
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
|
|
|
jsval id = (jsval)identifier;
|
|
|
|
JSBool ok = JS_FALSE;
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
AutoCXPusher pusher(cx);
|
2004-07-12 15:53:22 +00:00
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
jsval v = NPVariantToJSVal(npp, cx, value);
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
if (JSVAL_IS_STRING(id)) {
|
|
|
|
JSString *str = JSVAL_TO_STRING(id);
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
ok = ::JS_SetUCProperty(cx, npjsobj->mJSObj, ::JS_GetStringChars(str),
|
2004-07-12 15:53:22 +00:00
|
|
|
::JS_GetStringLength(str), &v);
|
|
|
|
} else {
|
|
|
|
NS_ASSERTION(JSVAL_IS_INT(id), "id must be either string or int!\n");
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
ok = ::JS_SetElement(cx, npjsobj->mJSObj, JSVAL_TO_INT(id), &v);
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// return ok == JS_TRUE to quiet down compiler warning, even if
|
|
|
|
// return ok is what we really want.
|
|
|
|
return ok == JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool
|
|
|
|
nsJSObjWrapper::NP_RemoveProperty(NPObject *npobj, NPIdentifier identifier)
|
|
|
|
{
|
2004-07-30 04:00:05 +00:00
|
|
|
NPP npp = NPPStack::Peek();
|
|
|
|
JSContext *cx = GetJSContext(npp);
|
|
|
|
|
2006-03-01 00:13:38 +00:00
|
|
|
if (!cx || !npobj) {
|
|
|
|
ThrowJSException(cx,
|
|
|
|
"Null cx or npobj in nsJSObjWrapper::NP_RemoveProperty!");
|
|
|
|
|
2004-07-12 15:53:22 +00:00
|
|
|
return PR_FALSE;
|
2006-03-01 00:13:38 +00:00
|
|
|
}
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
|
|
|
jsval id = (jsval)identifier;
|
|
|
|
JSBool ok = JS_FALSE;
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
AutoCXPusher pusher(cx);
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
if (JSVAL_IS_STRING(id)) {
|
|
|
|
JSString *str = JSVAL_TO_STRING(id);
|
|
|
|
|
|
|
|
jsval unused;
|
2004-07-30 04:00:05 +00:00
|
|
|
ok = ::JS_DeleteUCProperty2(cx, npjsobj->mJSObj, ::JS_GetStringChars(str),
|
2004-07-12 15:53:22 +00:00
|
|
|
::JS_GetStringLength(str), &unused);
|
|
|
|
} else {
|
|
|
|
NS_ASSERTION(JSVAL_IS_INT(id), "id must be either string or int!\n");
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
ok = ::JS_DeleteElement(cx, npjsobj->mJSObj, JSVAL_TO_INT(id));
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// return ok == JS_TRUE to quiet down compiler warning, even if
|
|
|
|
// return ok is what we really want.
|
|
|
|
return ok == JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2006-03-01 00:13:38 +00:00
|
|
|
//static
|
|
|
|
bool
|
|
|
|
nsJSObjWrapper::NP_Enumerate(NPObject *npobj, NPIdentifier **identifier,
|
|
|
|
uint32_t *count)
|
|
|
|
{
|
|
|
|
NPP npp = NPPStack::Peek();
|
|
|
|
JSContext *cx = GetJSContext(npp);
|
|
|
|
|
|
|
|
*identifier = 0;
|
|
|
|
*count = 0;
|
|
|
|
|
|
|
|
if (!cx || !npobj) {
|
|
|
|
ThrowJSException(cx,
|
|
|
|
"Null cx or npobj in nsJSObjWrapper::NP_Enumerate!");
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
|
|
|
|
|
|
|
|
AutoCXPusher pusher(cx);
|
|
|
|
|
|
|
|
JSIdArray *ida = ::JS_Enumerate(cx, npjsobj->mJSObj);
|
|
|
|
if (!ida) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*count = ida->length;
|
|
|
|
*identifier = (NPIdentifier *)PR_Malloc(*count * sizeof(NPIdentifier));
|
|
|
|
if (!*identifier) {
|
|
|
|
ThrowJSException(cx, "Memory allocation failed for NPIdentifier!");
|
|
|
|
|
|
|
|
::JS_DestroyIdArray(cx, ida);
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (PRUint32 i = 0; i < *count; i++) {
|
|
|
|
jsval v;
|
|
|
|
if (!::JS_IdToValue(cx, ida->vector[i], &v)) {
|
|
|
|
::JS_DestroyIdArray(cx, ida);
|
|
|
|
PR_Free(*identifier);
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (JSVAL_IS_STRING(v)) {
|
|
|
|
JSString *str = JSVAL_TO_STRING(v);
|
|
|
|
|
|
|
|
if (!JS_InternUCStringN(cx, ::JS_GetStringChars(str),
|
|
|
|
::JS_GetStringLength(str))) {
|
|
|
|
::JS_DestroyIdArray(cx, ida);
|
|
|
|
PR_Free(*identifier);
|
|
|
|
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
NS_ASSERTION(JSVAL_IS_INT(v),
|
|
|
|
"The element in ida must be either string or int!\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
(*identifier)[i] = (NPIdentifier)v;
|
|
|
|
}
|
|
|
|
|
|
|
|
::JS_DestroyIdArray(cx, ida);
|
|
|
|
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
2004-07-12 15:53:22 +00:00
|
|
|
class JSObjWrapperHashEntry : public PLDHashEntryHdr
|
|
|
|
{
|
|
|
|
public:
|
2004-07-30 04:00:05 +00:00
|
|
|
nsJSObjWrapper *mJSObjWrapper;
|
2004-07-12 15:53:22 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
PR_STATIC_CALLBACK(PLDHashNumber)
|
|
|
|
JSObjWrapperHash(PLDHashTable *table, const void *key)
|
|
|
|
{
|
|
|
|
const nsJSObjWrapperKey *e = NS_STATIC_CAST(const nsJSObjWrapperKey *, key);
|
|
|
|
|
|
|
|
return (PLDHashNumber)((PRWord)e->mJSObj ^ (PRWord)e->mNpp) >> 2;
|
|
|
|
}
|
|
|
|
|
2004-07-12 15:53:22 +00:00
|
|
|
PR_STATIC_CALLBACK(const void *)
|
2004-07-30 04:00:05 +00:00
|
|
|
JSObjWrapperHashGetKey(PLDHashTable *table, PLDHashEntryHdr *entry)
|
2004-07-12 15:53:22 +00:00
|
|
|
{
|
|
|
|
JSObjWrapperHashEntry *e =
|
|
|
|
NS_STATIC_CAST(JSObjWrapperHashEntry *, entry);
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
return NS_STATIC_CAST(nsJSObjWrapperKey *, e->mJSObjWrapper);
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(PRBool)
|
2004-07-30 04:00:05 +00:00
|
|
|
JSObjWrapperHashMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry,
|
2004-07-12 15:53:22 +00:00
|
|
|
const void *key)
|
|
|
|
{
|
2004-07-30 04:00:05 +00:00
|
|
|
const nsJSObjWrapperKey *objWrapperKey =
|
|
|
|
NS_STATIC_CAST(const nsJSObjWrapperKey *, key);
|
2004-07-12 15:53:22 +00:00
|
|
|
const JSObjWrapperHashEntry *e =
|
|
|
|
NS_STATIC_CAST(const JSObjWrapperHashEntry *, entry);
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
return (e->mJSObjWrapper->mJSObj == objWrapperKey->mJSObj &&
|
|
|
|
e->mJSObjWrapper->mNpp == objWrapperKey->mNpp);
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Look up or create an NPObject that wraps the JSObject obj.
|
|
|
|
|
|
|
|
// static
|
|
|
|
NPObject *
|
|
|
|
nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JSObject *obj)
|
|
|
|
{
|
|
|
|
if (!npp) {
|
|
|
|
NS_ERROR("Null NPP passed to nsJSObjWrapper::GetNewOrUsed()!");
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cx) {
|
|
|
|
cx = GetJSContext(npp);
|
|
|
|
|
|
|
|
if (!cx) {
|
|
|
|
NS_ERROR("Unable to find a JSContext in "
|
|
|
|
"nsJSObjWrapper::GetNewOrUsed()!");
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JSClass *clazz = JS_GET_CLASS(cx, obj);
|
|
|
|
|
|
|
|
if (clazz == &sNPObjectJSWrapperClass) {
|
|
|
|
// obj is one of our own, its private data is the NPObject we're
|
|
|
|
// looking for.
|
|
|
|
|
|
|
|
NPObject *npobj = (NPObject *)::JS_GetPrivate(cx, obj);
|
|
|
|
|
|
|
|
return _retainobject(npobj);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sJSObjWrappers.ops) {
|
2006-02-23 09:36:43 +00:00
|
|
|
// No hash yet (or any more), initialize it.
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
static PLDHashTableOps ops =
|
|
|
|
{
|
|
|
|
PL_DHashAllocTable,
|
|
|
|
PL_DHashFreeTable,
|
2004-07-30 04:00:05 +00:00
|
|
|
JSObjWrapperHashGetKey,
|
|
|
|
JSObjWrapperHash,
|
|
|
|
JSObjWrapperHashMatchEntry,
|
2004-07-12 15:53:22 +00:00
|
|
|
PL_DHashMoveEntryStub,
|
|
|
|
PL_DHashClearEntryStub,
|
|
|
|
PL_DHashFinalizeStub
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!PL_DHashTableInit(&sJSObjWrappers, &ops, nsnull,
|
|
|
|
sizeof(JSObjWrapperHashEntry), 16)) {
|
|
|
|
NS_ERROR("Error initializing PLDHashTable!");
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
nsJSObjWrapperKey key(obj, npp);
|
|
|
|
|
2004-07-12 15:53:22 +00:00
|
|
|
JSObjWrapperHashEntry *entry =
|
|
|
|
NS_STATIC_CAST(JSObjWrapperHashEntry *,
|
2004-07-30 04:00:05 +00:00
|
|
|
PL_DHashTableOperate(&sJSObjWrappers, &key, PL_DHASH_ADD));
|
2004-07-12 15:53:22 +00:00
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
if (PL_DHASH_ENTRY_IS_BUSY(entry) && entry->mJSObjWrapper) {
|
2004-07-12 15:53:22 +00:00
|
|
|
// Found a live nsJSObjWrapper, return it.
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
return _retainobject(entry->mJSObjWrapper);
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// No existing nsJSObjWrapper, create one.
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
nsJSObjWrapper *wrapper =
|
|
|
|
(nsJSObjWrapper *)_createobject(npp, &sJSObjWrapperNPClass);
|
2004-07-12 15:53:22 +00:00
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
if (!wrapper) {
|
2004-07-12 15:53:22 +00:00
|
|
|
// OOM? Remove the stale entry from the hash.
|
|
|
|
|
|
|
|
PL_DHashTableRawRemove(&sJSObjWrappers, entry);
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
wrapper->mJSObj = obj;
|
2004-07-12 15:53:22 +00:00
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
entry->mJSObjWrapper = wrapper;
|
|
|
|
|
|
|
|
NS_ASSERTION(wrapper->mNpp == npp, "nsJSObjWrapper::mNpp not initialized!");
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
// Root the JSObject, its lifetime is now tied to that of the
|
|
|
|
// NPObject.
|
2004-07-30 04:00:05 +00:00
|
|
|
if (!::JS_AddNamedRoot(cx, &wrapper->mJSObj, "nsJSObjWrapper::mJSObject")) {
|
2004-07-12 15:53:22 +00:00
|
|
|
NS_ERROR("Failed to root JSObject!");
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
_releaseobject(wrapper);
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
PL_DHashTableRawRemove(&sJSObjWrappers, entry);
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
return wrapper;
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static NPObject *
|
|
|
|
GetNPObject(JSContext *cx, JSObject *obj)
|
|
|
|
{
|
|
|
|
while (JS_GET_CLASS(cx, obj) != &sNPObjectJSWrapperClass) {
|
|
|
|
obj = ::JS_GetPrototype(cx, obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!obj) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (NPObject *)::JS_GetPrivate(cx, obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
NPObjWrapper_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|
|
|
{
|
|
|
|
NPObject *npobj = GetNPObject(cx, obj);
|
|
|
|
|
|
|
|
if (!npobj || !npobj->_class || !npobj->_class->hasProperty ||
|
|
|
|
!npobj->_class->hasMethod) {
|
|
|
|
ThrowJSException(cx, "Bad NPObject as private data!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We must permit methods here since JS_DefineUCFunction() will add
|
|
|
|
// the function as a property
|
|
|
|
if (!npobj->_class->hasProperty(npobj, (NPIdentifier)id) &&
|
|
|
|
!npobj->_class->hasMethod(npobj, (NPIdentifier)id)) {
|
|
|
|
ThrowJSException(cx, "Trying to add unsupported property on scriptable "
|
|
|
|
"plugin object!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
return ReportExceptionIfPending(cx);
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
NPObjWrapper_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|
|
|
{
|
|
|
|
NPObject *npobj = GetNPObject(cx, obj);
|
|
|
|
|
|
|
|
if (!npobj || !npobj->_class || !npobj->_class->hasProperty) {
|
|
|
|
ThrowJSException(cx, "Bad NPObject as private data!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!npobj->_class->hasProperty(npobj, (NPIdentifier)id)) {
|
|
|
|
ThrowJSException(cx, "Trying to remove unsupported property on scriptable "
|
|
|
|
"plugin object!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
return ReportExceptionIfPending(cx);
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
NPObjWrapper_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|
|
|
{
|
|
|
|
NPObject *npobj = GetNPObject(cx, obj);
|
|
|
|
|
|
|
|
if (!npobj || !npobj->_class || !npobj->_class->hasProperty ||
|
|
|
|
!npobj->_class->setProperty) {
|
|
|
|
ThrowJSException(cx, "Bad NPObject as private data!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!npobj->_class->hasProperty(npobj, (NPIdentifier)id)) {
|
|
|
|
ThrowJSException(cx, "Trying to set unsupported property on scriptable "
|
|
|
|
"plugin object!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
// Find out what plugin (NPP) is the owner of the object we're
|
|
|
|
// manipulating, and make it own any JSObject wrappers created here.
|
|
|
|
NPP npp = LookupNPP(npobj);
|
|
|
|
|
|
|
|
if (!npp) {
|
|
|
|
ThrowJSException(cx, "No NPP found for NPObject!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
2004-07-12 15:53:22 +00:00
|
|
|
NPVariant npv;
|
2004-07-30 04:00:05 +00:00
|
|
|
if (!JSValToNPVariant(npp, cx, *vp, &npv)) {
|
2004-07-12 15:53:22 +00:00
|
|
|
ThrowJSException(cx, "Error converting jsval to NPVariant!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool ok = npobj->_class->setProperty(npobj, (NPIdentifier)id, &npv);
|
|
|
|
|
|
|
|
// Release the variant
|
|
|
|
_releasevariantvalue(&npv);
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
ThrowJSException(cx, "Error setting property on scriptable plugin "
|
|
|
|
"object!");
|
2004-07-30 04:00:05 +00:00
|
|
|
|
|
|
|
return JS_FALSE;
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
return ReportExceptionIfPending(cx);
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
NPObjWrapper_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|
|
|
{
|
|
|
|
NPObject *npobj = GetNPObject(cx, obj);
|
|
|
|
|
|
|
|
if (!npobj || !npobj->_class || !npobj->_class->hasProperty ||
|
|
|
|
!npobj->_class->hasMethod || !npobj->_class->getProperty) {
|
|
|
|
ThrowJSException(cx, "Bad NPObject as private data!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
2005-07-14 02:36:41 +00:00
|
|
|
PRBool hasProperty = npobj->_class->hasProperty(npobj, (NPIdentifier)id);
|
|
|
|
PRBool hasMethod = npobj->_class->hasMethod(npobj, (NPIdentifier)id);
|
|
|
|
NPP npp = nsnull;
|
|
|
|
if (hasProperty) {
|
|
|
|
// Find out what plugin (NPP) is the owner of the object we're
|
|
|
|
// manipulating, and make it own any JSObject wrappers created
|
|
|
|
// here.
|
|
|
|
npp = LookupNPP(npobj);
|
|
|
|
if (!npp) {
|
|
|
|
ThrowJSException(cx, "No NPP found for NPObject!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// To support ambiguous members, we return NPObject Member class here.
|
|
|
|
if (hasProperty && hasMethod)
|
|
|
|
return CreateNPObjectMember(npp, cx, obj, npobj, id, vp);
|
|
|
|
|
|
|
|
if (hasProperty) {
|
2004-07-12 15:53:22 +00:00
|
|
|
NPVariant npv;
|
|
|
|
VOID_TO_NPVARIANT(npv);
|
|
|
|
|
|
|
|
if (!npobj->_class->getProperty(npobj, (NPIdentifier)id, &npv)) {
|
|
|
|
ThrowJSException(cx, "Error setting property on scriptable plugin "
|
|
|
|
"object!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*vp = NPVariantToJSVal(npp, cx, &npv);
|
|
|
|
|
|
|
|
// *vp now owns the value, release our reference.
|
|
|
|
_releasevariantvalue(&npv);
|
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2005-07-14 02:36:41 +00:00
|
|
|
if (!hasMethod) {
|
2004-07-30 04:00:05 +00:00
|
|
|
ThrowJSException(cx, "Trying to get unsupported property on scriptable "
|
|
|
|
"plugin object!");
|
2004-07-12 15:53:22 +00:00
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
return JS_FALSE;
|
|
|
|
}
|
2004-07-12 15:53:22 +00:00
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
return ReportExceptionIfPending(cx);
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
CallNPMethod(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|
|
|
jsval *rval)
|
|
|
|
{
|
|
|
|
while (JS_GET_CLASS(cx, obj) != &sNPObjectJSWrapperClass) {
|
|
|
|
obj = ::JS_GetPrototype(cx, obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!obj) {
|
|
|
|
ThrowJSException(cx, "NPMethod called on non-NPObject wrapped JSObject!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NPObject *npobj = (NPObject *)::JS_GetPrivate(cx, obj);
|
|
|
|
|
|
|
|
if (!npobj || !npobj->_class || !npobj->_class->invoke) {
|
|
|
|
ThrowJSException(cx, "Bad NPObject as private data!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
// Find out what plugin (NPP) is the owner of the object we're
|
|
|
|
// manipulating, and make it own any JSObject wrappers created here.
|
|
|
|
NPP npp = LookupNPP(npobj);
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
if (!npp) {
|
2004-07-30 04:00:05 +00:00
|
|
|
ThrowJSException(cx, "Error finding NPP for NPObject!");
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NPVariant npargs_buf[8];
|
|
|
|
NPVariant *npargs = npargs_buf;
|
|
|
|
|
|
|
|
if (argc > (sizeof(npargs_buf) / sizeof(NPVariant))) {
|
|
|
|
// Our stack buffer isn't large enough to hold all arguments,
|
|
|
|
// malloc a buffer.
|
|
|
|
npargs = (NPVariant *)PR_Malloc(argc * sizeof(NPVariant));
|
|
|
|
|
|
|
|
if (!npargs) {
|
|
|
|
ThrowJSException(cx, "Out of memory!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert arguments
|
|
|
|
PRUint32 i;
|
|
|
|
for (i = 0; i < argc; ++i) {
|
|
|
|
if (!JSValToNPVariant(npp, cx, argv[i], npargs + i)) {
|
|
|
|
ThrowJSException(cx, "Error converting jsvals to NPVariants!");
|
|
|
|
|
2005-12-22 03:16:16 +00:00
|
|
|
if (npargs != npargs_buf) {
|
|
|
|
PR_Free(npargs);
|
|
|
|
}
|
|
|
|
|
2004-07-12 15:53:22 +00:00
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NPVariant v;
|
|
|
|
VOID_TO_NPVARIANT(v);
|
|
|
|
|
2004-08-30 04:31:16 +00:00
|
|
|
JSObject *funobj = JSVAL_TO_OBJECT(argv[-2]);
|
|
|
|
JSBool ok;
|
|
|
|
|
|
|
|
if (funobj != obj) {
|
|
|
|
// A obj.function() style call is made, get the method name from
|
|
|
|
// the function object.
|
|
|
|
|
|
|
|
JSFunction *fun = (JSFunction *)::JS_GetPrivate(cx, funobj);
|
|
|
|
jsval method = STRING_TO_JSVAL(::JS_GetFunctionId(fun));
|
|
|
|
|
|
|
|
ok = npobj->_class->invoke(npobj, (NPIdentifier)method, npargs, argc, &v);
|
|
|
|
} else {
|
|
|
|
// obj is a callable object that is being called, no method name
|
|
|
|
// available then. Invoke the default method.
|
|
|
|
|
|
|
|
ok = npobj->_class->invokeDefault(npobj, npargs, argc, &v);
|
|
|
|
}
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
// Release arguments.
|
|
|
|
for (i = 0; i < argc; ++i) {
|
|
|
|
_releasevariantvalue(npargs + i);
|
|
|
|
}
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
if (npargs != npargs_buf) {
|
2004-07-12 15:53:22 +00:00
|
|
|
PR_Free(npargs);
|
2004-07-30 04:00:05 +00:00
|
|
|
}
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
ThrowJSException(cx, "Error calling method on NPObject!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*rval = NPVariantToJSVal(npp, cx, &v);
|
|
|
|
|
|
|
|
// *rval now owns the value, release our reference.
|
|
|
|
_releasevariantvalue(&v);
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
return ReportExceptionIfPending(cx);
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
2006-03-01 00:13:38 +00:00
|
|
|
struct NPObjectEnumerateState {
|
|
|
|
PRUint32 index;
|
|
|
|
PRUint32 length;
|
|
|
|
NPIdentifier *value;
|
|
|
|
};
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
NPObjWrapper_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
|
|
|
jsval *statep, jsid *idp)
|
|
|
|
{
|
|
|
|
NPObject *npobj = GetNPObject(cx, obj);
|
|
|
|
NPIdentifier *enum_value;
|
|
|
|
PRUint32 length;
|
|
|
|
NPObjectEnumerateState *state;
|
|
|
|
|
|
|
|
if (!npobj || !npobj->_class) {
|
|
|
|
ThrowJSException(cx, "Bad NPObject as private data!");
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ASSERTION(statep, "Must have a statep to enumerate!");
|
|
|
|
|
|
|
|
switch(enum_op) {
|
|
|
|
case JSENUMERATE_INIT:
|
|
|
|
state = new NPObjectEnumerateState();
|
|
|
|
if (!state) {
|
|
|
|
ThrowJSException(cx, "Memory allocation failed for "
|
|
|
|
"NPObjectEnumerateState!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(npobj->_class) ||
|
|
|
|
!npobj->_class->enumerate) {
|
|
|
|
enum_value = 0;
|
|
|
|
length = 0;
|
|
|
|
} else if (!npobj->_class->enumerate(npobj, &enum_value, &length)) {
|
|
|
|
ThrowJSException(cx, "Error enumerating properties on scriptable "
|
|
|
|
"plugin object");
|
|
|
|
delete state;
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
state->value = enum_value;
|
|
|
|
state->length = length;
|
|
|
|
state->index = 0;
|
|
|
|
*statep = PRIVATE_TO_JSVAL(state);
|
|
|
|
if (idp) {
|
|
|
|
*idp = INT_TO_JSVAL(length);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case JSENUMERATE_NEXT:
|
|
|
|
state = (NPObjectEnumerateState *)JSVAL_TO_PRIVATE(*statep);
|
|
|
|
enum_value = state->value;
|
|
|
|
length = state->length;
|
|
|
|
if (state->index != length) {
|
|
|
|
return ::JS_ValueToId(cx, (jsval)enum_value[state->index++], idp);
|
|
|
|
}
|
|
|
|
|
|
|
|
// FALL THROUGH
|
|
|
|
|
|
|
|
case JSENUMERATE_DESTROY:
|
|
|
|
state = (NPObjectEnumerateState *)JSVAL_TO_PRIVATE(*statep);
|
|
|
|
if (state->value)
|
|
|
|
PR_Free(state->value);
|
|
|
|
delete state;
|
|
|
|
*statep = JSVAL_NULL;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
NPObjWrapper_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
|
|
|
|
JSObject **objp)
|
|
|
|
{
|
|
|
|
NPObject *npobj = GetNPObject(cx, obj);
|
|
|
|
|
|
|
|
if (!npobj || !npobj->_class || !npobj->_class->hasProperty ||
|
|
|
|
!npobj->_class->hasMethod) {
|
|
|
|
ThrowJSException(cx, "Bad NPObject as private data!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (npobj->_class->hasProperty(npobj, (NPIdentifier)id)) {
|
2004-08-30 04:31:16 +00:00
|
|
|
JSBool ok;
|
|
|
|
|
|
|
|
if (JSVAL_IS_STRING(id)) {
|
|
|
|
JSString *str = JSVAL_TO_STRING(id);
|
|
|
|
|
|
|
|
ok = ::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str),
|
|
|
|
::JS_GetStringLength(str), JSVAL_VOID, nsnull,
|
|
|
|
nsnull, JSPROP_ENUMERATE);
|
|
|
|
} else {
|
|
|
|
ok = ::JS_DefineElement(cx, obj, JSVAL_TO_INT(id), JSVAL_VOID, nsnull,
|
|
|
|
nsnull, JSPROP_ENUMERATE);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
2004-07-12 15:53:22 +00:00
|
|
|
*objp = obj;
|
|
|
|
} else if (npobj->_class->hasMethod(npobj, (NPIdentifier)id)) {
|
|
|
|
JSString *str = nsnull;
|
|
|
|
|
|
|
|
if (JSVAL_IS_STRING(id)) {
|
|
|
|
str = JSVAL_TO_STRING(id);
|
|
|
|
} else {
|
|
|
|
NS_ASSERTION(JSVAL_IS_INT(id), "id must be either string or int!\n");
|
|
|
|
|
|
|
|
str = ::JS_ValueToString(cx, id);
|
|
|
|
|
|
|
|
if (!str) {
|
|
|
|
// OOM. The JS engine throws exceptions for us in this case.
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JSFunction *fnc =
|
|
|
|
::JS_DefineUCFunction(cx, obj, ::JS_GetStringChars(str),
|
|
|
|
::JS_GetStringLength(str), CallNPMethod, 0,
|
|
|
|
JSPROP_ENUMERATE);
|
|
|
|
|
|
|
|
*objp = obj;
|
|
|
|
|
|
|
|
return fnc != nsnull;
|
|
|
|
}
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
return ReportExceptionIfPending(cx);
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(void)
|
|
|
|
NPObjWrapper_Finalize(JSContext *cx, JSObject *obj)
|
|
|
|
{
|
|
|
|
NPObject *npobj = (NPObject *)::JS_GetPrivate(cx, obj);
|
|
|
|
|
|
|
|
if (npobj) {
|
|
|
|
if (sNPObjWrappers.ops) {
|
|
|
|
PL_DHashTableOperate(&sNPObjWrappers, npobj, PL_DHASH_REMOVE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Let go of our NPObject
|
|
|
|
_releaseobject(npobj);
|
|
|
|
}
|
|
|
|
|
|
|
|
OnWrapperDestroyed();
|
|
|
|
}
|
|
|
|
|
2004-08-30 04:31:16 +00:00
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
NPObjWrapper_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|
|
|
jsval *rval)
|
|
|
|
{
|
|
|
|
return CallNPMethod(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, rval);
|
|
|
|
}
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
class NPObjWrapperHashEntry : public PLDHashEntryHdr
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
NPObject *mNPObj; // Must be the first member for the PLDHash stubs to work
|
|
|
|
JSObject *mJSObj;
|
|
|
|
NPP mNpp;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Look up or create a JSObject that wraps the NPObject npobj.
|
|
|
|
|
|
|
|
// static
|
|
|
|
JSObject *
|
|
|
|
nsNPObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, NPObject *npobj)
|
|
|
|
{
|
|
|
|
if (!npobj) {
|
|
|
|
NS_ERROR("Null NPObject passed to nsNPObjWrapper::GetNewOrUsed()!");
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (npobj->_class == &nsJSObjWrapper::sJSObjWrapperNPClass) {
|
|
|
|
// npobj is one of our own, return its existing JSObject.
|
|
|
|
|
|
|
|
return ((nsJSObjWrapper *)npobj)->mJSObj;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!npp) {
|
|
|
|
NS_ERROR("No npp passed to nsNPObjWrapper::GetNewOrUsed()!");
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sNPObjWrappers.ops) {
|
2006-02-23 09:36:43 +00:00
|
|
|
// No hash yet (or any more), initialize it.
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
if (!PL_DHashTableInit(&sNPObjWrappers, PL_DHashGetStubOps(), nsnull,
|
|
|
|
sizeof(NPObjWrapperHashEntry), 16)) {
|
|
|
|
NS_ERROR("Error initializing PLDHashTable!");
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NPObjWrapperHashEntry *entry =
|
|
|
|
NS_STATIC_CAST(NPObjWrapperHashEntry *,
|
|
|
|
PL_DHashTableOperate(&sNPObjWrappers, npobj,
|
|
|
|
PL_DHASH_ADD));
|
|
|
|
|
|
|
|
if (PL_DHASH_ENTRY_IS_BUSY(entry) && entry->mJSObj) {
|
|
|
|
// Found a live NPObject wrapper, return it.
|
|
|
|
return entry->mJSObj;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry->mNPObj = npobj;
|
|
|
|
entry->mNpp = npp;
|
|
|
|
|
|
|
|
// No existing JSObject, create one.
|
|
|
|
|
|
|
|
JSObject *obj = ::JS_NewObject(cx, &sNPObjectJSWrapperClass, nsnull, nsnull);
|
|
|
|
|
|
|
|
if (!obj) {
|
|
|
|
// OOM? Remove the stale entry from the hash.
|
|
|
|
|
|
|
|
PL_DHashTableRawRemove(&sJSObjWrappers, entry);
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
OnWrapperCreated();
|
|
|
|
|
|
|
|
entry->mJSObj = obj;
|
|
|
|
|
|
|
|
if (!::JS_SetPrivate(cx, obj, npobj)) {
|
|
|
|
NS_ERROR("Error setting private NPObject data in JS wrapper!");
|
|
|
|
|
|
|
|
PL_DHashTableRawRemove(&sJSObjWrappers, entry);
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The new JSObject now holds on to npobj
|
|
|
|
_retainobject(npobj);
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// PLDHashTable enumeration callbacks for destruction code.
|
|
|
|
PR_STATIC_CALLBACK(PLDHashOperator)
|
|
|
|
JSObjWrapperPluginDestroyedCallback(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
|
|
|
PRUint32 number, void *arg)
|
|
|
|
{
|
|
|
|
JSObjWrapperHashEntry *entry = (JSObjWrapperHashEntry *)hdr;
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
nsJSObjWrapper *npobj = entry->mJSObjWrapper;
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
if (npobj->mNpp == arg) {
|
|
|
|
// Prevent invalidate() and _releaseobject() from touching the hash
|
|
|
|
// we're enumerating.
|
|
|
|
const PLDHashTableOps *ops = table->ops;
|
|
|
|
table->ops = nsnull;
|
|
|
|
|
|
|
|
if (npobj->_class && npobj->_class->invalidate) {
|
|
|
|
npobj->_class->invalidate(npobj);
|
|
|
|
}
|
|
|
|
|
|
|
|
_releaseobject(npobj);
|
|
|
|
|
|
|
|
table->ops = ops;
|
|
|
|
|
|
|
|
return PL_DHASH_REMOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(PLDHashOperator)
|
|
|
|
NPObjWrapperPluginDestroyedCallback(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
|
|
|
PRUint32 number, void *arg)
|
|
|
|
{
|
|
|
|
NPObjWrapperHashEntry *entry = (NPObjWrapperHashEntry *)hdr;
|
|
|
|
|
|
|
|
if (entry->mNpp == arg) {
|
|
|
|
NPObject *npobj = entry->mNPObj;
|
|
|
|
|
|
|
|
if (npobj->_class && npobj->_class->invalidate) {
|
|
|
|
npobj->_class->invalidate(npobj);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Force deallocation of plugin objects since the plugin they came
|
|
|
|
// from is being torn down.
|
|
|
|
if (npobj->_class && npobj->_class->deallocate) {
|
|
|
|
npobj->_class->deallocate(npobj);
|
|
|
|
} else {
|
|
|
|
PR_Free(npobj);
|
|
|
|
}
|
|
|
|
|
|
|
|
JSContext *cx = GetJSContext((NPP)arg);
|
|
|
|
|
2005-07-20 12:36:55 +00:00
|
|
|
if (cx) {
|
|
|
|
::JS_SetPrivate(cx, entry->mJSObj, nsnull);
|
|
|
|
} else {
|
|
|
|
NS_ERROR("dangling entry->mJSObj JSPrivate because we can't find cx");
|
|
|
|
}
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
return PL_DHASH_REMOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
void
|
|
|
|
nsJSNPRuntime::OnPluginDestroy(NPP npp)
|
|
|
|
{
|
|
|
|
if (sJSObjWrappers.ops) {
|
|
|
|
PL_DHashTableEnumerate(&sJSObjWrappers,
|
|
|
|
JSObjWrapperPluginDestroyedCallback, npp);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sNPObjWrappers.ops) {
|
|
|
|
PL_DHashTableEnumerate(&sNPObjWrappers,
|
|
|
|
NPObjWrapperPluginDestroyedCallback, npp);
|
|
|
|
}
|
2005-11-04 01:01:08 +00:00
|
|
|
|
|
|
|
// If this plugin was scripted from a webpage, the plugin's
|
|
|
|
// scriptable object will be on the DOM element's prototype
|
|
|
|
// chain. Now that the plugin is being destroyed we need to pull the
|
|
|
|
// plugin's scriptable object out of that prototype chain.
|
|
|
|
JSContext *cx = GetJSContext(npp);
|
|
|
|
if (!cx || !npp) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the plugin instance so that we can (eventually) get to the
|
|
|
|
// DOM element
|
|
|
|
ns4xPluginInstance *inst = (ns4xPluginInstance *)npp->ndata;
|
|
|
|
if (!inst) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIPluginInstancePeer> pip;
|
|
|
|
inst->GetPeer(getter_AddRefs(pip));
|
|
|
|
nsCOMPtr<nsIPluginTagInfo2> pti2(do_QueryInterface(pip));
|
|
|
|
if (!pti2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMElement> element;
|
|
|
|
pti2->GetDOMElement(getter_AddRefs(element));
|
|
|
|
if (!element) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the DOM element's JS object.
|
|
|
|
nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID()));
|
|
|
|
if (!xpc) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-11-22 15:51:41 +00:00
|
|
|
// OK. Now we have to get our hands on the right scope object, since
|
|
|
|
// GetWrappedNativeOfNativeObject doesn't call PreCreate and hence won't get
|
|
|
|
// the right scope if we pass in something bogus. The right scope lives on
|
|
|
|
// the script global of the element's document.
|
|
|
|
// XXXbz we MUST have a better way of doing this... perhaps
|
|
|
|
// GetWrappedNativeOfNativeObject _should_ call preCreate?
|
|
|
|
nsCOMPtr<nsIContent> content(do_QueryInterface(element));
|
|
|
|
if (!content) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIDocument* doc = content->GetOwnerDoc();
|
|
|
|
if (!doc) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIScriptGlobalObject* sgo = doc->GetScriptGlobalObject();
|
|
|
|
if (!sgo) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSObject* globalObj = sgo->GetGlobalJSObject();
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
nsIScriptContext* scx = sgo->GetContext();
|
|
|
|
if (scx) {
|
|
|
|
NS_ASSERTION((JSContext *)scx->GetNativeContext() == cx,
|
|
|
|
"Unexpected JS context");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-11-11 20:38:41 +00:00
|
|
|
nsCOMPtr<nsISupports> supp(do_QueryInterface(element));
|
|
|
|
nsCOMPtr<nsIXPConnectWrappedNative> holder;
|
2005-11-22 15:51:41 +00:00
|
|
|
xpc->GetWrappedNativeOfNativeObject(cx, globalObj, supp,
|
2005-11-11 20:38:41 +00:00
|
|
|
NS_GET_IID(nsISupports),
|
|
|
|
getter_AddRefs(holder));
|
2005-11-04 01:01:08 +00:00
|
|
|
if (!holder) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSObject *obj, *proto;
|
|
|
|
holder->GetJSObject(&obj);
|
|
|
|
|
|
|
|
// Loop over the DOM element's JS object prototype chain and remove
|
|
|
|
// all JS objects of the class sNPObjectJSWrapperClass (there should
|
|
|
|
// be only one, but remove all instances found in case the page put
|
|
|
|
// more than one of the plugin's scriptable objects on the prototype
|
|
|
|
// chain).
|
|
|
|
while (obj && (proto = ::JS_GetPrototype(cx, obj))) {
|
|
|
|
if (JS_GET_CLASS(cx, proto) == &sNPObjectJSWrapperClass) {
|
|
|
|
// We found an NPObject on the proto chain, get its prototype...
|
|
|
|
proto = ::JS_GetPrototype(cx, proto);
|
|
|
|
|
|
|
|
// ... and pull it out of the chain.
|
|
|
|
::JS_SetPrototype(cx, obj, proto);
|
|
|
|
}
|
|
|
|
|
|
|
|
obj = proto;
|
|
|
|
}
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
|
|
|
|
// Find the NPP for a NPObject.
|
2004-07-12 15:53:22 +00:00
|
|
|
static NPP
|
2004-07-30 04:00:05 +00:00
|
|
|
LookupNPP(NPObject *npobj)
|
2004-07-12 15:53:22 +00:00
|
|
|
{
|
2004-07-30 04:00:05 +00:00
|
|
|
if (npobj->_class == &nsJSObjWrapper::sJSObjWrapperNPClass) {
|
|
|
|
NS_ERROR("NPP requested for NPObject of class "
|
|
|
|
"nsJSObjWrapper::sJSObjWrapperNPClass!\n");
|
2004-07-12 15:53:22 +00:00
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
return nsnull;
|
|
|
|
}
|
2004-07-12 15:53:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
NPObjWrapperHashEntry *entry =
|
|
|
|
NS_STATIC_CAST(NPObjWrapperHashEntry *,
|
|
|
|
PL_DHashTableOperate(&sNPObjWrappers, npobj,
|
|
|
|
PL_DHASH_ADD));
|
2004-07-12 15:53:22 +00:00
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
if (PL_DHASH_ENTRY_IS_FREE(entry)) {
|
|
|
|
return nsnull;
|
2004-07-12 15:53:22 +00:00
|
|
|
}
|
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
NS_ASSERTION(entry->mNpp, "Live NPObject entry w/o an NPP!");
|
2004-07-12 15:53:22 +00:00
|
|
|
|
2004-07-30 04:00:05 +00:00
|
|
|
return entry->mNpp;
|
|
|
|
}
|
2005-07-14 02:36:41 +00:00
|
|
|
|
|
|
|
bool
|
|
|
|
CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj,
|
|
|
|
NPObject* npobj, jsval id, jsval *vp)
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(vp, false);
|
|
|
|
|
|
|
|
if (!npobj || !npobj->_class || !npobj->_class->getProperty ||
|
|
|
|
!npobj->_class->invoke) {
|
|
|
|
ThrowJSException(cx, "Bad NPObject");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
NPObjectMemberPrivate *memberPrivate =
|
|
|
|
(NPObjectMemberPrivate *)PR_Malloc(sizeof(NPObjectMemberPrivate));
|
|
|
|
if (!memberPrivate)
|
|
|
|
return false;
|
|
|
|
|
2006-02-25 00:32:03 +00:00
|
|
|
// Make sure to clear all members in case something fails here
|
|
|
|
// during initialization.
|
|
|
|
memset(memberPrivate, 0, sizeof(NPObjectMemberPrivate));
|
|
|
|
|
2005-07-14 02:36:41 +00:00
|
|
|
JSObject *memobj = ::JS_NewObject(cx, &sNPObjectMemberClass, nsnull, nsnull);
|
|
|
|
if (!memobj) {
|
|
|
|
PR_Free(memberPrivate);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
*vp = OBJECT_TO_JSVAL(memobj);
|
|
|
|
::JS_AddRoot(cx, vp);
|
|
|
|
|
|
|
|
::JS_SetPrivate(cx, memobj, (void *)memberPrivate);
|
|
|
|
|
|
|
|
jsval fieldValue;
|
|
|
|
NPVariant npv;
|
|
|
|
VOID_TO_NPVARIANT(npv);
|
|
|
|
if (!npobj->_class->getProperty(npobj, (NPIdentifier)id, &npv)) {
|
|
|
|
::JS_RemoveRoot(cx, vp);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fieldValue = NPVariantToJSVal(npp, cx, &npv);
|
|
|
|
|
2006-02-25 00:32:03 +00:00
|
|
|
// npobjWrapper is the JSObject through which we make sure we don't
|
|
|
|
// outlive the underlying NPObject, so make sure it points to the
|
|
|
|
// real JSObject wrapper for the NPObject.
|
|
|
|
while (JS_GET_CLASS(cx, obj) != &sNPObjectJSWrapperClass) {
|
|
|
|
obj = ::JS_GetPrototype(cx, obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
memberPrivate->npobjWrapper = obj;
|
2005-07-14 02:36:41 +00:00
|
|
|
|
|
|
|
memberPrivate->fieldValue = fieldValue;
|
|
|
|
memberPrivate->methodName = id;
|
|
|
|
memberPrivate->npp = npp;
|
|
|
|
|
|
|
|
::JS_RemoveRoot(cx, vp);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
NPObjectMember_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
|
|
|
{
|
|
|
|
NPObjectMemberPrivate *memberPrivate =
|
|
|
|
(NPObjectMemberPrivate *)::JS_GetInstancePrivate(cx, obj,
|
|
|
|
&sNPObjectMemberClass,
|
|
|
|
nsnull);
|
|
|
|
NS_ASSERTION(memberPrivate, "no Ambiguous Member Private data!");
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case JSTYPE_VOID:
|
|
|
|
case JSTYPE_STRING:
|
|
|
|
case JSTYPE_NUMBER:
|
|
|
|
case JSTYPE_BOOLEAN:
|
|
|
|
case JSTYPE_OBJECT:
|
|
|
|
*vp = memberPrivate->fieldValue;
|
|
|
|
return JS_TRUE;
|
|
|
|
case JSTYPE_FUNCTION:
|
|
|
|
// Leave this to NPObjectMember_Call.
|
|
|
|
return JS_TRUE;
|
|
|
|
default:
|
|
|
|
NS_ERROR("illegal operation on JSObject prototype object");
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(void)
|
|
|
|
NPObjectMember_Finalize(JSContext *cx, JSObject *obj)
|
|
|
|
{
|
|
|
|
NPObjectMemberPrivate *memberPrivate;
|
|
|
|
|
|
|
|
memberPrivate = (NPObjectMemberPrivate *)::JS_GetPrivate(cx, obj);
|
|
|
|
if (!memberPrivate)
|
|
|
|
return;
|
|
|
|
|
|
|
|
PR_Free(memberPrivate);
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(JSBool)
|
|
|
|
NPObjectMember_Call(JSContext *cx, JSObject *obj,
|
|
|
|
uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
JSObject *memobj = JSVAL_TO_OBJECT(argv[-2]);
|
|
|
|
NS_ENSURE_TRUE(memobj, JS_FALSE);
|
|
|
|
|
|
|
|
NPObjectMemberPrivate *memberPrivate =
|
|
|
|
(NPObjectMemberPrivate *)::JS_GetInstancePrivate(cx, memobj,
|
|
|
|
&sNPObjectMemberClass,
|
2006-02-25 00:32:03 +00:00
|
|
|
argv);
|
|
|
|
if (!memberPrivate || !memberPrivate->npobjWrapper)
|
2005-07-14 02:36:41 +00:00
|
|
|
return JS_FALSE;
|
|
|
|
|
2006-02-25 00:32:03 +00:00
|
|
|
NPObject *npobj = GetNPObject(cx, memberPrivate->npobjWrapper);
|
|
|
|
if (!npobj) {
|
|
|
|
ThrowJSException(cx, "Call on invalid member object");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
2005-07-14 02:36:41 +00:00
|
|
|
NPVariant npargs_buf[8];
|
|
|
|
NPVariant *npargs = npargs_buf;
|
|
|
|
|
|
|
|
if (argc > (sizeof(npargs_buf) / sizeof(NPVariant))) {
|
|
|
|
// Our stack buffer isn't large enough to hold all arguments,
|
|
|
|
// malloc a buffer.
|
|
|
|
npargs = (NPVariant *)PR_Malloc(argc * sizeof(NPVariant));
|
|
|
|
|
|
|
|
if (!npargs) {
|
|
|
|
ThrowJSException(cx, "Out of memory!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert arguments
|
|
|
|
PRUint32 i;
|
|
|
|
for (i = 0; i < argc; ++i) {
|
|
|
|
if (!JSValToNPVariant(memberPrivate->npp, cx, argv[i], npargs + i)) {
|
|
|
|
ThrowJSException(cx, "Error converting jsvals to NPVariants!");
|
|
|
|
|
|
|
|
if (npargs != npargs_buf) {
|
|
|
|
PR_Free(npargs);
|
|
|
|
}
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NPVariant npv;
|
|
|
|
JSBool ok;
|
2006-02-25 00:32:03 +00:00
|
|
|
ok = npobj->_class->invoke(npobj, (NPIdentifier)memberPrivate->methodName,
|
|
|
|
npargs, argc, &npv);
|
|
|
|
|
2005-07-14 02:36:41 +00:00
|
|
|
// Release arguments.
|
|
|
|
for (i = 0; i < argc; ++i) {
|
|
|
|
_releasevariantvalue(npargs + i);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (npargs != npargs_buf) {
|
|
|
|
PR_Free(npargs);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
ThrowJSException(cx, "Error calling method on NPObject!");
|
|
|
|
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*rval = NPVariantToJSVal(memberPrivate->npp, cx, &npv);
|
|
|
|
|
|
|
|
// *rval now owns the value, release our reference.
|
|
|
|
_releasevariantvalue(&npv);
|
|
|
|
|
|
|
|
return ReportExceptionIfPending(cx);
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_STATIC_DLL_CALLBACK(uint32)
|
|
|
|
NPObjectMember_Mark(JSContext *cx, JSObject *obj, void *arg)
|
|
|
|
{
|
|
|
|
NPObjectMemberPrivate *memberPrivate =
|
|
|
|
(NPObjectMemberPrivate *)::JS_GetInstancePrivate(cx, obj,
|
|
|
|
&sNPObjectMemberClass,
|
|
|
|
nsnull);
|
|
|
|
if (!memberPrivate)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!JSVAL_IS_PRIMITIVE(memberPrivate->fieldValue)) {
|
|
|
|
::JS_MarkGCThing(cx, JSVAL_TO_OBJECT(memberPrivate->fieldValue),
|
|
|
|
"NPObject Member => fieldValue", arg);
|
|
|
|
}
|
|
|
|
|
2006-02-25 00:32:03 +00:00
|
|
|
// There's no strong reference from our private data to the
|
|
|
|
// NPObject, so make sure to mark the NPObject wrapper to keep the
|
|
|
|
// NPObject alive as long as this NPObjectMember is alive.
|
|
|
|
if (memberPrivate->npobjWrapper) {
|
|
|
|
::JS_MarkGCThing(cx, memberPrivate->npobjWrapper,
|
|
|
|
"NPObject Member => npobjWrapper", arg);
|
|
|
|
}
|
|
|
|
|
2005-07-14 02:36:41 +00:00
|
|
|
return 0;
|
|
|
|
}
|