1 // Copyright (c) 2010 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_npobject_lifetime_test.h"
6
7 namespace NPAPIClient {
8
9 const int kNPObjectLifetimeTimer = 100;
10 const int kNPObjectLifetimeTimerElapse = 2000;
11
12 NPObject* NPObjectLifetimeTestInstance2::plugin_instance_object_ = NULL;
13
14 NPObjectDeletePluginInNPN_Evaluate*
15 NPObjectDeletePluginInNPN_Evaluate::g_npn_evaluate_test_instance_ = NULL;
16
NPObjectLifetimeTest(NPP id,NPNetscapeFuncs * host_functions)17 NPObjectLifetimeTest::NPObjectLifetimeTest(NPP id,
18 NPNetscapeFuncs *host_functions)
19 : PluginTest(id, host_functions),
20 other_plugin_instance_object_(NULL),
21 timer_id_(0) {
22 }
23
SetWindow(NPWindow * pNPWindow)24 NPError NPObjectLifetimeTest::SetWindow(NPWindow* pNPWindow) {
25 if (pNPWindow->window == NULL)
26 return NPERR_NO_ERROR;
27
28 HWND window_handle = reinterpret_cast<HWND>(pNPWindow->window);
29 if (!::GetProp(window_handle, L"Plugin_Instance")) {
30 // TODO: this propery leaks.
31 ::SetProp(window_handle, L"Plugin_Instance", this);
32 // We attempt to retreive the NPObject for the plugin instance identified
33 // by the NPObjectLifetimeTestInstance2 class as it may not have been
34 // instantiated yet.
35 timer_id_ = SetTimer(window_handle, kNPObjectLifetimeTimer,
36 kNPObjectLifetimeTimerElapse, TimerProc);
37 }
38 return NPERR_NO_ERROR;
39 }
40
TimerProc(HWND window,UINT message,UINT_PTR timer_id,DWORD elapsed_milli_seconds)41 void CALLBACK NPObjectLifetimeTest::TimerProc(
42 HWND window, UINT message, UINT_PTR timer_id,
43 DWORD elapsed_milli_seconds) {
44
45 NPObjectLifetimeTest* this_instance =
46 reinterpret_cast<NPObjectLifetimeTest*>
47 (::GetProp(window, L"Plugin_Instance"));
48 KillTimer(window, this_instance->timer_id_);
49 ::RemoveProp(window, L"Plugin_Instance");
50
51 this_instance->timer_id_ = 0;
52
53 this_instance->other_plugin_instance_object_ =
54 NPObjectLifetimeTestInstance2::plugin_instance_object_;
55 this_instance->HostFunctions()->retainobject(
56 this_instance->other_plugin_instance_object_);
57
58 NPString script;
59 script.UTF8Characters = "javascript:DeleteSecondPluginInstance()";
60 script.UTF8Length = static_cast<uint32_t>(strlen(script.UTF8Characters));
61
62 this_instance->HostFunctions()->geturlnotify(
63 this_instance->id(), "javascript:DeleteSecondPluginInstance()", NULL,
64 reinterpret_cast<void*>(1));
65 }
66
URLNotify(const char * url,NPReason reason,void * data)67 void NPObjectLifetimeTest::URLNotify(const char* url, NPReason reason,
68 void* data) {
69 // Create a "location" identifier.
70 NPIdentifier identifier = HostFunctions()->getstringidentifier("location");
71 // Declare a local variant value.
72 NPVariant variantValue;
73 // Get the location property from the window object (which is another object).
74 bool b1 = HostFunctions()->getproperty(id(), other_plugin_instance_object_,
75 identifier, &variantValue );
76 HostFunctions()->releaseobject(other_plugin_instance_object_);
77 other_plugin_instance_object_ = NULL;
78 // If this test failed, then we'd have crashed by now.
79 SignalTestCompleted();
80 }
81
NPObjectLifetimeTestInstance2(NPP id,NPNetscapeFuncs * host_functions)82 NPObjectLifetimeTestInstance2::NPObjectLifetimeTestInstance2(
83 NPP id, NPNetscapeFuncs *host_functions)
84 : PluginTest(id, host_functions) {
85 }
86
~NPObjectLifetimeTestInstance2()87 NPObjectLifetimeTestInstance2::~NPObjectLifetimeTestInstance2() {
88 if (plugin_instance_object_) {
89 HostFunctions()->releaseobject(plugin_instance_object_);
90 plugin_instance_object_ = NULL;
91 }
92 }
93
SetWindow(NPWindow * pNPWindow)94 NPError NPObjectLifetimeTestInstance2::SetWindow(NPWindow* pNPWindow) {
95 if (pNPWindow->window == NULL)
96 return NPERR_NO_ERROR;
97
98 if (!plugin_instance_object_) {
99 if (!HostFunctions()->getvalue(id(), NPNVWindowNPObject,
100 &plugin_instance_object_)) {
101 SetError("Failed to get NPObject for plugin instance2");
102 SignalTestCompleted();
103 return NPERR_GENERIC_ERROR;
104 }
105 }
106
107 return NPERR_NO_ERROR;
108 }
109
110
NPObjectDeletePluginInNPN_Evaluate(NPP id,NPNetscapeFuncs * host_functions)111 NPObjectDeletePluginInNPN_Evaluate::NPObjectDeletePluginInNPN_Evaluate(
112 NPP id, NPNetscapeFuncs *host_functions)
113 : PluginTest(id, host_functions),
114 plugin_instance_object_(NULL),
115 timer_id_(0) {
116 g_npn_evaluate_test_instance_ = this;
117 }
118
~NPObjectDeletePluginInNPN_Evaluate()119 NPObjectDeletePluginInNPN_Evaluate::~NPObjectDeletePluginInNPN_Evaluate() {
120 if (plugin_instance_object_) {
121 HostFunctions()->releaseobject(plugin_instance_object_);
122 plugin_instance_object_ = NULL;
123 }
124 }
125
SetWindow(NPWindow * np_window)126 NPError NPObjectDeletePluginInNPN_Evaluate::SetWindow(NPWindow* np_window) {
127 if (np_window->window == NULL)
128 return NPERR_NO_ERROR;
129
130 HWND window_handle = reinterpret_cast<HWND>(np_window->window);
131 // We setup a timerproc to invoke NPN_Evaluate to destroy this plugin
132 // instance. This is to ensure that we don't destroy the plugin instance
133 // while it is being used in webkit as this leads to crashes and is a
134 // more accurate representation of the renderer crash as described in
135 // http://b/issue?id=1134683.
136 if (!timer_id_) {
137 timer_id_ = SetTimer(window_handle, kNPObjectLifetimeTimer,
138 kNPObjectLifetimeTimerElapse, TimerProc);
139 }
140 return NPERR_NO_ERROR;
141 }
142
TimerProc(HWND window,UINT message,UINT_PTR timer_id,DWORD elapsed_milli_seconds)143 void CALLBACK NPObjectDeletePluginInNPN_Evaluate::TimerProc(
144 HWND window, UINT message, UINT_PTR timer_id,
145 DWORD elapsed_milli_seconds) {
146
147 KillTimer(window, g_npn_evaluate_test_instance_->timer_id_);
148 g_npn_evaluate_test_instance_->timer_id_ = 0;
149 NPObject *window_obj = NULL;
150 g_npn_evaluate_test_instance_->HostFunctions()->getvalue(
151 g_npn_evaluate_test_instance_->id(), NPNVWindowNPObject,
152 &window_obj);
153
154 if (!window_obj) {
155 g_npn_evaluate_test_instance_->SetError(
156 "Failed to get NPObject for plugin instance2");
157 g_npn_evaluate_test_instance_->SignalTestCompleted();
158 return;
159 }
160
161 std::string script = "javascript:DeletePluginWithinScript()";
162 NPString script_string;
163 script_string.UTF8Characters = script.c_str();
164 script_string.UTF8Length =
165 static_cast<unsigned int>(script.length());
166
167 NPVariant result_var;
168 bool result = g_npn_evaluate_test_instance_->HostFunctions()->evaluate(
169 g_npn_evaluate_test_instance_->id(), window_obj,
170 &script_string, &result_var);
171 // If this test failed we would have crashed by now.
172 }
173
174 } // namespace NPAPIClient
175