blob: 733107d2dc3added16613bf41d80af9683b23ad0 [file] [log] [blame]
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/test/plugin/plugin_delete_plugin_in_deallocate_test.h"
#include "base/basictypes.h"
#include "base/compiler_specific.h"
namespace {
NPAPIClient::DeletePluginInDeallocateTest* g_signalling_instance_ = NULL;
class DeletePluginInDeallocateTestNPObject : public NPObject {
public:
DeletePluginInDeallocateTestNPObject()
: NPObject(), id_(NULL), host_functions_(NULL), deallocate_count_(0) {}
static NPObject* Allocate(NPP npp, NPClass* npclass) {
return new DeletePluginInDeallocateTestNPObject();
}
static void Deallocate(NPObject* npobject) {
DeletePluginInDeallocateTestNPObject* object =
reinterpret_cast<DeletePluginInDeallocateTestNPObject*>(npobject);
++object->deallocate_count_;
// Call window.deletePlugin to tear-down our plugin from inside deallocate.
if (object->deallocate_count_ == 1) {
NPIdentifier delete_id =
object->host_functions_->getstringidentifier("deletePlugin");
NPObject* window_obj = NULL;
object->host_functions_->getvalue(object->id_, NPNVWindowNPObject,
&window_obj);
NPVariant rv;
object->host_functions_->invoke(object->id_, window_obj, delete_id, NULL,
0, &rv);
}
}
NPP id_;
NPNetscapeFuncs* host_functions_;
int deallocate_count_;
};
NPClass* GetDeletePluginInDeallocateTestClass() {
static NPClass plugin_class = {
NP_CLASS_STRUCT_VERSION,
DeletePluginInDeallocateTestNPObject::Allocate,
DeletePluginInDeallocateTestNPObject::Deallocate,
NULL, // Invalidate
NULL, // HasMethod
NULL, // Invoke
NULL, // InvokeDefault
NULL, // HasProperty
NULL, // GetProperty
NULL, // SetProperty
NULL, // RemoveProperty
};
return &plugin_class;
}
} // namespace
namespace NPAPIClient {
DeletePluginInDeallocateTest::DeletePluginInDeallocateTest(
NPP id, NPNetscapeFuncs* host_functions)
: PluginTest(id, host_functions), npobject_(NULL), test_started_(false) {
}
NPError DeletePluginInDeallocateTest::SetWindow(NPWindow* pNPWindow) {
#if !defined(OS_MACOSX)
if (pNPWindow->window == NULL)
return NPERR_NO_ERROR;
#endif
// Ensure that we run the test once, even if SetWindow is called again.
if (test_started_)
return NPERR_NO_ERROR;
test_started_ = true;
// Because of http://crbug.com/94829, we have to have a second plugin
// instance that we can use to signal completion.
if (test_id() == "signaller") {
g_signalling_instance_ = this;
return NPERR_NO_ERROR;
}
// Create a custom NPObject and give our Id and the Netscape function table.
npobject_ = HostFunctions()->createobject(
id(), GetDeletePluginInDeallocateTestClass());
DeletePluginInDeallocateTestNPObject* test_object =
reinterpret_cast<DeletePluginInDeallocateTestNPObject*>(npobject_);
test_object->id_ = id();
test_object->host_functions_ = HostFunctions();
// Fetch the window script object for our page.
NPObject* window = NULL;
HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window);
// Pass it to the window.setTestObject function, which will later release it.
NPIdentifier set_test_object_id =
HostFunctions()->getstringidentifier("setTestObject");
NPVariant func_var;
NULL_TO_NPVARIANT(func_var);
HostFunctions()->getproperty(id(), window, set_test_object_id, &func_var);
NPObject* func = NPVARIANT_TO_OBJECT(func_var);
NPVariant func_arg;
OBJECT_TO_NPVARIANT(npobject_, func_arg);
NPVariant func_result;
HostFunctions()->invokeDefault(id(), func, &func_arg, 1,
&func_result);
// Release the object - the page's reference should keep it alive.
HostFunctions()->releaseobject(npobject_);
return NPERR_NO_ERROR;
}
NPError DeletePluginInDeallocateTest::Destroy() {
// Because of http://crbug.com/94829, we can't signal completion from within
// the NPP_Destroy of the plugin that is being destroyed. We work-around
// that by testing using a second instance, and signalling though the main
// test instance.
// There should always be a signalling instance by the time we reach here.
if (!g_signalling_instance_)
return NPERR_NO_ERROR;
// If we're the signalling instance, do nothing.
if (g_signalling_instance_ == this)
return NPERR_NO_ERROR;
if (!npobject_) {
g_signalling_instance_->SetError("SetWindow was not invoked.");
} else {
// Verify that our object was deallocated exactly once.
DeletePluginInDeallocateTestNPObject* test_object =
reinterpret_cast<DeletePluginInDeallocateTestNPObject*>(npobject_);
if (test_object->deallocate_count_ != 1)
g_signalling_instance_->SetError(
"Object was not deallocated exactly once.");
delete test_object;
}
g_signalling_instance_->SignalTestCompleted();
return NPERR_NO_ERROR;
}
} // namespace NPAPIClient