Bug 594774. Test a=blocking-beta6+
authorRobert O'Callahan <roc@ocallahan.org>
Wed, 15 Sep 2010 11:30:27 -0400
changeset 53936 25b165f66af394612577e27497e945b3d6e29304
parent 53935 a08e5d5a32563ef087bf3ee3c4d74f3a10cbb13a
child 53937 0d1a1547836087a26ce08e0e50226cf819ded593
child 53945 63136f3a12bf9db26d890021d7de30199688b406
push idunknown
push userunknown
push dateunknown
reviewersblocking-beta6
bugs594774
milestone2.0b7pre
Bug 594774. Test a=blocking-beta6+
modules/plugin/test/crashtests/522512-1.html
modules/plugin/test/crashtests/crashtests.list
modules/plugin/test/testplugin/README
modules/plugin/test/testplugin/nptest.cpp
modules/plugin/test/testplugin/nptest.h
modules/plugin/test/testplugin/nptest_gtk2.cpp
modules/plugin/test/testplugin/nptest_macosx.mm
modules/plugin/test/testplugin/nptest_windows.cpp
new file mode 100644
--- /dev/null
+++ b/modules/plugin/test/crashtests/522512-1.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<head>
+<script>
+var doingTest = false;
+function onPaint() {
+  if (!doingTest)
+    return;
+
+  var d = document.getElementById("d");
+  if (d) {
+    document.body.removeChild(d);
+  }
+  document.documentElement.removeAttribute("class");
+}
+function runTest() {
+  doingTest = true;
+  // Force a repaint of the entire page
+  document.body.style.backgroundColor = "lime";
+}
+window.addEventListener("MozReftestInvalidate", runTest, false);
+</script>
+</head>
+<body>
+  <embed type="application/x-test" paintscript="onPaint()"
+         style="position:absolute; top:20px; left:20px; width:200px; height:200px;"></embed>
+  <div id="d" style="position:absolute; top:50px; left:50px; width:100px; height:100px">
+    Hello Kitty
+  </div>
+</body>
+</html>
--- a/modules/plugin/test/crashtests/crashtests.list
+++ b/modules/plugin/test/crashtests/crashtests.list
@@ -1,7 +1,7 @@
 load 41276-1.html
 load 48856-1.html
-
 load 110650-1.html
+load 522512-1.html
 skip-if(cocoaWidget) script 539897-1.html
 script 540114-1.html
 load 570884.html
--- a/modules/plugin/test/testplugin/README
+++ b/modules/plugin/test/testplugin/README
@@ -125,16 +125,23 @@ available.
 * timerTest(callback) - initiates tests of NPN_ScheduleTimer &
 NPN_UnscheduleTimer.  When finished, calls the script callback
 with a boolean value, indicating whether the tests were successful.
 
 * asyncCallbackTest(callback) - initiates tests of
 NPN_PluginThreadAsyncCall.  When finished, calls the script callback
 with a boolean value, indicating whether the tests were successful.
 
+* paintscript="..." content attribute
+If the "paintscript" attribute is set on the plugin element during plugin
+initialization, then every time the plugin paints it gets the contents of that
+attribute and evaluates it as a script in the context of the plugin's DOM
+window. This is useful for testing evil plugin code that might, for example,
+modify the DOM during painting.
+
 == Private browsing ==
 
 The test plugin object supports the following scriptable methods:
 
 * queryPrivateModeState
 Returns the value of NPN_GetValue(NPNVprivateModeBool).
 
 * lastReportedPrivateModeState
--- a/modules/plugin/test/testplugin/nptest.cpp
+++ b/modules/plugin/test/testplugin/nptest.cpp
@@ -688,16 +688,17 @@ NPP_New(NPMIMEType pluginType, NPP insta
   instanceData->failureCode = 0;
   instanceData->callOnDestroy = NULL;
   instanceData->streamChunkSize = 1024;
   instanceData->streamBuf = NULL;
   instanceData->streamBufSize = 0;
   instanceData->fileBuf = NULL;
   instanceData->fileBufSize = 0;
   instanceData->throwOnNextInvoke = false;
+  instanceData->runScriptOnPaint = false;
   instanceData->testrange = NULL;
   instanceData->hasWidget = false;
   instanceData->npnNewStream = false;
   instanceData->invalidateDuringPaint = false;
   instanceData->writeCount = 0;
   instanceData->writeReadyCount = 0;
   memset(&instanceData->window, 0, sizeof(instanceData->window));
   instanceData->crashOnDestroy = false;
@@ -738,31 +739,31 @@ NPP_New(NPMIMEType pluginType, NPP insta
     else if (strcmp(argn[i], "color") == 0) {
       scriptableObject->drawColor = parseHexColor(argv[i], strlen(argv[i]));
     }
     else if (strcmp(argn[i], "wmode") == 0) {
       if (strcmp(argv[i], "window") == 0) {
         requestWindow = true;
       }
     }
-	  if (strcmp(argn[i], "streammode") == 0) {
+    if (strcmp(argn[i], "streammode") == 0) {
       if (strcmp(argv[i], "normal") == 0) {
         instanceData->streamMode = NP_NORMAL;
       }
       else if ((strcmp(argv[i], "asfile") == 0) &&
                 strlen(argv[i]) == strlen("asfile")) {
         instanceData->streamMode = NP_ASFILE;
       }
       else if (strcmp(argv[i], "asfileonly") == 0) {
         instanceData->streamMode = NP_ASFILEONLY;
       }
       else if (strcmp(argv[i], "seek") == 0) {
         instanceData->streamMode = NP_SEEK;
       }
-	  }
+    }
     if (strcmp(argn[i], "streamchunksize") == 0) {
       instanceData->streamChunkSize = atoi(argv[i]);
     }
     if (strcmp(argn[i], "failurecode") == 0) {
       instanceData->failureCode = atoi(argv[i]);
     }
     if (strcmp(argn[i], "functiontofail") == 0) {
       instanceData->functionToFail = getFuncFromString(argv[i]);
@@ -806,16 +807,19 @@ NPP_New(NPMIMEType pluginType, NPP insta
     }
     if (strcmp(argn[i], "newstream") == 0 &&
         strcmp(argv[i], "true") == 0) {
       instanceData->npnNewStream = true;
     }
     if (strcmp(argn[i], "newcrash") == 0) {
       IntentionalCrash();
     }
+    if (strcmp(argn[i], "paintscript") == 0) {
+      instanceData->runScriptOnPaint = true;
+    }
     // "cleanupwidget" is only used with nptest_gtk, defaulting to true.  It
     // indicates whether the plugin should destroy its window in response to
     // NPP_Destroy (or let the platform destroy the widget when the parent
     // window gets destroyed).
     if (strcmp(argn[i], "cleanupwidget") == 0 &&
         strcmp(argv[i], "false") == 0) {
       instanceData->cleanupWidget = false;
     }
@@ -2385,16 +2389,43 @@ void notifyDidPaint(InstanceData* instan
   if (instanceData->invalidateDuringPaint) {
     NPRect r;
     r.left = 0;
     r.top = 0;
     r.right = instanceData->window.width;
     r.bottom = instanceData->window.height;
     NPN_InvalidateRect(instanceData->npp, &r);
   }
+
+  if (instanceData->runScriptOnPaint) {
+    NPObject* o = NULL;
+    NPN_GetValue(instanceData->npp, NPNVPluginElementNPObject, &o);
+    if (o) {
+      NPVariant param;
+      STRINGZ_TO_NPVARIANT("paintscript", param);
+      NPVariant result;
+      NPN_Invoke(instanceData->npp, o, NPN_GetStringIdentifier("getAttribute"),
+                 &param, 1, &result);
+
+      if (NPVARIANT_IS_STRING(result)) {
+        NPObject* windowObject;
+        NPN_GetValue(instanceData->npp, NPNVWindowNPObject, &windowObject);
+        if (windowObject) {
+          NPVariant evalResult;
+          NPN_Evaluate(instanceData->npp, windowObject,
+                       (NPString*)&NPVARIANT_TO_STRING(result), &evalResult);
+          NPN_ReleaseVariantValue(&evalResult);
+          NPN_ReleaseObject(windowObject);
+        }
+      }
+
+      NPN_ReleaseVariantValue(&result);
+      NPN_ReleaseObject(o);
+    }
+  }
 }
 
 static const NPClass kTestSharedNPClass = {
   NP_CLASS_STRUCT_VERSION,
   // Everything else is NULL
 };
 
 static bool getObjectValue(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
--- a/modules/plugin/test/testplugin/nptest.h
+++ b/modules/plugin/test/testplugin/nptest.h
@@ -94,16 +94,17 @@ typedef struct InstanceData {
   NPWindow window;
   TestNPObject* scriptableObject;
   PlatformData* platformData;
   int32_t instanceCountWatchGeneration;
   bool lastReportedPrivateModeState;
   bool hasWidget;
   bool npnNewStream;
   bool throwOnNextInvoke;
+  bool runScriptOnPaint;
   uint32_t timerID[2];
   bool timerTestResult;
   bool asyncCallbackResult;
   bool invalidateDuringPaint;
   int32_t winX;
   int32_t winY;
   int32_t lastMouseX;
   int32_t lastMouseY;
--- a/modules/plugin/test/testplugin/nptest_gtk2.cpp
+++ b/modules/plugin/test/testplugin/nptest_gtk2.cpp
@@ -160,23 +160,24 @@ pluginDrawWindow(InstanceData* instanceD
 {
   NPWindow& window = instanceData->window;
   // When we have a widget, window.x/y are meaningless since our
   // widget is always positioned correctly and we just draw into it at 0,0
   int x = instanceData->hasWidget ? 0 : window.x;
   int y = instanceData->hasWidget ? 0 : window.y;
   int width = window.width;
   int height = window.height;
+  
+  notifyDidPaint(instanceData);
 
   if (instanceData->scriptableObject->drawMode == DM_SOLID_COLOR) {
     // drawing a solid color for reftests
     pluginDrawSolid(instanceData, gdkWindow,
                     invalidRect.x, invalidRect.y,
                     invalidRect.width, invalidRect.height);
-    notifyDidPaint(instanceData);
     return;
   }
 
   NPP npp = instanceData->npp;
   if (!npp)
     return;
 
   const char* uaString = NPN_UserAgent(npp);
@@ -212,18 +213,16 @@ pluginDrawWindow(InstanceData* instanceD
   PangoContext* pangoContext = gdk_pango_context_get();
   PangoLayout* pangoTextLayout = pango_layout_new(pangoContext);
   pango_layout_set_width(pangoTextLayout, (width - 10) * PANGO_SCALE);
   pango_layout_set_text(pangoTextLayout, uaString, -1);
   gdk_draw_layout(gdkWindow, gdkContext, x + 5, y + 5, pangoTextLayout);
   g_object_unref(pangoTextLayout);
 
   g_object_unref(gdkContext);
-
-  notifyDidPaint(instanceData);
 }
 
 static gboolean
 ExposeWidget(GtkWidget* widget, GdkEventExpose* event,
              gpointer user_data)
 {
   InstanceData* instanceData = static_cast<InstanceData*>(user_data);
   pluginDrawWindow(instanceData, event->window, event->area);
--- a/modules/plugin/test/testplugin/nptest_macosx.mm
+++ b/modules/plugin/test/testplugin/nptest_macosx.mm
@@ -134,16 +134,18 @@ GetColorsFromRGBA(PRUint32 rgba, float* 
 }
 
 static void
 pluginDraw(InstanceData* instanceData, NPCocoaEvent* event)
 {
   if (!instanceData)
     return;
 
+  notifyDidPaint(instanceData);
+
   NPP npp = instanceData->npp;
   if (!npp)
     return;
   
   const char* uaString = NPN_UserAgent(npp);
   if (!uaString)
     return;
 
@@ -236,18 +238,16 @@ pluginDraw(InstanceData* instanceData, N
     CGContextSetRGBFillColor(cgContext, r, g, b, a);
     CGContextDrawPath(cgContext, kCGPathFill);
 
     // restore the cgcontext gstate
     CGContextRestoreGState(cgContext);
     break;
   }
   }
-
-  notifyDidPaint(instanceData);
 }
 
 int16_t
 pluginHandleEvent(InstanceData* instanceData, void* event)
 {
 #ifndef NP_NO_CARBON
   if (instanceData->eventModel == NPEventModelCarbon) {
     EventRecord* carbonEvent = (EventRecord*)event;
--- a/modules/plugin/test/testplugin/nptest_windows.cpp
+++ b/modules/plugin/test/testplugin/nptest_windows.cpp
@@ -197,16 +197,18 @@ pluginDraw(InstanceData* instanceData)
 {
   NPP npp = instanceData->npp;
   if (!npp)
     return;
 
   HDC hdc = NULL;
   PAINTSTRUCT ps;
 
+  notifyDidPaint(instanceData);
+
   if (instanceData->hasWidget)
     hdc = ::BeginPaint((HWND)instanceData->window.window, &ps);
   else
     hdc = (HDC)instanceData->window.window;
 
   if (hdc == NULL)
     return;
 
@@ -222,18 +224,16 @@ pluginDraw(InstanceData* instanceData)
   int height = instanceData->window.height;
   drawToDC(instanceData, hdc, x, y, width, height);
 
   // Pop our hdc changes off the resource stack
   RestoreDC(hdc, savedDCID);
 
   if (instanceData->hasWidget)
     ::EndPaint((HWND)instanceData->window.window, &ps);
-
-  notifyDidPaint(instanceData);
 }
 
 /* script interface */
 
 int32_t
 pluginGetEdge(InstanceData* instanceData, RectEdge edge)
 {
   if (!instanceData || !instanceData->hasWidget)