Bug 556849 - '[OOPP] Reduce unnecessary HasProperty calls for plugin scriptable objects'. r=jst+josh+bsmedberg.

This commit is contained in:
Ben Turner 2010-04-07 17:16:19 -07:00
Родитель ee46b4c33a
Коммит 9053c0fc61
9 изменённых файлов: 351 добавлений и 116 удалений

Просмотреть файл

@ -92,10 +92,6 @@ both:
rpc HasProperty(PPluginIdentifier aId)
returns (bool aHasProperty);
rpc GetProperty(PPluginIdentifier aId)
returns (Variant aResult,
bool aSuccess);
rpc SetProperty(PPluginIdentifier aId,
Variant aValue)
returns (bool aSuccess);
@ -120,6 +116,24 @@ both:
// temporarily protects the protocol object again for the duration of the call.
async Protect();
async Unprotect();
/**
* GetProperty is slightly wonky due to the way we support NPObjects that have
* methods and properties with the same name. When child calls parent we
* simply return a property. When parent calls child, however, we need to do
* several checks at once and return all the results simultaneously.
*/
parent:
rpc GetParentProperty(PPluginIdentifier aId)
returns (Variant aResult,
bool aSuccess);
child:
rpc GetChildProperty(PPluginIdentifier aId)
returns (bool aHasProperty,
bool aHasMethod,
Variant aResult,
bool aSuccess);
};
} // namespace plugins

Просмотреть файл

@ -257,8 +257,8 @@ PluginScriptableObjectChild::ScriptableGetProperty(NPObject* aObject,
Variant result;
bool success;
actor->CallGetProperty(static_cast<PPluginIdentifierChild*>(aName), &result,
&success);
actor->CallGetParentProperty(static_cast<PPluginIdentifierChild*>(aName),
&result, &success);
if (!success) {
return false;
@ -831,45 +831,49 @@ PluginScriptableObjectChild::AnswerHasProperty(PPluginIdentifierChild* aId,
}
bool
PluginScriptableObjectChild::AnswerGetProperty(PPluginIdentifierChild* aId,
Variant* aResult,
bool* aSuccess)
PluginScriptableObjectChild::AnswerGetChildProperty(PPluginIdentifierChild* aId,
bool* aHasProperty,
bool* aHasMethod,
Variant* aResult,
bool* aSuccess)
{
AssertPluginThread();
*aHasProperty = *aHasMethod = *aSuccess = false;
*aResult = void_t();
if (mInvalidated) {
NS_WARNING("Calling AnswerGetProperty with an invalidated object!");
*aResult = void_t();
*aSuccess = false;
return true;
}
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
if (!(mObject->_class && mObject->_class->getProperty)) {
*aResult = void_t();
*aSuccess = false;
if (!(mObject->_class && mObject->_class->hasProperty &&
mObject->_class->hasMethod && mObject->_class->getProperty)) {
return true;
}
NPVariant result;
VOID_TO_NPVARIANT(result);
PluginIdentifierChild* id = static_cast<PluginIdentifierChild*>(aId);
if (!mObject->_class->getProperty(mObject, id->ToNPIdentifier(), &result)) {
*aResult = void_t();
*aSuccess = false;
return true;
}
NPIdentifier id = static_cast<PluginIdentifierChild*>(aId)->ToNPIdentifier();
Variant converted;
if ((*aSuccess = ConvertToRemoteVariant(result, converted, GetInstance(),
false))) {
DeferNPVariantLastRelease(&PluginModuleChild::sBrowserFuncs, &result);
*aResult = converted;
}
else {
*aResult = void_t();
*aHasProperty = mObject->_class->hasProperty(mObject, id);
*aHasMethod = mObject->_class->hasMethod(mObject, id);
if (*aHasProperty) {
NPVariant result;
VOID_TO_NPVARIANT(result);
if (!mObject->_class->getProperty(mObject, id, &result)) {
return true;
}
Variant converted;
if ((*aSuccess = ConvertToRemoteVariant(result, converted, GetInstance(),
false))) {
DeferNPVariantLastRelease(&PluginModuleChild::sBrowserFuncs, &result);
*aResult = converted;
}
}
return true;
@ -891,7 +895,15 @@ PluginScriptableObjectChild::AnswerSetProperty(PPluginIdentifierChild* aId,
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
if (!(mObject->_class && mObject->_class->setProperty)) {
if (!(mObject->_class && mObject->_class->hasProperty &&
mObject->_class->setProperty)) {
*aSuccess = false;
return true;
}
NPIdentifier id = static_cast<PluginIdentifierChild*>(aId)->ToNPIdentifier();
if (!mObject->_class->hasProperty(mObject, id)) {
*aSuccess = false;
return true;
}
@ -899,9 +911,7 @@ PluginScriptableObjectChild::AnswerSetProperty(PPluginIdentifierChild* aId,
NPVariant converted;
ConvertToVariant(aValue, converted);
PluginIdentifierChild* id = static_cast<PluginIdentifierChild*>(aId);
if ((*aSuccess = mObject->_class->setProperty(mObject, id->ToNPIdentifier(),
&converted))) {
if ((*aSuccess = mObject->_class->setProperty(mObject, id, &converted))) {
PluginModuleChild::sBrowserFuncs.releasevariantvalue(&converted);
}
return true;
@ -922,13 +932,17 @@ PluginScriptableObjectChild::AnswerRemoveProperty(PPluginIdentifierChild* aId,
NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
NS_ASSERTION(mType == LocalObject, "Bad type!");
if (!(mObject->_class && mObject->_class->removeProperty)) {
if (!(mObject->_class && mObject->_class->hasProperty &&
mObject->_class->removeProperty)) {
*aSuccess = false;
return true;
}
PluginIdentifierChild* id = static_cast<PluginIdentifierChild*>(aId);
*aSuccess = mObject->_class->removeProperty(mObject, id->ToNPIdentifier());
NPIdentifier id = static_cast<PluginIdentifierChild*>(aId)->ToNPIdentifier();
*aSuccess = mObject->_class->hasProperty(mObject, id) ?
mObject->_class->removeProperty(mObject, id) :
true;
return true;
}

Просмотреть файл

@ -107,9 +107,11 @@ public:
bool* aHasProperty);
virtual bool
AnswerGetProperty(PPluginIdentifierChild* aId,
Variant* aResult,
bool* aSuccess);
AnswerGetChildProperty(PPluginIdentifierChild* aId,
bool* aHasProperty,
bool* aHasMethod,
Variant* aResult,
bool* aSuccess);
virtual bool
AnswerSetProperty(PPluginIdentifierChild* aId,

Просмотреть файл

@ -321,46 +321,9 @@ PluginScriptableObjectParent::ScriptableGetProperty(NPObject* aObject,
NPIdentifier aName,
NPVariant* aResult)
{
if (aObject->_class != GetClass()) {
NS_ERROR("Don't know what kind of object this is!");
return false;
}
ParentNPObject* object = reinterpret_cast<ParentNPObject*>(aObject);
if (object->invalidated) {
NS_WARNING("Calling method on an invalidated object!");
return false;
}
PPluginIdentifierParent* identifier = GetIdentifier(aObject, aName);
if (!identifier) {
return false;
}
ProtectedActor<PluginScriptableObjectParent> actor(object->parent);
if (!actor) {
return false;
}
NS_ASSERTION(actor->Type() == Proxy, "Bad type!");
Variant result;
bool success;
if (!actor->CallGetProperty(identifier, &result, &success)) {
NS_WARNING("Failed to send message!");
return false;
}
if (!success) {
return false;
}
if (!ConvertToVariant(result, *aResult, actor->GetInstance())) {
NS_WARNING("Failed to convert result!");
return false;
}
return true;
// See GetPropertyHelper below.
NS_NOTREACHED("Shouldn't ever call this directly!");
return false;
}
// static
@ -964,9 +927,10 @@ PluginScriptableObjectParent::AnswerHasProperty(PPluginIdentifierParent* aId,
}
bool
PluginScriptableObjectParent::AnswerGetProperty(PPluginIdentifierParent* aId,
Variant* aResult,
bool* aSuccess)
PluginScriptableObjectParent::AnswerGetParentProperty(
PPluginIdentifierParent* aId,
Variant* aResult,
bool* aSuccess)
{
if (!mObject) {
NS_WARNING("Calling AnswerGetProperty with an invalidated object!");
@ -1287,3 +1251,43 @@ PluginScriptableObjectParent::AnswerNPN_Evaluate(const nsCString& aScript,
*aResult = convertedResult;
return true;
}
JSBool
PluginScriptableObjectParent::GetPropertyHelper(NPIdentifier aName,
PRBool* aHasProperty,
PRBool* aHasMethod,
NPVariant* aResult)
{
NS_ASSERTION(Type() == Proxy, "Bad type!");
ParentNPObject* object = static_cast<ParentNPObject*>(mObject);
if (object->invalidated) {
NS_WARNING("Calling method on an invalidated object!");
return JS_FALSE;
}
PPluginIdentifierParent* identifier = GetIdentifier(GetInstance(), aName);
if (!identifier) {
return JS_FALSE;
}
bool hasProperty, hasMethod, success;
Variant result;
if (!CallGetChildProperty(identifier, &hasProperty, &hasMethod, &result,
&success)) {
return JS_FALSE;
}
if (!success) {
return JS_FALSE;
}
if (!ConvertToVariant(result, *aResult, GetInstance())) {
NS_WARNING("Failed to convert result!");
return JS_FALSE;
}
*aHasProperty = hasProperty;
*aHasMethod = hasMethod;
return JS_TRUE;
}

Просмотреть файл

@ -41,6 +41,7 @@
#include "mozilla/plugins/PPluginScriptableObjectParent.h"
#include "jsapi.h"
#include "npfunctions.h"
#include "npruntime.h"
@ -96,9 +97,9 @@ public:
bool* aHasProperty);
virtual bool
AnswerGetProperty(PPluginIdentifierParent* aId,
Variant* aResult,
bool* aSuccess);
AnswerGetParentProperty(PPluginIdentifierParent* aId,
Variant* aResult,
bool* aSuccess);
virtual bool
AnswerSetProperty(PPluginIdentifierParent* aId,
@ -168,6 +169,11 @@ public:
return mType;
}
JSBool GetPropertyHelper(NPIdentifier aName,
PRBool* aHasProperty,
PRBool* aHasMethod,
NPVariant* aResult);
private:
static NPObject*
ScriptableAllocate(NPP aInstance,

Просмотреть файл

@ -36,6 +36,10 @@
*
* ***** END LICENSE BLOCK ***** */
#ifdef MOZ_IPC
#include "base/basictypes.h"
#endif
// FIXME(bug 332648): Give me a real API please!
#include "jscntxt.h"
@ -55,6 +59,12 @@
using namespace mozilla::plugins::parent;
#ifdef MOZ_IPC
#include "mozilla/plugins/PluginScriptableObjectParent.h"
using mozilla::plugins::PluginScriptableObjectParent;
using mozilla::plugins::ParentNPObject;
#endif
// 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
@ -82,6 +92,20 @@ static nsIJSContextStack *sContextStack;
static nsTArray<NPObject*>* sDelayedReleases;
namespace {
inline bool
NPObjectIsOutOfProcessProxy(NPObject *obj)
{
#ifdef MOZ_IPC
return obj->_class == PluginScriptableObjectParent::GetClass();
#else
return false;
#endif
}
} // anonymous namespace
// Helper class that reports any JS exceptions that were thrown while
// the plugin executed JS.
@ -155,8 +179,8 @@ NPObjWrapper_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval);
static JSBool
CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj,
NPObject *npobj, jsval id, jsval *vp);
CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj, NPObject *npobj,
jsval id, NPVariant* getPropertyResult, jsval *vp);
static JSClass sNPObjectJSWrapperClass =
{
@ -1182,6 +1206,10 @@ NPObjWrapper_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
return JS_FALSE;
}
if (NPObjectIsOutOfProcessProxy(npobj)) {
return JS_TRUE;
}
PluginDestructionGuard pdg(LookupNPP(npobj));
JSBool hasProperty = npobj->_class->hasProperty(npobj, (NPIdentifier)id);
@ -1220,12 +1248,14 @@ NPObjWrapper_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
PluginDestructionGuard pdg(LookupNPP(npobj));
JSBool hasProperty = npobj->_class->hasProperty(npobj, (NPIdentifier)id);
if (!ReportExceptionIfPending(cx))
return JS_FALSE;
if (!NPObjectIsOutOfProcessProxy(npobj)) {
JSBool hasProperty = npobj->_class->hasProperty(npobj, (NPIdentifier)id);
if (!ReportExceptionIfPending(cx))
return JS_FALSE;
if (!hasProperty)
return JS_TRUE;
if (!hasProperty)
return JS_TRUE;
}
if (!npobj->_class->removeProperty(npobj, (NPIdentifier)id))
*vp = JSVAL_FALSE;
@ -1257,14 +1287,16 @@ NPObjWrapper_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
PluginDestructionGuard pdg(npp);
JSBool hasProperty = npobj->_class->hasProperty(npobj, (NPIdentifier)id);
if (!ReportExceptionIfPending(cx))
return JS_FALSE;
if (!NPObjectIsOutOfProcessProxy(npobj)) {
JSBool hasProperty = npobj->_class->hasProperty(npobj, (NPIdentifier)id);
if (!ReportExceptionIfPending(cx))
return JS_FALSE;
if (!hasProperty) {
ThrowJSException(cx, "Trying to set unsupported property on NPObject!");
if (!hasProperty) {
ThrowJSException(cx, "Trying to set unsupported property on NPObject!");
return JS_FALSE;
return JS_FALSE;
}
}
NPVariant npv;
@ -1311,22 +1343,53 @@ NPObjWrapper_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
PluginDestructionGuard pdg(npp);
PRBool hasProperty = npobj->_class->hasProperty(npobj, (NPIdentifier)id);
PRBool hasProperty, hasMethod;
NPVariant npv;
VOID_TO_NPVARIANT(npv);
#ifdef MOZ_IPC
if (NPObjectIsOutOfProcessProxy(npobj)) {
PluginScriptableObjectParent* actor =
static_cast<ParentNPObject*>(npobj)->parent;
JSBool success = actor->GetPropertyHelper((NPIdentifier)id, &hasProperty,
&hasMethod, &npv);
if (!ReportExceptionIfPending(cx)) {
if (success)
_releasevariantvalue(&npv);
return JS_FALSE;
}
if (success) {
// We return NPObject Member class here to support ambiguous members.
if (hasProperty && hasMethod)
return CreateNPObjectMember(npp, cx, obj, npobj, id, &npv, vp);
if (hasProperty) {
*vp = NPVariantToJSVal(npp, cx, &npv);
_releasevariantvalue(&npv);
if (!ReportExceptionIfPending(cx))
return JS_FALSE;
}
}
return JS_TRUE;
}
#endif
hasProperty = npobj->_class->hasProperty(npobj, (NPIdentifier)id);
if (!ReportExceptionIfPending(cx))
return JS_FALSE;
PRBool hasMethod = npobj->_class->hasMethod(npobj, (NPIdentifier)id);
hasMethod = npobj->_class->hasMethod(npobj, (NPIdentifier)id);
if (!ReportExceptionIfPending(cx))
return JS_FALSE;
// We return NPObject Member class here to support ambiguous members.
if (hasProperty && hasMethod)
return CreateNPObjectMember(npp, cx, obj, npobj, id, vp);
return CreateNPObjectMember(npp, cx, obj, npobj, id, nsnull, vp);
if (hasProperty) {
NPVariant npv;
VOID_TO_NPVARIANT(npv);
if (npobj->_class->getProperty(npobj, (NPIdentifier)id, &npv))
*vp = NPVariantToJSVal(npp, cx, &npv);
@ -2048,8 +2111,8 @@ LookupNPP(NPObject *npobj)
}
JSBool
CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj,
NPObject* npobj, jsval id, jsval *vp)
CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj, NPObject* npobj,
jsval id, NPVariant* getPropertyResult, jsval *vp)
{
NS_ENSURE_TRUE(vp, JS_FALSE);
@ -2082,18 +2145,27 @@ CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj,
jsval fieldValue;
NPVariant npv;
VOID_TO_NPVARIANT(npv);
NPBool hasProperty;
NPBool hasProperty = npobj->_class->getProperty(npobj, (NPIdentifier)id,
&npv);
if (ReportExceptionIfPending(cx)) {
::JS_RemoveRoot(cx, vp);
return JS_FALSE;
if (getPropertyResult) {
// Plugin has already handed us the value we want here.
npv = *getPropertyResult;
hasProperty = true;
}
else {
VOID_TO_NPVARIANT(npv);
if (!hasProperty) {
::JS_RemoveRoot(cx, vp);
return JS_FALSE;
NPBool hasProperty = npobj->_class->getProperty(npobj, (NPIdentifier)id,
&npv);
if (!ReportExceptionIfPending(cx)) {
::JS_RemoveRoot(cx, vp);
return JS_FALSE;
}
if (!hasProperty) {
::JS_RemoveRoot(cx, vp);
return JS_FALSE;
}
}
fieldValue = NPVariantToJSVal(npp, cx, &npv);

Просмотреть файл

@ -85,6 +85,7 @@ _MOCHITEST_FILES = \
test_hanging.html \
crashing_subpage.html \
test_GCrace.html \
test_propertyAndMethod.html \
$(NULL)
# test_npruntime_npnsetexception.html \ Disabled for e10s

Просмотреть файл

@ -0,0 +1,50 @@
<html>
<head>
<title>NPObject with property and method with the same name</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body onload="run()">
<embed id="plugin" type="application/x-test" wmode="window"></embed>
<script class="testbody" type="application/javascript">
if (typeof Object.getPrototypeOf !== "function") {
if (typeof "test".__proto__ === "object") {
Object.getPrototypeOf = function(object) {
return object.__proto__;
};
} else {
Object.getPrototypeOf = function(object) {
// May break if the constructor has been tampered with
return object.constructor.prototype;
};
}
}
SimpleTest.waitForExplicitFinish();
function run() {
var plugin = document.getElementById("plugin");
var pluginProto = Object.getPrototypeOf(plugin);
delete pluginProto.propertyAndMethod;
ok(isNaN(plugin.propertyAndMethod + 0), "Shouldn't be set yet!");
plugin.propertyAndMethod = 5;
is(plugin.propertyAndMethod, 5, "Should be set to 5!");
delete pluginProto.propertyAndMethod;
ok(isNaN(plugin.propertyAndMethod + 0), "Shouldn't be set any more!");
var res = plugin.propertyAndMethod();
is(res, 5, "Method invocation should return 5!");
SimpleTest.finish();
}
</script>
</body>
</html>

Просмотреть файл

@ -157,6 +157,7 @@ static bool hangPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount
static bool getClipboardText(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool callOnDestroy(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool reinitWidget(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool propertyAndMethod(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static const NPUTF8* sPluginMethodIdentifierNames[] = {
"npnEvaluateTest",
@ -199,6 +200,7 @@ static const NPUTF8* sPluginMethodIdentifierNames[] = {
"getClipboardText",
"callOnDestroy",
"reinitWidget",
"propertyAndMethod"
};
static NPIdentifier sPluginMethodIdentifiers[ARRAY_LENGTH(sPluginMethodIdentifierNames)];
static const ScriptableFunction sPluginMethodFunctions[ARRAY_LENGTH(sPluginMethodIdentifierNames)] = {
@ -242,7 +244,13 @@ static const ScriptableFunction sPluginMethodFunctions[ARRAY_LENGTH(sPluginMetho
getClipboardText,
callOnDestroy,
reinitWidget,
propertyAndMethod
};
static const NPUTF8* sPluginPropertyIdentifierNames[] = {
"propertyAndMethod"
};
static NPIdentifier sPluginPropertyIdentifiers[ARRAY_LENGTH(sPluginPropertyIdentifierNames)];
static NPVariant sPluginPropertyValues[ARRAY_LENGTH(sPluginPropertyIdentifierNames)];
struct URLNotifyData
{
@ -307,6 +315,9 @@ static void initializeIdentifiers()
if (!sIdentifiersInitialized) {
NPN_GetStringIdentifiers(sPluginMethodIdentifierNames,
ARRAY_LENGTH(sPluginMethodIdentifierNames), sPluginMethodIdentifiers);
NPN_GetStringIdentifiers(sPluginPropertyIdentifierNames,
ARRAY_LENGTH(sPluginPropertyIdentifierNames), sPluginPropertyIdentifiers);
sIdentifiersInitialized = true;
// Check whether NULL is handled in NPN_GetStringIdentifiers
@ -320,6 +331,9 @@ static void clearIdentifiers()
{
memset(sPluginMethodIdentifiers, 0,
ARRAY_LENGTH(sPluginMethodIdentifiers) * sizeof(NPIdentifier));
memset(sPluginPropertyIdentifiers, 0,
ARRAY_LENGTH(sPluginPropertyIdentifiers) * sizeof(NPIdentifier));
sIdentifiersInitialized = false;
}
@ -446,6 +460,25 @@ getFuncFromString(const char* funcname)
return FUNCTION_NONE;
}
static void
DuplicateNPVariant(NPVariant& aDest, const NPVariant& aSrc)
{
if (NPVARIANT_IS_STRING(aSrc)) {
NPString src = NPVARIANT_TO_STRING(aSrc);
char* buf = new char[src.UTF8Length];
strncpy(buf, src.UTF8Characters, src.UTF8Length);
STRINGN_TO_NPVARIANT(buf, src.UTF8Length, aDest);
}
else if (NPVARIANT_IS_OBJECT(aSrc)) {
NPObject* obj =
NPN_RetainObject(NPVARIANT_TO_OBJECT(aSrc));
OBJECT_TO_NPVARIANT(obj, aDest);
}
else {
aDest = aSrc;
}
}
//
// function signatures
//
@ -533,6 +566,10 @@ NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs)
initializeIdentifiers();
for (int i = 0; i < ARRAY_LENGTH(sPluginPropertyValues); i++) {
VOID_TO_NPVARIANT(sPluginPropertyValues[i]);
}
memset(&sNPClass, 0, sizeof(NPClass));
sNPClass.structVersion = NP_CLASS_STRUCT_VERSION;
sNPClass.allocate = (NPAllocateFunctionPtr)scriptableAllocate;
@ -575,6 +612,10 @@ NPError OSCALL NP_Shutdown()
{
clearIdentifiers();
for (int i = 0; i < ARRAY_LENGTH(sPluginPropertyValues); i++) {
NPN_ReleaseVariantValue(&sPluginPropertyValues[i]);
}
return NPERR_NO_ERROR;
}
@ -1544,24 +1585,47 @@ scriptableInvokeDefault(NPObject* npobj, const NPVariant* args, uint32_t argCoun
bool
scriptableHasProperty(NPObject* npobj, NPIdentifier name)
{
for (int i = 0; i < int(ARRAY_LENGTH(sPluginPropertyIdentifiers)); i++) {
if (name == sPluginPropertyIdentifiers[i])
return true;
}
return false;
}
bool
scriptableGetProperty(NPObject* npobj, NPIdentifier name, NPVariant* result)
{
for (int i = 0; i < int(ARRAY_LENGTH(sPluginPropertyIdentifiers)); i++) {
if (name == sPluginPropertyIdentifiers[i]) {
DuplicateNPVariant(*result, sPluginPropertyValues[i]);
return true;
}
}
return false;
}
bool
scriptableSetProperty(NPObject* npobj, NPIdentifier name, const NPVariant* value)
{
for (int i = 0; i < int(ARRAY_LENGTH(sPluginPropertyIdentifiers)); i++) {
if (name == sPluginPropertyIdentifiers[i]) {
NPN_ReleaseVariantValue(&sPluginPropertyValues[i]);
DuplicateNPVariant(sPluginPropertyValues[i], *value);
return true;
}
}
return false;
}
bool
scriptableRemoveProperty(NPObject* npobj, NPIdentifier name)
{
for (int i = 0; i < int(ARRAY_LENGTH(sPluginPropertyIdentifiers)); i++) {
if (name == sPluginPropertyIdentifiers[i]) {
NPN_ReleaseVariantValue(&sPluginPropertyValues[i]);
return true;
}
}
return false;
}
@ -2687,3 +2751,11 @@ reinitWidget(NPObject* npobj, const NPVariant* args, uint32_t argCount,
pluginWidgetInit(id, id->window.window);
return true;
}
bool
propertyAndMethod(NPObject* npobj, const NPVariant* args, uint32_t argCount,
NPVariant* result)
{
INT32_TO_NPVARIANT(5, *result);
return true;
}