• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/test/plugin/plugin_delete_plugin_in_deallocate_test.h"
6 
7 #include "base/basictypes.h"
8 #include "base/compiler_specific.h"
9 
10 namespace {
11 
12 NPAPIClient::DeletePluginInDeallocateTest* g_signalling_instance_ = NULL;
13 
14 class DeletePluginInDeallocateTestNPObject : public NPObject {
15  public:
DeletePluginInDeallocateTestNPObject()16   DeletePluginInDeallocateTestNPObject()
17       : NPObject(), id_(NULL), host_functions_(NULL), deallocate_count_(0) {}
18 
Allocate(NPP npp,NPClass * npclass)19   static NPObject* Allocate(NPP npp, NPClass* npclass) {
20     return new DeletePluginInDeallocateTestNPObject();
21   }
22 
Deallocate(NPObject * npobject)23   static void Deallocate(NPObject* npobject) {
24     DeletePluginInDeallocateTestNPObject* object =
25         reinterpret_cast<DeletePluginInDeallocateTestNPObject*>(npobject);
26     ++object->deallocate_count_;
27 
28     // Call window.deletePlugin to tear-down our plugin from inside deallocate.
29     if (object->deallocate_count_ == 1) {
30       NPIdentifier delete_id =
31           object->host_functions_->getstringidentifier("deletePlugin");
32       NPObject* window_obj = NULL;
33       object->host_functions_->getvalue(object->id_, NPNVWindowNPObject,
34                                         &window_obj);
35       NPVariant rv;
36       object->host_functions_->invoke(object->id_, window_obj, delete_id, NULL,
37                                       0, &rv);
38     }
39   }
40 
41   NPP id_;
42   NPNetscapeFuncs* host_functions_;
43   int deallocate_count_;
44 };
45 
GetDeletePluginInDeallocateTestClass()46 NPClass* GetDeletePluginInDeallocateTestClass() {
47   static NPClass plugin_class = {
48     NP_CLASS_STRUCT_VERSION,
49     DeletePluginInDeallocateTestNPObject::Allocate,
50     DeletePluginInDeallocateTestNPObject::Deallocate,
51     NULL, // Invalidate
52     NULL, // HasMethod
53     NULL, // Invoke
54     NULL, // InvokeDefault
55     NULL, // HasProperty
56     NULL, // GetProperty
57     NULL, // SetProperty
58     NULL, // RemoveProperty
59   };
60   return &plugin_class;
61 }
62 
63 }  // namespace
64 
65 namespace NPAPIClient {
66 
DeletePluginInDeallocateTest(NPP id,NPNetscapeFuncs * host_functions)67 DeletePluginInDeallocateTest::DeletePluginInDeallocateTest(
68     NPP id, NPNetscapeFuncs* host_functions)
69     : PluginTest(id, host_functions), npobject_(NULL), test_started_(false) {
70 }
71 
SetWindow(NPWindow * pNPWindow)72 NPError DeletePluginInDeallocateTest::SetWindow(NPWindow* pNPWindow) {
73 #if !defined(OS_MACOSX)
74   if (pNPWindow->window == NULL)
75     return NPERR_NO_ERROR;
76 #endif
77 
78   // Ensure that we run the test once, even if SetWindow is called again.
79   if (test_started_)
80     return NPERR_NO_ERROR;
81   test_started_ = true;
82 
83   // Because of http://crbug.com/94829, we have to have a second plugin
84   // instance that we can use to signal completion.
85   if (test_id() == "signaller") {
86     g_signalling_instance_ = this;
87     return NPERR_NO_ERROR;
88   }
89 
90   // Create a custom NPObject and give our Id and the Netscape function table.
91   npobject_ = HostFunctions()->createobject(
92       id(), GetDeletePluginInDeallocateTestClass());
93   DeletePluginInDeallocateTestNPObject* test_object =
94       reinterpret_cast<DeletePluginInDeallocateTestNPObject*>(npobject_);
95   test_object->id_ = id();
96   test_object->host_functions_ = HostFunctions();
97 
98   // Fetch the window script object for our page.
99   NPObject* window = NULL;
100   HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window);
101 
102   // Pass it to the window.setTestObject function, which will later release it.
103   NPIdentifier set_test_object_id =
104       HostFunctions()->getstringidentifier("setTestObject");
105   NPVariant func_var;
106   NULL_TO_NPVARIANT(func_var);
107   HostFunctions()->getproperty(id(), window, set_test_object_id, &func_var);
108 
109   NPObject* func = NPVARIANT_TO_OBJECT(func_var);
110   NPVariant func_arg;
111   OBJECT_TO_NPVARIANT(npobject_, func_arg);
112   NPVariant func_result;
113   HostFunctions()->invokeDefault(id(), func, &func_arg, 1,
114                                  &func_result);
115 
116   // Release the object - the page's reference should keep it alive.
117   HostFunctions()->releaseobject(npobject_);
118 
119   return NPERR_NO_ERROR;
120 }
121 
Destroy()122 NPError DeletePluginInDeallocateTest::Destroy() {
123   // Because of http://crbug.com/94829, we can't signal completion from within
124   // the NPP_Destroy of the plugin that is being destroyed.  We work-around
125   // that by testing using a second instance, and signalling though the main
126   // test instance.
127 
128   // There should always be a signalling instance by the time we reach here.
129   if (!g_signalling_instance_)
130     return NPERR_NO_ERROR;
131 
132   // If we're the signalling instance, do nothing.
133   if (g_signalling_instance_ == this)
134     return NPERR_NO_ERROR;
135 
136   if (!npobject_) {
137     g_signalling_instance_->SetError("SetWindow was not invoked.");
138   } else {
139     // Verify that our object was deallocated exactly once.
140     DeletePluginInDeallocateTestNPObject* test_object =
141         reinterpret_cast<DeletePluginInDeallocateTestNPObject*>(npobject_);
142     if (test_object->deallocate_count_ != 1)
143       g_signalling_instance_->SetError(
144           "Object was not deallocated exactly once.");
145     delete test_object;
146   }
147 
148   g_signalling_instance_->SignalTestCompleted();
149 
150   return NPERR_NO_ERROR;
151 }
152 
153 } // namespace NPAPIClient
154