Bug 509693. Make Windows test plugin in windowed mode have a child widget, and add API so we can check that that child widget is in the right place. r=josh
authorRobert O'Callahan <robert@ocallahan.org>
Thu, 24 Sep 2009 21:35:17 +1200
changeset 33358 bfbd630be11a85141bc887af3326b4710ab9a2ee
parent 33357 f3c07913015f8a79464adb52186e4188374b720a
child 33359 298772a42ecc8e3ab88ff9034430ef650ac2e188
push idunknown
push userunknown
push dateunknown
reviewersjosh
bugs509693
milestone1.9.3a1pre
Bug 509693. Make Windows test plugin in windowed mode have a child widget, and add API so we can check that that child widget is in the right place. r=josh
modules/plugin/test/testplugin/README
modules/plugin/test/testplugin/nptest.cpp
modules/plugin/test/testplugin/nptest_gtk2.cpp
modules/plugin/test/testplugin/nptest_macosx.mm
modules/plugin/test/testplugin/nptest_os2.cpp
modules/plugin/test/testplugin/nptest_platform.h
modules/plugin/test/testplugin/nptest_qt.cpp
modules/plugin/test/testplugin/nptest_windows.cpp
--- a/modules/plugin/test/testplugin/README
+++ b/modules/plugin/test/testplugin/README
@@ -206,8 +206,16 @@ The attributes which control stream test
   via calls to NPP_NewStream etc, and if a "frame" attribute is present, the
   contents of that stream will be passed back to the browser and displayed
   in the specified frame via NPN_GetURL.
 
 "newstream": if "true", then any stream which is sent to a frame in the browser
   is sent via calls to NPN_NewStream and NPN_Write.  Doing so will cause 
   the browser to store the stream data in a file, and set the frame's
   location to the corresponding file:// url.
+
+== Internal consistency ==
+
+* doInternalConsistencyCheck()
+Does internal consistency checking, returning an empty string if everything is
+OK, otherwise returning some kind of error string. On Windows, in windowed
+mode, this checks that the position of the plugin's internal child
+window has not been disturbed relative to the plugin window.
--- a/modules/plugin/test/testplugin/nptest.cpp
+++ b/modules/plugin/test/testplugin/nptest.cpp
@@ -74,16 +74,17 @@ static bool getClipRegionRectCount(NPObj
 static bool getClipRegionRectEdge(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool startWatchingInstanceCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getInstanceCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool stopWatchingInstanceCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool unscheduleAllTimers(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getLastMouseX(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getLastMouseY(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getError(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
+static bool doInternalConsistencyCheck(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 
 static const NPUTF8* sPluginMethodIdentifierNames[] = {
   "setUndefinedValueTest",
   "identifierToStringTest",
   "timerTest",
   "queryPrivateModeState",
   "lastReportedPrivateModeState",
   "hasWidget",
@@ -92,16 +93,17 @@ static const NPUTF8* sPluginMethodIdenti
   "getClipRegionRectEdge",
   "startWatchingInstanceCount",
   "getInstanceCount",
   "stopWatchingInstanceCount",
   "unscheduleAllTimers",
   "getLastMouseX",
   "getLastMouseY",
   "getError",
+  "doInternalConsistencyCheck",
 };
 static NPIdentifier sPluginMethodIdentifiers[ARRAY_LENGTH(sPluginMethodIdentifierNames)];
 static const ScriptableFunction sPluginMethodFunctions[ARRAY_LENGTH(sPluginMethodIdentifierNames)] = {
   setUndefinedValueTest,
   identifierToStringTest,
   timerTest,
   queryPrivateModeState,
   lastReportedPrivateModeState,
@@ -111,16 +113,17 @@ static const ScriptableFunction sPluginM
   getClipRegionRectEdge,
   startWatchingInstanceCount,
   getInstanceCount,
   stopWatchingInstanceCount,
   unscheduleAllTimers,
   getLastMouseX,
   getLastMouseY,
   getError,
+  doInternalConsistencyCheck,
 };
 
 static char* NPN_GetURLNotifyCookie = "NPN_GetURLNotify_Cookie";
 
 static bool sIdentifiersInitialized = false;
 
 /**
  * Incremented for every startWatchingInstanceCount.
@@ -1328,16 +1331,38 @@ getLastMouseY(NPObject* npobj, const NPV
   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
   INT32_TO_NPVARIANT(id->lastMouseY, *result);
   return true;
 }
 
 static bool
 getError(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
 {
+  if (argCount != 0)
+    return false;
+
   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
   if (id->err.str().length() == 0)
     STRINGZ_TO_NPVARIANT(strdup("pass"), *result);
   else
     STRINGZ_TO_NPVARIANT(strdup(id->err.str().c_str()), *result);
   return true;
 }
+
+static bool
+doInternalConsistencyCheck(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+  if (argCount != 0)
+    return false;
+
+  NPP npp = static_cast<TestNPObject*>(npobj)->npp;
+  InstanceData* id = static_cast<InstanceData*>(npp->pdata);
+  string error;
+  pluginDoInternalConsistencyCheck(id, error);
+  NPUTF8* utf8String = (NPUTF8*)NPN_MemAlloc(error.length() + 1);
+  if (!utf8String) {
+    return false;
+  }
+  memcpy(utf8String, error.c_str(), error.length() + 1);
+  STRINGZ_TO_NPVARIANT(utf8String, *result);
+  return true;
+}
--- a/modules/plugin/test/testplugin/nptest_gtk2.cpp
+++ b/modules/plugin/test/testplugin/nptest_gtk2.cpp
@@ -37,24 +37,16 @@
 #include "npapi.h"
 #include <gdk/gdk.h>
 #ifdef MOZ_X11
 #include <gdk/gdkx.h>
 #include <X11/extensions/shape.h>
 #endif
 #include <gtk/gtk.h>
 
-/**
- * XXX In various places in this file we use GDK APIs to inspect the
- * window ancestors of the plugin. These APIs will not work properly if
- * this plugin is used in a browser that does not use GDK for all its
- * widgets. They would also fail for out-of-process plugins. These should
- * be fixed to use raw X APIs instead.
- */
-
 struct _PlatformData {
   Display* display;
   GtkWidget* plug;
 };
 
 bool
 pluginSupportsWindowMode()
 {
@@ -542,8 +534,12 @@ int32_t pluginGetClipRegionRectEdge(Inst
     return rect.y;
   case EDGE_RIGHT:
     return rect.x + rect.width;
   case EDGE_BOTTOM:
     return rect.y + rect.height;
   }
   return NPTEST_INT32_ERROR;
 }
+
+void pluginDoInternalConsistencyCheck(InstanceData* instanceData, string& error)
+{
+}
--- a/modules/plugin/test/testplugin/nptest_macosx.mm
+++ b/modules/plugin/test/testplugin/nptest_macosx.mm
@@ -373,8 +373,12 @@ int32_t pluginGetClipRegionRectEdge(Inst
     return w->clipRect.top + COCOA_TITLEBAR_HEIGHT;
   case EDGE_RIGHT:
     return w->clipRect.right;
   case EDGE_BOTTOM:
     return w->clipRect.bottom + COCOA_TITLEBAR_HEIGHT;
   }
   return NPTEST_INT32_ERROR;
 }
+
+void pluginDoInternalConsistencyCheck(InstanceData* instanceData, string& error)
+{
+}
--- a/modules/plugin/test/testplugin/nptest_os2.cpp
+++ b/modules/plugin/test/testplugin/nptest_os2.cpp
@@ -86,8 +86,12 @@ int32_t pluginGetClipRegionRectCount(Ins
 }
 
 int32_t pluginGetClipRegionRectEdge(InstanceData* instanceData, 
     int32_t rectIndex, RectEdge edge)
 {
   // XXX nothing here yet since we don't support windowed plugins
   return NPTEST_INT32_ERROR;
 }
+
+void pluginDoInternalConsistencyCheck(InstanceData* instanceData, string& error)
+{
+}
--- a/modules/plugin/test/testplugin/nptest_platform.h
+++ b/modules/plugin/test/testplugin/nptest_platform.h
@@ -108,9 +108,16 @@ int32_t pluginGetClipRegionRectCount(Ins
  * clip region, relative to the top-left corner of the toplevel window
  * containing the plugin, including window decorations. Only works for
  * window-mode plugins and Mac plugins.
  * Returns NPTEST_ERROR on error.
  */
 int32_t pluginGetClipRegionRectEdge(InstanceData* instanceData, 
     int32_t rectIndex, RectEdge edge);
 
+/**
+ * Check that the platform-specific plugin state is internally consistent.
+ * Just return if everything is OK, otherwise append error messages
+ * to 'error' separated by \n.
+ */
+void pluginDoInternalConsistencyCheck(InstanceData* instanceData, string& error);
+
 #endif // nptest_platform_h_
--- a/modules/plugin/test/testplugin/nptest_qt.cpp
+++ b/modules/plugin/test/testplugin/nptest_qt.cpp
@@ -86,8 +86,12 @@ int32_t pluginGetClipRegionRectCount(Ins
 }
 
 int32_t pluginGetClipRegionRectEdge(InstanceData* instanceData, 
     int32_t rectIndex, RectEdge edge)
 {
   // XXX nothing here yet since we don't support windowed plugins
   return NPTEST_INT32_ERROR;
 }
+
+void pluginDoInternalConsistencyCheck(InstanceData* instanceData, string& error)
+{
+}
--- a/modules/plugin/test/testplugin/nptest_windows.cpp
+++ b/modules/plugin/test/testplugin/nptest_windows.cpp
@@ -38,54 +38,77 @@
 #include <windowsx.h>
 
 #pragma comment(lib, "msimg32.lib")
 
 void SetSubclass(HWND hWnd, InstanceData* instanceData);
 void ClearSubclass(HWND hWnd);
 LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
+struct _PlatformData {
+  HWND childWindow;
+};
+
 bool
 pluginSupportsWindowMode()
 {
   return true;
 }
 
 bool
 pluginSupportsWindowlessMode()
 {
   return true;
 }
 
 NPError
 pluginInstanceInit(InstanceData* instanceData)
 {
+  instanceData->platformData = static_cast<PlatformData*>
+    (NPN_MemAlloc(sizeof(PlatformData)));
+  if (!instanceData->platformData)
+    return NPERR_OUT_OF_MEMORY_ERROR;
+
+  instanceData->platformData->childWindow = NULL;
   return NPERR_NO_ERROR;
 }
 
 void
 pluginInstanceShutdown(InstanceData* instanceData)
 {
+  NPN_MemFree(instanceData->platformData);
+  instanceData->platformData = 0;
 }
 
 void
 pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow)
 {
   instanceData->window = *newWindow;
 }
 
+#define CHILD_WIDGET_SIZE 10
+
 void
 pluginWidgetInit(InstanceData* instanceData, void* oldWindow)
 {
   HWND hWnd = (HWND)instanceData->window.window;
   if (oldWindow) {
     HWND hWndOld = (HWND)oldWindow;
     ClearSubclass(hWndOld);
+    if (instanceData->platformData->childWindow) {
+      ::DestroyWindow(instanceData->platformData->childWindow);
+    }
   }
+
   SetSubclass(hWnd, instanceData);
+
+  instanceData->platformData->childWindow =
+    ::CreateWindowW(L"SCROLLBAR", L"Dummy child window", 
+                    WS_CHILD, 0, 0, CHILD_WIDGET_SIZE, CHILD_WIDGET_SIZE, hWnd, NULL,
+                    NULL, NULL);
 }
 
 static void
 drawToDC(InstanceData* instanceData, HDC dc,
          int x, int y, int width, int height)
 {
   HBITMAP offscreenBitmap = ::CreateCompatibleBitmap(dc, width, height);
   if (!offscreenBitmap)
@@ -443,8 +466,35 @@ ClearSubclass(HWND hWnd)
 void
 SetSubclass(HWND hWnd, InstanceData* instanceData)
 {
   // Subclass the plugin window so we can handle our own windows events.
   SetProp(hWnd, "InstanceData", (HANDLE)instanceData);
   WNDPROC origProc = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)PluginWndProc);
   SetProp(hWnd, "MozillaWndProc", (HANDLE)origProc);
 }
+
+static void checkEquals(int a, int b, const char* msg, string& error)
+{
+  if (a == b) {
+    return;
+  }
+
+  error.append(msg);
+  char buf[100];
+  sprintf(buf, " (got %d, expected %d)\n", a, b);
+  error.append(buf);
+}
+
+void pluginDoInternalConsistencyCheck(InstanceData* instanceData, string& error)
+{
+  if (instanceData->platformData->childWindow) {
+    RECT childRect;
+    ::GetWindowRect(instanceData->platformData->childWindow, &childRect);
+    RECT ourRect;
+    HWND hWnd = (HWND)instanceData->window.window;
+    ::GetWindowRect(hWnd, &ourRect);
+    checkEquals(childRect.left, ourRect.left, "Child widget left", error);
+    checkEquals(childRect.top, ourRect.top, "Child widget top", error);
+    checkEquals(childRect.right, childRect.left + CHILD_WIDGET_SIZE, "Child widget width", error);
+    checkEquals(childRect.bottom, childRect.top + CHILD_WIDGET_SIZE, "Child widget height", error);
+  }
+}