diff options
Diffstat (limited to 'webkit/plugins/npapi/test')
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 |