Home | History | Annotate | Download | only in plugin
      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 
     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 
     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 
     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 
     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 
     82 NPObjectLifetimeTestInstance2::NPObjectLifetimeTestInstance2(
     83     NPP id, NPNetscapeFuncs *host_functions)
     84     : PluginTest(id, host_functions) {
     85 }
     86 
     87 NPObjectLifetimeTestInstance2::~NPObjectLifetimeTestInstance2() {
     88   if (plugin_instance_object_) {
     89     HostFunctions()->releaseobject(plugin_instance_object_);
     90     plugin_instance_object_ = NULL;
     91   }
     92 }
     93 
     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 
    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 
    119 NPObjectDeletePluginInNPN_Evaluate::~NPObjectDeletePluginInNPN_Evaluate() {
    120   if (plugin_instance_object_) {
    121     HostFunctions()->releaseobject(plugin_instance_object_);
    122     plugin_instance_object_ = NULL;
    123   }
    124 }
    125 
    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 
    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