summaryrefslogtreecommitdiffstats
path: root/webkit/plugins/npapi/test
diff options
context:
space:
mode:
Diffstat (limited to 'webkit/plugins/npapi/test')
-rw-r--r--webkit/plugins/npapi/test/Info.plist46
-rw-r--r--webkit/plugins/npapi/test/npapi_constants.cc12
-rw-r--r--webkit/plugins/npapi/test/npapi_constants.h22
-rw-r--r--webkit/plugins/npapi/test/npapi_test.cc122
-rw-r--r--webkit/plugins/npapi/test/npapi_test.def6
-rw-r--r--webkit/plugins/npapi/test/npapi_test.rc102
-rw-r--r--webkit/plugins/npapi/test/plugin_arguments_test.cc69
-rw-r--r--webkit/plugins/npapi/test/plugin_arguments_test.h43
-rw-r--r--webkit/plugins/npapi/test/plugin_client.cc240
-rw-r--r--webkit/plugins/npapi/test/plugin_client.h45
-rw-r--r--webkit/plugins/npapi/test/plugin_create_instance_in_paint.cc78
-rw-r--r--webkit/plugins/npapi/test/plugin_create_instance_in_paint.h33
-rw-r--r--webkit/plugins/npapi/test/plugin_delete_plugin_in_stream_test.cc45
-rw-r--r--webkit/plugins/npapi/test/plugin_delete_plugin_in_stream_test.h30
-rw-r--r--webkit/plugins/npapi/test/plugin_get_javascript_url2_test.cc134
-rw-r--r--webkit/plugins/npapi/test/plugin_get_javascript_url2_test.h38
-rw-r--r--webkit/plugins/npapi/test/plugin_get_javascript_url_test.cc218
-rw-r--r--webkit/plugins/npapi/test/plugin_get_javascript_url_test.h47
-rw-r--r--webkit/plugins/npapi/test/plugin_geturl_test.cc414
-rw-r--r--webkit/plugins/npapi/test/plugin_geturl_test.h61
-rw-r--r--webkit/plugins/npapi/test/plugin_javascript_open_popup.cc103
-rw-r--r--webkit/plugins/npapi/test/plugin_javascript_open_popup.h47
-rw-r--r--webkit/plugins/npapi/test/plugin_new_fails_test.cc18
-rw-r--r--webkit/plugins/npapi/test/plugin_new_fails_test.h21
-rw-r--r--webkit/plugins/npapi/test/plugin_npobject_lifetime_test.cc174
-rw-r--r--webkit/plugins/npapi/test/plugin_npobject_lifetime_test.h82
-rw-r--r--webkit/plugins/npapi/test/plugin_npobject_proxy_test.cc51
-rw-r--r--webkit/plugins/npapi/test/plugin_npobject_proxy_test.h27
-rw-r--r--webkit/plugins/npapi/test/plugin_private_test.cc57
-rw-r--r--webkit/plugins/npapi/test/plugin_private_test.h25
-rw-r--r--webkit/plugins/npapi/test/plugin_schedule_timer_test.cc116
-rw-r--r--webkit/plugins/npapi/test/plugin_schedule_timer_test.h68
-rw-r--r--webkit/plugins/npapi/test/plugin_setup_test.cc22
-rw-r--r--webkit/plugins/npapi/test/plugin_setup_test.h24
-rw-r--r--webkit/plugins/npapi/test/plugin_test.cc155
-rw-r--r--webkit/plugins/npapi/test/plugin_test.h134
-rw-r--r--webkit/plugins/npapi/test/plugin_test_factory.cc104
-rw-r--r--webkit/plugins/npapi/test/plugin_test_factory.h22
-rw-r--r--webkit/plugins/npapi/test/plugin_thread_async_call_test.cc117
-rw-r--r--webkit/plugins/npapi/test/plugin_thread_async_call_test.h39
-rw-r--r--webkit/plugins/npapi/test/plugin_window_size_test.cc55
-rw-r--r--webkit/plugins/npapi/test/plugin_window_size_test.h24
-rw-r--r--webkit/plugins/npapi/test/plugin_windowed_test.cc150
-rw-r--r--webkit/plugins/npapi/test/plugin_windowed_test.h33
-rw-r--r--webkit/plugins/npapi/test/plugin_windowless_test.cc261
-rw-r--r--webkit/plugins/npapi/test/plugin_windowless_test.h35
-rw-r--r--webkit/plugins/npapi/test/resource.h15
47 files changed, 3784 insertions, 0 deletions
diff --git a/webkit/plugins/npapi/test/Info.plist b/webkit/plugins/npapi/test/Info.plist
new file mode 100644
index 0000000..37145fd
--- /dev/null
+++ b/webkit/plugins/npapi/test/Info.plist
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>NPAPITestPlugIn</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.chromium.npapi_test_plugin</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>BRPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>CFPlugInDynamicRegisterFunction</key>
+ <string></string>
+ <key>CFPlugInDynamicRegistration</key>
+ <string>NO</string>
+ <key>WebPluginDescription</key>
+ <string>Simple NPAPI plug-in for Chromium unit tests</string>
+ <key>WebPluginMIMETypes</key>
+ <dict>
+ <key>application/vnd.npapi-test</key>
+ <dict>
+ <key>WebPluginExtensions</key>
+ <array>
+ <string>npapitest</string>
+ </array>
+ <key>WebPluginTypeDescription</key>
+ <string>test npapi</string>
+ </dict>
+ </dict>
+ <key>WebPluginName</key>
+ <string>Chromium NPAPI Test Plugin</string>
+</dict>
+</plist>
diff --git a/webkit/plugins/npapi/test/npapi_constants.cc b/webkit/plugins/npapi/test/npapi_constants.cc
new file mode 100644
index 0000000..94d3284
--- /dev/null
+++ b/webkit/plugins/npapi/test/npapi_constants.cc
@@ -0,0 +1,12 @@
+// Copyright (c) 2010 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 "webkit/plugins/npapi/test/npapi_constants.h"
+
+namespace NPAPIClient {
+
+const char kTestCompleteCookie[] = "status";
+const char kTestCompleteSuccess[] = "OK";
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/npapi_constants.h b/webkit/plugins/npapi/test/npapi_constants.h
new file mode 100644
index 0000000..2d375b0
--- /dev/null
+++ b/webkit/plugins/npapi/test/npapi_constants.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2010 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.
+
+// Constants for the NPAPI test
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_NPAPI_CONSTANTS_H_
+#define WEBKIT_PLUGINS_NPAPI_TEST_NPAPI_CONSTANTS_H_
+
+namespace NPAPIClient {
+
+// The name of the cookie which will be used to communicate between
+// the plugin and the test harness.
+extern const char kTestCompleteCookie[];
+
+// The cookie value which will be sent to the client upon successful
+// test.
+extern const char kTestCompleteSuccess[];
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_NPAPI_CONSTANTS_H_
diff --git a/webkit/plugins/npapi/test/npapi_test.cc b/webkit/plugins/npapi/test/npapi_test.cc
new file mode 100644
index 0000000..26dc45d
--- /dev/null
+++ b/webkit/plugins/npapi/test/npapi_test.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2010 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.
+
+//
+// npapitest
+//
+// This is a NPAPI Plugin Program which is used to test the Browser's NPAPI
+// host implementation. It is used in conjunction with the npapi_unittest.
+//
+// As a NPAPI Plugin, you can invoke it by creating a web page of the following
+// type:
+//
+// <embed src="content-to-load" type="application/vnd.npapi-test"
+// name="test-name">
+//
+// arguments:
+// src: This is the initial content which will be sent to the plugin.
+// type: Must be "application/vnd.npapi-test"
+// name: The testcase to run when invoked
+// id: The id of the test being run (for testing concurrent plugins)
+//
+// The Plugin drives the actual test, calling host functions and validating the
+// Host callbacks which it receives. It is the duty of the plugin to record
+// all errors.
+//
+// To indicate test completion, the plugin expects the containing HTML page to
+// implement two javascript functions:
+// onSuccess(string testname);
+// onFailure(string testname, string results);
+// The HTML host pages used in this test will then set a document cookie
+// which the automated test framework can poll for and discover that the
+// test has completed.
+//
+//
+// TESTS
+// When the PluginClient receives a NPP_New callback from the browser,
+// it looks at the "name" argument which is passed in. It verifies that
+// the name matches a known test, and instantiates that test. The test is
+// a subclass of PluginTest.
+//
+//
+
+#include "base/basictypes.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define EXPORT __attribute__((visibility ("default")))
+#else
+#define EXPORT
+#endif
+
+#include "webkit/plugins/npapi/test/plugin_client.h"
+
+#if defined(OS_WIN)
+BOOL API_CALL DllMain(HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved) {
+ return TRUE;
+}
+#endif
+
+extern "C" {
+EXPORT NPError API_CALL NP_GetEntryPoints(NPPluginFuncs* pFuncs) {
+ return NPAPIClient::PluginClient::GetEntryPoints(pFuncs);
+}
+
+EXPORT NPError API_CALL NP_Shutdown() {
+ return NPAPIClient::PluginClient::Shutdown();
+}
+
+#if defined(OS_WIN) || defined(OS_MACOSX)
+EXPORT NPError API_CALL NP_Initialize(NPNetscapeFuncs* npnFuncs) {
+ return NPAPIClient::PluginClient::Initialize(npnFuncs);
+}
+#elif defined(OS_POSIX)
+EXPORT NPError API_CALL NP_Initialize(NPNetscapeFuncs* npnFuncs,
+ NPPluginFuncs* nppFuncs) {
+ NPError error = NPAPIClient::PluginClient::Initialize(npnFuncs);
+ if (error == NPERR_NO_ERROR) {
+ error = NP_GetEntryPoints(nppFuncs);
+ }
+ return error;
+}
+
+EXPORT NPError API_CALL NP_GetValue(NPP instance, NPPVariable variable,
+ void* value) {
+ NPError err = NPERR_NO_ERROR;
+
+ switch (variable) {
+ case NPPVpluginNameString:
+ *(static_cast<const char**>(value)) = "NPAPI Test Plugin";
+ break;
+ case NPPVpluginDescriptionString:
+ *(static_cast<const char**>(value)) =
+ "Simple NPAPI plug-in for Chromium unit tests";
+ break;
+ case NPPVpluginNeedsXEmbed:
+ *(static_cast<NPBool*>(value)) = true;
+ break;
+ default:
+ err = NPERR_GENERIC_ERROR;
+ break;
+ }
+
+ return err;
+}
+
+EXPORT const char* API_CALL NP_GetMIMEDescription(void) {
+ // The layout test LayoutTests/fast/js/navigator-mimeTypes-length.html
+ // asserts that the number of mimetypes handled by plugins should be
+ // greater than the number of plugins. We specify a mimetype here so
+ // this plugin has at least one.
+ return "application/vnd.npapi-test:npapitest:test npapi";
+}
+#endif // OS_POSIX
+} // extern "C"
+
+namespace WebCore {
+ const char* currentTextBreakLocaleID() { return "en_us"; }
+}
diff --git a/webkit/plugins/npapi/test/npapi_test.def b/webkit/plugins/npapi/test/npapi_test.def
new file mode 100644
index 0000000..4481c16
--- /dev/null
+++ b/webkit/plugins/npapi/test/npapi_test.def
@@ -0,0 +1,6 @@
+LIBRARY npapi_test_plugin
+
+EXPORTS
+ NP_GetEntryPoints @1
+ NP_Initialize @2
+ NP_Shutdown @3
diff --git a/webkit/plugins/npapi/test/npapi_test.rc b/webkit/plugins/npapi/test/npapi_test.rc
new file mode 100644
index 0000000..524dda4
--- /dev/null
+++ b/webkit/plugins/npapi/test/npapi_test.rc
@@ -0,0 +1,102 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904e4"
+ BEGIN
+ VALUE "FileDescription", "NPAPI Test Plugin"
+ VALUE "FileVersion", "1, 0, 0, 1"
+ VALUE "InternalName", "npapi_test_plugin"
+ VALUE "LegalCopyright", "Copyright (C) 2007"
+ VALUE "MIMEType", "application/vnd.npapi-test"
+ VALUE "OriginalFilename", "npapi_test_plugin.dll"
+ VALUE "ProductName", "NPAPI Test Plugin"
+ VALUE "ProductVersion", "1, 0, 0, 1"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1252
+ END
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/webkit/plugins/npapi/test/plugin_arguments_test.cc b/webkit/plugins/npapi/test/plugin_arguments_test.cc
new file mode 100644
index 0000000..fe1e54e
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_arguments_test.cc
@@ -0,0 +1,69 @@
+// Copyright (c) 2010 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 "webkit/plugins/npapi/test/plugin_arguments_test.h"
+
+#include "base/basictypes.h"
+#include "base/string_util.h"
+#include "base/stringprintf.h"
+
+namespace NPAPIClient {
+
+PluginArgumentsTest::PluginArgumentsTest(NPP id,
+ NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+NPError PluginArgumentsTest::New(uint16 mode, int16 argc,
+ const char* argn[], const char* argv[],
+ NPSavedData* saved) {
+ // mode: should be the string either "NP_EMBED" or "NP_FULL",
+ // depending on the mode passed in.
+ // count: the count of "val" arguments. If the value is
+ // 2, then we'll find arguments "val1" and "val2". If
+ // the value is 0, then there will be no "val" arguments.
+ // size: each val string will be this size * the value's
+ // index. E.g if size is "10", val1 will be 10bytes,
+ // and val2 will be 20bytes.
+ const char *mode_string = GetArgValue("mode", argc, argn, argv);
+ ExpectAsciiStringNotEqual(mode_string, (const char *)NULL);
+ if (mode_string != NULL) {
+ std::string mode_dep_string = mode_string;
+ if (mode == NP_EMBED)
+ ExpectStringLowerCaseEqual(mode_dep_string, "np_embed");
+ else if (mode == NP_FULL)
+ ExpectStringLowerCaseEqual(mode_dep_string, "np_full");
+ }
+
+ const char *count_string = GetArgValue("count", argc, argn, argv);
+ if (count_string != NULL) {
+ int max_args = atoi(count_string);
+
+ const char *size_string = GetArgValue("size", argc, argn, argv);
+ ExpectAsciiStringNotEqual(size_string, (const char *)NULL);
+ if (size_string != NULL) {
+ int size = atoi(size_string);
+
+ for (int index = 1; index <= max_args; index++) {
+ std::string arg_name = base::StringPrintf("%s%d", "val", index);
+ const char *val_string = GetArgValue(arg_name.c_str(), argc, argn,
+ argv);
+ ExpectAsciiStringNotEqual(val_string, (const char*)NULL);
+ if (val_string != NULL)
+ ExpectIntegerEqual((int)strlen(val_string), (index*size));
+ }
+ }
+ }
+
+ return PluginTest::New(mode, argc, argn, argv, saved);
+}
+
+NPError PluginArgumentsTest::SetWindow(NPWindow* pNPWindow) {
+ // This test just tests the arguments. We're done now.
+ this->SignalTestCompleted();
+
+ return NPERR_NO_ERROR;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_arguments_test.h b/webkit/plugins/npapi/test/plugin_arguments_test.h
new file mode 100644
index 0000000..c2a0eaa
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_arguments_test.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_ARGUMENTS_TEST_H_
+#define WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_ARGUMENTS_TEST_H_
+
+#include "webkit/plugins/npapi/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// The PluginArgumentsTest test that we properly receive arguments
+// intended for the plugin.
+//
+// This is basically overkill for testing that the arguments passed
+// to the plugin match what we expect.
+//
+// We expect to find the following arguments:
+// mode: should be the string either "NP_EMBED" or "NP_FULL",
+// depending on the mode passed in.
+// count: the count of "val" arguments. If the value is
+// 2, then we'll find arguments "val1" and "val2". If
+// the value is 0, then there will be no "val" arguments.
+// size: each val string will be this size * the value's
+// index. E.g if size is "10", val1 will be 10bytes,
+// and val2 will be 20bytes.
+//
+class PluginArgumentsTest : public PluginTest {
+ public:
+ // Constructor.
+ PluginArgumentsTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ // Initialize this PluginTest based on the arguments from NPP_New.
+ virtual NPError New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved);
+
+ // NPAPI SetWindow handler.
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_ARGUMENTS_TEST_H_
diff --git a/webkit/plugins/npapi/test/plugin_client.cc b/webkit/plugins/npapi/test/plugin_client.cc
new file mode 100644
index 0000000..0b28250
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_client.cc
@@ -0,0 +1,240 @@
+// Copyright (c) 2010 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 "webkit/plugins/npapi/test/plugin_client.h"
+
+#include "base/string_util.h"
+#include "webkit/plugins/npapi/test/plugin_test.h"
+#include "webkit/plugins/npapi/test/plugin_test_factory.h"
+
+namespace NPAPIClient {
+
+NPNetscapeFuncs* PluginClient::host_functions_;
+
+NPError PluginClient::GetEntryPoints(NPPluginFuncs* pFuncs) {
+ if (pFuncs == NULL)
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+
+ if (pFuncs->size < sizeof(NPPluginFuncs))
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+
+ pFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
+ pFuncs->newp = NPP_New;
+ pFuncs->destroy = NPP_Destroy;
+ pFuncs->setwindow = NPP_SetWindow;
+ pFuncs->newstream = NPP_NewStream;
+ pFuncs->destroystream = NPP_DestroyStream;
+ pFuncs->asfile = NPP_StreamAsFile;
+ pFuncs->writeready = NPP_WriteReady;
+ pFuncs->write = NPP_Write;
+ pFuncs->print = NPP_Print;
+ pFuncs->event = NPP_HandleEvent;
+ pFuncs->urlnotify = NPP_URLNotify;
+ pFuncs->getvalue = NPP_GetValue;
+ pFuncs->setvalue = NPP_SetValue;
+ pFuncs->javaClass = NULL;
+ pFuncs->urlredirectnotify = NPP_URLRedirectNotify;
+
+ return NPERR_NO_ERROR;
+}
+
+NPError PluginClient::Initialize(NPNetscapeFuncs* pFuncs) {
+ if (pFuncs == NULL) {
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+ }
+
+ if (static_cast<unsigned char>((pFuncs->version >> 8) & 0xff) >
+ NP_VERSION_MAJOR) {
+ return NPERR_INCOMPATIBLE_VERSION_ERROR;
+ }
+
+#if defined(OS_WIN)
+ // Check if we should crash.
+ HANDLE crash_event = CreateEvent(NULL, TRUE, FALSE, L"TestPluginCrashOnInit");
+ if (WaitForSingleObject(crash_event, 0) == WAIT_OBJECT_0) {
+ int *zero = NULL;
+ *zero = 0;
+ }
+ CloseHandle(crash_event);
+#endif
+
+ host_functions_ = pFuncs;
+
+ return NPERR_NO_ERROR;
+}
+
+NPError PluginClient::Shutdown() {
+ return NPERR_NO_ERROR;
+}
+
+} // namespace NPAPIClient
+
+extern "C" {
+NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode,
+ int16 argc, char* argn[], char* argv[], NPSavedData* saved) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ // We look at the test name requested via the plugin arguments. We match
+ // that against a given test and try to instantiate it.
+
+ // lookup the name parameter
+ std::string test_name;
+ for (int name_index = 0; name_index < argc; name_index++) {
+ if (base::strcasecmp(argn[name_index], "name") == 0) {
+ test_name = argv[name_index];
+ break;
+ }
+ }
+ if (test_name.empty())
+ return NPERR_GENERIC_ERROR; // no name found
+
+ NPAPIClient::PluginTest* new_test = NPAPIClient::CreatePluginTest(test_name,
+ instance, NPAPIClient::PluginClient::HostFunctions());
+ if (new_test == NULL) {
+ // If we don't have a test case for this, create a
+ // generic one which basically never fails.
+ LOG(WARNING) << "Unknown test name '" << test_name
+ << "'; using default test.";
+ new_test = new NPAPIClient::PluginTest(instance,
+ NPAPIClient::PluginClient::HostFunctions());
+ }
+
+ NPError ret = new_test->New(mode, argc, (const char**)argn,
+ (const char**)argv, saved);
+ if ((ret == NPERR_NO_ERROR) && new_test->IsWindowless()) {
+ NPAPIClient::PluginClient::HostFunctions()->setvalue(
+ instance, NPPVpluginWindowBool, NULL);
+ }
+
+ return ret;
+}
+
+NPError NPP_Destroy(NPP instance, NPSavedData** save) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ NPAPIClient::PluginTest* plugin =
+ reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
+
+ NPError rv = plugin->Destroy();
+ delete plugin;
+ return rv;
+}
+
+NPError NPP_SetWindow(NPP instance, NPWindow* pNPWindow) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ NPAPIClient::PluginTest* plugin =
+ reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
+
+ return plugin->SetWindow(pNPWindow);
+}
+
+NPError NPP_NewStream(NPP instance, NPMIMEType type,
+ NPStream* stream, NPBool seekable, uint16* stype) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ NPAPIClient::PluginTest* plugin =
+ reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
+
+ return plugin->NewStream(type, stream, seekable, stype);
+}
+
+int32 NPP_WriteReady(NPP instance, NPStream *stream) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ NPAPIClient::PluginTest* plugin =
+ reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
+
+ return plugin->WriteReady(stream);
+}
+
+int32 NPP_Write(NPP instance, NPStream *stream, int32 offset,
+ int32 len, void *buffer) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ NPAPIClient::PluginTest* plugin =
+ reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
+
+ return plugin->Write(stream, offset, len, buffer);
+}
+
+NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ NPAPIClient::PluginTest* plugin =
+ reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
+
+ return plugin->DestroyStream(stream, reason);
+}
+
+void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) {
+ if (instance == NULL)
+ return;
+
+ NPAPIClient::PluginTest* plugin =
+ reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
+
+ return plugin->StreamAsFile(stream, fname);
+}
+
+void NPP_Print(NPP instance, NPPrint* printInfo) {
+ if (instance == NULL)
+ return;
+
+ // XXXMB - do work here.
+}
+
+void NPP_URLNotify(NPP instance, const char* url, NPReason reason,
+ void* notifyData) {
+ if (instance == NULL)
+ return;
+
+ NPAPIClient::PluginTest* plugin =
+ reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
+
+ return plugin->URLNotify(url, reason, notifyData);
+}
+
+NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ // XXXMB - do work here.
+ return NPERR_GENERIC_ERROR;
+}
+
+NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) {
+ if (instance == NULL)
+ return NPERR_INVALID_INSTANCE_ERROR;
+
+ // XXXMB - do work here.
+ return NPERR_GENERIC_ERROR;
+}
+
+int16 NPP_HandleEvent(NPP instance, void* event) {
+ if (instance == NULL)
+ return 0;
+
+ NPAPIClient::PluginTest* plugin =
+ reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
+
+ return plugin->HandleEvent(event);
+}
+
+void NPP_URLRedirectNotify(NPP instance, const char* url, int32_t status,
+ void* notify_data) {
+ if (instance) {
+ NPAPIClient::PluginTest* plugin =
+ reinterpret_cast<NPAPIClient::PluginTest*>(instance->pdata);
+ plugin->URLRedirectNotify(url, status, notify_data);
+ }
+}
+} // extern "C"
diff --git a/webkit/plugins/npapi/test/plugin_client.h b/webkit/plugins/npapi/test/plugin_client.h
new file mode 100644
index 0000000..c06be2d
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_client.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_CLIENT_H_
+#define WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_CLIENT_H_
+
+#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/npapi/bindings/nphostapi.h"
+
+namespace NPAPIClient {
+
+// A PluginClient is a NPAPI Plugin. This class contains
+// the bootstrapping functions used by the browser to load
+// the plugin.
+class PluginClient {
+ public:
+ // Although not documented in the NPAPI specification, this function
+ // gets the list of entry points in the NPAPI Plugin (client) for the
+ // NPAPI Host to call.
+ static NPError GetEntryPoints(NPPluginFuncs* pFuncs);
+
+ // The browser calls this function only once: when a plug-in is loaded,
+ // before the first instance is created. This is the first function that
+ // the browser calls. NP_Initialize tells the plug-in that the browser has
+ // loaded it and provides global initialization. Allocate any memory or
+ // resources shared by all instances of your plug-in at this time.
+ static NPError Initialize(NPNetscapeFuncs* pFuncs);
+
+ // The browser calls this function once after the last instance of your
+ // plug-in is destroyed, before unloading the plug-in library itself. Use
+ // NP_Shutdown to delete any data allocated in NP_Initialize to be shared
+ // by all instances of a plug-in.
+ static NPError Shutdown();
+
+ // The table of functions provided by the host.
+ static NPNetscapeFuncs *HostFunctions() { return host_functions_; }
+
+ private:
+ static NPNetscapeFuncs* host_functions_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_CLIENT_H_
diff --git a/webkit/plugins/npapi/test/plugin_create_instance_in_paint.cc b/webkit/plugins/npapi/test/plugin_create_instance_in_paint.cc
new file mode 100644
index 0000000..09d6bdc
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_create_instance_in_paint.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2010 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 "webkit/plugins/npapi/test/plugin_create_instance_in_paint.h"
+
+#include "webkit/plugins/npapi/test/plugin_client.h"
+
+namespace NPAPIClient {
+
+CreateInstanceInPaintTest::CreateInstanceInPaintTest(
+ NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ window_(NULL), created_(false) {
+}
+
+NPError CreateInstanceInPaintTest::SetWindow(NPWindow* pNPWindow) {
+ if (pNPWindow->window == NULL)
+ return NPERR_NO_ERROR;
+
+ if (test_id() == "1") {
+ if (!window_) {
+ static ATOM window_class = 0;
+ if (!window_class) {
+ WNDCLASSEX wcex;
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.style = CS_DBLCLKS;
+ wcex.lpfnWndProc =
+ &NPAPIClient::CreateInstanceInPaintTest::WindowProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = GetModuleHandle(NULL);
+ wcex.hIcon = 0;
+ wcex.hCursor = 0;
+ wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1);
+ wcex.lpszMenuName = 0;
+ wcex.lpszClassName = L"CreateInstanceInPaintTestWindowClass";
+ wcex.hIconSm = 0;
+ window_class = RegisterClassEx(&wcex);
+ }
+
+ HWND parent = reinterpret_cast<HWND>(pNPWindow->window);
+ window_ = CreateWindowEx(
+ WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
+ MAKEINTATOM(window_class), 0,
+ WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE ,
+ 0, 0, 100, 100, parent, 0, GetModuleHandle(NULL), 0);
+ DCHECK(window_);
+ // TODO: this property leaks.
+ ::SetProp(window_, L"Plugin_Instance", this);
+ }
+ } else if (test_id() == "2") {
+ SignalTestCompleted();
+ } else {
+ NOTREACHED();
+ }
+ return NPERR_NO_ERROR;
+}
+
+LRESULT CALLBACK CreateInstanceInPaintTest::WindowProc(
+ HWND window, UINT message, WPARAM wparam, LPARAM lparam) {
+ if (message == WM_PAINT) {
+ CreateInstanceInPaintTest* this_instance =
+ reinterpret_cast<CreateInstanceInPaintTest*>
+ (::GetProp(window, L"Plugin_Instance"));
+ if (this_instance->test_id() == "1" && !this_instance->created_) {
+ ::RemoveProp(window, L"Plugin_Instance");
+ this_instance->created_ = true;
+ this_instance->HostFunctions()->geturlnotify(
+ this_instance->id(), "javascript:CreateNewInstance()", NULL,
+ reinterpret_cast<void*>(1));
+ }
+ }
+
+ return DefWindowProc(window, message, wparam, lparam);
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_create_instance_in_paint.h b/webkit/plugins/npapi/test/plugin_create_instance_in_paint.h
new file mode 100644
index 0000000..59f196f
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_create_instance_in_paint.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2009 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_CREATE_INSTANCE_IN_PAINT_H_
+#define WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_CREATE_INSTANCE_IN_PAINT_H_
+
+#include "webkit/plugins/npapi/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// This class tests that creating a new plugin via script while handling a
+// Windows message doesn't cause a deadlock.
+class CreateInstanceInPaintTest : public PluginTest {
+ public:
+ // Constructor.
+ CreateInstanceInPaintTest(NPP id, NPNetscapeFuncs *host_functions);
+ //
+ // NPAPI functions
+ //
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+
+ private:
+ static LRESULT CALLBACK WindowProc(
+ HWND window, UINT message, WPARAM wparam, LPARAM lparam);
+
+ HWND window_;
+ bool created_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_CREATE_INSTANCE_IN_PAINT_H_
diff --git a/webkit/plugins/npapi/test/plugin_delete_plugin_in_stream_test.cc b/webkit/plugins/npapi/test/plugin_delete_plugin_in_stream_test.cc
new file mode 100644
index 0000000..fad7992
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_delete_plugin_in_stream_test.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2010 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 "webkit/plugins/npapi/test/plugin_delete_plugin_in_stream_test.h"
+
+#include "webkit/plugins/npapi/test/plugin_client.h"
+
+namespace NPAPIClient {
+
+#define kUrl "javascript:window.location+\"\""
+#define kUrlStreamId 1
+
+DeletePluginInStreamTest::DeletePluginInStreamTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ test_started_(false) {
+}
+
+NPError DeletePluginInStreamTest::SetWindow(NPWindow* pNPWindow) {
+ if (pNPWindow->window == NULL)
+ return NPERR_NO_ERROR;
+
+ if (!test_started_) {
+ std::string url = "self_delete_plugin_stream.html";
+ HostFunctions()->geturlnotify(id(), url.c_str(), NULL,
+ reinterpret_cast<void*>(kUrlStreamId));
+ test_started_ = true;
+ }
+ return NPERR_NO_ERROR;
+}
+
+NPError DeletePluginInStreamTest::NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype) {
+ NPIdentifier delete_id = HostFunctions()->getstringidentifier("DeletePluginWithinScript");
+
+ NPObject *window_obj = NULL;
+ HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window_obj);
+
+ NPVariant rv;
+ HostFunctions()->invoke(id(), window_obj, delete_id, NULL, 0, &rv);
+
+ return NPERR_NO_ERROR;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_delete_plugin_in_stream_test.h b/webkit/plugins/npapi/test/plugin_delete_plugin_in_stream_test.h
new file mode 100644
index 0000000..dca9de3
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_delete_plugin_in_stream_test.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_DELETE_PLUGIN_IN_STREAM_TEST_H_
+#define WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_DELETE_PLUGIN_IN_STREAM_TEST_H_
+
+#include "webkit/plugins/npapi/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// This class tests
+class DeletePluginInStreamTest : public PluginTest {
+ public:
+ // Constructor.
+ DeletePluginInStreamTest(NPP id, NPNetscapeFuncs *host_functions);
+ //
+ // NPAPI functions
+ //
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+ virtual NPError NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype);
+ private:
+ bool test_started_;
+ std::string self_url_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_DELETE_PLUGIN_IN_STREAM_TEST_H_
diff --git a/webkit/plugins/npapi/test/plugin_get_javascript_url2_test.cc b/webkit/plugins/npapi/test/plugin_get_javascript_url2_test.cc
new file mode 100644
index 0000000..e7595f2
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_get_javascript_url2_test.cc
@@ -0,0 +1,134 @@
+// Copyright (c) 2010 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 "webkit/plugins/npapi/test/plugin_get_javascript_url2_test.h"
+
+#include "base/basictypes.h"
+
+// url for "self".
+#define SELF_URL "javascript:window.location+\"\""
+// The identifier for the self url stream.
+#define SELF_URL_STREAM_ID 1
+
+// The identifier for the fetched url stream.
+#define FETCHED_URL_STREAM_ID 2
+
+// The maximum chunk size of stream data.
+#define STREAM_CHUNK 197
+
+const int kNPNEvaluateTimerID = 100;
+const int kNPNEvaluateTimerElapse = 50;
+
+namespace NPAPIClient {
+
+ExecuteGetJavascriptUrl2Test::ExecuteGetJavascriptUrl2Test(
+ NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ test_started_(false) {
+}
+
+NPError ExecuteGetJavascriptUrl2Test::SetWindow(NPWindow* pNPWindow) {
+ if (pNPWindow->window == NULL)
+ return NPERR_NO_ERROR;
+
+ if (!test_started_) {
+ std::string url = SELF_URL;
+ HostFunctions()->geturlnotify(id(), url.c_str(), "_self",
+ reinterpret_cast<void*>(SELF_URL_STREAM_ID));
+ test_started_ = true;
+ }
+ return NPERR_NO_ERROR;
+}
+
+NPError ExecuteGetJavascriptUrl2Test::NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype) {
+ if (stream == NULL) {
+ SetError("NewStream got null stream");
+ return NPERR_INVALID_PARAM;
+ }
+
+ COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
+ cast_validity_check);
+ unsigned long stream_id = reinterpret_cast<unsigned long>(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+ return NPERR_NO_ERROR;
+}
+
+int32 ExecuteGetJavascriptUrl2Test::WriteReady(NPStream *stream) {
+ return STREAM_CHUNK;
+}
+
+int32 ExecuteGetJavascriptUrl2Test::Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer) {
+ if (stream == NULL) {
+ SetError("Write got null stream");
+ return -1;
+ }
+ if (len < 0 || len > STREAM_CHUNK) {
+ SetError("Write got bogus stream chunk size");
+ return -1;
+ }
+
+ COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
+ cast_validity_check);
+ unsigned long stream_id = reinterpret_cast<unsigned long>(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ self_url_.append(static_cast<char*>(buffer), len);
+ break;
+ default:
+ SetError("Unexpected write callback");
+ break;
+ }
+ // Pretend that we took all the data.
+ return len;
+}
+
+
+NPError ExecuteGetJavascriptUrl2Test::DestroyStream(NPStream *stream, NPError reason) {
+ if (stream == NULL) {
+ SetError("NewStream got null stream");
+ return NPERR_INVALID_PARAM;
+ }
+
+ COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
+ cast_validity_check);
+ unsigned long stream_id = reinterpret_cast<unsigned long>(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ // don't care
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+ return NPERR_NO_ERROR;
+}
+
+void ExecuteGetJavascriptUrl2Test::URLNotify(const char* url, NPReason reason, void* data) {
+ COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(data),
+ cast_validity_check);
+
+ unsigned long stream_id = reinterpret_cast<unsigned long>(data);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ if (strcmp(url, SELF_URL) != 0)
+ SetError("URLNotify reported incorrect url for SELF_URL");
+ if (self_url_.empty())
+ SetError("Failed to obtain window location.");
+ SignalTestCompleted();
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_get_javascript_url2_test.h b/webkit/plugins/npapi/test/plugin_get_javascript_url2_test.h
new file mode 100644
index 0000000..b5c398e
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_get_javascript_url2_test.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_PLUGINS_TEST_PLUGIN_GET_JAVASCRIPT_URL2_H_
+#define WEBKIT_PLUGINS_NPAPI_PLUGINS_TEST_PLUGIN_GET_JAVASCRIPT_URL2_H_
+
+#include "webkit/plugins/npapi/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// This class tests NPP_GetURLNotify for a javascript URL with _top
+// as the target frame.
+class ExecuteGetJavascriptUrl2Test : public PluginTest {
+ public:
+ // Constructor.
+ ExecuteGetJavascriptUrl2Test(NPP id, NPNetscapeFuncs *host_functions);
+
+ //
+ // NPAPI functions
+ //
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+ virtual NPError NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype);
+ virtual int32 WriteReady(NPStream *stream);
+ virtual int32 Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer);
+ virtual NPError DestroyStream(NPStream *stream, NPError reason);
+ virtual void URLNotify(const char* url, NPReason reason, void* data);
+
+ private:
+ bool test_started_;
+ std::string self_url_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_PLUGINS_TEST_PLUGIN_GET_JAVASCRIPT_URL2_H_
diff --git a/webkit/plugins/npapi/test/plugin_get_javascript_url_test.cc b/webkit/plugins/npapi/test/plugin_get_javascript_url_test.cc
new file mode 100644
index 0000000..ea32fac
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_get_javascript_url_test.cc
@@ -0,0 +1,218 @@
+// Copyright (c) 2010 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 "webkit/plugins/npapi/test/plugin_get_javascript_url_test.h"
+
+#include "base/basictypes.h"
+
+// url for "self".
+#define SELF_URL "javascript:window.location+\"\""
+// The identifier for the self url stream.
+#define SELF_URL_STREAM_ID 1
+
+// The identifier for the fetched url stream.
+#define FETCHED_URL_STREAM_ID 2
+
+// The maximum chunk size of stream data.
+#define STREAM_CHUNK 197
+
+const int kNPNEvaluateTimerID = 100;
+const int kNPNEvaluateTimerElapse = 50;
+
+
+namespace NPAPIClient {
+
+ExecuteGetJavascriptUrlTest::ExecuteGetJavascriptUrlTest(
+ NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ test_started_(false),
+#ifdef OS_WIN
+ window_(NULL),
+#endif
+ npn_evaluate_context_(false) {
+}
+
+NPError ExecuteGetJavascriptUrlTest::SetWindow(NPWindow* pNPWindow) {
+ if (pNPWindow->window == NULL)
+ return NPERR_NO_ERROR;
+
+ if (!test_started_) {
+ std::string url = SELF_URL;
+ HostFunctions()->geturlnotify(id(), url.c_str(), "_top",
+ reinterpret_cast<void*>(SELF_URL_STREAM_ID));
+ test_started_ = true;
+
+#ifdef OS_WIN
+ HWND window_handle = reinterpret_cast<HWND>(pNPWindow->window);
+ if (!::GetProp(window_handle, L"Plugin_Instance")) {
+ // TODO: this propery leaks.
+ ::SetProp(window_handle, L"Plugin_Instance", this);
+ // We attempt to retreive the NPObject for the plugin instance identified
+ // by the NPObjectLifetimeTestInstance2 class as it may not have been
+ // instantiated yet.
+ SetTimer(window_handle, kNPNEvaluateTimerID, kNPNEvaluateTimerElapse,
+ TimerProc);
+ }
+ window_ = window_handle;
+#endif
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+#ifdef OS_WIN
+void CALLBACK ExecuteGetJavascriptUrlTest::TimerProc(
+ HWND window, UINT message, UINT timer_id, unsigned long elapsed_time) {
+ ExecuteGetJavascriptUrlTest* this_instance =
+ reinterpret_cast<ExecuteGetJavascriptUrlTest*>
+ (::GetProp(window, L"Plugin_Instance"));
+
+ ::RemoveProp(window, L"Plugin_Instance");
+
+ NPObject *window_obj = NULL;
+ this_instance->HostFunctions()->getvalue(this_instance->id(),
+ NPNVWindowNPObject,
+ &window_obj);
+ if (!window_obj) {
+ this_instance->SetError("Failed to get NPObject for plugin instance2");
+ this_instance->SignalTestCompleted();
+ return;
+ }
+
+ std::string script = "javascript:window.location";
+ NPString script_string;
+ script_string.UTF8Characters = script.c_str();
+ script_string.UTF8Length = static_cast<unsigned int>(script.length());
+ NPVariant result_var;
+
+ this_instance->npn_evaluate_context_ = true;
+ NPError result = this_instance->HostFunctions()->evaluate(
+ this_instance->id(), window_obj, &script_string, &result_var);
+ this_instance->npn_evaluate_context_ = false;
+}
+#endif
+
+NPError ExecuteGetJavascriptUrlTest::NewStream(NPMIMEType type,
+ NPStream* stream,
+ NPBool seekable,
+ uint16* stype) {
+ if (stream == NULL) {
+ SetError("NewStream got null stream");
+ return NPERR_INVALID_PARAM;
+ }
+
+ if (npn_evaluate_context_) {
+ SetError("NewStream received in context of NPN_Evaluate");
+ return NPERR_NO_ERROR;
+ }
+
+ COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
+ cast_validity_check);
+ unsigned long stream_id = reinterpret_cast<unsigned long>(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+ return NPERR_NO_ERROR;
+}
+
+int32 ExecuteGetJavascriptUrlTest::WriteReady(NPStream *stream) {
+ if (npn_evaluate_context_) {
+ SetError("WriteReady received in context of NPN_Evaluate");
+ return NPERR_NO_ERROR;
+ }
+ return STREAM_CHUNK;
+}
+
+int32 ExecuteGetJavascriptUrlTest::Write(NPStream *stream, int32 offset,
+ int32 len, void *buffer) {
+ if (stream == NULL) {
+ SetError("Write got null stream");
+ return -1;
+ }
+ if (len < 0 || len > STREAM_CHUNK) {
+ SetError("Write got bogus stream chunk size");
+ return -1;
+ }
+
+ if (npn_evaluate_context_) {
+ SetError("Write received in context of NPN_Evaluate");
+ return len;
+ }
+
+ COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
+ cast_validity_check);
+ unsigned long stream_id = reinterpret_cast<unsigned long>(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ self_url_.append(static_cast<char*>(buffer), len);
+ break;
+ default:
+ SetError("Unexpected write callback");
+ break;
+ }
+ // Pretend that we took all the data.
+ return len;
+}
+
+
+NPError ExecuteGetJavascriptUrlTest::DestroyStream(NPStream *stream,
+ NPError reason) {
+ if (stream == NULL) {
+ SetError("NewStream got null stream");
+ return NPERR_INVALID_PARAM;
+ }
+
+#ifdef OS_WIN
+ KillTimer(window_, kNPNEvaluateTimerID);
+#endif
+
+ if (npn_evaluate_context_) {
+ SetError("DestroyStream received in context of NPN_Evaluate");
+ return NPERR_NO_ERROR;
+ }
+
+ COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
+ cast_validity_check);
+ unsigned long stream_id = reinterpret_cast<unsigned long>(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ // don't care
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+ return NPERR_NO_ERROR;
+}
+
+void ExecuteGetJavascriptUrlTest::URLNotify(const char* url, NPReason reason,
+ void* data) {
+ COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(data),
+ cast_validity_check);
+
+ if (npn_evaluate_context_) {
+ SetError("URLNotify received in context of NPN_Evaluate");
+ return;
+ }
+
+ unsigned long stream_id = reinterpret_cast<unsigned long>(data);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ if (strcmp(url, SELF_URL) != 0)
+ SetError("URLNotify reported incorrect url for SELF_URL");
+ if (self_url_.empty())
+ SetError("Failed to obtain window location.");
+ SignalTestCompleted();
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_get_javascript_url_test.h b/webkit/plugins/npapi/test/plugin_get_javascript_url_test.h
new file mode 100644
index 0000000..9aab3f9
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_get_javascript_url_test.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_PLUGINS_TEST_PLUGIN_GET_JAVASCRIPT_URL_H_
+#define WEBKIT_PLUGINS_NPAPI_PLUGINS_TEST_PLUGIN_GET_JAVASCRIPT_URL_H_
+
+#include "webkit/plugins/npapi/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// This class tests NPP_GetURLNotify for a javascript URL with _top
+// as the target frame.
+class ExecuteGetJavascriptUrlTest : public PluginTest {
+ public:
+ // Constructor.
+ ExecuteGetJavascriptUrlTest(NPP id, NPNetscapeFuncs *host_functions);
+ //
+ // NPAPI functions
+ //
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+ virtual NPError NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype);
+ virtual int32 WriteReady(NPStream *stream);
+ virtual int32 Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer);
+ virtual NPError DestroyStream(NPStream *stream, NPError reason);
+ virtual void URLNotify(const char* url, NPReason reason, void* data);
+
+ private:
+#if defined(OS_WIN)
+ static void CALLBACK TimerProc(HWND window, UINT message, UINT timer_id,
+ unsigned long elapsed_time);
+#endif
+ bool test_started_;
+ // This flag is set to true in the context of the NPN_Evaluate call.
+ bool npn_evaluate_context_;
+ std::string self_url_;
+
+#if defined(OS_WIN)
+ HWND window_;
+#endif
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_PLUGINS_TEST_PLUGIN_GET_JAVASCRIPT_URL_H_
diff --git a/webkit/plugins/npapi/test/plugin_geturl_test.cc b/webkit/plugins/npapi/test/plugin_geturl_test.cc
new file mode 100644
index 0000000..850a0b5
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_geturl_test.cc
@@ -0,0 +1,414 @@
+// Copyright (c) 2010 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 "webkit/plugins/npapi/test/plugin_geturl_test.h"
+
+#include <stdio.h>
+
+#include "base/basictypes.h"
+#include "base/file_util.h"
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
+
+// url for "self". The %22%22 is to make a statement for javascript to
+// evaluate and return.
+#define SELF_URL "javascript:window.location+\"\""
+
+// The identifier for the self url stream.
+#define SELF_URL_STREAM_ID 1
+
+// The identifier for the fetched url stream.
+#define FETCHED_URL_STREAM_ID 2
+
+// url for testing GetURL with a bogus URL.
+#define BOGUS_URL "bogoproto:///x:/asdf.xysdhffieasdf.asdhj/"
+
+// url for testing redirect notifications sent to plugins.
+#define REDIRECT_SRC_URL \
+ "http://mock.http/npapi/plugin_read_page_redirect_src.html"
+
+// The notification id for the redirect notification url.
+#define REDIRECT_SRC_URL_NOTIFICATION_ID 4
+
+// The identifier for the bogus url stream.
+#define BOGUS_URL_STREAM_ID 3
+
+// The maximum chunk size of stream data.
+#define STREAM_CHUNK 197
+
+namespace NPAPIClient {
+
+PluginGetURLTest::PluginGetURLTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ tests_started_(false),
+ tests_in_progress_(0),
+ test_file_(NULL),
+ expect_404_response_(false),
+ npn_evaluate_context_(false),
+ handle_url_redirects_(false),
+ received_url_redirect_notification_(false) {
+}
+
+NPError PluginGetURLTest::New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved) {
+ const char* page_not_found_url = GetArgValue("page_not_found_url", argc,
+ argn, argv);
+ if (page_not_found_url) {
+ page_not_found_url_ = page_not_found_url;
+ expect_404_response_ = true;
+ }
+
+ const char* fail_write_url = GetArgValue("fail_write_url", argc,
+ argn, argv);
+ if (fail_write_url) {
+ fail_write_url_ = fail_write_url;
+ }
+
+ const char* referrer_target_url = GetArgValue("ref_target", argc,
+ argn, argv);
+ if (referrer_target_url) {
+ referrer_target_url_ = referrer_target_url;
+ }
+
+ if (!base::strcasecmp(GetArgValue("name", argc, argn, argv),
+ "geturlredirectnotify")) {
+ handle_url_redirects_ = true;
+ }
+ return PluginTest::New(mode, argc, argn, argv, saved);
+}
+
+NPError PluginGetURLTest::SetWindow(NPWindow* pNPWindow) {
+ if (pNPWindow->window == NULL)
+ return NPERR_NO_ERROR;
+
+ if (!tests_started_) {
+ tests_started_ = true;
+
+ tests_in_progress_++;
+
+ if (expect_404_response_) {
+ HostFunctions()->geturl(id(), page_not_found_url_.c_str(), NULL);
+ return NPERR_NO_ERROR;
+ } else if (!fail_write_url_.empty()) {
+ HostFunctions()->geturl(id(), fail_write_url_.c_str(), NULL);
+ return NPERR_NO_ERROR;
+ } else if (!referrer_target_url_.empty()) {
+ HostFunctions()->pushpopupsenabledstate(id(), true);
+ HostFunctions()->geturl(id(), referrer_target_url_.c_str(), "_blank");
+ HostFunctions()->poppopupsenabledstate(id());
+ return NPERR_NO_ERROR;
+ } else if (handle_url_redirects_) {
+ HostFunctions()->geturlnotify(
+ id(), REDIRECT_SRC_URL, NULL,
+ reinterpret_cast<void*>(REDIRECT_SRC_URL_NOTIFICATION_ID));
+ return NPERR_NO_ERROR;
+ }
+
+ std::string url = SELF_URL;
+ HostFunctions()->geturlnotify(id(), url.c_str(), NULL,
+ reinterpret_cast<void*>(SELF_URL_STREAM_ID));
+
+ tests_in_progress_++;
+ std::string bogus_url = BOGUS_URL;
+ HostFunctions()->geturlnotify(id(), bogus_url.c_str(), NULL,
+ reinterpret_cast<void*>(BOGUS_URL_STREAM_ID));
+ }
+ return NPERR_NO_ERROR;
+}
+
+NPError PluginGetURLTest::NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype) {
+ if (stream == NULL) {
+ SetError("NewStream got null stream");
+ return NPERR_INVALID_PARAM;
+ }
+
+ if (test_completed()) {
+ return PluginTest::NewStream(type, stream, seekable, stype);
+ }
+
+ if (!referrer_target_url_.empty()) {
+ return NPERR_NO_ERROR;
+ }
+
+ COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
+ cast_validity_check);
+
+ if (expect_404_response_) {
+ NPObject *window_obj = NULL;
+ HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window_obj);
+ if (!window_obj) {
+ SetError("Failed to get NPObject for plugin instance2");
+ SignalTestCompleted();
+ return NPERR_NO_ERROR;
+ }
+
+ std::string script = "javascript:alert('Hi there from plugin');";
+ NPString script_string;
+ script_string.UTF8Characters = script.c_str();
+ script_string.UTF8Length = static_cast<unsigned int>(script.length());
+ NPVariant result_var;
+
+ npn_evaluate_context_ = true;
+ HostFunctions()->evaluate(id(), window_obj, &script_string, &result_var);
+ npn_evaluate_context_ = false;
+ return NPERR_NO_ERROR;
+ }
+
+ if (!fail_write_url_.empty()) {
+ return NPERR_NO_ERROR;
+ }
+
+
+ unsigned long stream_id = reinterpret_cast<unsigned long>(
+ stream->notifyData);
+
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ break;
+ case FETCHED_URL_STREAM_ID:
+ {
+ std::string filename = self_url_;
+ if (filename.find("file:///", 0) != 0) {
+ SetError("Test expects a file-url.");
+ break;
+ }
+
+ // TODO(evanm): use the net:: functions to convert file:// URLs to
+ // on-disk file paths. But it probably doesn't actually matter in
+ // this test.
+
+#if defined(OS_WIN)
+ filename = filename.substr(8); // remove "file:///"
+ // Assume an ASCII path on Windows.
+ FilePath path = FilePath(ASCIIToWide(filename));
+#else
+ filename = filename.substr(7); // remove "file://"
+ FilePath path = FilePath(filename);
+#endif
+
+ test_file_ = file_util::OpenFile(path, "r");
+ if (!test_file_) {
+ SetError("Could not open source file");
+ }
+ }
+ break;
+ case BOGUS_URL_STREAM_ID:
+ SetError("Unexpected NewStream for BOGUS_URL");
+ break;
+ case REDIRECT_SRC_URL_NOTIFICATION_ID:
+ SetError("Should not redirect to URL when plugin denied it.");
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+ return NPERR_NO_ERROR;
+}
+
+int32 PluginGetURLTest::WriteReady(NPStream *stream) {
+ if (test_completed()) {
+ return PluginTest::WriteReady(stream);
+ }
+
+ if (!referrer_target_url_.empty()) {
+ return STREAM_CHUNK;
+ }
+
+ COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
+ cast_validity_check);
+ unsigned long stream_id = reinterpret_cast<unsigned long>(
+ stream->notifyData);
+ if (stream_id == BOGUS_URL_STREAM_ID)
+ SetError("Received WriteReady for BOGUS_URL");
+
+ return STREAM_CHUNK;
+}
+
+int32 PluginGetURLTest::Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer) {
+ if (test_completed()) {
+ return PluginTest::Write(stream, offset, len, buffer);
+ }
+
+ if (!fail_write_url_.empty()) {
+ SignalTestCompleted();
+ return -1;
+ }
+
+ if (!referrer_target_url_.empty()) {
+ return len;
+ }
+
+ if (stream == NULL) {
+ SetError("Write got null stream");
+ return -1;
+ }
+ if (len < 0 || len > STREAM_CHUNK) {
+ SetError("Write got bogus stream chunk size");
+ return -1;
+ }
+
+ COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
+ cast_validity_check);
+ unsigned long stream_id = reinterpret_cast<unsigned long>(
+ stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ self_url_.append(static_cast<char*>(buffer), len);
+ break;
+ case FETCHED_URL_STREAM_ID:
+ {
+ char read_buffer[STREAM_CHUNK];
+ int32 bytes = fread(read_buffer, 1, len, test_file_);
+ // Technically, fread could return fewer than len
+ // bytes. But this is not likely.
+ if (bytes != len)
+ SetError("Did not read correct bytelength from source file");
+ if (memcmp(read_buffer, buffer, len))
+ SetError("Content mismatch between data and source!");
+ }
+ break;
+ case BOGUS_URL_STREAM_ID:
+ SetError("Unexpected write callback for BOGUS_URL");
+ break;
+ default:
+ SetError("Unexpected write callback");
+ break;
+ }
+ // Pretend that we took all the data.
+ return len;
+}
+
+
+NPError PluginGetURLTest::DestroyStream(NPStream *stream, NPError reason) {
+ if (test_completed()) {
+ return PluginTest::DestroyStream(stream, reason);
+ }
+
+ if (stream == NULL) {
+ SetError("NewStream got null stream");
+ return NPERR_INVALID_PARAM;
+ }
+
+ COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
+ cast_validity_check);
+
+ if (expect_404_response_) {
+ if (npn_evaluate_context_) {
+ SetError("Received destroyStream in the context of NPN_Evaluate.");
+ }
+
+ SignalTestCompleted();
+ return NPERR_NO_ERROR;
+ }
+
+ if (!referrer_target_url_.empty()) {
+ return NPERR_NO_ERROR;
+ }
+
+ unsigned long stream_id =
+ reinterpret_cast<unsigned long>(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ // don't care
+ break;
+ case FETCHED_URL_STREAM_ID:
+ {
+ char read_buffer[STREAM_CHUNK];
+ size_t bytes = fread(read_buffer, 1, sizeof(read_buffer), test_file_);
+ if (bytes != 0)
+ SetError("Data and source mismatch on length");
+ file_util::CloseFile(test_file_);
+ }
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+ return NPERR_NO_ERROR;
+}
+
+void PluginGetURLTest::StreamAsFile(NPStream* stream, const char* fname) {
+ if (stream == NULL) {
+ SetError("NewStream got null stream");
+ return;
+ }
+
+ COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(stream->notifyData),
+ cast_validity_check);
+ unsigned long stream_id =
+ reinterpret_cast<unsigned long>(stream->notifyData);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ // don't care
+ break;
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+}
+
+void PluginGetURLTest::URLNotify(const char* url, NPReason reason, void* data) {
+ if (!tests_in_progress_) {
+ SetError("URLNotify received after tests completed");
+ return;
+ }
+
+ if (!url) {
+ SetError("URLNotify received NULL url");
+ return;
+ }
+
+ COMPILE_ASSERT(sizeof(unsigned long) <= sizeof(data), cast_validity_check);
+ unsigned long stream_id = reinterpret_cast<unsigned long>(data);
+ switch (stream_id) {
+ case SELF_URL_STREAM_ID:
+ if (strcmp(url, SELF_URL) != 0)
+ SetError("URLNotify reported incorrect url for SELF_URL");
+
+ // We have our stream url. Go fetch it.
+ HostFunctions()->geturlnotify(id(), self_url_.c_str(), NULL,
+ reinterpret_cast<void*>(FETCHED_URL_STREAM_ID));
+ break;
+ case FETCHED_URL_STREAM_ID:
+ if (!url || strcmp(url, self_url_.c_str()) != 0)
+ SetError("URLNotify reported incorrect url for FETCHED_URL");
+ tests_in_progress_--;
+ break;
+ case BOGUS_URL_STREAM_ID:
+ if (reason != NPRES_NETWORK_ERR) {
+ std::string err = "BOGUS_URL received unexpected URLNotify status: ";
+ err.append(base::IntToString(reason));
+ SetError(err);
+ }
+ tests_in_progress_--;
+ break;
+ case REDIRECT_SRC_URL_NOTIFICATION_ID: {
+ if (!received_url_redirect_notification_) {
+ SetError("Failed to receive URLRedirect notification");
+ }
+ tests_in_progress_--;
+ break;
+ }
+ default:
+ SetError("Unexpected NewStream callback");
+ break;
+ }
+
+ if (tests_in_progress_ == 0)
+ SignalTestCompleted();
+}
+
+void PluginGetURLTest::URLRedirectNotify(const char* url,
+ int32_t status,
+ void* notify_data) {
+ if (!base::strcasecmp(url, "http://mock.http/npapi/plugin_read_page.html")) {
+ received_url_redirect_notification_ = true;
+ // Disallow redirect notification.
+ HostFunctions()->urlredirectresponse(id(), notify_data, false);
+ }
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_geturl_test.h b/webkit/plugins/npapi/test/plugin_geturl_test.h
new file mode 100644
index 0000000..79c623b
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_geturl_test.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_GETURL_TEST_H_
+#define WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_GETURL_TEST_H_
+
+#include <stdio.h>
+
+#include "webkit/plugins/npapi/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// The PluginGetURLTest test functionality of the NPN_GetURL
+// and NPN_GetURLNotify methods.
+//
+// This test first discovers it's URL by sending a GetURL request
+// for 'javascript:top.location'. After receiving that, the
+// test will request the url itself (again via GetURL).
+class PluginGetURLTest : public PluginTest {
+ public:
+ // Constructor.
+ PluginGetURLTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ //
+ // NPAPI functions
+ //
+ virtual NPError New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved);
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+ virtual NPError NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype);
+ virtual int32 WriteReady(NPStream *stream);
+ virtual int32 Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer);
+ virtual NPError DestroyStream(NPStream *stream, NPError reason);
+ virtual void StreamAsFile(NPStream* stream, const char* fname);
+ virtual void URLNotify(const char* url, NPReason reason, void* data);
+ virtual void URLRedirectNotify(const char* url, int32_t status,
+ void* notify_data);
+
+ private:
+ bool tests_started_;
+ int tests_in_progress_;
+ std::string self_url_;
+ FILE* test_file_;
+ bool expect_404_response_;
+ // This flag is set to true in the context of the NPN_Evaluate call.
+ bool npn_evaluate_context_;
+ // The following two flags handle URL redirect notifications received by
+ // plugins.
+ bool handle_url_redirects_;
+ bool received_url_redirect_notification_;
+ std::string page_not_found_url_;
+ std::string fail_write_url_;
+ std::string referrer_target_url_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_GETURL_TEST_H_
diff --git a/webkit/plugins/npapi/test/plugin_javascript_open_popup.cc b/webkit/plugins/npapi/test/plugin_javascript_open_popup.cc
new file mode 100644
index 0000000..583a55e
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_javascript_open_popup.cc
@@ -0,0 +1,103 @@
+// Copyright (c) 2010 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 "build/build_config.h"
+#include "webkit/plugins/npapi/test/plugin_javascript_open_popup.h"
+
+#if defined(USE_X11)
+#include "third_party/npapi/bindings/npapi_x11.h"
+#endif
+#include "webkit/plugins/npapi/test/plugin_client.h"
+
+namespace NPAPIClient {
+
+ExecuteJavascriptOpenPopupWithPluginTest::
+ ExecuteJavascriptOpenPopupWithPluginTest(NPP id,
+ NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ popup_window_test_started_(false) {
+}
+
+int16 ExecuteJavascriptOpenPopupWithPluginTest::SetWindow(
+ NPWindow* window) {
+ if (window->window == NULL)
+ return NPERR_NO_ERROR;
+
+ if (!popup_window_test_started_) {
+ popup_window_test_started_ = true;
+ HostFunctions()->geturl(
+ id(), "popup_window_with_target_plugin.html", "_blank");
+ }
+ return NPERR_NO_ERROR;
+}
+
+// ExecuteJavascriptPopupWindowTargetPluginTest member defines.
+ExecuteJavascriptPopupWindowTargetPluginTest::
+ ExecuteJavascriptPopupWindowTargetPluginTest(
+ NPP id, NPNetscapeFuncs* host_functions)
+ : PluginTest(id, host_functions),
+ test_completed_(false) {
+}
+
+int16 ExecuteJavascriptPopupWindowTargetPluginTest::SetWindow(
+ NPWindow* window) {
+ if (window->window == NULL)
+ return NPERR_NO_ERROR;
+
+ if (!test_completed_) {
+ if (CheckWindow(window)) {
+ SignalTestCompleted();
+ test_completed_ = true;
+ }
+ }
+ return PluginTest::SetWindow(window);
+}
+
+#if defined(OS_WIN)
+bool ExecuteJavascriptPopupWindowTargetPluginTest::CheckWindow(
+ NPWindow* window) {
+ HWND window_handle = reinterpret_cast<HWND>(window->window);
+
+ if (IsWindow(window_handle)) {
+ HWND parent_window = GetParent(window_handle);
+ if (!IsWindow(parent_window) || parent_window == GetDesktopWindow())
+ SetError("Windowed plugin instantiated with NULL parent");
+ return true;
+ }
+
+ return false;
+}
+
+#elif defined(USE_X11)
+// This code blindly follows the same sorts of verifications done on
+// the Windows side. Does it make sense on X? Maybe not really, but
+// it can't hurt to do extra validations.
+bool ExecuteJavascriptPopupWindowTargetPluginTest::CheckWindow(
+ NPWindow* window) {
+ Window xwindow = reinterpret_cast<Window>(window->window);
+ // Grab a pointer to the extra SetWindow data so we can grab the display out.
+ NPSetWindowCallbackStruct* extra =
+ static_cast<NPSetWindowCallbackStruct*>(window->ws_info);
+
+ if (xwindow) {
+ Window root, parent;
+ Status status = XQueryTree(extra->display, xwindow, &root, &parent,
+ NULL, NULL); // NULL children info.
+ DCHECK(status != 0);
+ if (!parent || parent == root)
+ SetError("Windowed plugin instantiated with NULL parent");
+ return true;
+ }
+
+ return false;
+}
+#elif defined(OS_MACOSX)
+bool ExecuteJavascriptPopupWindowTargetPluginTest::CheckWindow(
+ NPWindow* window) {
+ // TODO(port) scaffolding--replace with a real test once NPWindow is done.
+ return false;
+}
+#endif
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_javascript_open_popup.h b/webkit/plugins/npapi/test/plugin_javascript_open_popup.h
new file mode 100644
index 0000000..6381d25
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_javascript_open_popup.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_JAVASCRIPT_OPEN_POPUP_H_
+#define WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_JAVASCRIPT_OPEN_POPUP_H_
+
+#include "webkit/plugins/npapi/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// This class tests the case where a windowed plugin instance is
+// instantiated in a popup window. The plugin instance needs to
+// have a valid parent window.
+class ExecuteJavascriptOpenPopupWithPluginTest : public PluginTest {
+ public:
+ // Constructor.
+ ExecuteJavascriptOpenPopupWithPluginTest(
+ NPP id, NPNetscapeFuncs *host_functions);
+ // NPAPI SetWindow handler.
+ virtual NPError SetWindow(NPWindow* window);
+
+ private:
+ bool popup_window_test_started_;
+};
+
+// This class represents a windowed plugin instance instantiated within a
+// popup window. It verifies that the plugin instance has a valid parent.
+class ExecuteJavascriptPopupWindowTargetPluginTest : public PluginTest {
+ public:
+ ExecuteJavascriptPopupWindowTargetPluginTest(
+ NPP id, NPNetscapeFuncs *host_functions);
+ // NPAPI SetWindow handler.
+ virtual NPError SetWindow(NPWindow* window);
+
+ private:
+ // Do a platform-specific validation of the passed-in |window|.
+ // E.g. on Windows, verifies window->window is a reasonable HWND.
+ // Returns true if the test should be marked complete.
+ bool CheckWindow(NPWindow* window);
+
+ bool test_completed_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_JAVASCRIPT_OPEN_POPUP_H_
diff --git a/webkit/plugins/npapi/test/plugin_new_fails_test.cc b/webkit/plugins/npapi/test/plugin_new_fails_test.cc
new file mode 100644
index 0000000..71cff01
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_new_fails_test.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2010 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 "webkit/plugins/npapi/test/plugin_new_fails_test.h"
+
+namespace NPAPIClient {
+
+NewFailsTest::NewFailsTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+NPError NewFailsTest::New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved) {
+ return NPERR_GENERIC_ERROR;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_new_fails_test.h b/webkit/plugins/npapi/test/plugin_new_fails_test.h
new file mode 100644
index 0000000..334323e
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_new_fails_test.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_PLUGIN_NEW_FAILS_TEST_H_
+#define WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_PLUGIN_NEW_FAILS_TEST_H_
+
+#include "webkit/plugins/npapi/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+class NewFailsTest : public PluginTest {
+ public:
+ NewFailsTest(NPP id, NPNetscapeFuncs *host_functions);
+ virtual NPError New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_PLUGIN_NPP_NEW_FAILS_TEST_H_
diff --git a/webkit/plugins/npapi/test/plugin_npobject_lifetime_test.cc b/webkit/plugins/npapi/test/plugin_npobject_lifetime_test.cc
new file mode 100644
index 0000000..f493238
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_npobject_lifetime_test.cc
@@ -0,0 +1,174 @@
+// Copyright (c) 2010 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 "webkit/plugins/npapi/test/plugin_npobject_lifetime_test.h"
+
+namespace NPAPIClient {
+
+const int kNPObjectLifetimeTimer = 100;
+const int kNPObjectLifetimeTimerElapse = 2000;
+
+NPObject* NPObjectLifetimeTestInstance2::plugin_instance_object_ = NULL;
+
+NPObjectDeletePluginInNPN_Evaluate*
+ NPObjectDeletePluginInNPN_Evaluate::g_npn_evaluate_test_instance_ = NULL;
+
+NPObjectLifetimeTest::NPObjectLifetimeTest(NPP id,
+ NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ other_plugin_instance_object_(NULL),
+ timer_id_(0) {
+}
+
+NPError NPObjectLifetimeTest::SetWindow(NPWindow* pNPWindow) {
+ if (pNPWindow->window == NULL)
+ return NPERR_NO_ERROR;
+
+ HWND window_handle = reinterpret_cast<HWND>(pNPWindow->window);
+ if (!::GetProp(window_handle, L"Plugin_Instance")) {
+ // TODO: this propery leaks.
+ ::SetProp(window_handle, L"Plugin_Instance", this);
+ // We attempt to retreive the NPObject for the plugin instance identified
+ // by the NPObjectLifetimeTestInstance2 class as it may not have been
+ // instantiated yet.
+ timer_id_ = SetTimer(window_handle, kNPObjectLifetimeTimer,
+ kNPObjectLifetimeTimerElapse, TimerProc);
+ }
+ return NPERR_NO_ERROR;
+}
+
+void CALLBACK NPObjectLifetimeTest::TimerProc(
+ HWND window, UINT message, UINT timer_id,
+ unsigned long elapsed_milli_seconds) {
+
+ NPObjectLifetimeTest* this_instance =
+ reinterpret_cast<NPObjectLifetimeTest*>
+ (::GetProp(window, L"Plugin_Instance"));
+ KillTimer(window, this_instance->timer_id_);
+ ::RemoveProp(window, L"Plugin_Instance");
+
+ this_instance->timer_id_ = 0;
+
+ this_instance->other_plugin_instance_object_ =
+ NPObjectLifetimeTestInstance2::plugin_instance_object_;
+ this_instance->HostFunctions()->retainobject(
+ this_instance->other_plugin_instance_object_);
+
+ NPString script;
+ script.UTF8Characters = "javascript:DeleteSecondPluginInstance()";
+ script.UTF8Length = static_cast<uint32_t>(strlen(script.UTF8Characters));
+
+ this_instance->HostFunctions()->geturlnotify(
+ this_instance->id(), "javascript:DeleteSecondPluginInstance()", NULL,
+ reinterpret_cast<void*>(1));
+}
+
+void NPObjectLifetimeTest::URLNotify(const char* url, NPReason reason,
+ void* data) {
+ // Create a "location" identifier.
+ NPIdentifier identifier = HostFunctions()->getstringidentifier("location");
+ // Declare a local variant value.
+ NPVariant variantValue;
+ // Get the location property from the window object (which is another object).
+ bool b1 = HostFunctions()->getproperty(id(), other_plugin_instance_object_,
+ identifier, &variantValue );
+ HostFunctions()->releaseobject(other_plugin_instance_object_);
+ other_plugin_instance_object_ = NULL;
+ // If this test failed, then we'd have crashed by now.
+ SignalTestCompleted();
+}
+
+NPObjectLifetimeTestInstance2::NPObjectLifetimeTestInstance2(
+ NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+NPObjectLifetimeTestInstance2::~NPObjectLifetimeTestInstance2() {
+ if (plugin_instance_object_) {
+ HostFunctions()->releaseobject(plugin_instance_object_);
+ plugin_instance_object_ = NULL;
+ }
+}
+
+NPError NPObjectLifetimeTestInstance2::SetWindow(NPWindow* pNPWindow) {
+ if (pNPWindow->window == NULL)
+ return NPERR_NO_ERROR;
+
+ if (!plugin_instance_object_) {
+ if (!HostFunctions()->getvalue(id(), NPNVWindowNPObject,
+ &plugin_instance_object_)) {
+ SetError("Failed to get NPObject for plugin instance2");
+ SignalTestCompleted();
+ return NPERR_GENERIC_ERROR;
+ }
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+
+NPObjectDeletePluginInNPN_Evaluate::NPObjectDeletePluginInNPN_Evaluate(
+ NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ plugin_instance_object_(NULL),
+ timer_id_(0) {
+ g_npn_evaluate_test_instance_ = this;
+}
+
+NPObjectDeletePluginInNPN_Evaluate::~NPObjectDeletePluginInNPN_Evaluate() {
+ if (plugin_instance_object_) {
+ HostFunctions()->releaseobject(plugin_instance_object_);
+ plugin_instance_object_ = NULL;
+ }
+}
+
+NPError NPObjectDeletePluginInNPN_Evaluate::SetWindow(NPWindow* np_window) {
+ if (np_window->window == NULL)
+ return NPERR_NO_ERROR;
+
+ HWND window_handle = reinterpret_cast<HWND>(np_window->window);
+ // We setup a timerproc to invoke NPN_Evaluate to destroy this plugin
+ // instance. This is to ensure that we don't destroy the plugin instance
+ // while it is being used in webkit as this leads to crashes and is a
+ // more accurate representation of the renderer crash as described in
+ // http://b/issue?id=1134683.
+ if (!timer_id_) {
+ timer_id_ = SetTimer(window_handle, kNPObjectLifetimeTimer,
+ kNPObjectLifetimeTimerElapse, TimerProc);
+ }
+ return NPERR_NO_ERROR;
+}
+
+void CALLBACK NPObjectDeletePluginInNPN_Evaluate::TimerProc(
+ HWND window, UINT message, UINT timer_id,
+ unsigned long elapsed_milli_seconds) {
+
+ KillTimer(window, g_npn_evaluate_test_instance_->timer_id_);
+ g_npn_evaluate_test_instance_->timer_id_ = 0;
+ NPObject *window_obj = NULL;
+ g_npn_evaluate_test_instance_->HostFunctions()->getvalue(
+ g_npn_evaluate_test_instance_->id(), NPNVWindowNPObject,
+ &window_obj);
+
+ if (!window_obj) {
+ g_npn_evaluate_test_instance_->SetError(
+ "Failed to get NPObject for plugin instance2");
+ g_npn_evaluate_test_instance_->SignalTestCompleted();
+ return;
+ }
+
+ std::string script = "javascript:DeletePluginWithinScript()";
+ NPString script_string;
+ script_string.UTF8Characters = script.c_str();
+ script_string.UTF8Length =
+ static_cast<unsigned int>(script.length());
+
+ NPVariant result_var;
+ bool result = g_npn_evaluate_test_instance_->HostFunctions()->evaluate(
+ g_npn_evaluate_test_instance_->id(), window_obj,
+ &script_string, &result_var);
+ // If this test failed we would have crashed by now.
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_npobject_lifetime_test.h b/webkit/plugins/npapi/test/plugin_npobject_lifetime_test.h
new file mode 100644
index 0000000..12cf4e2
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_npobject_lifetime_test.h
@@ -0,0 +1,82 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_NPOBJECT_LIFETIME_TEST_H_
+#define WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_NPOBJECT_LIFETIME_TEST_H_
+
+#include "build/build_config.h"
+#include "webkit/plugins/npapi/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// The NPObjectLifeTime class tests the case where a plugin has an NPObject
+// which points to a different plugin instance on a different frame in the
+// page and whether refcounts on this npobject are valid when the source frame
+// is destroyed.
+class NPObjectLifetimeTest : public PluginTest {
+ public:
+ // Constructor.
+ NPObjectLifetimeTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ // NPAPI SetWindow handler.
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+
+ virtual void URLNotify(const char* url, NPReason reason, void* data);
+
+ protected:
+ NPObject* other_plugin_instance_object_;
+
+#if defined(OS_WIN)
+ static void CALLBACK TimerProc(HWND window, UINT message, UINT timer_id,
+ unsigned long elapsed_milli_seconds);
+ UINT_PTR timer_id_;
+#endif
+ DISALLOW_IMPLICIT_CONSTRUCTORS(NPObjectLifetimeTest);
+};
+
+// The NPObjectLifetimeTestInstance2 class represents the plugin instance
+// which is deleted by the NPObjectLifeTime class via a javascript function.
+class NPObjectLifetimeTestInstance2 : public PluginTest {
+ public:
+ // Constructor.
+ NPObjectLifetimeTestInstance2(NPP id, NPNetscapeFuncs *host_functions);
+ ~NPObjectLifetimeTestInstance2();
+
+ // NPAPI SetWindow handler.
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+ protected:
+ static NPObject* plugin_instance_object_;
+ friend class NPObjectLifetimeTest;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(NPObjectLifetimeTestInstance2);
+};
+
+// The NPObjectLifeTime class tests the case where a plugin instance is
+// destroyed in NPN_Evaluate
+class NPObjectDeletePluginInNPN_Evaluate : public PluginTest {
+ public:
+ // Constructor.
+ NPObjectDeletePluginInNPN_Evaluate(NPP id, NPNetscapeFuncs *host_functions);
+ ~NPObjectDeletePluginInNPN_Evaluate();
+
+ // NPAPI SetWindow handler.
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+
+ protected:
+ NPObject* plugin_instance_object_;
+#if defined(OS_WIN)
+ static void CALLBACK TimerProc(HWND window, UINT message, UINT timer_id,
+ unsigned long elapsed_milli_seconds);
+ UINT_PTR timer_id_;
+#endif
+
+ private:
+ static NPObjectDeletePluginInNPN_Evaluate* g_npn_evaluate_test_instance_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(NPObjectDeletePluginInNPN_Evaluate);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_NPOBJECT_LIFETIME_TEST_H_
diff --git a/webkit/plugins/npapi/test/plugin_npobject_proxy_test.cc b/webkit/plugins/npapi/test/plugin_npobject_proxy_test.cc
new file mode 100644
index 0000000..c9cd27f
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_npobject_proxy_test.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2010 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 "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+#if defined(OS_WIN)
+#define STRSAFE_NO_DEPRECATE
+#include <strsafe.h>
+#endif
+#include "webkit/plugins/npapi/test/plugin_npobject_proxy_test.h"
+
+namespace NPAPIClient {
+
+NPObjectProxyTest::NPObjectProxyTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+NPError NPObjectProxyTest::SetWindow(NPWindow* pNPWindow) {
+ if (pNPWindow->window == NULL)
+ return NPERR_NO_ERROR;
+
+ NPIdentifier document_id = HostFunctions()->getstringidentifier("document");
+ NPIdentifier create_text_node_id = HostFunctions()->getstringidentifier("createTextNode");
+ NPIdentifier append_child_id = HostFunctions()->getstringidentifier("appendChild");
+
+ NPVariant docv;
+ NPObject *window_obj = NULL;
+ HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window_obj);
+
+ HostFunctions()->getproperty(id(), window_obj, document_id, &docv);
+ NPObject *doc = NPVARIANT_TO_OBJECT(docv);
+
+ NPVariant strv;
+ MSVC_SUPPRESS_WARNING(4267);
+ STRINGZ_TO_NPVARIANT("div", strv);
+
+ NPVariant textv;
+ HostFunctions()->invoke(id(), doc, create_text_node_id, &strv, 1, &textv);
+
+ NPVariant v;
+ HostFunctions()->invoke(id(), doc, append_child_id, &textv, 1, &v);
+
+ // If this test failed, then we'd have crashed by now.
+ SignalTestCompleted();
+
+ return NPERR_NO_ERROR;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_npobject_proxy_test.h b/webkit/plugins/npapi/test/plugin_npobject_proxy_test.h
new file mode 100644
index 0000000..8585d0f
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_npobject_proxy_test.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_NPOBJECT_PROXY_TEST_H_
+#define WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_NPOBJECT_PROXY_TEST_H_
+
+#include "webkit/plugins/npapi/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// The NPObjectProxyTest tests that when we proxy an NPObject that is itself
+// a proxy, we don't create a new proxy but instead just use the original
+// pointer.
+
+class NPObjectProxyTest : public PluginTest {
+ public:
+ // Constructor.
+ NPObjectProxyTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ // NPAPI SetWindow handler.
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_NPOBJECT_PROXY_TEST_H_
diff --git a/webkit/plugins/npapi/test/plugin_private_test.cc b/webkit/plugins/npapi/test/plugin_private_test.cc
new file mode 100644
index 0000000..b3aabce
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_private_test.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2010 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 "webkit/plugins/npapi/test/plugin_private_test.h"
+
+#include "base/basictypes.h"
+#include "base/string_util.h"
+#include "webkit/plugins/npapi/test/plugin_client.h"
+
+namespace NPAPIClient {
+
+PrivateTest::PrivateTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+NPError PrivateTest::New(uint16 mode, int16 argc,
+ const char* argn[], const char* argv[],
+ NPSavedData* saved) {
+ PluginTest::New(mode, argc, argn, argv, saved);
+
+ NPBool private_mode = 0;
+ NPNetscapeFuncs* browser = NPAPIClient::PluginClient::HostFunctions();
+ NPError result = browser->getvalue(
+ id(), NPNVprivateModeBool, &private_mode);
+ if (result != NPERR_NO_ERROR) {
+ SetError("Failed to read NPNVprivateModeBool value.");
+ } else {
+ NPIdentifier location = HostFunctions()->getstringidentifier("location");
+ NPIdentifier href = HostFunctions()->getstringidentifier("href");
+
+ NPObject *window_obj = NULL;
+ HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window_obj);
+
+ NPVariant location_var;
+ HostFunctions()->getproperty(id(), window_obj, location, &location_var);
+
+ NPVariant href_var;
+ HostFunctions()->getproperty(id(), NPVARIANT_TO_OBJECT(location_var), href,
+ &href_var);
+ std::string href_str(href_var.value.stringValue.UTF8Characters,
+ href_var.value.stringValue.UTF8Length);
+ bool private_expected = href_str.find("?private") != href_str.npos;
+ if (private_mode != static_cast<NPBool>(private_expected))
+ SetError("NPNVprivateModeBool returned incorrect value.");
+
+ HostFunctions()->releasevariantvalue(&href_var);
+ HostFunctions()->releasevariantvalue(&location_var);
+ HostFunctions()->releaseobject(window_obj);
+ }
+
+ SignalTestCompleted();
+
+ return NPERR_NO_ERROR;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_private_test.h b/webkit/plugins/npapi/test/plugin_private_test.h
new file mode 100644
index 0000000..9079a11
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_private_test.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_PRIVATE_TEST_H_
+#define WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_PRIVATE_TEST_H_
+
+#include "webkit/plugins/npapi/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// The PluginPrivateTest tests that a plugin can query if the browser is in
+// private browsing mode.
+class PrivateTest : public PluginTest {
+ public:
+ PrivateTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ // Initialize this PluginTest based on the arguments from NPP_New.
+ virtual NPError New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_PRIVATE_TEST_H_
diff --git a/webkit/plugins/npapi/test/plugin_schedule_timer_test.cc b/webkit/plugins/npapi/test/plugin_schedule_timer_test.cc
new file mode 100644
index 0000000..831ab29
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_schedule_timer_test.cc
@@ -0,0 +1,116 @@
+// Copyright (c) 2010 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 "webkit/plugins/npapi/test/plugin_schedule_timer_test.h"
+#include "webkit/plugins/npapi/test/plugin_client.h"
+
+using base::Time;
+
+namespace NPAPIClient {
+
+// The times below are accurate but they are not tested against because it
+// might make the test flakey.
+ScheduleTimerTest::Event
+ ScheduleTimerTest::schedule_[ScheduleTimerTest::kNumEvents] = {
+ { 0, -1, 0, 100, false, -1 }, // schedule 0 100ms no-repeat
+ { 100, 0, 0, 200, false, -1 }, // schedule 0 200ms no-repeat
+ { 300, 0, 0, 100, true, -1 }, // schedule 0 100ms repeat
+ { 400, 0, 1, 50, true, -1 }, // schedule 1 50ms repeat
+ { 450, 1, -1, 0, true, -1 }, // receive 1 repeating
+ { 500, 0, -1, 0, true, -1 }, // receive 0 repeating
+ { 500, 1, -1, 0, true, -1 }, // receive 1 repeating
+ { 550, 1, -1, 0, true, -1 }, // receive 1 repeating
+ { 600, 0, -1, 0, true, 0 }, // receive 0 repeating and unschedule
+ { 600, 1, 2, 400, true, 1 }, // receive 1 repeating and unschedule
+ { 1000, 2, -1, 0, true, 2 }, // receive final and unschedule
+};
+
+ScheduleTimerTest::ScheduleTimerTest(
+ NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ num_received_events_(0) {
+ for (int i = 0; i < kNumTimers; ++i) {
+ timer_ids_[i] = 0;
+ }
+ for (int i = 0; i < kNumEvents; ++i) {
+ received_events_[i] = false;
+ }
+}
+
+NPError ScheduleTimerTest::New(
+ uint16 mode, int16 argc, const char* argn[], const char* argv[],
+ NPSavedData* saved) {
+ NPError error = PluginTest::New(mode, argc, argn, argv, saved);
+ if (error != NPERR_NO_ERROR)
+ return error;
+
+ start_time_ = Time::Now();
+ HandleEvent(0);
+
+ return NPERR_NO_ERROR;
+}
+
+void ScheduleTimerTest::OnTimer(uint32 timer_id) {
+ Time current_time = Time::Now();
+ int relative_time = static_cast<int>(
+ (current_time - start_time_).InMilliseconds());
+
+ // See if there is a matching unreceived event.
+ int event_index = FindUnreceivedEvent(relative_time, timer_id);
+ if (event_index < 0) {
+ SetError("Received unexpected timer event");
+ SignalTestCompleted();
+ return;
+ }
+
+ HandleEvent(event_index);
+
+ // Finish test if all events have happened.
+ if (num_received_events_ == kNumEvents)
+ SignalTestCompleted();
+}
+
+int ScheduleTimerTest::FindUnreceivedEvent(int time, uint32 timer_id) {
+ for (int i = 0; i < kNumEvents; ++i) {
+ const Event& event = schedule_[i];
+ if (!received_events_[i] &&
+ timer_ids_[event.received_index] == timer_id) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+namespace {
+void OnTimerHelper(NPP id, uint32 timer_id) {
+ ScheduleTimerTest* plugin_object =
+ static_cast<ScheduleTimerTest*>(id->pdata);
+ if (plugin_object) {
+ plugin_object->OnTimer(timer_id);
+ }
+}
+}
+
+void ScheduleTimerTest::HandleEvent(int event_index) {
+ const Event& event = schedule_[event_index];
+
+ // Mark event as received.
+ DCHECK(!received_events_[event_index]);
+ received_events_[event_index] = true;
+ ++num_received_events_;
+
+ // Unschedule timer if present.
+ if (event.unscheduled_index >= 0) {
+ HostFunctions()->unscheduletimer(
+ id(), timer_ids_[event.unscheduled_index]);
+ }
+
+ // Schedule timer if present.
+ if (event.scheduled_index >= 0) {
+ timer_ids_[event.scheduled_index] = HostFunctions()->scheduletimer(
+ id(), event.scheduled_interval, event.schedule_repeated, OnTimerHelper);
+ }
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_schedule_timer_test.h b/webkit/plugins/npapi/test/plugin_schedule_timer_test.h
new file mode 100644
index 0000000..043672c
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_schedule_timer_test.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_SCHEDULE_TIMER_TEST_H
+#define WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_SCHEDULE_TIMER_TEST_H
+
+#include "base/at_exit.h"
+#include "base/time.h"
+#include "webkit/plugins/npapi/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// This class tests scheduling and unscheduling of timers using
+// NPN_ScheduleTimer and NPN_UnscheduleTimer.
+class ScheduleTimerTest : public PluginTest {
+ public:
+ ScheduleTimerTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ virtual NPError New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved);
+
+ void OnTimer(uint32 timer_id);
+
+ private:
+ // base::Time needs one of these.
+ base::AtExitManager at_exit_manager_;
+
+ // Table mapping timer index (as used in event schedule) to timer id.
+ static const int kNumTimers = 3;
+ uint32 timer_ids_[kNumTimers];
+
+ // Schedule of events for test.
+ static const int kNumEvents = 11;
+ struct Event {
+ int time;
+
+ // The index of the timer that triggered the event or -1 for the first
+ // event.
+ int received_index;
+
+ // The index of the timer to schedule on this event or -1.
+ int scheduled_index;
+
+ // Info about the timer to be scheduled (if any).
+ uint32 scheduled_interval;
+ bool schedule_repeated;
+
+ // The index of the timer to unschedule on this event or -1.
+ int unscheduled_index;
+ };
+ static Event schedule_[kNumEvents];
+ int num_received_events_;
+
+ // Set of events that have been received (by index).
+ bool received_events_[kNumEvents];
+
+ // Time of initial event.
+ base::Time start_time_;
+
+ // Returns index of matching unreceived event or -1 if not found.
+ int FindUnreceivedEvent(int time, uint32 timer_id);
+ void HandleEvent(int event_index);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_SCHEDULE_TIMER_TEST_H
diff --git a/webkit/plugins/npapi/test/plugin_setup_test.cc b/webkit/plugins/npapi/test/plugin_setup_test.cc
new file mode 100644
index 0000000..ded1379
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_setup_test.cc
@@ -0,0 +1,22 @@
+// Copyright (c) 2010 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 "base/basictypes.h"
+#include "base/string_util.h"
+
+#include "webkit/plugins/npapi/test/plugin_setup_test.h"
+
+namespace NPAPIClient {
+
+PluginSetupTest::PluginSetupTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+NPError PluginSetupTest::SetWindow(NPWindow* pNPWindow) {
+ this->SignalTestCompleted();
+
+ return NPERR_NO_ERROR;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_setup_test.h b/webkit/plugins/npapi/test/plugin_setup_test.h
new file mode 100644
index 0000000..709b3b1
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_setup_test.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_SETUP_TEST_H_
+#define WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_SETUP_TEST_H_
+
+#include "webkit/plugins/npapi/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// A very simple test that just sets up a new plug-in.
+class PluginSetupTest : public PluginTest {
+ public:
+ // Constructor.
+ PluginSetupTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ // NPAPI SetWindow handler.
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_SETUP_TEST_H_
diff --git a/webkit/plugins/npapi/test/plugin_test.cc b/webkit/plugins/npapi/test/plugin_test.cc
new file mode 100644
index 0000000..c948010
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_test.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2010 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 "webkit/plugins/npapi/test/plugin_test.h"
+
+#include "base/string_util.h"
+#include "webkit/plugins/npapi/test/npapi_constants.h"
+
+namespace NPAPIClient {
+
+PluginTest::PluginTest(NPP id, NPNetscapeFuncs *host_functions) {
+ id_ = id;
+ id_->pdata = this;
+ host_functions_ = host_functions;
+ test_completed_ = false;
+}
+
+NPError PluginTest::New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved) {
+ test_name_ = this->GetArgValue("name", argc, argn, argv);
+ test_id_ = this->GetArgValue("id", argc, argn, argv);
+ return NPERR_NO_ERROR;
+}
+
+NPError PluginTest::Destroy() {
+ return NPERR_NO_ERROR;
+}
+
+NPError PluginTest::SetWindow(NPWindow* pNPWindow) {
+ return NPERR_NO_ERROR;
+}
+
+// It's a shame I have to implement URLEncode. But, using webkit's
+// or using chrome's means a ball of string of dlls and dependencies that
+// is very very long. After spending far too much time on it,
+// I'll just encode it myself. Too bad Microsoft doesn't implement
+// this in a reusable way either. Both webkit and chrome will
+// end up using libicu, which is a string of dependencies we don't
+// want.
+
+inline unsigned char toHex(const unsigned char x) {
+ return x > 9 ? (x + 'A' - 10) : (x + '0');
+}
+
+std::string URLEncode(const std::string &sIn) {
+ std::string sOut;
+
+ const size_t length = sIn.length();
+ for (size_t idx = 0; idx < length;) {
+ const char ch = sIn.at(idx);
+ if (isalnum(ch)) {
+ sOut.append(1, ch);
+ } else if (isspace(ch) && ((ch != '\n') && (ch != '\r'))) {
+ sOut.append(1, '+');
+ } else {
+ sOut.append(1, '%');
+ sOut.append(1, toHex(ch>>4));
+ sOut.append(1, toHex(ch%16));
+ }
+ idx++;
+ }
+ return sOut;
+}
+
+void PluginTest::SignalTestCompleted() {
+ NPObject *window_obj = NULL;
+ host_functions_->getvalue(id_, NPNVWindowNPObject, &window_obj);
+ if (!window_obj)
+ return;
+
+ test_completed_ = true;
+ // To signal test completion, we expect a couple of
+ // javascript functions to be defined in the webpage
+ // which hosts this plugin:
+ // onSuccess(test_name, test_id)
+ // onFailure(test_name, test_id, error_message)
+ std::string script("javascript:");
+ if (Succeeded()) {
+ script.append("onSuccess(\"");
+ script.append(test_name_);
+ script.append("\",\"");
+ script.append(test_id_);
+ script.append("\");");
+ } else {
+ script.append("onFailure(\"");
+ script.append(test_name_);
+ script.append("\",\"");
+ script.append(test_id_);
+ script.append("\",\"");
+ script.append(test_status_);
+ script.append("\");");
+ }
+
+ NPString script_string;
+ script_string.UTF8Characters = script.c_str();
+ script_string.UTF8Length = static_cast<unsigned int>(script.length());
+
+ NPVariant result_var;
+ host_functions_->evaluate(id_, window_obj, &script_string, &result_var);
+}
+
+const char *PluginTest::GetArgValue(const char *name, const int16 argc,
+ const char *argn[], const char *argv[]) {
+ for (int idx = 0; idx < argc; idx++)
+ if (base::strcasecmp(argn[idx], name) == 0)
+ return argv[idx];
+ return NULL;
+}
+
+void PluginTest::SetError(const std::string &msg) {
+ test_status_.append(msg);
+}
+
+NPError PluginTest::NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype) {
+ // There is no default action here.
+ return NPERR_NO_ERROR;
+}
+
+int32 PluginTest::WriteReady(NPStream *stream) {
+ // Take data in small chunks
+ return 4096;
+}
+
+int32 PluginTest::Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer) {
+ // Pretend that we took all the data.
+ return len;
+}
+
+NPError PluginTest::DestroyStream(NPStream *stream, NPError reason) {
+ // There is no default action.
+ return NPERR_NO_ERROR;
+}
+
+void PluginTest::StreamAsFile(NPStream* stream, const char* fname) {
+ // There is no default action.
+}
+
+void PluginTest::URLNotify(const char* url, NPReason reason, void* data) {
+ // There is no default action
+}
+
+int16 PluginTest::HandleEvent(void* event) {
+ // There is no default action
+ return 0;
+}
+
+void PluginTest::URLRedirectNotify(const char* url, int32_t status,
+ void* notify_data) {
+ // There is no default action
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_test.h b/webkit/plugins/npapi/test/plugin_test.h
new file mode 100644
index 0000000..fee09d3
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_test.h
@@ -0,0 +1,134 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_TEST_H_
+#define WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_TEST_H_
+
+#include <string>
+
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "third_party/npapi/bindings/npapi.h"
+#include "third_party/npapi/bindings/nphostapi.h"
+
+namespace NPAPIClient {
+
+// A PluginTest represents an instance of the plugin, which in
+// our case is a test case.
+class PluginTest {
+ public:
+ // Constructor.
+ PluginTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ // Destructor
+ virtual ~PluginTest() {}
+
+ // Returns true if the test runs in windowless plugin mode.
+ virtual bool IsWindowless() const { return false; }
+
+ //
+ // NPAPI Functions
+ //
+ virtual NPError New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved);
+ virtual NPError Destroy();
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+ virtual NPError NewStream(NPMIMEType type, NPStream* stream,
+ NPBool seekable, uint16* stype);
+ virtual int32 WriteReady(NPStream *stream);
+ virtual int32 Write(NPStream *stream, int32 offset, int32 len,
+ void *buffer);
+ virtual NPError DestroyStream(NPStream *stream, NPError reason);
+ virtual void StreamAsFile(NPStream* stream, const char* fname);
+ virtual void URLNotify(const char* url, NPReason reason, void* data);
+ virtual int16 HandleEvent(void* event);
+ virtual void URLRedirectNotify(const char* url, int32_t status,
+ void* notify_data);
+ // Returns true if the test has not had any errors.
+ bool Succeeded() { return test_status_.length() == 0; }
+
+ // Sets an error for the test case. Appends the msg to the
+ // error that will be returned from the test.
+ void SetError(const std::string &msg);
+
+ // Expect two string values are equal, and if not, logs an
+ // appropriate error about it.
+ void ExpectStringLowerCaseEqual(const std::string &val1, const std::string &val2) {
+ if (!LowerCaseEqualsASCII(val1, val2.c_str())) {
+ std::string err;
+ err = "Expected Equal for '";
+ err.append(val1);
+ err.append("' and '");
+ err.append(val2);
+ err.append("'");
+ SetError(err);
+ }
+ };
+
+ // Expect two values to not be equal, and if they are
+ // logs an appropriate error about it.
+ void ExpectAsciiStringNotEqual(const char *val1, const char *val2) {
+ if (val1 == val2) {
+ std::string err;
+ err = "Expected Not Equal for '";
+ err.append(val1);
+ err.append("' and '");
+ err.append(val2);
+ err.append("'");
+ SetError(err);
+ }
+ }
+ // Expect two integer values are equal, and if not, logs an
+ // appropriate error about it.
+ void ExpectIntegerEqual(int val1, int val2) {
+ if (val1 != val2) {
+ std::string err;
+ err = "Expected Equal for '";
+ err.append(base::IntToString(val1));
+ err.append("' and '");
+ err.append(base::IntToString(val2));
+ err.append("'");
+ SetError(err);
+ }
+ }
+
+
+ protected:
+ // Signals to the Test that invoked us that the test is
+ // completed. This is done by forcing the plugin to
+ // set a cookie in the browser window, which the test program
+ // is waiting for. Note - because this is done by
+ // using javascript, the browser must have the frame
+ // setup before the plugin calls this function. So plugin
+ // tests MUST NOT call this function prior to having
+ // received the SetWindow() callback from the browser.
+ void SignalTestCompleted();
+
+ // Helper function to lookup names in the input array.
+ // If the name is found, returns the value, otherwise
+ // returns NULL.
+ const char *GetArgValue(const char *name, const int16 argc,
+ const char *argn[], const char *argv[]);
+
+ // Access to the list of functions provided
+ // by the NPAPI host.
+ NPNetscapeFuncs *HostFunctions() { return host_functions_; }
+
+ // The NPP Identifier for this plugin instance.
+ NPP id() { return id_; }
+ std::string test_id() const { return test_id_; }
+ std::string test_name() const { return test_name_; }
+ bool test_completed() const { return test_completed_; }
+ private:
+ NPP id_;
+ NPNetscapeFuncs * host_functions_;
+ std::string test_name_;
+ std::string test_id_;
+ std::string test_status_;
+ bool test_completed_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_TEST_H_
diff --git a/webkit/plugins/npapi/test/plugin_test_factory.cc b/webkit/plugins/npapi/test/plugin_test_factory.cc
new file mode 100644
index 0000000..779ad00
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_test_factory.cc
@@ -0,0 +1,104 @@
+// Copyright (c) 2010 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 "webkit/plugins/npapi/test/plugin_test_factory.h"
+
+#include "webkit/plugins/npapi/test/plugin_arguments_test.h"
+#include "webkit/plugins/npapi/test/plugin_delete_plugin_in_stream_test.h"
+#include "webkit/plugins/npapi/test/plugin_get_javascript_url_test.h"
+#include "webkit/plugins/npapi/test/plugin_get_javascript_url2_test.h"
+#include "webkit/plugins/npapi/test/plugin_geturl_test.h"
+#include "webkit/plugins/npapi/test/plugin_javascript_open_popup.h"
+#include "webkit/plugins/npapi/test/plugin_new_fails_test.h"
+#include "webkit/plugins/npapi/test/plugin_npobject_lifetime_test.h"
+#include "webkit/plugins/npapi/test/plugin_npobject_proxy_test.h"
+#include "webkit/plugins/npapi/test/plugin_private_test.h"
+#include "webkit/plugins/npapi/test/plugin_schedule_timer_test.h"
+#include "webkit/plugins/npapi/test/plugin_setup_test.h"
+#include "webkit/plugins/npapi/test/plugin_thread_async_call_test.h"
+#include "webkit/plugins/npapi/test/plugin_window_size_test.h"
+#if defined(OS_WIN)
+#include "webkit/plugins/npapi/test/plugin_windowed_test.h"
+#endif
+#include "webkit/plugins/npapi/test/plugin_windowless_test.h"
+
+namespace NPAPIClient {
+
+PluginTest* CreatePluginTest(const std::string& test_name,
+ NPP instance,
+ NPNetscapeFuncs* host_functions) {
+ PluginTest* new_test = NULL;
+
+ if (test_name == "arguments") {
+ new_test = new PluginArgumentsTest(instance, host_functions);
+ } else if (test_name == "geturl" || test_name == "geturl_404_response" ||
+ test_name == "geturl_fail_write" ||
+ test_name == "plugin_referrer_test" ||
+ test_name == "geturlredirectnotify") {
+ new_test = new PluginGetURLTest(instance, host_functions);
+ } else if (test_name == "npobject_proxy") {
+ new_test = new NPObjectProxyTest(instance, host_functions);
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ // TODO(port): plugin_windowless_test.*.
+ } else if (test_name == "execute_script_delete_in_paint" ||
+ test_name == "execute_script_delete_in_mouse_move" ||
+ test_name == "delete_frame_test" ||
+ test_name == "multiple_instances_sync_calls" ||
+ test_name == "no_hang_if_init_crashes" ||
+ test_name == "convert_point") {
+ new_test = new WindowlessPluginTest(instance, host_functions);
+#endif
+ } else if (test_name == "getjavascripturl") {
+ new_test = new ExecuteGetJavascriptUrlTest(instance, host_functions);
+ } else if (test_name == "getjavascripturl2") {
+ new_test = new ExecuteGetJavascriptUrl2Test(instance, host_functions);
+#if defined(OS_WIN)
+ // TODO(port): plugin_window_size_test.*.
+ } else if (test_name == "checkwindowrect") {
+ new_test = new PluginWindowSizeTest(instance, host_functions);
+#endif
+ } else if (test_name == "self_delete_plugin_stream") {
+ new_test = new DeletePluginInStreamTest(instance, host_functions);
+#if defined(OS_WIN)
+ // TODO(port): plugin_npobject_lifetime_test.*.
+ } else if (test_name == "npobject_lifetime_test") {
+ new_test = new NPObjectLifetimeTest(instance, host_functions);
+ } else if (test_name == "npobject_lifetime_test_second_instance") {
+ new_test = new NPObjectLifetimeTestInstance2(instance, host_functions);
+ } else if (test_name == "new_fails") {
+ new_test = new NewFailsTest(instance, host_functions);
+ } else if (test_name == "npobject_delete_plugin_in_evaluate" ||
+ test_name == "npobject_delete_create_plugin_in_evaluate") {
+ new_test = new NPObjectDeletePluginInNPN_Evaluate(instance, host_functions);
+#endif
+ } else if (test_name == "plugin_javascript_open_popup_with_plugin") {
+ new_test = new ExecuteJavascriptOpenPopupWithPluginTest(
+ instance, host_functions);
+ } else if (test_name == "plugin_popup_with_plugin_target") {
+ new_test = new ExecuteJavascriptPopupWindowTargetPluginTest(
+ instance, host_functions);
+ } else if (test_name == "plugin_thread_async_call") {
+ new_test = new PluginThreadAsyncCallTest(instance, host_functions);
+ } else if (test_name == "private") {
+ new_test = new PrivateTest(instance, host_functions);
+ } else if (test_name == "schedule_timer") {
+ new_test = new ScheduleTimerTest(instance, host_functions);
+#if defined(OS_WIN)
+ // TODO(port): plugin_windowed_test.*.
+ } else if (test_name == "hidden_plugin" ||
+ test_name == "create_instance_in_paint" ||
+ test_name == "alert_in_window_message" ||
+ test_name == "ensure_scripting_works_in_destroy" ||
+ test_name == "invoke_js_function_on_create") {
+ new_test = new WindowedPluginTest(instance, host_functions);
+#endif
+ } else if (test_name == "setup") {
+ // "plugin" is the name for plugin documents.
+ new_test = new PluginSetupTest(instance, host_functions);
+ }
+
+ return new_test;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_test_factory.h b/webkit/plugins/npapi/test/plugin_test_factory.h
new file mode 100644
index 0000000..f1ed661
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_test_factory.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_TEST_FACTROY_H__
+#define WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_TEST_FACTROY_H__
+
+#include <string>
+
+#include "third_party/npapi/bindings/nphostapi.h"
+
+namespace NPAPIClient {
+
+class PluginTest;
+
+extern PluginTest* CreatePluginTest(const std::string& test_name,
+ NPP instance,
+ NPNetscapeFuncs* host_functions);
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_TEST_FACTROY_H__
diff --git a/webkit/plugins/npapi/test/plugin_thread_async_call_test.cc b/webkit/plugins/npapi/test/plugin_thread_async_call_test.cc
new file mode 100644
index 0000000..e28f84e
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_thread_async_call_test.cc
@@ -0,0 +1,117 @@
+// Copyright (c) 2010 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 "webkit/plugins/npapi/test/plugin_thread_async_call_test.h"
+
+#include "base/at_exit.h"
+#include "base/message_loop.h"
+#include "base/thread.h"
+#include "webkit/plugins/npapi/test/plugin_client.h"
+
+namespace NPAPIClient {
+
+namespace {
+
+// There are two plugin instances in this test. The long lived instance is used
+// for reporting errors and signalling test completion. The short lived one is
+// used to verify that async callbacks are not invoked after NPP_Destroy.
+PluginThreadAsyncCallTest* g_short_lived_instance;
+PluginThreadAsyncCallTest* g_long_lived_instance;
+
+void OnCallSucceededHelper(void* data) {
+ static_cast<PluginThreadAsyncCallTest*>(data)->OnCallSucceeded();
+}
+
+class AsyncCallTask : public Task {
+ public:
+ AsyncCallTask(PluginThreadAsyncCallTest* test_class)
+ : test_class_(test_class) {}
+
+ void Run() {
+ test_class_->AsyncCall();
+ }
+
+ private:
+ PluginThreadAsyncCallTest* test_class_;
+};
+
+void OnCallFailed(void* data) {
+ g_long_lived_instance->SetError("Async callback invoked after NPP_Destroy");
+}
+
+void OnCallCompletedHelper(void* data) {
+ static_cast<PluginThreadAsyncCallTest*>(data)->OnCallCompleted();
+}
+}
+
+PluginThreadAsyncCallTest::PluginThreadAsyncCallTest(
+ NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+NPError PluginThreadAsyncCallTest::New(
+ uint16 mode, int16 argc, const char* argn[], const char* argv[],
+ NPSavedData* saved) {
+ NPError error = PluginTest::New(mode, argc, argn, argv, saved);
+ if (error != NPERR_NO_ERROR)
+ return error;
+
+ // Determine whether this is the short lived instance.
+ for (int i = 0; i < argc; ++i) {
+ if (base::strcasecmp(argn[i], "short_lived") == 0) {
+ if (base::strcasecmp(argv[i], "true") == 0) {
+ g_short_lived_instance = this;
+ } else {
+ g_long_lived_instance = this;
+ }
+ }
+ }
+
+ // Schedule an async call that will succeed. Make sure to call that API from
+ // a different thread to fully test it.
+ if (this == g_short_lived_instance) {
+ at_exit_manager_.reset(new base::AtExitManager());
+ base::Thread random_thread("random_thread");
+ random_thread.Start();
+ random_thread.message_loop()->PostTask(FROM_HERE, new AsyncCallTask(this));
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+void PluginThreadAsyncCallTest::AsyncCall() {
+ HostFunctions()->pluginthreadasynccall(id(), OnCallSucceededHelper, this);
+}
+
+void PluginThreadAsyncCallTest::OnCallSucceeded() {
+ // Delete the short lived instance.
+ NPIdentifier delete_id = HostFunctions()->getstringidentifier(
+ "deleteShortLivedInstance");
+
+ NPObject *window_obj = NULL;
+ HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window_obj);
+
+ NPVariant result;
+ HostFunctions()->invoke(id(), window_obj, delete_id, NULL, 0, &result);
+}
+
+NPError PluginThreadAsyncCallTest::Destroy() {
+ if (this == g_short_lived_instance) {
+ // Schedule an async call that should not be called.
+ HostFunctions()->pluginthreadasynccall(id(), OnCallFailed, NULL);
+
+ // Schedule an async call to end the test using the long lived instance.
+ HostFunctions()->pluginthreadasynccall(g_long_lived_instance->id(),
+ OnCallCompletedHelper,
+ g_long_lived_instance);
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+void PluginThreadAsyncCallTest::OnCallCompleted() {
+ SignalTestCompleted();
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_thread_async_call_test.h b/webkit/plugins/npapi/test/plugin_thread_async_call_test.h
new file mode 100644
index 0000000..9e6a011
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_thread_async_call_test.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_THREAD_ASYNC_CALL_TEST_H_
+#define WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_THREAD_ASYNC_CALL_TEST_H_
+
+#include "base/scoped_ptr.h"
+#include "webkit/plugins/npapi/test/plugin_test.h"
+
+namespace base {
+class AtExitManager;
+}
+
+namespace NPAPIClient {
+
+// This class tests scheduling and unscheduling of async callbacks using
+// NPN_PluginThreadAsyncCall.
+class PluginThreadAsyncCallTest : public PluginTest {
+ public:
+ PluginThreadAsyncCallTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ virtual NPError New(uint16 mode, int16 argc, const char* argn[],
+ const char* argv[], NPSavedData* saved);
+
+ virtual NPError Destroy();
+
+ void AsyncCall();
+ void OnCallSucceeded();
+ void OnCallCompleted();
+
+ private:
+ // base::Thread needs one of these.
+ scoped_ptr<base::AtExitManager> at_exit_manager_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_THREAD_ASYNC_CALL_TEST_H_
diff --git a/webkit/plugins/npapi/test/plugin_window_size_test.cc b/webkit/plugins/npapi/test/plugin_window_size_test.cc
new file mode 100644
index 0000000..abc08ad
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_window_size_test.cc
@@ -0,0 +1,55 @@
+// Copyright (c) 2010 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 "webkit/plugins/npapi/test/plugin_window_size_test.h"
+#include "webkit/plugins/npapi/test/plugin_client.h"
+
+namespace NPAPIClient {
+
+PluginWindowSizeTest::PluginWindowSizeTest(NPP id,
+ NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+}
+
+NPError PluginWindowSizeTest::SetWindow(NPWindow* pNPWindow) {
+ if (pNPWindow->window == NULL)
+ return NPERR_NO_ERROR;
+
+ HWND window = reinterpret_cast<HWND>(pNPWindow->window);
+ if (!pNPWindow || !::IsWindow(window)) {
+ SetError("Invalid arguments passed in");
+ return NPERR_INVALID_PARAM;
+ }
+
+ RECT window_rect = {0};
+ window_rect.left = pNPWindow->x;
+ window_rect.top = pNPWindow->y;
+ window_rect.right = pNPWindow->width;
+ window_rect.bottom = pNPWindow->height;
+
+ if (!::IsRectEmpty(&window_rect)) {
+ RECT client_rect = {0};
+ ::GetClientRect(window, &client_rect);
+ if (::IsRectEmpty(&client_rect)) {
+ SetError("The client rect of the plugin window is empty. Test failed");
+ }
+
+ // Bug 6742: ensure that the coordinates passed in are relative to the
+ // parent HWND.
+ POINT origin_from_os;
+ RECT window_rect_from_os;
+ ::GetWindowRect(window, &window_rect_from_os);
+ origin_from_os.x = window_rect_from_os.left;
+ origin_from_os.y = window_rect_from_os.top;
+ ::ScreenToClient(GetParent(window), &origin_from_os);
+ if (origin_from_os.x != pNPWindow->x || origin_from_os.y != pNPWindow->y)
+ SetError("Wrong position passed in to SetWindow! Test failed");
+
+ SignalTestCompleted();
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_window_size_test.h b/webkit/plugins/npapi/test/plugin_window_size_test.h
new file mode 100644
index 0000000..5a49479
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_window_size_test.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_WINDOW_SIZE_TEST_H_
+#define WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_WINDOW_SIZE_TEST_H_
+
+#include "webkit/plugins/npapi/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// This class tests whether the plugin window has a non zero rect
+// on the second SetWindow call.
+class PluginWindowSizeTest : public PluginTest {
+ public:
+ // Constructor.
+ PluginWindowSizeTest(NPP id, NPNetscapeFuncs *host_functions);
+ // NPAPI SetWindow handler
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_WINDOW_SIZE_TEST_H_
diff --git a/webkit/plugins/npapi/test/plugin_windowed_test.cc b/webkit/plugins/npapi/test/plugin_windowed_test.cc
new file mode 100644
index 0000000..5635ec5
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_windowed_test.cc
@@ -0,0 +1,150 @@
+// Copyright (c) 2010 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 "webkit/plugins/npapi/test/plugin_windowed_test.h"
+#include "webkit/plugins/npapi/test/plugin_client.h"
+
+namespace NPAPIClient {
+
+WindowedPluginTest::WindowedPluginTest(NPP id, NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions),
+ window_(NULL), done_(false) {
+}
+
+WindowedPluginTest::~WindowedPluginTest() {
+ if (window_)
+ DestroyWindow(window_);
+}
+
+NPError WindowedPluginTest::SetWindow(NPWindow* pNPWindow) {
+ if (pNPWindow->window == NULL)
+ return NPERR_NO_ERROR;
+
+ if (test_name() == "create_instance_in_paint" && test_id() == "2") {
+ SignalTestCompleted();
+ return NPERR_NO_ERROR;
+ }
+
+ if (window_)
+ return NPERR_NO_ERROR;
+
+ HWND parent = reinterpret_cast<HWND>(pNPWindow->window);
+ if (!pNPWindow || !::IsWindow(parent)) {
+ SetError("Invalid arguments passed in");
+ return NPERR_INVALID_PARAM;
+ }
+
+ if ((test_name() == "create_instance_in_paint" && test_id() == "1") ||
+ test_name() == "alert_in_window_message" ||
+ test_name() == "invoke_js_function_on_create") {
+ static ATOM window_class = 0;
+ if (!window_class) {
+ WNDCLASSEX wcex;
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.style = CS_DBLCLKS;
+ wcex.lpfnWndProc = &NPAPIClient::WindowedPluginTest::WindowProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = GetModuleHandle(NULL);
+ wcex.hIcon = 0;
+ wcex.hCursor = 0;
+ wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1);
+ wcex.lpszMenuName = 0;
+ wcex.lpszClassName = L"CreateInstanceInPaintTestWindowClass";
+ wcex.hIconSm = 0;
+ window_class = RegisterClassEx(&wcex);
+ }
+
+ window_ = CreateWindowEx(
+ WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
+ MAKEINTATOM(window_class), 0,
+ WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE ,
+ 0, 0, 100, 100, parent, 0, GetModuleHandle(NULL), 0);
+ DCHECK(window_);
+ // TODO: this propery leaks.
+ ::SetProp(window_, L"Plugin_Instance", this);
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+NPError WindowedPluginTest::Destroy() {
+ if (test_name() != "ensure_scripting_works_in_destroy")
+ return NPERR_NO_ERROR;
+
+ // Bug 23706: ensure that scripting works with no asserts.
+ NPObject *window_obj = NULL;
+ HostFunctions()->getvalue(id(), NPNVWindowNPObject,&window_obj);
+
+ if (!window_obj) {
+ SetError("Failed to get NPObject for plugin instance");
+ } else {
+ std::string script = "javascript:GetMagicNumber()";
+ NPString script_string;
+ script_string.UTF8Characters = script.c_str();
+ script_string.UTF8Length =
+ static_cast<unsigned int>(script.length());
+
+ NPVariant result_var;
+ bool result = HostFunctions()->evaluate(
+ id(), window_obj, &script_string, &result_var);
+ if (!result ||
+ result_var.type != NPVariantType_Double ||
+ result_var.value.doubleValue != 42.0) {
+ SetError("Failed to script during NPP_Destroy");
+ }
+ }
+
+ SignalTestCompleted();
+ return NPERR_NO_ERROR;
+}
+
+void WindowedPluginTest::CallJSFunction(
+ WindowedPluginTest* this_ptr, const char* function) {
+ NPIdentifier function_id = this_ptr->HostFunctions()->getstringidentifier(
+ function);
+
+ NPObject *window_obj = NULL;
+ this_ptr->HostFunctions()->getvalue(
+ this_ptr->id(), NPNVWindowNPObject, &window_obj);
+
+ NPVariant rv;
+ this_ptr->HostFunctions()->invoke(
+ this_ptr->id(), window_obj, function_id, NULL, 0, &rv);
+}
+
+LRESULT CALLBACK WindowedPluginTest::WindowProc(
+ HWND window, UINT message, WPARAM wparam, LPARAM lparam) {
+ WindowedPluginTest* this_ptr =
+ reinterpret_cast<WindowedPluginTest*>
+ (::GetProp(window, L"Plugin_Instance"));
+
+ if (this_ptr && !this_ptr->done_) {
+ if (this_ptr->test_name() == "create_instance_in_paint" &&
+ message == WM_PAINT) {
+ this_ptr->done_ = true;
+ CallJSFunction(this_ptr, "CreateNewInstance");
+ } else if (this_ptr->test_name() == "alert_in_window_message" &&
+ message == WM_PAINT) {
+ this_ptr->done_ = true;
+ // We call this function twice as we want to display two alerts
+ // and verify that we don't hang the browser.
+ CallJSFunction(this_ptr, "CallAlert");
+ CallJSFunction(this_ptr, "CallAlert");
+ } else if (this_ptr->test_name() ==
+ "invoke_js_function_on_create" &&
+ message == WM_PAINT) {
+ this_ptr->done_ = true;
+ CallJSFunction(this_ptr, "PluginCreated");
+ }
+
+ if (this_ptr->done_) {
+ ::RemoveProp(window, L"Plugin_Instance");
+ }
+ }
+
+ return DefWindowProc(window, message, wparam, lparam);
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_windowed_test.h b/webkit/plugins/npapi/test/plugin_windowed_test.h
new file mode 100644
index 0000000..4906933
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_windowed_test.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_WINDOWED_TEST_H
+#define WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_WINDOWED_TEST_H
+
+#include "webkit/plugins/npapi/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// This class contains a list of windowed plugin tests. Please add additional
+// tests to this class.
+class WindowedPluginTest : public PluginTest {
+ public:
+ WindowedPluginTest(NPP id, NPNetscapeFuncs *host_functions);
+ ~WindowedPluginTest();
+
+ private:
+ static LRESULT CALLBACK WindowProc(
+ HWND window, UINT message, WPARAM wparam, LPARAM lparam);
+ static void CallJSFunction(WindowedPluginTest*, const char*);
+
+ virtual NPError SetWindow(NPWindow* pNPWindow);
+ virtual NPError Destroy();
+
+ HWND window_;
+ bool done_;
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_WINDOWED_TEST_H
diff --git a/webkit/plugins/npapi/test/plugin_windowless_test.cc b/webkit/plugins/npapi/test/plugin_windowless_test.cc
new file mode 100644
index 0000000..17b9ca7
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_windowless_test.cc
@@ -0,0 +1,261 @@
+// Copyright (c) 2010 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.
+
+#define STRSAFE_NO_DEPRECATE
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "webkit/plugins/npapi/test/plugin_windowless_test.h"
+#include "webkit/plugins/npapi/test/plugin_client.h"
+
+#if defined(OS_MACOSX)
+#include <ApplicationServices/ApplicationServices.h>
+#include <Carbon/Carbon.h>
+#endif
+
+namespace NPAPIClient {
+
+// Remember the first plugin instance for tests involving multiple instances
+WindowlessPluginTest* g_other_instance = NULL;
+
+WindowlessPluginTest::WindowlessPluginTest(NPP id,
+ NPNetscapeFuncs *host_functions)
+ : PluginTest(id, host_functions) {
+ if (!g_other_instance)
+ g_other_instance = this;
+}
+
+static bool IsPaintEvent(NPEvent* np_event) {
+#if defined(OS_WIN)
+ return WM_PAINT == np_event->event;
+#elif defined(OS_MACOSX)
+ return np_event->what == updateEvt;
+#endif
+}
+
+static bool IsMouseMoveEvent(NPEvent* np_event) {
+#if defined(OS_WIN)
+ return WM_MOUSEMOVE == np_event->event;
+#elif defined(OS_MACOSX)
+ return np_event->what == nullEvent;
+#endif
+}
+
+static bool IsMouseUpEvent(NPEvent* np_event) {
+#if defined(OS_WIN)
+ return WM_LBUTTONUP == np_event->event;
+#elif defined(OS_MACOSX)
+ return np_event->what == mouseUp;
+#endif
+}
+
+static bool IsWindowActivationEvent(NPEvent* np_event) {
+#if defined(OS_WIN)
+ NOTIMPLEMENTED();
+ return false;
+#elif defined(OS_MACOSX)
+ return np_event->what == activateEvt;
+#endif
+}
+
+int16 WindowlessPluginTest::HandleEvent(void* event) {
+
+ NPNetscapeFuncs* browser = NPAPIClient::PluginClient::HostFunctions();
+
+ NPBool supports_windowless = 0;
+ NPError result = browser->getvalue(id(), NPNVSupportsWindowless,
+ &supports_windowless);
+ if ((result != NPERR_NO_ERROR) || (supports_windowless != TRUE)) {
+ SetError("Failed to read NPNVSupportsWindowless value");
+ SignalTestCompleted();
+ return PluginTest::HandleEvent(event);
+ }
+
+ NPEvent* np_event = reinterpret_cast<NPEvent*>(event);
+ if (IsPaintEvent(np_event)) {
+#if defined(OS_WIN)
+ HDC paint_dc = reinterpret_cast<HDC>(np_event->wParam);
+ if (paint_dc == NULL) {
+ SetError("Invalid Window DC passed to HandleEvent for WM_PAINT");
+ SignalTestCompleted();
+ return NPERR_GENERIC_ERROR;
+ }
+
+ HRGN clipping_region = CreateRectRgn(0, 0, 0, 0);
+ if (!GetClipRgn(paint_dc, clipping_region)) {
+ SetError("No clipping region set in window DC");
+ DeleteObject(clipping_region);
+ SignalTestCompleted();
+ return NPERR_GENERIC_ERROR;
+ }
+
+ DeleteObject(clipping_region);
+#endif
+
+ if (test_name() == "execute_script_delete_in_paint") {
+ ExecuteScriptDeleteInPaint(browser);
+ } else if (test_name() == "multiple_instances_sync_calls") {
+ MultipleInstanceSyncCalls(browser);
+ }
+#if OS_MACOSX
+ } else if (IsWindowActivationEvent(np_event) &&
+ test_name() == "convert_point") {
+ ConvertPoint(browser);
+#endif
+ } else if (IsMouseMoveEvent(np_event) &&
+ test_name() == "execute_script_delete_in_mouse_move") {
+ ExecuteScript(browser, id(), "DeletePluginWithinScript();", NULL);
+ SignalTestCompleted();
+ } else if (IsMouseUpEvent(np_event) &&
+ test_name() == "delete_frame_test") {
+ ExecuteScript(
+ browser, id(),
+ "parent.document.getElementById('frame').outerHTML = ''", NULL);
+ }
+ // If this test failed, then we'd have crashed by now.
+ return PluginTest::HandleEvent(event);
+}
+
+NPError WindowlessPluginTest::ExecuteScript(NPNetscapeFuncs* browser, NPP id,
+ const std::string& script, NPVariant* result) {
+ std::string script_url = "javascript:";
+ script_url += script;
+
+ NPString script_string = { script_url.c_str(), script_url.length() };
+ NPObject *window_obj = NULL;
+ browser->getvalue(id, NPNVWindowNPObject, &window_obj);
+
+ NPVariant unused_result;
+ if (!result)
+ result = &unused_result;
+
+ return browser->evaluate(id, window_obj, &script_string, result);
+}
+
+void WindowlessPluginTest::ExecuteScriptDeleteInPaint(
+ NPNetscapeFuncs* browser) {
+ const NPUTF8* urlString = "javascript:DeletePluginWithinScript()";
+ const NPUTF8* targetString = NULL;
+ browser->geturl(id(), urlString, targetString);
+ SignalTestCompleted();
+}
+
+void WindowlessPluginTest::MultipleInstanceSyncCalls(NPNetscapeFuncs* browser) {
+ if (this == g_other_instance)
+ return;
+
+ DCHECK(g_other_instance);
+ ExecuteScript(browser, g_other_instance->id(), "TestCallback();", NULL);
+ SignalTestCompleted();
+}
+
+#if defined(OS_MACOSX)
+std::string StringForPoint(int x, int y) {
+ std::string point_string("(");
+ point_string.append(base::IntToString(x));
+ point_string.append(", ");
+ point_string.append(base::IntToString(y));
+ point_string.append(")");
+ return point_string;
+}
+#endif
+
+void WindowlessPluginTest::ConvertPoint(NPNetscapeFuncs* browser) {
+#if defined(OS_MACOSX)
+ // First, just sanity-test that round trips work.
+ NPCoordinateSpace spaces[] = { NPCoordinateSpacePlugin,
+ NPCoordinateSpaceWindow,
+ NPCoordinateSpaceFlippedWindow,
+ NPCoordinateSpaceScreen,
+ NPCoordinateSpaceFlippedScreen };
+ for (unsigned int i = 0; i < arraysize(spaces); ++i) {
+ for (unsigned int j = 0; j < arraysize(spaces); ++j) {
+ double x, y, round_trip_x, round_trip_y;
+ if (!(browser->convertpoint(id(), 0, 0, spaces[i], &x, &y, spaces[j])) ||
+ !(browser->convertpoint(id(), x, y, spaces[j], &round_trip_x,
+ &round_trip_y, spaces[i]))) {
+ SetError("Conversion failed");
+ SignalTestCompleted();
+ return;
+ }
+ if (i != j && x == 0 && y == 0) {
+ SetError("Converting a coordinate should change it");
+ SignalTestCompleted();
+ return;
+ }
+ if (round_trip_x != 0 || round_trip_y != 0) {
+ SetError("Round-trip conversion should return the original point");
+ SignalTestCompleted();
+ return;
+ }
+ }
+ }
+
+ // Now, more extensive testing on a single point.
+ double screen_x, screen_y;
+ browser->convertpoint(id(), 0, 0, NPCoordinateSpacePlugin,
+ &screen_x, &screen_y, NPCoordinateSpaceScreen);
+ double flipped_screen_x, flipped_screen_y;
+ browser->convertpoint(id(), 0, 0, NPCoordinateSpacePlugin,
+ &flipped_screen_x, &flipped_screen_y,
+ NPCoordinateSpaceFlippedScreen);
+ double window_x, window_y;
+ browser->convertpoint(id(), 0, 0, NPCoordinateSpacePlugin,
+ &window_x, &window_y, NPCoordinateSpaceWindow);
+ double flipped_window_x, flipped_window_y;
+ browser->convertpoint(id(), 0, 0, NPCoordinateSpacePlugin,
+ &flipped_window_x, &flipped_window_y,
+ NPCoordinateSpaceFlippedWindow);
+
+ CGRect main_display_bounds = CGDisplayBounds(CGMainDisplayID());
+
+ // Check that all the coordinates are right. The constants below are based on
+ // the window frame set in the UI test and the content offset in the test
+ // html. Y-coordinates are not checked exactly so that the test is robust
+ // against toolbar changes, info and bookmark bar visibility, etc.
+ const int kWindowHeight = 400;
+ const int kWindowXOrigin = 50;
+ const int kWindowYOrigin = 50;
+ const int kPluginXContentOffset = 50;
+ const int kPluginYContentOffset = 50;
+ const int kChromeYTolerance = 200;
+
+ std::string error_string;
+ if (screen_x != flipped_screen_x)
+ error_string = "Flipping screen coordinates shouldn't change x";
+ else if (flipped_screen_y != main_display_bounds.size.height - screen_y)
+ error_string = "Flipped screen coordinates should be flipped vertically";
+ else if (screen_x != kWindowXOrigin + kPluginXContentOffset)
+ error_string = "Screen x location is wrong";
+ else if (flipped_screen_y < kWindowYOrigin + kPluginYContentOffset ||
+ flipped_screen_y > kWindowYOrigin + kPluginYContentOffset +
+ kChromeYTolerance)
+ error_string = "Screen y location is wrong";
+ else if (window_x != flipped_window_x)
+ error_string = "Flipping window coordinates shouldn't change x";
+ else if (flipped_window_y != kWindowHeight - window_y)
+ error_string = "Flipped window coordinates should be flipped vertically";
+ else if (window_x != kPluginXContentOffset)
+ error_string = "Window x location is wrong";
+ else if (flipped_window_y < kPluginYContentOffset ||
+ flipped_window_y > kPluginYContentOffset + kChromeYTolerance)
+ error_string = "Window y location is wrong";
+
+ if (!error_string.empty()) {
+ error_string.append(" - ");
+ error_string.append(StringForPoint(screen_x, screen_y));
+ error_string.append(" - ");
+ error_string.append(StringForPoint(flipped_screen_x, flipped_screen_y));
+ error_string.append(" - ");
+ error_string.append(StringForPoint(window_x, window_y));
+ error_string.append(" - ");
+ error_string.append(StringForPoint(flipped_window_x, flipped_window_y));
+ SetError(error_string);
+ }
+#else
+ SetError("Unimplemented");
+#endif
+ SignalTestCompleted();
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/plugins/npapi/test/plugin_windowless_test.h b/webkit/plugins/npapi/test/plugin_windowless_test.h
new file mode 100644
index 0000000..6f5ce15
--- /dev/null
+++ b/webkit/plugins/npapi/test/plugin_windowless_test.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2010 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.
+
+#ifndef WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_EXECUTE_SCRIPT_DELETE_TEST_H_
+#define WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_EXECUTE_SCRIPT_DELETE_TEST_H_
+
+#include "webkit/plugins/npapi/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// This class contains a list of windowless plugin tests. Please add additional
+// tests to this class.
+class WindowlessPluginTest : public PluginTest {
+ public:
+ // Constructor.
+ WindowlessPluginTest(NPP id, NPNetscapeFuncs *host_functions);
+
+ // These tests run in windowless plugin mode.
+ virtual bool IsWindowless() const { return true; }
+
+ // NPAPI HandleEvent handler
+ virtual int16 HandleEvent(void* event);
+
+ protected:
+ NPError ExecuteScript(NPNetscapeFuncs* browser, NPP id,
+ const std::string& script, NPVariant* result);
+ void ExecuteScriptDeleteInPaint(NPNetscapeFuncs* browser);
+ void MultipleInstanceSyncCalls(NPNetscapeFuncs* browser);
+ void ConvertPoint(NPNetscapeFuncs* browser);
+};
+
+} // namespace NPAPIClient
+
+#endif // WEBKIT_PLUGINS_NPAPI_TEST_PLUGIN_EXECUTE_SCRIPT_DELETE_TEST_H_
diff --git a/webkit/plugins/npapi/test/resource.h b/webkit/plugins/npapi/test/resource.h
new file mode 100644
index 0000000..422861f
--- /dev/null
+++ b/webkit/plugins/npapi/test/resource.h
@@ -0,0 +1,15 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by npapi_test.rc
+//
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif