From d20dd3d2b4e62d45b1ecae10d4e9cf743d6b21ed Mon Sep 17 00:00:00 2001
From: "alokp@chromium.org"
 <alokp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Fri, 26 Mar 2010 18:54:29 +0000
Subject: Added a test for pepper3d. It ensures that we can successfully load a
 pepper 3d plugin and render. Review URL:
 http://codereview.chromium.org/1073003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42793 0039d316-1c4b-4281-b951-d872f2087c98
---
 build/all.gyp                                      |   1 -
 chrome/chrome_tests.gypi                           |   8 +-
 chrome/test/data/pepper/pepper_3d.html             |  17 ++
 chrome/test/ui/npapi_test_helper.cc                |  17 +-
 chrome/test/ui/npapi_test_helper.h                 |  14 +-
 chrome/test/ui/npapi_uitest.cc                     |   8 +-
 chrome/test/ui/pepper_uitest.cc                    |  42 +++++
 webkit/glue/plugins/test/npapi_test.rc             |  14 +-
 webkit/glue/plugins/test/plugin_client.cc          | 133 ++------------
 .../test/plugin_create_instance_in_paint.cc        |   3 +
 .../test/plugin_delete_plugin_in_stream_test.cc    |   3 +
 .../test/plugin_get_javascript_url2_test.cc        |   3 +
 .../plugins/test/plugin_get_javascript_url_test.cc |   3 +
 webkit/glue/plugins/test/plugin_geturl_test.cc     |   3 +
 .../plugins/test/plugin_javascript_open_popup.cc   |   8 +-
 .../plugins/test/plugin_npobject_lifetime_test.cc  |   9 +
 .../plugins/test/plugin_npobject_proxy_test.cc     |   3 +
 webkit/glue/plugins/test/plugin_test.h             |   3 +
 webkit/glue/plugins/test/plugin_test_factory.cc    |  97 ++++++++++
 webkit/glue/plugins/test/plugin_test_factory.h     |  22 +++
 .../glue/plugins/test/plugin_window_size_test.cc   |   3 +
 webkit/glue/plugins/test/plugin_windowed_test.cc   |   3 +
 webkit/glue/plugins/test/plugin_windowless_test.cc |  17 +-
 webkit/glue/plugins/test/plugin_windowless_test.h  |  10 +-
 webkit/glue/plugins/test/resource.h                |   9 +-
 webkit/tools/pepper_test_plugin/pepper_3d_test.cc  | 198 +++++++++++++++++++++
 webkit/tools/pepper_test_plugin/pepper_3d_test.h   |  56 ++++++
 .../pepper_test_plugin/pepper_test_factory.cc      |  23 +++
 .../tools/pepper_test_plugin/pepper_test_plugin.cc |  25 +++
 webkit/tools/test_shell/test_shell.gypi            |  49 ++++-
 30 files changed, 619 insertions(+), 185 deletions(-)
 create mode 100644 chrome/test/data/pepper/pepper_3d.html
 create mode 100644 chrome/test/ui/pepper_uitest.cc
 create mode 100644 webkit/glue/plugins/test/plugin_test_factory.cc
 create mode 100644 webkit/glue/plugins/test/plugin_test_factory.h
 create mode 100644 webkit/tools/pepper_test_plugin/pepper_3d_test.cc
 create mode 100644 webkit/tools/pepper_test_plugin/pepper_3d_test.h
 create mode 100644 webkit/tools/pepper_test_plugin/pepper_test_factory.cc
 create mode 100644 webkit/tools/pepper_test_plugin/pepper_test_plugin.cc

diff --git a/build/all.gyp b/build/all.gyp
index 2428e5a..4091392 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -37,7 +37,6 @@
         '../third_party/sqlite/sqlite.gyp:*',
         '../third_party/WebKit/WebKit/chromium/WebKit.gyp:*',
         '../third_party/zlib/zlib.gyp:*',
-        '../webkit/tools/pepper_test_plugin/pepper_test_plugin.gyp:*',
         '../webkit/webkit.gyp:*',
         'util/build_util.gyp:*',
         'temp_gyp/googleurl.gyp:*',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index df9a869..34cc702 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -172,12 +172,6 @@
             '../build/linux/system.gyp:gtk',
           ],
         }],
-        ['OS=="linux" or OS=="freebsd"', {
-          'sources!': [
-            # TODO(port)
-            'test/ui/npapi_test_helper.cc',
-          ],
-        }],
       ],
     },
     {
@@ -322,6 +316,7 @@
         'test/ui/mouseleave_uitest.cc',
         'test/ui/npapi_uitest.cc',
         'test/ui/omnibox_uitest.cc',
+        'test/ui/pepper_uitest.cc',
         'test/ui/sandbox_uitests.cc',
         'test/ui/sunspider_uitest.cc',
         'test/ui/v8_benchmark_uitest.cc',
@@ -332,6 +327,7 @@
         ['target_arch!="x64" and target_arch!="arm"', {
           'dependencies': [
             '../webkit/webkit.gyp:npapi_test_plugin',
+            '../webkit/webkit.gyp:pepper_test_plugin',
           ],
         }],
         ['OS=="linux"', {
diff --git a/chrome/test/data/pepper/pepper_3d.html b/chrome/test/data/pepper/pepper_3d.html
new file mode 100644
index 0000000..df1bea7
--- /dev/null
+++ b/chrome/test/data/pepper/pepper_3d.html
@@ -0,0 +1,17 @@
+<html>
+<head>
+<title>Pepper3D Test</title>
+<script src="../npapi/npapi.js"></script>
+</head>
+
+<body>
+<div id="statusPanel" style="border: 1px solid red; width: 100%">
+Test running....
+</div>
+
+<object type="pepper-application/x-pepper-test-plugin"
+    id="1"
+    name="pepper_3d"
+    width="256" height="256" />
+</body>
+</html>
diff --git a/chrome/test/ui/npapi_test_helper.cc b/chrome/test/ui/npapi_test_helper.cc
index 1c8e7f1..d5e24ad 100644
--- a/chrome/test/ui/npapi_test_helper.cc
+++ b/chrome/test/ui/npapi_test_helper.cc
@@ -17,16 +17,18 @@
 
 #if defined(OS_WIN)
 static const char kNpapiTestPluginName[] = "npapi_test_plugin.dll";
-static const char kPepperTestPluginName[] = "pepper_test_plugin.dll";
 #elif defined(OS_MACOSX)
 static const char kNpapiTestPluginName[] = "npapi_test_plugin.plugin";
-static const char kPepperTestPluginName[] = "PepperTestPlugin.plugin";
 static const char kLayoutPluginName[] = "TestNetscapePlugIn.plugin";
 #elif defined(OS_LINUX)
 static const char kNpapiTestPluginName[] = "libnpapi_test_plugin.so";
-static const char kPepperTestPluginName[] = "libpepper_test_plugin.so";
 #endif
 
+namespace npapi_test {
+const char kTestCompleteCookie[] = "status";
+const char kTestCompleteSuccess[] = "OK";
+}  // namespace npapi_test.
+
 NPAPITesterBase::NPAPITesterBase(const std::string& test_plugin_name)
   : test_plugin_name_(test_plugin_name) {
 }
@@ -105,12 +107,3 @@ void NPAPIIncognitoTester::SetUp() {
   launch_arguments_.AppendSwitch(switches::kIncognito);
   NPAPITester::SetUp();
 }
-
-PepperTester::PepperTester() : NPAPITesterBase(kPepperTestPluginName) {
-}
-
-void PepperTester::SetUp() {
-  // TODO(alokp): Add command-line arguments
-  // --no-sandbox --internal-pepper --enable-gpu-plugin
-  NPAPITesterBase::SetUp();
-}
diff --git a/chrome/test/ui/npapi_test_helper.h b/chrome/test/ui/npapi_test_helper.h
index a0c2f3b..8896713 100644
--- a/chrome/test/ui/npapi_test_helper.h
+++ b/chrome/test/ui/npapi_test_helper.h
@@ -7,6 +7,13 @@
 
 #include "chrome/test/ui/ui_test.h"
 
+namespace npapi_test {
+extern const char kTestCompleteCookie[];
+extern const char kTestCompleteSuccess[];
+const int kLongWaitTimeout = 30 * 1000;
+const int kShortWaitTimeout = 5 * 1000;
+}  // namespace npapi_test.
+
 // Base class for NPAPI tests. It provides common functionality between
 // regular NPAPI plugins and pepper NPAPI plugins. The base classes provide the
 // name of the plugin they need test in the constructor. This base class will
@@ -51,11 +58,4 @@ class NPAPIIncognitoTester : public NPAPITester {
   virtual void SetUp();
 };
 
-// Helper class pepper NPAPI tests.
-class PepperTester : public NPAPITesterBase {
- protected:
-  PepperTester();
-  virtual void SetUp();
-};
-
 #endif  // CHROME_TEST_UI_NPAPI_TEST_HELPER_H_
diff --git a/chrome/test/ui/npapi_uitest.cc b/chrome/test/ui/npapi_uitest.cc
index 6d1d8ca..c43bad4 100644
--- a/chrome/test/ui/npapi_uitest.cc
+++ b/chrome/test/ui/npapi_uitest.cc
@@ -28,10 +28,10 @@
 #include "chrome/test/ui/npapi_test_helper.h"
 #include "net/base/net_util.h"
 
-const char kTestCompleteCookie[] = "status";
-const char kTestCompleteSuccess[] = "OK";
-const int kLongWaitTimeout = 30 * 1000;
-const int kShortWaitTimeout = 5 * 1000;
+using npapi_test::kTestCompleteCookie;
+using npapi_test::kTestCompleteSuccess;
+using npapi_test::kLongWaitTimeout;
+using npapi_test::kShortWaitTimeout;
 
 // Test passing arguments to a plugin.
 TEST_F(NPAPITester, Arguments) {
diff --git a/chrome/test/ui/pepper_uitest.cc b/chrome/test/ui/pepper_uitest.cc
new file mode 100644
index 0000000..be247e2
--- /dev/null
+++ b/chrome/test/ui/pepper_uitest.cc
@@ -0,0 +1,42 @@
+// 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 "chrome/common/chrome_switches.h"
+#include "chrome/test/ui/npapi_test_helper.h"
+
+#if defined(OS_WIN)
+static const char kPepperTestPluginName[] = "pepper_test_plugin.dll";
+#elif defined(OS_MACOSX)
+static const char kPepperTestPluginName[] = "PepperTestPlugin.plugin";
+#elif defined(OS_LINUX)
+static const char kPepperTestPluginName[] = "libpepper_test_plugin.so";
+#endif
+
+using npapi_test::kTestCompleteCookie;
+using npapi_test::kTestCompleteSuccess;
+using npapi_test::kLongWaitTimeout;
+using npapi_test::kShortWaitTimeout;
+
+// Helper class pepper NPAPI tests.
+class PepperTester : public NPAPITesterBase {
+ protected:
+  PepperTester() : NPAPITesterBase(kPepperTestPluginName) {}
+
+  virtual void SetUp() {
+    launch_arguments_.AppendSwitch(switches::kInternalPepper);
+    launch_arguments_.AppendSwitch(switches::kEnableGPUPlugin);
+    NPAPITesterBase::SetUp();
+  }
+};
+
+// Test that a pepper 3d plugin loads and renders.
+// TODO(alokp): Enable the test after making sure it works on all platforms
+// and buildbots have OpenGL support.
+TEST_F(PepperTester, DISABLED_Pepper3D) {
+  GURL url = GetTestUrl(L"pepper", L"pepper_3d.html");
+  ASSERT_NO_FATAL_FAILURE(NavigateToURL(url));
+  WaitForFinish("pepper_3d", "1", url,
+                kTestCompleteCookie, kTestCompleteSuccess,
+                kLongWaitTimeout);
+}
diff --git a/webkit/glue/plugins/test/npapi_test.rc b/webkit/glue/plugins/test/npapi_test.rc
index a337ce6..524dda4 100644
--- a/webkit/glue/plugins/test/npapi_test.rc
+++ b/webkit/glue/plugins/test/npapi_test.rc
@@ -67,21 +67,21 @@ VS_VERSION_INFO VERSIONINFO
 BEGIN
     BLOCK "StringFileInfo"
     BEGIN
-        BLOCK "040904E4"
+        BLOCK "040904e4"
         BEGIN
-            VALUE "FileDescription", "npapites Dynamic Link Library"
+            VALUE "FileDescription", "NPAPI Test Plugin"
             VALUE "FileVersion", "1, 0, 0, 1"
-            VALUE "InternalName", "npapites"
+            VALUE "InternalName", "npapi_test_plugin"
             VALUE "LegalCopyright", "Copyright (C) 2007"
-            VALUE "OriginalFilename", "npapites.dll"
-            VALUE "ProductName", " npapites Dynamic Link Library"
+            VALUE "MIMEType", "application/vnd.npapi-test"
+            VALUE "OriginalFilename", "npapi_test_plugin.dll"
+            VALUE "ProductName", "NPAPI Test Plugin"
             VALUE "ProductVersion", "1, 0, 0, 1"
-            VALUE "MIMEType", "application/vnd.npapi-test\0"
         END
     END
     BLOCK "VarFileInfo"
     BEGIN
-        VALUE "Translation", 0x409, 1200
+        VALUE "Translation", 0x409, 1252
     END
 END
 
diff --git a/webkit/glue/plugins/test/plugin_client.cc b/webkit/glue/plugins/test/plugin_client.cc
index 0d0a76d..1cf57e7 100644
--- a/webkit/glue/plugins/test/plugin_client.cc
+++ b/webkit/glue/plugins/test/plugin_client.cc
@@ -2,31 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
+#include "webkit/glue/plugins/test/plugin_client.h"
 
 #include "base/string_util.h"
-#include "webkit/glue/plugins/test/plugin_client.h"
-#include "webkit/glue/plugins/test/plugin_arguments_test.h"
-#include "webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h"
-#include "webkit/glue/plugins/test/plugin_get_javascript_url_test.h"
-#include "webkit/glue/plugins/test/plugin_get_javascript_url2_test.h"
-#include "webkit/glue/plugins/test/plugin_geturl_test.h"
-#include "webkit/glue/plugins/test/plugin_javascript_open_popup.h"
-#include "webkit/glue/plugins/test/plugin_new_fails_test.h"
-#include "webkit/glue/plugins/test/plugin_private_test.h"
-#include "webkit/glue/plugins/test/plugin_schedule_timer_test.h"
-#include "webkit/glue/plugins/test/plugin_thread_async_call_test.h"
-#include "webkit/glue/plugins/test/plugin_npobject_lifetime_test.h"
-#include "webkit/glue/plugins/test/plugin_npobject_proxy_test.h"
-#include "webkit/glue/plugins/test/plugin_window_size_test.h"
-#if defined(OS_WIN)
-#include "webkit/glue/plugins/test/plugin_windowed_test.h"
-#endif
-#include "webkit/glue/plugins/test/plugin_windowless_test.h"
-#include "third_party/npapi/bindings/npapi.h"
-#include "third_party/npapi/bindings/npruntime.h"
+#include "webkit/glue/plugins/test/plugin_test.h"
+#include "webkit/glue/plugins/test/plugin_test_factory.h"
 
 namespace NPAPIClient {
 
@@ -100,112 +80,31 @@ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode,
 
   // lookup the name parameter
   std::string test_name;
-  for (int name_index = 0; name_index < argc; name_index++)
+  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
 
-  NPError ret = NPERR_GENERIC_ERROR;
-  bool windowless_plugin = false;
-
-  NPAPIClient::PluginTest *new_test = NULL;
-  if (test_name == "arguments") {
-    new_test = new NPAPIClient::PluginArgumentsTest(instance,
-      NPAPIClient::PluginClient::HostFunctions());
-  } else if (test_name == "geturl" || test_name == "geturl_404_response" ||
-             test_name == "geturl_fail_write" ||
-             test_name == "plugin_referrer_test") {
-    new_test = new NPAPIClient::PluginGetURLTest(instance,
-      NPAPIClient::PluginClient::HostFunctions());
-  } else if (test_name == "npobject_proxy") {
-    new_test = new NPAPIClient::NPObjectProxyTest(instance,
-      NPAPIClient::PluginClient::HostFunctions());
-#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 NPAPIClient::WindowlessPluginTest(instance,
-      NPAPIClient::PluginClient::HostFunctions(), test_name);
-    windowless_plugin = true;
-#endif
-  } else if (test_name == "getjavascripturl") {
-    new_test = new NPAPIClient::ExecuteGetJavascriptUrlTest(instance,
-      NPAPIClient::PluginClient::HostFunctions());
-  } else if (test_name == "getjavascripturl2") {
-    new_test = new NPAPIClient::ExecuteGetJavascriptUrl2Test(instance,
-      NPAPIClient::PluginClient::HostFunctions());
-#if defined(OS_WIN)
-  // TODO(port): plugin_window_size_test.*.
-  } else if (test_name == "checkwindowrect") {
-    new_test = new NPAPIClient::PluginWindowSizeTest(instance,
-      NPAPIClient::PluginClient::HostFunctions());
-#endif
-  } else if (test_name == "self_delete_plugin_stream") {
-    new_test = new NPAPIClient::DeletePluginInStreamTest(instance,
-      NPAPIClient::PluginClient::HostFunctions());
-#if defined(OS_WIN)
-  // TODO(port): plugin_npobject_lifetime_test.*.
-  } else if (test_name == "npobject_lifetime_test") {
-    new_test = new NPAPIClient::NPObjectLifetimeTest(instance,
-      NPAPIClient::PluginClient::HostFunctions());
-  } else if (test_name == "npobject_lifetime_test_second_instance") {
-    new_test = new NPAPIClient::NPObjectLifetimeTestInstance2(instance,
-      NPAPIClient::PluginClient::HostFunctions());
-  } else if (test_name == "new_fails") {
-    new_test = new NPAPIClient::NewFailsTest(instance,
-        NPAPIClient::PluginClient::HostFunctions());
-  } else if (test_name == "npobject_delete_plugin_in_evaluate") {
-    new_test = new NPAPIClient::NPObjectDeletePluginInNPN_Evaluate(instance,
-      NPAPIClient::PluginClient::HostFunctions());
-#endif
-  } else if (test_name == "plugin_javascript_open_popup_with_plugin") {
-    new_test = new NPAPIClient::ExecuteJavascriptOpenPopupWithPluginTest(
-        instance, NPAPIClient::PluginClient::HostFunctions());
-  } else if (test_name == "plugin_popup_with_plugin_target") {
-    new_test = new NPAPIClient::ExecuteJavascriptPopupWindowTargetPluginTest(
-        instance, NPAPIClient::PluginClient::HostFunctions());
-  } else if (test_name == "plugin_thread_async_call") {
-    new_test = new NPAPIClient::PluginThreadAsyncCallTest(
-        instance, NPAPIClient::PluginClient::HostFunctions());
-  } else if (test_name == "private") {
-    new_test = new NPAPIClient::PrivateTest(instance,
-      NPAPIClient::PluginClient::HostFunctions());
-  } else if (test_name == "schedule_timer") {
-    new_test = new NPAPIClient::ScheduleTimerTest(
-        instance, NPAPIClient::PluginClient::HostFunctions());
-#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") {
-    new_test = new NPAPIClient::WindowedPluginTest(instance,
-        NPAPIClient::PluginClient::HostFunctions());
-#endif
-  } else {
+  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());
+        NPAPIClient::PluginClient::HostFunctions());
   }
 
-  if (new_test) {
-    ret = new_test->New(mode, argc, (const char**)argn,
-                       (const char**)argv, saved);
-    if ((ret == NPERR_NO_ERROR) && windowless_plugin) {
-      NPAPIClient::PluginClient::HostFunctions()->setvalue(
-            instance, NPPVpluginWindowBool, NULL);
-    }
+  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;
@@ -227,10 +126,6 @@ NPError NPP_SetWindow(NPP instance, NPWindow* pNPWindow) {
   if (instance == NULL)
     return NPERR_INVALID_INSTANCE_ERROR;
 
-  if (pNPWindow->window == NULL) {
-    return NPERR_NO_ERROR;
-  }
-
   NPAPIClient::PluginTest *plugin =
     (NPAPIClient::PluginTest*)instance->pdata;
 
diff --git a/webkit/glue/plugins/test/plugin_create_instance_in_paint.cc b/webkit/glue/plugins/test/plugin_create_instance_in_paint.cc
index 00f41da..0bea703 100644
--- a/webkit/glue/plugins/test/plugin_create_instance_in_paint.cc
+++ b/webkit/glue/plugins/test/plugin_create_instance_in_paint.cc
@@ -15,6 +15,9 @@ CreateInstanceInPaintTest::CreateInstanceInPaintTest(
 }
 
 NPError CreateInstanceInPaintTest::SetWindow(NPWindow* pNPWindow) {
+  if (pNPWindow->window == NULL)
+    return NPERR_NO_ERROR;
+
   if (test_id() == "1") {
     if (!window_) {
       static ATOM window_class = 0;
diff --git a/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.cc b/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.cc
index 761ad3e..15318b4 100644
--- a/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.cc
+++ b/webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.cc
@@ -17,6 +17,9 @@ DeletePluginInStreamTest::DeletePluginInStreamTest(NPP id, NPNetscapeFuncs *host
 }
 
 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,
diff --git a/webkit/glue/plugins/test/plugin_get_javascript_url2_test.cc b/webkit/glue/plugins/test/plugin_get_javascript_url2_test.cc
index e332328..d17dced 100644
--- a/webkit/glue/plugins/test/plugin_get_javascript_url2_test.cc
+++ b/webkit/glue/plugins/test/plugin_get_javascript_url2_test.cc
@@ -29,6 +29,9 @@ ExecuteGetJavascriptUrl2Test::ExecuteGetJavascriptUrl2Test(
 }
 
 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",
diff --git a/webkit/glue/plugins/test/plugin_get_javascript_url_test.cc b/webkit/glue/plugins/test/plugin_get_javascript_url_test.cc
index 46d1ef9..cc6bc19 100644
--- a/webkit/glue/plugins/test/plugin_get_javascript_url_test.cc
+++ b/webkit/glue/plugins/test/plugin_get_javascript_url_test.cc
@@ -33,6 +33,9 @@ ExecuteGetJavascriptUrlTest::ExecuteGetJavascriptUrlTest(NPP id, NPNetscapeFuncs
 }
 
 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",
diff --git a/webkit/glue/plugins/test/plugin_geturl_test.cc b/webkit/glue/plugins/test/plugin_geturl_test.cc
index c2b9795..fab83c9 100644
--- a/webkit/glue/plugins/test/plugin_geturl_test.cc
+++ b/webkit/glue/plugins/test/plugin_geturl_test.cc
@@ -64,6 +64,9 @@ NPError PluginGetURLTest::New(uint16 mode, int16 argc, const char* argn[],
 }
 
 NPError PluginGetURLTest::SetWindow(NPWindow* pNPWindow) {
+  if (pNPWindow->window == NULL)
+    return NPERR_NO_ERROR;
+
   if (!tests_started_) {
     tests_started_ = true;
 
diff --git a/webkit/glue/plugins/test/plugin_javascript_open_popup.cc b/webkit/glue/plugins/test/plugin_javascript_open_popup.cc
index 0d3f0c0..0f93bf4 100644
--- a/webkit/glue/plugins/test/plugin_javascript_open_popup.cc
+++ b/webkit/glue/plugins/test/plugin_javascript_open_popup.cc
@@ -21,12 +21,15 @@ ExecuteJavascriptOpenPopupWithPluginTest::
 
 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 PluginTest::SetWindow(window);
+  return NPERR_NO_ERROR;
 }
 
 // ExecuteJavascriptPopupWindowTargetPluginTest member defines.
@@ -39,6 +42,9 @@ ExecuteJavascriptPopupWindowTargetPluginTest::
 
 int16 ExecuteJavascriptPopupWindowTargetPluginTest::SetWindow(
     NPWindow* window) {
+  if (window->window == NULL)
+    return NPERR_NO_ERROR;
+
   if (!test_completed_) {
     if (CheckWindow(window)) {
       SignalTestCompleted();
diff --git a/webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc b/webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc
index 1ae0fac..b62a764 100644
--- a/webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc
+++ b/webkit/glue/plugins/test/plugin_npobject_lifetime_test.cc
@@ -21,6 +21,9 @@ NPObjectLifetimeTest::NPObjectLifetimeTest(NPP id,
 }
 
 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")) {
     ::SetProp(window_handle, L"Plugin_Instance", this);
@@ -84,6 +87,9 @@ NPObjectLifetimeTestInstance2::~NPObjectLifetimeTestInstance2() {
 }
 
 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_)) {
@@ -113,6 +119,9 @@ NPObjectDeletePluginInNPN_Evaluate::~NPObjectDeletePluginInNPN_Evaluate() {
 }
 
 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
diff --git a/webkit/glue/plugins/test/plugin_npobject_proxy_test.cc b/webkit/glue/plugins/test/plugin_npobject_proxy_test.cc
index 5e80cf5..5b3a2ca 100644
--- a/webkit/glue/plugins/test/plugin_npobject_proxy_test.cc
+++ b/webkit/glue/plugins/test/plugin_npobject_proxy_test.cc
@@ -18,6 +18,9 @@ NPObjectProxyTest::NPObjectProxyTest(NPP id, NPNetscapeFuncs *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");
diff --git a/webkit/glue/plugins/test/plugin_test.h b/webkit/glue/plugins/test/plugin_test.h
index 07bbdcd..f06307ea 100644
--- a/webkit/glue/plugins/test/plugin_test.h
+++ b/webkit/glue/plugins/test/plugin_test.h
@@ -23,6 +23,9 @@ class PluginTest {
   // Destructor
   virtual ~PluginTest() {}
 
+  // Returns true if the test runs in windowless plugin mode.
+  virtual bool IsWindowless() const { return false; }
+
   //
   // NPAPI Functions
   //
diff --git a/webkit/glue/plugins/test/plugin_test_factory.cc b/webkit/glue/plugins/test/plugin_test_factory.cc
new file mode 100644
index 0000000..e2b42b3
--- /dev/null
+++ b/webkit/glue/plugins/test/plugin_test_factory.cc
@@ -0,0 +1,97 @@
+// 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/glue/plugins/test/plugin_test_factory.h"
+
+#include "webkit/glue/plugins/test/plugin_arguments_test.h"
+#include "webkit/glue/plugins/test/plugin_delete_plugin_in_stream_test.h"
+#include "webkit/glue/plugins/test/plugin_get_javascript_url_test.h"
+#include "webkit/glue/plugins/test/plugin_get_javascript_url2_test.h"
+#include "webkit/glue/plugins/test/plugin_geturl_test.h"
+#include "webkit/glue/plugins/test/plugin_javascript_open_popup.h"
+#include "webkit/glue/plugins/test/plugin_new_fails_test.h"
+#include "webkit/glue/plugins/test/plugin_npobject_lifetime_test.h"
+#include "webkit/glue/plugins/test/plugin_npobject_proxy_test.h"
+#include "webkit/glue/plugins/test/plugin_private_test.h"
+#include "webkit/glue/plugins/test/plugin_schedule_timer_test.h"
+#include "webkit/glue/plugins/test/plugin_thread_async_call_test.h"
+#include "webkit/glue/plugins/test/plugin_window_size_test.h"
+#if defined(OS_WIN)
+#include "webkit/glue/plugins/test/plugin_windowed_test.h"
+#endif
+#include "webkit/glue/plugins/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") {
+    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") {
+    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") {
+    new_test = new WindowedPluginTest(instance, host_functions);
+#endif
+  }
+
+  return new_test;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/plugin_test_factory.h b/webkit/glue/plugins/test/plugin_test_factory.h
new file mode 100644
index 0000000..3fd38d5
--- /dev/null
+++ b/webkit/glue/plugins/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_PORT_PLUGINS_TEST_PLUGIN_TEST_FACTROY_H__
+#define WEBKIT_PORT_PLUGINS_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_PORT_PLUGINS_TEST_PLUGIN_TEST_FACTROY_H__
diff --git a/webkit/glue/plugins/test/plugin_window_size_test.cc b/webkit/glue/plugins/test/plugin_window_size_test.cc
index a0cb687..9bfabca 100644
--- a/webkit/glue/plugins/test/plugin_window_size_test.cc
+++ b/webkit/glue/plugins/test/plugin_window_size_test.cc
@@ -13,6 +13,9 @@ PluginWindowSizeTest::PluginWindowSizeTest(NPP id,
 }
 
 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");
diff --git a/webkit/glue/plugins/test/plugin_windowed_test.cc b/webkit/glue/plugins/test/plugin_windowed_test.cc
index 102e214..5ae8e30 100644
--- a/webkit/glue/plugins/test/plugin_windowed_test.cc
+++ b/webkit/glue/plugins/test/plugin_windowed_test.cc
@@ -18,6 +18,9 @@ WindowedPluginTest::~WindowedPluginTest() {
 }
 
 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;
diff --git a/webkit/glue/plugins/test/plugin_windowless_test.cc b/webkit/glue/plugins/test/plugin_windowless_test.cc
index 665072e..ae6e26e 100644
--- a/webkit/glue/plugins/test/plugin_windowless_test.cc
+++ b/webkit/glue/plugins/test/plugin_windowless_test.cc
@@ -16,10 +16,9 @@ namespace NPAPIClient {
 // Remember the first plugin instance for tests involving multiple instances
 WindowlessPluginTest* g_other_instance = NULL;
 
-WindowlessPluginTest::WindowlessPluginTest(
-    NPP id, NPNetscapeFuncs *host_functions, const std::string& test_name)
-  : PluginTest(id, host_functions),
-    test_name_(test_name) {
+WindowlessPluginTest::WindowlessPluginTest(NPP id,
+                                           NPNetscapeFuncs *host_functions)
+    : PluginTest(id, host_functions) {
   if (!g_other_instance)
     g_other_instance = this;
 }
@@ -91,22 +90,22 @@ int16 WindowlessPluginTest::HandleEvent(void* event) {
     DeleteObject(clipping_region);
 #endif
 
-    if (test_name_ == "execute_script_delete_in_paint") {
+    if (test_name() == "execute_script_delete_in_paint") {
       ExecuteScriptDeleteInPaint(browser);
-    } else if (test_name_ == "multiple_instances_sync_calls") {
+    } else if (test_name() == "multiple_instances_sync_calls") {
       MultipleInstanceSyncCalls(browser);
     }
 #if OS_MACOSX
   } else if (IsWindowActivationEvent(np_event) &&
-             test_name_ == "convert_point") {
+             test_name() == "convert_point") {
       ConvertPoint(browser);
 #endif
   } else if (IsMouseMoveEvent(np_event) &&
-             test_name_ == "execute_script_delete_in_mouse_move") {
+             test_name() == "execute_script_delete_in_mouse_move") {
     ExecuteScript(browser, id(), "DeletePluginWithinScript();", NULL);
     SignalTestCompleted();
   } else if (IsMouseUpEvent(np_event) &&
-             test_name_ == "delete_frame_test") {
+             test_name() == "delete_frame_test") {
     ExecuteScript(
         browser, id(),
         "parent.document.getElementById('frame').outerHTML = ''", NULL);
diff --git a/webkit/glue/plugins/test/plugin_windowless_test.h b/webkit/glue/plugins/test/plugin_windowless_test.h
index 7ca13af..f336653 100644
--- a/webkit/glue/plugins/test/plugin_windowless_test.h
+++ b/webkit/glue/plugins/test/plugin_windowless_test.h
@@ -14,8 +14,11 @@ namespace NPAPIClient {
 class WindowlessPluginTest : public PluginTest {
  public:
   // Constructor.
-  WindowlessPluginTest(NPP id, NPNetscapeFuncs *host_functions,
-                       const std::string& test_name);
+  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);
 
@@ -25,9 +28,6 @@ class WindowlessPluginTest : public PluginTest {
   void ExecuteScriptDeleteInPaint(NPNetscapeFuncs* browser);
   void MultipleInstanceSyncCalls(NPNetscapeFuncs* browser);
   void ConvertPoint(NPNetscapeFuncs* browser);
-
- private:
-  std::string test_name_;
 };
 
 } // namespace NPAPIClient
diff --git a/webkit/glue/plugins/test/resource.h b/webkit/glue/plugins/test/resource.h
index 0d23ee9..c52fa82 100644
--- a/webkit/glue/plugins/test/resource.h
+++ b/webkit/glue/plugins/test/resource.h
@@ -1,13 +1,10 @@
-// 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.
-
 //{{NO_DEPENDENCIES}}
 // Microsoft Visual C++ generated include file.
-// Used by npapitest.rc
+// Used by npapi_test.rc
+//
 
 // Next default values for new objects
-//
+// 
 #ifdef APSTUDIO_INVOKED
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        101
diff --git a/webkit/tools/pepper_test_plugin/pepper_3d_test.cc b/webkit/tools/pepper_test_plugin/pepper_3d_test.cc
new file mode 100644
index 0000000..60d57f9
--- /dev/null
+++ b/webkit/tools/pepper_test_plugin/pepper_3d_test.cc
@@ -0,0 +1,198 @@
+// 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/tools/pepper_test_plugin/pepper_3d_test.h"
+
+namespace {
+const int32 kCommandBufferSize = 1024 * 1024;
+}  // namespace
+
+namespace NPAPIClient {
+
+Pepper3DTest::Pepper3DTest(NPP id, NPNetscapeFuncs *host_functions)
+    : PluginTest(id, host_functions),
+      pepper_extensions_(NULL),
+      device_3d_(NULL),
+      pgl_context_(PGL_NO_CONTEXT) {
+  memset(&context_3d_, 0, sizeof(context_3d_));
+
+  esInitContext(&es_context_);
+  memset(&es_data_, 0, sizeof(es_data_));
+  es_context_.userData = &es_data_;
+}
+
+Pepper3DTest::~Pepper3DTest() {
+}
+
+NPError Pepper3DTest::New(uint16 mode, int16 argc, const char* argn[],
+                          const char* argv[], NPSavedData* saved) {
+  return PluginTest::New(mode, argc, argn, argv, saved);
+}
+
+NPError Pepper3DTest::Destroy() {
+  DestroyContext();
+  pglTerminate();
+  return NPERR_NO_ERROR;
+}
+
+NPError Pepper3DTest::SetWindow(NPWindow* window) {
+  // Create context if needed.
+  CreateContext();
+
+  es_context_.width = window->width;
+  es_context_.height = window->height;
+
+  return NPERR_NO_ERROR;
+}
+
+void Pepper3DTest::RepaintCallback(NPP npp, NPDeviceContext3D* /* context */) {
+  Pepper3DTest* plugin = static_cast<Pepper3DTest*>(npp->pdata);
+  plugin->Paint();
+}
+
+void Pepper3DTest::CreateContext() {
+  if (pgl_context_ != PGL_NO_CONTEXT)
+    return;
+
+  HostFunctions()->getvalue(id(), NPNVPepperExtensions, &pepper_extensions_);
+  if (pepper_extensions_ == NULL) {
+    SetError("Could not acquire pepper extensions");
+    SignalTestCompleted();
+    return;
+  }
+
+  device_3d_ = pepper_extensions_->acquireDevice(id(), NPPepper3DDevice);
+  if (device_3d_ == NULL) {
+    SetError("Could not acquire 3D device");
+    SignalTestCompleted();
+    return;
+  }
+
+  // Initialize a 3D context.
+  NPDeviceContext3DConfig config;
+  config.commandBufferSize = kCommandBufferSize;
+  if (device_3d_->initializeContext(id(), &config, &context_3d_)
+      != NPERR_NO_ERROR) {
+    SetError("Could not initialize 3D context");
+    SignalTestCompleted();
+    return;
+  }
+  context_3d_.repaintCallback = RepaintCallback;
+
+  // Initialize PGL and create a PGL context.
+  if (!pglInitialize()) {
+    SetError("Could not initialize PGL");
+    SignalTestCompleted();
+    return;
+  }
+  pgl_context_ = pglCreateContext(id(), device_3d_, &context_3d_);
+  if (pgl_context_ == PGL_NO_CONTEXT) {
+    SetError("Could not initialize PGL context");
+    SignalTestCompleted();
+    return;
+  }
+
+  // Initialize OpenGL.
+  MakeContextCurrent();
+  InitGL();
+  pglMakeCurrent(PGL_NO_CONTEXT);
+}
+
+void Pepper3DTest::DestroyContext() {
+  if (pgl_context_ == PGL_NO_CONTEXT)
+    return;
+
+  MakeContextCurrent();
+  ReleaseGL();
+  if (!pglDestroyContext(pgl_context_)) {
+    SetError("Could not destroy PGL context");
+  }
+  pgl_context_ = PGL_NO_CONTEXT;
+
+  if (device_3d_->destroyContext(id(), &context_3d_) != NPERR_NO_ERROR) {
+    SetError("Could not destroy 3D context");
+  }
+}
+
+void Pepper3DTest::MakeContextCurrent() {
+  DCHECK(pgl_context_ != PGL_NO_CONTEXT);
+
+  if (!pglMakeCurrent(pgl_context_)) {
+    SetError("Could not make PGL context current");
+  }
+}
+
+void Pepper3DTest::Paint() {
+  MakeContextCurrent();
+  DrawGL();
+  TestGL();
+  SwapBuffers();
+  pglMakeCurrent(PGL_NO_CONTEXT);
+
+  // Painting once is enough to check correctness.
+  SignalTestCompleted();
+}
+
+void Pepper3DTest::SwapBuffers() {
+  if (!pglSwapBuffers()) {
+    SetError("Could not swap buffers");
+  }
+}
+
+void Pepper3DTest::InitGL() {
+  if (!stInit(&es_context_)) {
+    SetError("Could not initialize OpenGL resources");
+  }
+}
+
+void Pepper3DTest::ReleaseGL() {
+  stShutDown(&es_context_);
+}
+
+void Pepper3DTest::DrawGL() {
+  stDraw(&es_context_);
+}
+
+void Pepper3DTest::TestGL() {
+  // NW quadrant is red.
+  GLint x = es_context_.width / 4;
+  GLint y = (3 * es_context_.height) / 4;
+  GLubyte red_color[3] = {255, 0, 0};
+  TestPixel(x, y, red_color);
+
+  // NE quadrant is green.
+  x = (3 * es_context_.width) / 4;
+  y = (3 * es_context_.height) / 4;
+  GLubyte green_color[3] = {0, 255, 0};
+  TestPixel(x, y, green_color);
+
+  // SW quadrant is blue.
+  x = es_context_.width / 4;
+  y = es_context_.height / 4;
+  GLubyte blue_color[3] = {0, 0, 255};
+  TestPixel(x, y, blue_color);
+
+  // SE quadrant is yellow.
+  x = (3 * es_context_.width) / 4;
+  y = es_context_.height / 4;
+  GLubyte yellow_color[3] = {255, 255, 0};
+  TestPixel(x, y, yellow_color);
+
+  // Mid-point is black.
+  x = es_context_.width / 2;
+  y = es_context_.height / 2;
+  GLubyte black_color[3] = {0, 0, 0};
+  TestPixel(x, y, black_color);
+}
+
+void Pepper3DTest::TestPixel(int x, int y, const GLubyte expected_color[3]) {
+  GLubyte pixel_color[4];
+  glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel_color);
+
+  ExpectIntegerEqual(pixel_color[0], expected_color[0]);
+  ExpectIntegerEqual(pixel_color[1], expected_color[1]);
+  ExpectIntegerEqual(pixel_color[2], expected_color[2]);
+}
+
+}  // namespace NPAPIClient
diff --git a/webkit/tools/pepper_test_plugin/pepper_3d_test.h b/webkit/tools/pepper_test_plugin/pepper_3d_test.h
new file mode 100644
index 0000000..f9801d7
--- /dev/null
+++ b/webkit/tools/pepper_test_plugin/pepper_3d_test.h
@@ -0,0 +1,56 @@
+// 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_GLUE_PLUGINS_TEST_PLUGIN_PEPPER_3D_TEST_H
+#define WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_PEPPER_3D_TEST_H
+
+#include "gpu/pgl/pgl.h"
+#include "third_party/gles2_book/Chapter_11/Stencil_Test/Stencil_Test.h"
+#include "webkit/glue/plugins/test/plugin_test.h"
+
+namespace NPAPIClient {
+
+// This class contains a list of windowed plugin tests. Please add additional
+// tests to this class.
+class Pepper3DTest : public PluginTest {
+ public:
+  Pepper3DTest(NPP id, NPNetscapeFuncs *host_functions);
+  ~Pepper3DTest();
+
+  // Pepper tests run in windowless plugin mode.
+  virtual bool IsWindowless() const { return true; }
+
+  // NPAPI functions.
+  virtual NPError New(uint16 mode, int16 argc, const char* argn[],
+                      const char* argv[], NPSavedData* saved);
+  virtual NPError Destroy();
+  virtual NPError SetWindow(NPWindow* window);
+
+ private:
+  static void RepaintCallback(NPP, NPDeviceContext3D*);
+
+  void CreateContext();
+  void DestroyContext();
+  void MakeContextCurrent();
+  void Paint();
+  void SwapBuffers();
+
+  void InitGL();
+  void ReleaseGL();
+  void DrawGL();
+  void TestGL();
+  void TestPixel(int x, int y, const GLubyte expected_color[3]);
+
+  NPExtensions* pepper_extensions_;
+  NPDevice* device_3d_;
+  NPDeviceContext3D context_3d_;
+  PGLContext pgl_context_;
+
+  ESContext es_context_;
+  STUserData es_data_;
+};
+
+} // namespace NPAPIClient
+
+#endif  // WEBKIT_GLUE_PLUGINS_TEST_PLUGIN_PEPPER_3D_TEST_H
diff --git a/webkit/tools/pepper_test_plugin/pepper_test_factory.cc b/webkit/tools/pepper_test_plugin/pepper_test_factory.cc
new file mode 100644
index 0000000..1e22d0b
--- /dev/null
+++ b/webkit/tools/pepper_test_plugin/pepper_test_factory.cc
@@ -0,0 +1,23 @@
+// 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/glue/plugins/test/plugin_test_factory.h"
+
+#include "webkit/tools/pepper_test_plugin/pepper_3d_test.h"
+
+namespace NPAPIClient {
+
+PluginTest* CreatePluginTest(const std::string& test_name,
+                             NPP instance,
+                             NPNetscapeFuncs* host_functions) {
+  PluginTest* new_test = NULL;
+
+  if (test_name == "pepper_3d") {
+    new_test = new Pepper3DTest(instance, host_functions);
+  }
+
+  return new_test;
+}
+
+} // namespace NPAPIClient
diff --git a/webkit/tools/pepper_test_plugin/pepper_test_plugin.cc b/webkit/tools/pepper_test_plugin/pepper_test_plugin.cc
new file mode 100644
index 0000000..4560a79
--- /dev/null
+++ b/webkit/tools/pepper_test_plugin/pepper_test_plugin.cc
@@ -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.
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define EXPORT __attribute__((visibility ("default")))
+#else
+#define EXPORT
+#endif
+
+#include "webkit/glue/plugins/test/plugin_client.h"
+
+extern "C" {
+EXPORT NPError API_CALL NP_GetEntryPoints(NPPluginFuncs* pFuncs) {
+  return NPAPIClient::PluginClient::GetEntryPoints(pFuncs);
+}
+
+EXPORT NPError API_CALL NP_Initialize(NPNetscapeFuncs* pFuncs) {
+  return NPAPIClient::PluginClient::Initialize(pFuncs);
+}
+
+EXPORT NPError API_CALL NP_Shutdown() {
+  return NPAPIClient::PluginClient::Shutdown();
+}
+} // extern "C"
diff --git a/webkit/tools/test_shell/test_shell.gypi b/webkit/tools/test_shell/test_shell.gypi
index c5f3802..c82bd79 100644
--- a/webkit/tools/test_shell/test_shell.gypi
+++ b/webkit/tools/test_shell/test_shell.gypi
@@ -572,6 +572,23 @@
     ['target_arch!="x64" and target_arch!="arm"', {
       'targets': [
         {
+          'target_name': 'npapi_test_common',
+          'type': 'static_library',
+          'dependencies': [
+            '<(DEPTH)/base/base.gyp:base',
+            '<(DEPTH)/third_party/npapi/npapi.gyp:npapi',
+          ],
+          'sources': [
+            '../../glue/plugins/test/npapi_constants.cc',
+            '../../glue/plugins/test/npapi_constants.h',
+            '../../glue/plugins/test/plugin_client.cc',
+            '../../glue/plugins/test/plugin_client.h',
+            '../../glue/plugins/test/plugin_test.cc',
+            '../../glue/plugins/test/plugin_test.h',
+            '../../glue/plugins/test/plugin_test_factory.h',
+          ],
+        },
+        {
           'target_name': 'npapi_test_plugin',
           'type': 'loadable_module',
           'variables': {
@@ -580,20 +597,15 @@
           'mac_bundle': 1,
           'msvs_guid': '0D04AEC1-6B68-492C-BCCF-808DFD69ABC6',
           'dependencies': [
-            '<(DEPTH)/base/base.gyp:base',
             '<(DEPTH)/third_party/icu/icu.gyp:icuuc',
-            '<(DEPTH)/third_party/npapi/npapi.gyp:npapi',
+            'npapi_test_common',
           ],
           'sources': [
-            '../../glue/plugins/test/npapi_constants.cc',
-            '../../glue/plugins/test/npapi_constants.h',
             '../../glue/plugins/test/npapi_test.cc',
             '../../glue/plugins/test/npapi_test.def',
             '../../glue/plugins/test/npapi_test.rc',
             '../../glue/plugins/test/plugin_arguments_test.cc',
             '../../glue/plugins/test/plugin_arguments_test.h',
-            '../../glue/plugins/test/plugin_client.cc',
-            '../../glue/plugins/test/plugin_client.h',
             '../../glue/plugins/test/plugin_create_instance_in_paint.cc',
             '../../glue/plugins/test/plugin_create_instance_in_paint.h',
             '../../glue/plugins/test/plugin_delete_plugin_in_stream_test.cc',
@@ -620,8 +632,7 @@
             '../../glue/plugins/test/plugin_windowed_test.h',
             '../../glue/plugins/test/plugin_private_test.cc',
             '../../glue/plugins/test/plugin_private_test.h',
-            '../../glue/plugins/test/plugin_test.cc',
-            '../../glue/plugins/test/plugin_test.h',
+            '../../glue/plugins/test/plugin_test_factory.cc',
             '../../glue/plugins/test/plugin_window_size_test.cc',
             '../../glue/plugins/test/plugin_window_size_test.h',
             '../../glue/plugins/test/plugin_windowless_test.cc',
@@ -672,6 +683,28 @@
             }],
           ],
         },
+        {
+          'target_name': 'pepper_test_plugin',
+          'type': 'loadable_module',
+          'mac_bundle': 1,
+          'msvs_guid': 'EE00E36E-9E8C-4DFB-925E-FBE32CEDB91A',
+          'dependencies': [
+            '<(DEPTH)/gpu/gpu.gyp:pgl',
+            '<(DEPTH)/third_party/gles2_book/gles2_book.gyp:stencil_test',
+            'npapi_test_common',
+          ],
+          'sources': [
+            '../pepper_test_plugin/pepper_3d_test.cc',
+            '../pepper_test_plugin/pepper_3d_test.h',
+            '../pepper_test_plugin/pepper_test_factory.cc',
+            '../pepper_test_plugin/pepper_test_plugin.cc',
+            '../pepper_test_plugin/pepper_test_plugin.def',
+            '../pepper_test_plugin/pepper_test_plugin.rc',
+          ],
+          'xcode_settings': {
+            'INFOPLIST_FILE': '<(DEPTH)/webkit/tools/pepper_test_plugin/Info.plist',
+          },
+        },
       ],
     }],
     ['OS=="linux"  or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', {
-- 
cgit v1.1