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
7namespace NPAPIClient {
8
9const int kNPObjectLifetimeTimer = 100;
10const int kNPObjectLifetimeTimerElapse = 2000;
11
12NPObject* NPObjectLifetimeTestInstance2::plugin_instance_object_ = NULL;
13
14NPObjectDeletePluginInNPN_Evaluate*
15    NPObjectDeletePluginInNPN_Evaluate::g_npn_evaluate_test_instance_ = NULL;
16
17NPObjectLifetimeTest::NPObjectLifetimeTest(NPP id,
18                                           NPNetscapeFuncs *host_functions)
19    : PluginTest(id, host_functions),
20      other_plugin_instance_object_(NULL),
21      timer_id_(0) {
22}
23
24NPError 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
41void 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
67void 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
82NPObjectLifetimeTestInstance2::NPObjectLifetimeTestInstance2(
83    NPP id, NPNetscapeFuncs *host_functions)
84    : PluginTest(id, host_functions) {
85}
86
87NPObjectLifetimeTestInstance2::~NPObjectLifetimeTestInstance2() {
88  if (plugin_instance_object_) {
89    HostFunctions()->releaseobject(plugin_instance_object_);
90    plugin_instance_object_ = NULL;
91  }
92}
93
94NPError 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
111NPObjectDeletePluginInNPN_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
119NPObjectDeletePluginInNPN_Evaluate::~NPObjectDeletePluginInNPN_Evaluate() {
120  if (plugin_instance_object_) {
121    HostFunctions()->releaseobject(plugin_instance_object_);
122    plugin_instance_object_ = NULL;
123  }
124}
125
126NPError 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
143void 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