summaryrefslogtreecommitdiffstats
path: root/dom/plugins/test/mochitest
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /dom/plugins/test/mochitest
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'dom/plugins/test/mochitest')
-rw-r--r--dom/plugins/test/mochitest/307-xo-redirect.sjs6
-rw-r--r--dom/plugins/test/mochitest/browser.ini15
-rw-r--r--dom/plugins/test/mochitest/browser_bug1163570.js96
-rw-r--r--dom/plugins/test/mochitest/browser_bug1196539.js119
-rw-r--r--dom/plugins/test/mochitest/browser_pluginscroll.js302
-rw-r--r--dom/plugins/test/mochitest/browser_tabswitchbetweenplugins.js105
-rw-r--r--dom/plugins/test/mochitest/chrome.ini34
-rw-r--r--dom/plugins/test/mochitest/cocoa_focus.html142
-rw-r--r--dom/plugins/test/mochitest/cocoa_window_focus.html95
-rw-r--r--dom/plugins/test/mochitest/crashing_subpage.html4
-rw-r--r--dom/plugins/test/mochitest/dialog_watcher.js183
-rw-r--r--dom/plugins/test/mochitest/file_authident.js6
-rw-r--r--dom/plugins/test/mochitest/file_bug1245545.js22
-rw-r--r--dom/plugins/test/mochitest/file_bug738396.html87
-rw-r--r--dom/plugins/test/mochitest/file_bug771202.html8
-rw-r--r--dom/plugins/test/mochitest/file_bug863792.html45
-rw-r--r--dom/plugins/test/mochitest/file_checkcookie.sjs17
-rw-r--r--dom/plugins/test/mochitest/file_setcookie.html9
-rw-r--r--dom/plugins/test/mochitest/hang_test.js114
-rw-r--r--dom/plugins/test/mochitest/hangui_common.js20
-rw-r--r--dom/plugins/test/mochitest/hangui_iface.js121
-rw-r--r--dom/plugins/test/mochitest/hangui_subpage.html4
-rw-r--r--dom/plugins/test/mochitest/head.js133
-rw-r--r--dom/plugins/test/mochitest/large-pic.jpgbin0 -> 98570 bytes
-rw-r--r--dom/plugins/test/mochitest/loremipsum.txt11
-rw-r--r--dom/plugins/test/mochitest/loremipsum.xtest11
-rw-r--r--dom/plugins/test/mochitest/loremipsum.xtest^headers^1
-rw-r--r--dom/plugins/test/mochitest/loremipsum_file.txt11
-rw-r--r--dom/plugins/test/mochitest/loremipsum_nocache.txt11
-rw-r--r--dom/plugins/test/mochitest/loremipsum_nocache.txt^headers^1
-rw-r--r--dom/plugins/test/mochitest/mixed_case_mime.sjs8
-rw-r--r--dom/plugins/test/mochitest/mochitest.ini150
-rw-r--r--dom/plugins/test/mochitest/neverending.sjs16
-rw-r--r--dom/plugins/test/mochitest/npruntime_identifiers_subpage.html4
-rw-r--r--dom/plugins/test/mochitest/plugin-stream-referer.sjs12
-rw-r--r--dom/plugins/test/mochitest/plugin-utils.js95
-rw-r--r--dom/plugins/test/mochitest/plugin_no_scroll_div.html10
-rw-r--r--dom/plugins/test/mochitest/plugin_scroll_invalidation.html60
-rw-r--r--dom/plugins/test/mochitest/plugin_subframe_test.html10
-rw-r--r--dom/plugins/test/mochitest/plugin_test.html11
-rw-r--r--dom/plugins/test/mochitest/plugin_visibility_loader.html6
-rw-r--r--dom/plugins/test/mochitest/plugin_window.html23
-rw-r--r--dom/plugins/test/mochitest/pluginstream.js39
-rw-r--r--dom/plugins/test/mochitest/post.sjs17
-rw-r--r--dom/plugins/test/mochitest/privatemode_perwindowpb.xul11
-rw-r--r--dom/plugins/test/mochitest/test_CrashService_crash.html28
-rw-r--r--dom/plugins/test/mochitest/test_CrashService_hang.html28
-rw-r--r--dom/plugins/test/mochitest/test_GCrace.html62
-rw-r--r--dom/plugins/test/mochitest/test_NPNVdocumentOrigin.html47
-rw-r--r--dom/plugins/test/mochitest/test_NPPVpluginWantsAllNetworkStreams.html77
-rw-r--r--dom/plugins/test/mochitest/test_bug1092842.html46
-rw-r--r--dom/plugins/test/mochitest/test_bug1165981.html81
-rw-r--r--dom/plugins/test/mochitest/test_bug1245545.html52
-rw-r--r--dom/plugins/test/mochitest/test_bug1307694.html41
-rw-r--r--dom/plugins/test/mochitest/test_bug406541.html100
-rw-r--r--dom/plugins/test/mochitest/test_bug479979.xul38
-rw-r--r--dom/plugins/test/mochitest/test_bug532208.html29
-rw-r--r--dom/plugins/test/mochitest/test_bug539565-1.html91
-rw-r--r--dom/plugins/test/mochitest/test_bug539565-2.html111
-rw-r--r--dom/plugins/test/mochitest/test_bug738396.html88
-rw-r--r--dom/plugins/test/mochitest/test_bug751809.html84
-rw-r--r--dom/plugins/test/mochitest/test_bug771202.html48
-rw-r--r--dom/plugins/test/mochitest/test_bug777098.html58
-rw-r--r--dom/plugins/test/mochitest/test_bug784131.html85
-rw-r--r--dom/plugins/test/mochitest/test_bug813906.html54
-rw-r--r--dom/plugins/test/mochitest/test_bug827160.html54
-rw-r--r--dom/plugins/test/mochitest/test_bug852315.html62
-rw-r--r--dom/plugins/test/mochitest/test_bug854082.html38
-rw-r--r--dom/plugins/test/mochitest/test_bug863792.html40
-rw-r--r--dom/plugins/test/mochitest/test_bug967694.html78
-rw-r--r--dom/plugins/test/mochitest/test_bug985859.html27
-rw-r--r--dom/plugins/test/mochitest/test_bug986930.html20
-rw-r--r--dom/plugins/test/mochitest/test_busy_hang.xul47
-rw-r--r--dom/plugins/test/mochitest/test_clear_site_data.html242
-rw-r--r--dom/plugins/test/mochitest/test_cocoa_focus.html28
-rw-r--r--dom/plugins/test/mochitest/test_cocoa_window_focus.html28
-rw-r--r--dom/plugins/test/mochitest/test_convertpoint.xul83
-rw-r--r--dom/plugins/test/mochitest/test_cookies.html23
-rw-r--r--dom/plugins/test/mochitest/test_copyText.html40
-rw-r--r--dom/plugins/test/mochitest/test_crash_nested_loop.html46
-rw-r--r--dom/plugins/test/mochitest/test_crash_notify.xul106
-rw-r--r--dom/plugins/test/mochitest/test_crash_notify_no_report.xul116
-rw-r--r--dom/plugins/test/mochitest/test_crash_submit.xul157
-rw-r--r--dom/plugins/test/mochitest/test_crashing.html62
-rw-r--r--dom/plugins/test/mochitest/test_crashing2.html74
-rw-r--r--dom/plugins/test/mochitest/test_defaultValue.html38
-rw-r--r--dom/plugins/test/mochitest/test_enumerate.html36
-rw-r--r--dom/plugins/test/mochitest/test_fullpage.html35
-rw-r--r--dom/plugins/test/mochitest/test_getauthenticationinfo.html81
-rw-r--r--dom/plugins/test/mochitest/test_hang_submit.xul165
-rw-r--r--dom/plugins/test/mochitest/test_hanging.html63
-rw-r--r--dom/plugins/test/mochitest/test_hangui.xul262
-rw-r--r--dom/plugins/test/mochitest/test_hidden_plugin.html44
-rw-r--r--dom/plugins/test/mochitest/test_idle_hang.xul47
-rw-r--r--dom/plugins/test/mochitest/test_instance_re-parent.html123
-rw-r--r--dom/plugins/test/mochitest/test_instance_unparent1.html51
-rw-r--r--dom/plugins/test/mochitest/test_instance_unparent2.html62
-rw-r--r--dom/plugins/test/mochitest/test_instance_unparent3.html54
-rw-r--r--dom/plugins/test/mochitest/test_instantiation.html33
-rw-r--r--dom/plugins/test/mochitest/test_mixed_case_mime.html29
-rw-r--r--dom/plugins/test/mochitest/test_multipleinstanceobjects.html24
-rw-r--r--dom/plugins/test/mochitest/test_newstreamondestroy.html36
-rw-r--r--dom/plugins/test/mochitest/test_npn_asynccall.html33
-rw-r--r--dom/plugins/test/mochitest/test_npn_timers.html33
-rw-r--r--dom/plugins/test/mochitest/test_npobject_getters.html21
-rw-r--r--dom/plugins/test/mochitest/test_npruntime.xul29
-rw-r--r--dom/plugins/test/mochitest/test_npruntime_construct.html32
-rw-r--r--dom/plugins/test/mochitest/test_npruntime_identifiers.html67
-rw-r--r--dom/plugins/test/mochitest/test_npruntime_npnevaluate.html101
-rw-r--r--dom/plugins/test/mochitest/test_npruntime_npninvoke.html162
-rw-r--r--dom/plugins/test/mochitest/test_npruntime_npninvokedefault.html153
-rw-r--r--dom/plugins/test/mochitest/test_object.html510
-rw-r--r--dom/plugins/test/mochitest/test_painting.html121
-rw-r--r--dom/plugins/test/mochitest/test_plugin_scroll_invalidation.html109
-rw-r--r--dom/plugins/test/mochitest/test_plugin_scroll_painting.html64
-rw-r--r--dom/plugins/test/mochitest/test_plugin_tag_clicktoplay.html35
-rw-r--r--dom/plugins/test/mochitest/test_pluginstream_3rdparty.html76
-rw-r--r--dom/plugins/test/mochitest/test_pluginstream_asfile.html33
-rw-r--r--dom/plugins/test/mochitest/test_pluginstream_asfileonly.html30
-rw-r--r--dom/plugins/test/mochitest/test_pluginstream_err.html165
-rw-r--r--dom/plugins/test/mochitest/test_pluginstream_geturl.html31
-rw-r--r--dom/plugins/test/mochitest/test_pluginstream_geturlnotify.html30
-rw-r--r--dom/plugins/test/mochitest/test_pluginstream_newstream.html32
-rw-r--r--dom/plugins/test/mochitest/test_pluginstream_post.html33
-rw-r--r--dom/plugins/test/mochitest/test_pluginstream_poststream.html31
-rw-r--r--dom/plugins/test/mochitest/test_pluginstream_referer.html55
-rw-r--r--dom/plugins/test/mochitest/test_pluginstream_seek.html33
-rw-r--r--dom/plugins/test/mochitest/test_pluginstream_seek_close.html45
-rw-r--r--dom/plugins/test/mochitest/test_pluginstream_src.html33
-rw-r--r--dom/plugins/test/mochitest/test_pluginstream_src_dynamic.html43
-rw-r--r--dom/plugins/test/mochitest/test_pluginstream_src_referer.html30
-rw-r--r--dom/plugins/test/mochitest/test_positioning.html56
-rw-r--r--dom/plugins/test/mochitest/test_privatemode_perwindowpb.xul120
-rw-r--r--dom/plugins/test/mochitest/test_propertyAndMethod.html51
-rw-r--r--dom/plugins/test/mochitest/test_queryCSSZoomFactor.html48
-rw-r--r--dom/plugins/test/mochitest/test_queryContentsScaleFactor.html31
-rw-r--r--dom/plugins/test/mochitest/test_queryContentsScaleFactorWindowed.html31
-rw-r--r--dom/plugins/test/mochitest/test_redirect_handling.html67
-rw-r--r--dom/plugins/test/mochitest/test_refresh_navigator_plugins.html68
-rw-r--r--dom/plugins/test/mochitest/test_secondPlugin.html73
-rw-r--r--dom/plugins/test/mochitest/test_src_url_change.html42
-rw-r--r--dom/plugins/test/mochitest/test_streamNotify.html89
-rw-r--r--dom/plugins/test/mochitest/test_streamatclose.html46
-rw-r--r--dom/plugins/test/mochitest/test_stringHandling.html35
-rw-r--r--dom/plugins/test/mochitest/test_twostreams.html46
-rw-r--r--dom/plugins/test/mochitest/test_visibility.html100
-rw-r--r--dom/plugins/test/mochitest/test_windowed_invalidate.html66
-rw-r--r--dom/plugins/test/mochitest/test_windowless_flash.html33
-rw-r--r--dom/plugins/test/mochitest/test_windowless_ime.html46
-rw-r--r--dom/plugins/test/mochitest/test_wmode.xul38
-rw-r--r--dom/plugins/test/mochitest/test_x11_error_crash.html27
-rw-r--r--dom/plugins/test/mochitest/test_xulbrowser_plugin_visibility.xul24
-rw-r--r--dom/plugins/test/mochitest/test_zero_opacity.html44
-rw-r--r--dom/plugins/test/mochitest/xulbrowser_plugin_visibility.xul139
154 files changed, 9497 insertions, 0 deletions
diff --git a/dom/plugins/test/mochitest/307-xo-redirect.sjs b/dom/plugins/test/mochitest/307-xo-redirect.sjs
new file mode 100644
index 000000000..b880978ce
--- /dev/null
+++ b/dom/plugins/test/mochitest/307-xo-redirect.sjs
@@ -0,0 +1,6 @@
+function handleRequest(request, response)
+{
+ response.setStatusLine(request.httpVersion, 307, "Moved temporarily");
+ response.setHeader("Location", "http://example.org/tests/dom/plugins/test/mochitest/loremipsum.txt");
+ response.setHeader("Content-Type", "text/html");
+}
diff --git a/dom/plugins/test/mochitest/browser.ini b/dom/plugins/test/mochitest/browser.ini
new file mode 100644
index 000000000..a28a22f10
--- /dev/null
+++ b/dom/plugins/test/mochitest/browser.ini
@@ -0,0 +1,15 @@
+[DEFAULT]
+support-files =
+ head.js
+ plugin_test.html
+ plugin_subframe_test.html
+ plugin_no_scroll_div.html
+
+[browser_bug1163570.js]
+skip-if = true # Bug 1249878
+[browser_bug1196539.js]
+skip-if = (!e10s || os != "win")
+[browser_tabswitchbetweenplugins.js]
+skip-if = (!e10s || os != "win")
+[browser_pluginscroll.js]
+skip-if = (true || !e10s || os != "win") # Bug 1213631
diff --git a/dom/plugins/test/mochitest/browser_bug1163570.js b/dom/plugins/test/mochitest/browser_bug1163570.js
new file mode 100644
index 000000000..c6a75d2ec
--- /dev/null
+++ b/dom/plugins/test/mochitest/browser_bug1163570.js
@@ -0,0 +1,96 @@
+var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+
+// simple tab load helper, pilfered from browser plugin tests
+function promiseTabLoad(tab, url, eventType="load") {
+ return new Promise((resolve) => {
+ function handle(event) {
+ if (event.originalTarget != tab.linkedBrowser.contentDocument ||
+ event.target.location.href == "about:blank" ||
+ (url && event.target.location.href != url)) {
+ return;
+ }
+ tab.linkedBrowser.removeEventListener(eventType, handle, true);
+ resolve(event);
+ }
+
+ tab.linkedBrowser.addEventListener(eventType, handle, true, true);
+ if (url) {
+ tab.linkedBrowser.loadURI(url);
+ }
+ });
+}
+
+// dom event listener helper
+function promiseWaitForEvent(object, eventName, capturing = false, chrome = false) {
+ return new Promise((resolve) => {
+ function listener(event) {
+ object.removeEventListener(eventName, listener, capturing, chrome);
+ resolve(event);
+ }
+ object.addEventListener(eventName, listener, capturing, chrome);
+ });
+}
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ window.focus();
+ });
+});
+
+add_task(function* () {
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+
+ let pluginTab = gBrowser.selectedTab = gBrowser.addTab();
+ let prefTab = gBrowser.addTab();
+
+ yield promiseTabLoad(pluginTab, gTestRoot + "plugin_test.html");
+ yield promiseTabLoad(prefTab, "about:preferences");
+
+ yield ContentTask.spawn(gBrowser.selectedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ Assert.ok(!!plugin, "plugin is loaded");
+ });
+
+ let ppromise = promiseWaitForEvent(window, "MozAfterPaint");
+ gBrowser.selectedTab = prefTab;
+ yield ppromise;
+
+ // We're going to switch tabs using actual mouse clicks, which helps
+ // reproduce this bug.
+ let tabStripContainer = document.getElementById("tabbrowser-tabs");
+
+ // diagnosis if front end layout changes
+ info("-> " + tabStripContainer.tagName); // tabs
+ info("-> " + tabStripContainer.firstChild.tagName); // tab
+ info("-> " + tabStripContainer.childNodes[0].label); // test harness tab
+ info("-> " + tabStripContainer.childNodes[1].label); // plugin tab
+ info("-> " + tabStripContainer.childNodes[2].label); // preferences tab
+
+ for (let iteration = 0; iteration < 5; iteration++) {
+ ppromise = promiseWaitForEvent(window, "MozAfterPaint");
+ EventUtils.synthesizeMouseAtCenter(tabStripContainer.childNodes[1], {}, window);
+ yield ppromise;
+
+ yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ Assert.ok(XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(),
+ "plugin is visible");
+ });
+
+ ppromise = promiseWaitForEvent(window, "MozAfterPaint");
+ EventUtils.synthesizeMouseAtCenter(tabStripContainer.childNodes[2], {}, window);
+ yield ppromise;
+
+ yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ Assert.ok(!XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible(),
+ "plugin is hidden");
+ });
+ }
+
+ gBrowser.removeTab(prefTab);
+ gBrowser.removeTab(pluginTab);
+});
diff --git a/dom/plugins/test/mochitest/browser_bug1196539.js b/dom/plugins/test/mochitest/browser_bug1196539.js
new file mode 100644
index 000000000..8b2210ccd
--- /dev/null
+++ b/dom/plugins/test/mochitest/browser_bug1196539.js
@@ -0,0 +1,119 @@
+var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+
+function checkPaintCount(aCount) {
+ ok(aCount != 0, "paint count can't be greater than zero, count was " + aCount);
+ ok(aCount < kMaxPaints, "paint count should be within limits, count was " + aCount);
+}
+
+// maximum number of paints we allow before failing. The test plugin doesn't
+// animate so this should really be just 1, but operating systems can
+// occasionally fire a few of these so we give these tests a fudge factor.
+// A bad regression would either be 0, or 100+.
+const kMaxPaints = 10;
+
+add_task(function* () {
+ let result, tabSwitchedPromise;
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+
+ let testTab = gBrowser.selectedTab;
+ let pluginTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gTestRoot + "plugin_test.html");
+ let homeTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:home");
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return !!plugin;
+ });
+ is(result, true, "plugin is loaded");
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return !XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, true, "plugin is hidden");
+
+ // reset plugin paint count
+ yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ XPCNativeWrapper.unwrap(plugin).resetPaintCount();
+ });
+
+ // select plugin tab
+ tabSwitchedPromise = waitTabSwitched();
+ gBrowser.selectedTab = pluginTab;
+ yield tabSwitchedPromise;
+
+ // wait a bit for spurious paints
+ yield waitForMs(100);
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, true, "plugin is visible");
+
+ // check for good paint count
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).getPaintCount();
+ });
+ checkPaintCount(result);
+
+ // select home tab
+ tabSwitchedPromise = waitTabSwitched();
+ gBrowser.selectedTab = homeTab;
+ yield tabSwitchedPromise;
+
+ // reset paint count
+ yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ XPCNativeWrapper.unwrap(plugin).resetPaintCount();
+ });
+
+ // wait a bit for spurious paints
+ yield waitForMs(100);
+
+ // check for no paint count
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).getPaintCount();
+ });
+ is(result, 0, "no paints, this is correct.");
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return !XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, true, "plugin is hidden");
+
+ // reset paint count
+ yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ XPCNativeWrapper.unwrap(plugin).resetPaintCount();
+ });
+
+ // select plugin tab
+ tabSwitchedPromise = waitTabSwitched();
+ gBrowser.selectedTab = pluginTab;
+ yield tabSwitchedPromise;
+
+ // check paint count
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).getPaintCount();
+ });
+ checkPaintCount(result);
+
+ gBrowser.removeTab(homeTab);
+ gBrowser.removeTab(pluginTab);
+});
diff --git a/dom/plugins/test/mochitest/browser_pluginscroll.js b/dom/plugins/test/mochitest/browser_pluginscroll.js
new file mode 100644
index 000000000..7314b8410
--- /dev/null
+++ b/dom/plugins/test/mochitest/browser_pluginscroll.js
@@ -0,0 +1,302 @@
+var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+
+/**
+ * tests for plugin windows and scroll
+ */
+
+function coordinatesRelativeToWindow(aX, aY, aElement) {
+ var targetWindow = aElement.ownerDocument.defaultView;
+ var scale = targetWindow.devicePixelRatio;
+ var rect = aElement.getBoundingClientRect();
+ return {
+ x: targetWindow.mozInnerScreenX + ((rect.left + aX) * scale),
+ y: targetWindow.mozInnerScreenY + ((rect.top + aY) * scale)
+ };
+}
+
+var apzEnabled = Preferences.get("layers.async-pan-zoom.enabled", false);
+var pluginHideEnabled = Preferences.get("gfx.e10s.hide-plugins-for-scroll", true);
+
+
+add_task(function* () {
+ registerCleanupFunction(function () {
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
+ });
+});
+
+add_task(function*() {
+ yield new Promise((resolve) => {
+ SpecialPowers.pushPrefEnv({
+ "set": [
+ ["general.smoothScroll", true],
+ ["general.smoothScroll.other", true],
+ ["general.smoothScroll.mouseWheel", true],
+ ["general.smoothScroll.other.durationMaxMS", 2000],
+ ["general.smoothScroll.other.durationMinMS", 1999],
+ ["general.smoothScroll.mouseWheel.durationMaxMS", 2000],
+ ["general.smoothScroll.mouseWheel.durationMinMS", 1999],
+ ]}, resolve);
+ });
+});
+
+/*
+ * test plugin visibility when scrolling with scroll wheel and apz in a top level document.
+ */
+
+add_task(function* () {
+ let result;
+
+ if (!apzEnabled) {
+ ok(true, "nothing to test, need apz");
+ return;
+ }
+
+ if (!pluginHideEnabled) {
+ ok(true, "nothing to test, need gfx.e10s.hide-plugins-for-scroll");
+ return;
+ }
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+
+ let testTab = gBrowser.selectedTab;
+ let pluginTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gTestRoot + "plugin_test.html");
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return !!plugin;
+ });
+ is(result, true, "plugin is loaded");
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, true, "plugin is visible");
+
+ let nativeId = nativeVerticalWheelEventMsg();
+ let utils = SpecialPowers.getDOMWindowUtils(window);
+ let screenCoords = coordinatesRelativeToWindow(10, 10,
+ gBrowser.selectedBrowser);
+ utils.sendNativeMouseScrollEvent(screenCoords.x, screenCoords.y,
+ nativeId, 0, -50, 0, 0, 0,
+ gBrowser.selectedBrowser);
+
+ yield waitScrollStart(gBrowser.selectedBrowser);
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, false, "plugin is hidden");
+
+ yield waitScrollFinish(gBrowser.selectedBrowser);
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, true, "plugin is visible");
+
+ gBrowser.removeTab(pluginTab);
+});
+
+/*
+ * test plugin visibility when scrolling with scroll wheel and apz in a sub document.
+ */
+
+add_task(function* () {
+ let result;
+
+ if (!apzEnabled) {
+ ok(true, "nothing to test, need apz");
+ return;
+ }
+
+ if (!pluginHideEnabled) {
+ ok(true, "nothing to test, need gfx.e10s.hide-plugins-for-scroll");
+ return;
+ }
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+
+ let testTab = gBrowser.selectedTab;
+ let pluginTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gTestRoot + "plugin_subframe_test.html");
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document.getElementById("subframe").contentDocument;
+ let plugin = doc.getElementById("testplugin");
+ return !!plugin;
+ });
+ is(result, true, "plugin is loaded");
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document.getElementById("subframe").contentDocument;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, true, "plugin is visible");
+
+ let nativeId = nativeVerticalWheelEventMsg();
+ let utils = SpecialPowers.getDOMWindowUtils(window);
+ let screenCoords = coordinatesRelativeToWindow(10, 10,
+ gBrowser.selectedBrowser);
+ utils.sendNativeMouseScrollEvent(screenCoords.x, screenCoords.y,
+ nativeId, 0, -50, 0, 0, 0,
+ gBrowser.selectedBrowser);
+
+ yield waitScrollStart(gBrowser.selectedBrowser);
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document.getElementById("subframe").contentDocument;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, false, "plugin is hidden");
+
+ yield waitScrollFinish(gBrowser.selectedBrowser);
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document.getElementById("subframe").contentDocument;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, true, "plugin is visible");
+
+ gBrowser.removeTab(pluginTab);
+});
+
+/*
+ * test visibility when scrolling with keyboard shortcuts for a top level document.
+ * This circumvents apz and relies on dom scroll, which is what we want to target
+ * for this test.
+ */
+
+add_task(function* () {
+ let result;
+
+ if (!pluginHideEnabled) {
+ ok(true, "nothing to test, need gfx.e10s.hide-plugins-for-scroll");
+ return;
+ }
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+
+ let testTab = gBrowser.selectedTab;
+ let pluginTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gTestRoot + "plugin_test.html");
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return !!plugin;
+ });
+ is(result, true, "plugin is loaded");
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, true, "plugin is visible");
+
+ EventUtils.synthesizeKey("VK_END", {});
+
+ yield waitScrollStart(gBrowser.selectedBrowser);
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, false, "plugin is hidden");
+
+ yield waitScrollFinish(gBrowser.selectedBrowser);
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, false, "plugin is hidden");
+
+ EventUtils.synthesizeKey("VK_HOME", {});
+
+ yield waitScrollFinish(gBrowser.selectedBrowser);
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, true, "plugin is visible");
+
+ gBrowser.removeTab(pluginTab);
+});
+
+/*
+ * test visibility when scrolling with keyboard shortcuts for a sub document.
+ */
+
+add_task(function* () {
+ let result;
+
+ if (!pluginHideEnabled) {
+ ok(true, "nothing to test, need gfx.e10s.hide-plugins-for-scroll");
+ return;
+ }
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+
+ let testTab = gBrowser.selectedTab;
+ let pluginTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gTestRoot + "plugin_subframe_test.html");
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document.getElementById("subframe").contentDocument;
+ let plugin = doc.getElementById("testplugin");
+ return !!plugin;
+ });
+ is(result, true, "plugin is loaded");
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document.getElementById("subframe").contentDocument;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, true, "plugin is visible");
+
+ EventUtils.synthesizeKey("VK_END", {});
+
+ yield waitScrollStart(gBrowser.selectedBrowser);
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document.getElementById("subframe").contentDocument;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, false, "plugin is hidden");
+
+ yield waitScrollFinish(gBrowser.selectedBrowser);
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document.getElementById("subframe").contentDocument;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, false, "plugin is hidden");
+
+ EventUtils.synthesizeKey("VK_HOME", {});
+
+ yield waitScrollFinish(gBrowser.selectedBrowser);
+
+ result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let doc = content.document.getElementById("subframe").contentDocument;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, true, "plugin is visible");
+
+ gBrowser.removeTab(pluginTab);
+});
diff --git a/dom/plugins/test/mochitest/browser_tabswitchbetweenplugins.js b/dom/plugins/test/mochitest/browser_tabswitchbetweenplugins.js
new file mode 100644
index 000000000..d1994c209
--- /dev/null
+++ b/dom/plugins/test/mochitest/browser_tabswitchbetweenplugins.js
@@ -0,0 +1,105 @@
+var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
+
+// tests that we get plugin updates when we flip between tabs that
+// have the same plugin in the same position in the page.
+
+add_task(function* () {
+ let result, tabSwitchedPromise;
+
+ setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+
+ let testTab = gBrowser.selectedTab;
+ let pluginTab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gTestRoot + "plugin_test.html");
+ let pluginTab2 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gTestRoot + "plugin_test.html");
+
+ result = yield ContentTask.spawn(pluginTab1.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return !!plugin;
+ });
+ is(result, true, "plugin1 is loaded");
+
+ result = yield ContentTask.spawn(pluginTab2.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return !!plugin;
+ });
+ is(result, true, "plugin2 is loaded");
+
+ // plugin tab 2 should be selected
+ is(gBrowser.selectedTab == pluginTab2, true, "plugin2 is selected");
+
+ result = yield ContentTask.spawn(pluginTab1.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, false, "plugin1 is hidden");
+
+ result = yield ContentTask.spawn(pluginTab2.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, true, "plugin2 is visible");
+
+ // select plugin1 tab
+ tabSwitchedPromise = waitTabSwitched();
+ gBrowser.selectedTab = pluginTab1;
+ yield tabSwitchedPromise;
+
+ result = yield ContentTask.spawn(pluginTab1.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, true, "plugin1 is visible");
+
+ result = yield ContentTask.spawn(pluginTab2.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, false, "plugin2 is hidden");
+
+ // select plugin2 tab
+ tabSwitchedPromise = waitTabSwitched();
+ gBrowser.selectedTab = pluginTab2;
+ yield tabSwitchedPromise;
+
+ result = yield ContentTask.spawn(pluginTab1.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, false, "plugin1 is hidden");
+
+ result = yield ContentTask.spawn(pluginTab2.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, true, "plugin2 is visible");
+
+ // select test tab
+ tabSwitchedPromise = waitTabSwitched();
+ gBrowser.selectedTab = testTab;
+ yield tabSwitchedPromise;
+
+ result = yield ContentTask.spawn(pluginTab1.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, false, "plugin1 is hidden");
+
+ result = yield ContentTask.spawn(pluginTab2.linkedBrowser, null, function*() {
+ let doc = content.document;
+ let plugin = doc.getElementById("testplugin");
+ return XPCNativeWrapper.unwrap(plugin).nativeWidgetIsVisible();
+ });
+ is(result, false, "plugin2 is hidden");
+
+ gBrowser.removeTab(pluginTab1);
+ gBrowser.removeTab(pluginTab2);
+});
diff --git a/dom/plugins/test/mochitest/chrome.ini b/dom/plugins/test/mochitest/chrome.ini
new file mode 100644
index 000000000..35a1c7ddc
--- /dev/null
+++ b/dom/plugins/test/mochitest/chrome.ini
@@ -0,0 +1,34 @@
+[DEFAULT]
+support-files =
+ hang_test.js
+ privatemode_perwindowpb.xul
+ plugin-utils.js
+
+[test_bug479979.xul]
+[test_bug751809.html]
+[test_busy_hang.xul]
+skip-if = (!crashreporter) || (os != "win")
+[test_clear_site_data.html]
+[test_convertpoint.xul]
+skip-if = toolkit != "cocoa"
+[test_crash_notify.xul]
+skip-if = !crashreporter
+[test_crash_notify_no_report.xul]
+skip-if = !crashreporter
+[test_crash_submit.xul]
+skip-if = !crashreporter
+[test_hang_submit.xul]
+skip-if = !crashreporter
+[test_hangui.xul]
+skip-if = (!crashreporter) || (os != "win")
+support-files = hangui_subpage.html hangui_common.js hangui_iface.js dialog_watcher.js
+[test_idle_hang.xul]
+skip-if = (!crashreporter) || (os != "win")
+[test_npruntime.xul]
+[test_plugin_tag_clicktoplay.html]
+[test_privatemode_perwindowpb.xul]
+[test_refresh_navigator_plugins.html]
+[test_xulbrowser_plugin_visibility.xul]
+skip-if = (toolkit == "cocoa") || (os == "win")
+support-files = xulbrowser_plugin_visibility.xul plugin_visibility_loader.html
+[test_wmode.xul]
diff --git a/dom/plugins/test/mochitest/cocoa_focus.html b/dom/plugins/test/mochitest/cocoa_focus.html
new file mode 100644
index 000000000..ca35fd7a1
--- /dev/null
+++ b/dom/plugins/test/mochitest/cocoa_focus.html
@@ -0,0 +1,142 @@
+<html>
+<head>
+ <title>NPCocoaEventFocusChanged Tests</title>
+</head>
+<body>
+ <embed id="plugin1" type="application/x-test" width="100" height="100"></embed>
+ <embed id="plugin2" type="application/x-test" width="100" height="100"></embed>
+ <script type="application/javascript">
+ function is(aLeft, aRight, aMessage) {
+ window.opener.SimpleTest.is(aLeft, aRight, aMessage);
+ }
+
+ function ok(aValue, aMessage) {
+ window.opener.SimpleTest.ok(aValue, aMessage);
+ }
+
+ function synthesizeNativeMouseEvent(aX, aY, aNativeMsg, aModifiers, aElement, aCallback) {
+ var observer = {
+ observe: function(aSubject, aTopic, aData) {
+ if (aCallback && aTopic == "mouseevent") {
+ aCallback(aData);
+ }
+ }
+ };
+ SpecialPowers.DOMWindowUtils.sendNativeMouseEvent(aX, aY, aNativeMsg, aModifiers, aElement, observer);
+ return true;
+ }
+
+ function* runTests() {
+ var utils = SpecialPowers.DOMWindowUtils;
+ var scale = utils.screenPixelsPerCSSPixel;
+
+ var plugin1 = document.getElementById("plugin1"); // What we're testing.
+ var plugin2 = document.getElementById("plugin2"); // Dummy.
+
+ var plugin1Bounds = plugin1.getBoundingClientRect();
+ var plugin2Bounds = plugin2.getBoundingClientRect();
+
+ var plugin1X = (window.mozInnerScreenX + plugin1Bounds.left + 10);
+ var plugin1Y = (window.mozInnerScreenY + plugin1Bounds.top + 10);
+ var plugin2X = (window.mozInnerScreenX + plugin2Bounds.left + 10);
+ var plugin2Y = (window.mozInnerScreenY + plugin2Bounds.top + 10);
+
+ const NSLeftMouseDown = 1,
+ NSLeftMouseUp = 2;
+
+ if (plugin1.getEventModel() != 1) {
+ window.opener.todo(false, "Skipping this test when not testing the Cocoa event model");
+ return;
+ }
+
+ // Initialize to 0 since there is no initial state event,
+ // plugins should assume they do not initially have focus.
+ var expectedEventCount = 0;
+
+ // Make sure initial event count is correct.
+ is(plugin1.getFocusEventCount(), expectedEventCount, "Focus event count should be " + expectedEventCount);
+
+ // Make sure initial focus state is unknown (assumed false).
+ var initialStateUnknown = false;
+ try {
+ plugin1.getFocusState();
+ } catch (e) {
+ initialStateUnknown = true;
+ }
+ is(initialStateUnknown, true, "Initial state should be unknown, assumed false.");
+
+ // Give the plugin focus (the window is already focused).
+ yield synthesizeNativeMouseEvent(plugin1X * scale, plugin1Y * scale, NSLeftMouseDown, 0, plugin1, continueTest);
+ yield synthesizeNativeMouseEvent(plugin1X * scale, plugin1Y * scale, NSLeftMouseUp, 0, plugin1, continueTest);
+ expectedEventCount++;
+
+ is(plugin1.getFocusState(), true, "(1) Plugin should have focus.");
+ is(plugin1.getFocusEventCount(), expectedEventCount, "Focus event count should be " + expectedEventCount);
+
+ // Make sure window activation state changes don't spontaneously
+ // change plugin focus.
+
+ // Blur the window.
+ SpecialPowers.focus(opener);
+
+ is(plugin1.getFocusState(), true, "(2) Plugin should still have focus.");
+ is(plugin1.getFocusEventCount(), expectedEventCount, "Focus event count should be " + expectedEventCount);
+
+ // Focus the window.
+ SpecialPowers.focus(window);
+
+ is(plugin1.getFocusState(), true, "(3) Plugin should still have focus.");
+ is(plugin1.getFocusEventCount(), expectedEventCount, "Focus event count should be " + expectedEventCount);
+
+ // Take focus from the plugin.
+ yield synthesizeNativeMouseEvent(plugin2X * scale, plugin2Y * scale, NSLeftMouseDown, 0, plugin2, continueTest);
+ yield synthesizeNativeMouseEvent(plugin2X * scale, plugin2Y * scale, NSLeftMouseUp, 0, plugin2, continueTest);
+ expectedEventCount++;
+
+ is(plugin1.getFocusState(), false, "(4) Plugin should not have focus.");
+ is(plugin1.getFocusEventCount(), expectedEventCount, "Focus event count should be " + expectedEventCount);
+
+ // Make sure window activation causes the plugin to be informed of focus
+ // changes that took place while the window was inactive.
+
+ // Give the plugin focus (the window is already focused).
+ yield synthesizeNativeMouseEvent(plugin1X * scale, plugin1Y * scale, NSLeftMouseDown, 0, plugin1, continueTest);
+ yield synthesizeNativeMouseEvent(plugin1X * scale, plugin1Y * scale, NSLeftMouseUp, 0, plugin1, continueTest);
+ expectedEventCount++;
+
+ // Blur the window.
+ SpecialPowers.focus(opener);
+
+ // Take focus from the plugin while the window is blurred.
+ plugin2.focus();
+
+ is(plugin1.getFocusState(), true, "(5) Plugin should still have focus.");
+ is(plugin1.getFocusEventCount(), expectedEventCount, "Focus event count should be " + expectedEventCount);
+
+ // Focus the window.
+ SpecialPowers.focus(window);
+ expectedEventCount++;
+
+ is(plugin1.getFocusState(), false, "(6) Plugin should not have focus.");
+ is(plugin1.getFocusEventCount(), expectedEventCount, "Focus event count should be " + expectedEventCount);
+ }
+
+ var gTestContinuation = null;
+ function continueTest() {
+ if (!gTestContinuation) {
+ gTestContinuation = runTests();
+ }
+ var ret = gTestContinuation.next();
+ if (ret.done) {
+ window.opener.testsFinished();
+ } else {
+ is(ret.value, true, "Mouse event successfully synthesized");
+ }
+ }
+
+ // Onload hander doesn't work for these tests -- no events arrive at the plugin.
+ window.opener.SimpleTest.waitForFocus(continueTest, window);
+
+ </script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/cocoa_window_focus.html b/dom/plugins/test/mochitest/cocoa_window_focus.html
new file mode 100644
index 000000000..8305b19a4
--- /dev/null
+++ b/dom/plugins/test/mochitest/cocoa_window_focus.html
@@ -0,0 +1,95 @@
+<html>
+<head>
+ <title>NPCocoaEventWindowFocusChanged Tests</title>
+</head>
+<body onload="runTests()">
+ <embed id="plugin1" type="application/x-test" width="400" height="400"></embed>
+ <embed id="plugin2" type="application/x-test" width="400" height="400"></embed>
+ <script type="application/javascript">
+ function is(aLeft, aRight, aMessage) {
+ window.opener.SimpleTest.is(aLeft, aRight, aMessage);
+ }
+
+ function ok(aValue, aMessage) {
+ window.opener.SimpleTest.ok(aValue, aMessage);
+ }
+
+ function executeSoon(func) {
+ window.opener.SimpleTest.executeSoon(func);
+ }
+
+ function waitForFocus(aCb, aTarget, aBlank) {
+ window.opener.SimpleTest.waitForFocus(aCb, aTarget, aBlank);
+ }
+
+ function runTests() {
+ var plugin1 = document.getElementById("plugin1");
+ var plugin2 = document.getElementById("plugin2");
+
+ if (plugin1.getEventModel() != 1) {
+ window.opener.todo(false, "Skipping this test when not testing the Cocoa event model");
+ window.opener.testsFinished();
+ return;
+ }
+
+ // The first plugin will have in-page focus for these tests.
+ plugin1.focus();
+
+ // The expected event count which applies to all instances.
+ // Initialize to 1 to account for the initial state event.
+ var expectedEventCount = 1;
+
+ // First make sure the plugins got an initial window focus event.
+ // Since this window was just opened it should be in the front. If
+ // the plugin has not been sent an initial window state then it will
+ // be in an unknown state and it will throw an exception.
+ try {
+ is(plugin1.getTopLevelWindowActivationState(), true, "Activation state should be: activated");
+ is(plugin1.getTopLevelWindowActivationEventCount(), expectedEventCount, "Window focus event count should be " + expectedEventCount);
+
+ is(plugin2.getTopLevelWindowActivationState(), true, "Activation state should be: activated");
+ is(plugin2.getTopLevelWindowActivationEventCount(), expectedEventCount, "Window focus event count should be " + expectedEventCount);
+ } catch (e) {
+ ok(false, "Plugin does not know its initial top-level window activation state!");
+ }
+
+ var fm = SpecialPowers.Services.focus;
+
+ waitForFocus(function() {
+ // Make sure the plugin handled the focus event before checking.
+ executeSoon(function() {
+ expectedEventCount++;
+
+ is(plugin1.getTopLevelWindowActivationState(), false, "Activation state should be: deactivated");
+ is(plugin1.getTopLevelWindowActivationEventCount(), expectedEventCount, "Window focus event count should be " + expectedEventCount);
+
+ is(plugin2.getTopLevelWindowActivationState(), false, "Activation state should be: deactivated");
+ is(plugin2.getTopLevelWindowActivationEventCount(), expectedEventCount, "Window focus event count should be " + expectedEventCount);
+
+ // Bring our window back to the front and make sure plugins were properly notified.
+ fm.focusedWindow = window;
+
+ waitForFocus(function() {
+ // Make sure the plugin handled the focus event before checking.
+ executeSoon(function() {
+ expectedEventCount++;
+
+ is(plugin1.getTopLevelWindowActivationState(), true, "Activation state should be: activated");
+ is(plugin1.getTopLevelWindowActivationEventCount(), expectedEventCount, "Window focus event count should be " + expectedEventCount);
+
+ is(plugin2.getTopLevelWindowActivationState(), true, "Activation state should be: activated");
+ is(plugin2.getTopLevelWindowActivationEventCount(), expectedEventCount, "Window focus event count should be " + expectedEventCount);
+
+ window.opener.testsFinished();
+ });
+ }, window);
+ });
+ }, window.opener);
+
+ // Send our window to the back and make sure plugins were properly notified.
+ // Calling window.blur() is not allowed.
+ fm.focusedWindow = window.opener;
+ }
+ </script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/crashing_subpage.html b/dom/plugins/test/mochitest/crashing_subpage.html
new file mode 100644
index 000000000..7c00f25c4
--- /dev/null
+++ b/dom/plugins/test/mochitest/crashing_subpage.html
@@ -0,0 +1,4 @@
+<html>
+<body onload="window.parent.frameLoaded()">
+ <h1>Crashing subpage</h1>
+ <embed id="plugin1" type="application/x-test" width="400" height="400" drawmode="solid" color="FF00FFFF"></embed>
diff --git a/dom/plugins/test/mochitest/dialog_watcher.js b/dom/plugins/test/mochitest/dialog_watcher.js
new file mode 100644
index 000000000..8a8c82997
--- /dev/null
+++ b/dom/plugins/test/mochitest/dialog_watcher.js
@@ -0,0 +1,183 @@
+const EVENT_OBJECT_SHOW = 0x8002;
+const EVENT_OBJECT_HIDE = 0x8003;
+const WINEVENT_OUTOFCONTEXT = 0;
+const WINEVENT_SKIPOWNPROCESS = 2;
+const QS_ALLINPUT = 0x04FF;
+const INFINITE = 0xFFFFFFFF;
+const WAIT_OBJECT_0 = 0;
+const WAIT_TIMEOUT = 258;
+const PM_NOREMOVE = 0;
+
+function DialogWatcher(titleText, onDialogStart, onDialogEnd) {
+ this.titleText = titleText;
+ this.onDialogStart = onDialogStart;
+ this.onDialogEnd = onDialogEnd;
+}
+
+DialogWatcher.prototype.init = function() {
+ this.hwnd = undefined;
+ if (!this.user32) {
+ this.user32 = ctypes.open("user32.dll");
+ }
+ if (!this.findWindow) {
+ this.findWindow = user32.declare("FindWindowW",
+ ctypes.winapi_abi,
+ ctypes.uintptr_t,
+ ctypes.char16_t.ptr,
+ ctypes.char16_t.ptr);
+ }
+ if (!this.winEventProcType) {
+ this.winEventProcType = ctypes.FunctionType(ctypes.stdcall_abi,
+ ctypes.void_t,
+ [ctypes.uintptr_t,
+ ctypes.uint32_t,
+ ctypes.uintptr_t,
+ ctypes.long,
+ ctypes.long,
+ ctypes.uint32_t,
+ ctypes.uint32_t]).ptr;
+ }
+ if (!this.setWinEventHook) {
+ this.setWinEventHook = user32.declare("SetWinEventHook",
+ ctypes.winapi_abi,
+ ctypes.uintptr_t,
+ ctypes.uint32_t,
+ ctypes.uint32_t,
+ ctypes.uintptr_t,
+ this.winEventProcType,
+ ctypes.uint32_t,
+ ctypes.uint32_t,
+ ctypes.uint32_t);
+ }
+ if (!this.unhookWinEvent) {
+ this.unhookWinEvent = user32.declare("UnhookWinEvent",
+ ctypes.winapi_abi,
+ ctypes.int,
+ ctypes.uintptr_t);
+ }
+ if (!this.pointType) {
+ this.pointType = ctypes.StructType("tagPOINT",
+ [ { "x": ctypes.long },
+ { "y": ctypes.long } ] );
+ }
+ if (!this.msgType) {
+ this.msgType = ctypes.StructType("tagMSG",
+ [ { "hwnd": ctypes.uintptr_t },
+ { "message": ctypes.uint32_t },
+ { "wParam": ctypes.uintptr_t },
+ { "lParam": ctypes.intptr_t },
+ { "time": ctypes.uint32_t },
+ { "pt": this.pointType } ] );
+ }
+ if (!this.peekMessage) {
+ this.peekMessage = user32.declare("PeekMessageW",
+ ctypes.winapi_abi,
+ ctypes.int,
+ this.msgType.ptr,
+ ctypes.uintptr_t,
+ ctypes.uint32_t,
+ ctypes.uint32_t,
+ ctypes.uint32_t);
+ }
+ if (!this.msgWaitForMultipleObjects) {
+ this.msgWaitForMultipleObjects = user32.declare("MsgWaitForMultipleObjects",
+ ctypes.winapi_abi,
+ ctypes.uint32_t,
+ ctypes.uint32_t,
+ ctypes.uintptr_t.ptr,
+ ctypes.int,
+ ctypes.uint32_t,
+ ctypes.uint32_t);
+ }
+ if (!this.getWindowTextW) {
+ this.getWindowTextW = user32.declare("GetWindowTextW",
+ ctypes.winapi_abi,
+ ctypes.int,
+ ctypes.uintptr_t,
+ ctypes.char16_t.ptr,
+ ctypes.int);
+ }
+ if (!this.messageBox) {
+ // Handy for debugging this code
+ this.messageBox = user32.declare("MessageBoxW",
+ ctypes.winapi_abi,
+ ctypes.int,
+ ctypes.uintptr_t,
+ ctypes.char16_t.ptr,
+ ctypes.char16_t.ptr,
+ ctypes.uint32_t);
+ }
+};
+
+DialogWatcher.prototype.getWindowText = function(hwnd) {
+ var bufType = ctypes.ArrayType(ctypes.char16_t);
+ var buffer = new bufType(256);
+
+ if (this.getWindowTextW(hwnd, buffer, buffer.length)) {
+ return buffer.readString();
+ }
+};
+
+DialogWatcher.prototype.processWindowEvents = function(timeout) {
+ var onWinEvent = function(self, hook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime) {
+ var nhwnd = Number(hwnd)
+ if (event == EVENT_OBJECT_SHOW) {
+ if (nhwnd == self.hwnd) {
+ // We've already picked up this event via FindWindow
+ return;
+ }
+ var windowText = self.getWindowText(hwnd);
+ if (windowText == self.titleText && self.onDialogStart) {
+ self.hwnd = nhwnd;
+ self.onDialogStart(nhwnd);
+ }
+ } else if (event == EVENT_OBJECT_HIDE && nhwnd == self.hwnd && self.onDialogEnd) {
+ self.onDialogEnd();
+ self.hwnd = null;
+ }
+ };
+ var self = this;
+ var callback = this.winEventProcType(function(hook, event, hwnd, idObject,
+ idChild, dwEventThread,
+ dwmsEventTime) {
+ onWinEvent(self, hook, event, hwnd, idObject, idChild, dwEventThread,
+ dwmsEventTime);
+ } );
+ var hook = this.setWinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE,
+ 0, callback, 0, 0,
+ WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
+ if (!hook) {
+ return;
+ }
+ // Check if the window is already showing
+ var hwnd = this.findWindow(null, this.titleText);
+ if (hwnd && hwnd > 0) {
+ this.hwnd = Number(hwnd);
+ if (this.onDialogStart) {
+ this.onDialogStart(this.hwnd);
+ }
+ }
+
+ if (!timeout) {
+ timeout = INFINITE;
+ }
+
+ var waitStatus = WAIT_OBJECT_0;
+ var expectingStart = this.onDialogStart && this.hwnd === undefined;
+ var startWaitTime = Date.now();
+ while (this.hwnd === undefined || this.onDialogEnd && this.hwnd) {
+ waitStatus = this.msgWaitForMultipleObjects(0, null, 0, expectingStart ?
+ INFINITE : timeout, 0);
+ if (waitStatus == WAIT_OBJECT_0) {
+ var msg = new this.msgType;
+ this.peekMessage(msg.address(), 0, 0, 0, PM_NOREMOVE);
+ }
+ if (waitStatus == WAIT_TIMEOUT || (Date.now() - startWaitTime) >= timeout) {
+ break;
+ }
+ }
+
+ this.unhookWinEvent(hook);
+ // Returns true if the hook was successful, something was found, and we never timed out
+ return this.hwnd !== undefined && waitStatus == WAIT_OBJECT_0;
+};
diff --git a/dom/plugins/test/mochitest/file_authident.js b/dom/plugins/test/mochitest/file_authident.js
new file mode 100644
index 000000000..f255fc30c
--- /dev/null
+++ b/dom/plugins/test/mochitest/file_authident.js
@@ -0,0 +1,6 @@
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+var am = Cc["@mozilla.org/network/http-auth-manager;1"].
+ getService(Ci.nsIHttpAuthManager);
+am.setAuthIdentity("http", "mochi.test", 8888, "basic", "testrealm", "",
+ "mochi.test", "user1", "password1");
diff --git a/dom/plugins/test/mochitest/file_bug1245545.js b/dom/plugins/test/mochitest/file_bug1245545.js
new file mode 100644
index 000000000..47cb618eb
--- /dev/null
+++ b/dom/plugins/test/mochitest/file_bug1245545.js
@@ -0,0 +1,22 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
+const { Services } = Cu.import('resource://gre/modules/Services.jsm');
+
+function getTestPlugin(pluginName) {
+ var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
+ var tags = ph.getPluginTags();
+ var name = pluginName || "Test Plug-in";
+ for (var tag of tags) {
+ if (tag.name == name) {
+ return tag;
+ }
+ }
+ return null;
+}
+
+addMessageListener('check-plugin-unload', function(message) {
+ var tag = getTestPlugin();
+ var results = sendAsyncMessage("check-plugin-unload", tag.loaded);
+});
diff --git a/dom/plugins/test/mochitest/file_bug738396.html b/dom/plugins/test/mochitest/file_bug738396.html
new file mode 100644
index 000000000..f91f8f3d9
--- /dev/null
+++ b/dom/plugins/test/mochitest/file_bug738396.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Helper for test_bug738396.html</title>
+ <meta charset="utf-8">
+</head>
+<body>
+ <!-- Test that the plugin sees "good" in each of these cases -->
+ <div id="codebasevis">
+ <applet codebase="good" codebase="bad" ></applet>
+
+ <applet codebase="bad">
+ <param name="codebase" value="good">
+ </applet>
+
+ <applet codebase="bad">
+ <param name="codebase" value="stillbad">
+ <param name="codebase" value="good">
+ </applet>
+
+ <applet>
+ <param name="codebase" value="good">
+ </applet>
+
+ <object type="application/x-java-test" codebase="good" codebase="bad"></object>
+
+ <object type="application/x-java-test" codebase="bad">
+ <param name="codebase" value="good">
+ </object>
+
+ <object type="application/x-java-test" codebase="bad">
+ <param name="codebase" value="stillbad">
+ <param name="codebase" value="good">
+ </object>
+
+ <object type="application/x-java-test">
+ <param name="codebase" value="good">
+ </object>
+
+ <embed type="application/x-java-test" codebase="good" codebase="bad">
+ </div>
+ <div id="blockedcodebase">
+ <!-- Test that none of these are allowed to load -->
+ <applet codebase="file:///" codebase="notused"></applet>
+
+ <applet codebase="notused">
+ <param name="codebase" value="file:///">
+ </applet>
+
+ <applet codebase="notused">
+ <param name="codebase" value="notused">
+ <param name="codebase" value="file:///">
+ </applet>
+
+ <applet>
+ <param name="codebase" value="file:///">
+ </applet>
+
+ <object type="application/x-java-test" codebase="file:///" codebase="notused"></object>
+
+ <object type="application/x-java-test" codebase="notused">
+ <param name="codebase" value="file:///">
+ </object>
+
+ <object type="application/x-java-test" codebase="notused">
+ <param name="codebase" value="notused">
+ <param name="codebase" value="file:///">
+ </object>
+
+ <object type="application/x-java-test">
+ <param name="codebase" value="file:///">
+ </object>
+
+ <embed type="application/x-java-test" codebase="file:///" codebase="notused">
+ </div>
+ <div id="nocodebase">
+ <applet></applet>
+ <object type="application/x-java-test"></object>
+ <embed type="application/x-java-test">
+ </div>
+ <div id="emptycodebase">
+ <applet codebase=""></applet>
+ <object type="application/x-java-test" codebase=""></object>
+ <embed type="application/x-java-test" codebase="">
+ </div>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/file_bug771202.html b/dom/plugins/test/mochitest/file_bug771202.html
new file mode 100644
index 000000000..935be65b2
--- /dev/null
+++ b/dom/plugins/test/mochitest/file_bug771202.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+ <embed id="pluginElement" type="application/x-test" width="200" height="200"></embed>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/file_bug863792.html b/dom/plugins/test/mochitest/file_bug863792.html
new file mode 100644
index 000000000..b4d3dc2e0
--- /dev/null
+++ b/dom/plugins/test/mochitest/file_bug863792.html
@@ -0,0 +1,45 @@
+<!doctype html>
+<html>
+<head>
+ <title>File for Bug 863792</title>
+
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <base href="chrome://browser/content/">
+</head>
+<body>
+<script type="application/javascript">
+
+// A plugin that removes itself from the document and inactivates said document
+// inside NPP_New. We should not leak the instance. See also test_bug854082
+
+var outerwindow = window;
+var i = document.createElement("iframe");
+i.width = 500;
+i.height = 500;
+var ob = document.body;
+document.body.appendChild(i);
+i.addEventListener("load", function loaded() {
+ var id = i.contentDocument;
+ var e = id.createElement("embed");
+ var callbackrun = false;
+ e.width = 200;
+ e.height = 200;
+ e.type = "application/x-test";
+ e.__defineSetter__("pluginFoundElement", function() {
+ window.console.log("pluginFoundElement");
+ e.style.display = "none";
+ e.clientTop;
+ i.removeEventListener("load", loaded);
+ ob.removeChild(i);
+ id.body.clientTop;
+ id.body.removeChild(e);
+ callbackrun = true;
+ });
+ id.body.appendChild(e);
+ e.clientTop;
+ e = id = i = ob = null;
+ SpecialPowers.forceCC(); SpecialPowers.forceGC();
+}, false);
+</script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/file_checkcookie.sjs b/dom/plugins/test/mochitest/file_checkcookie.sjs
new file mode 100644
index 000000000..9bfa04f59
--- /dev/null
+++ b/dom/plugins/test/mochitest/file_checkcookie.sjs
@@ -0,0 +1,17 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+function handleRequest(request, response) {
+ try {
+ var cookie = request.getHeader("Cookie");
+ } catch (e) {
+ cookie = "EMPTY_COOKIE";
+ }
+
+ // avoid confusing cache behaviors.
+ response.setHeader("Cache-Control", "no-cache", false);
+ // allow XHR requests accross origin.
+ response.setHeader("Access-control-allow-origin", "*");
+ response.setHeader("Content-type", "text/plain", false);
+ response.setStatusLine(request.httpVersion, "200", "OK");
+ response.write(cookie);
+}
diff --git a/dom/plugins/test/mochitest/file_setcookie.html b/dom/plugins/test/mochitest/file_setcookie.html
new file mode 100644
index 000000000..3838db7fe
--- /dev/null
+++ b/dom/plugins/test/mochitest/file_setcookie.html
@@ -0,0 +1,9 @@
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html>
+ <head>
+ <meta charset=UTF-8>
+ <body>
+ <script>document.cookie = "found=another_cookie";</script>
+ </body>
+</html>
diff --git a/dom/plugins/test/mochitest/hang_test.js b/dom/plugins/test/mochitest/hang_test.js
new file mode 100644
index 000000000..796093fa3
--- /dev/null
+++ b/dom/plugins/test/mochitest/hang_test.js
@@ -0,0 +1,114 @@
+
+Components.utils.import("resource://gre/modules/KeyValueParser.jsm");
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+
+var success = false;
+var observerFired = false;
+
+var testObserver = {
+ idleHang: true,
+
+ observe: function(subject, topic, data) {
+ observerFired = true;
+ ok(true, "Observer fired");
+ is(topic, "plugin-crashed", "Checking correct topic");
+ is(data, null, "Checking null data");
+ ok((subject instanceof Ci.nsIPropertyBag2), "got Propbag");
+ ok((subject instanceof Ci.nsIWritablePropertyBag2), "got writable Propbag");
+
+ var pluginId = subject.getPropertyAsAString("pluginDumpID");
+ isnot(pluginId, "", "got a non-empty plugin crash id");
+
+ // check plugin dump and extra files
+ let directoryService =
+ Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
+ let profD = directoryService.get("ProfD", Ci.nsIFile);
+ profD.append("minidumps");
+ let pluginDumpFile = profD.clone();
+ pluginDumpFile.append(pluginId + ".dmp");
+ ok(pluginDumpFile.exists(), "plugin minidump exists");
+
+ let pluginExtraFile = profD.clone();
+ pluginExtraFile.append(pluginId + ".extra");
+ ok(pluginExtraFile.exists(), "plugin extra file exists");
+
+ let extraData = parseKeyValuePairsFromFile(pluginExtraFile);
+
+ // check additional dumps
+
+ ok("additional_minidumps" in extraData, "got field for additional minidumps");
+ let additionalDumps = extraData.additional_minidumps.split(',');
+ ok(additionalDumps.indexOf('browser') >= 0, "browser in additional_minidumps");
+
+ let additionalDumpFiles = [];
+ for (let name of additionalDumps) {
+ let file = profD.clone();
+ file.append(pluginId + "-" + name + ".dmp");
+ ok(file.exists(), "additional dump '"+name+"' exists");
+ if (file.exists()) {
+ additionalDumpFiles.push(file);
+ }
+ }
+
+ // check cpu usage field
+
+ ok("PluginCpuUsage" in extraData, "got extra field for plugin cpu usage");
+ let cpuUsage = parseFloat(extraData["PluginCpuUsage"]);
+ if (this.idleHang) {
+ ok(cpuUsage == 0, "plugin cpu usage is 0%");
+ } else {
+ ok(cpuUsage > 0, "plugin cpu usage is >0%");
+ }
+
+ // check processor count field
+ ok("NumberOfProcessors" in extraData, "got extra field for processor count");
+ ok(parseInt(extraData["NumberOfProcessors"]) > 0, "number of processors is >0");
+
+ // cleanup, to be nice
+ pluginDumpFile.remove(false);
+ pluginExtraFile.remove(false);
+ for (let file of additionalDumpFiles) {
+ file.remove(false);
+ }
+ },
+
+ QueryInterface: function(iid) {
+ if (iid.equals(Ci.nsIObserver) ||
+ iid.equals(Ci.nsISupportsWeakReference) ||
+ iid.equals(Ci.nsISupports))
+ return this;
+ throw Components.results.NS_NOINTERFACE;
+ }
+};
+
+
+function onPluginCrashed(aEvent) {
+ ok(true, "Plugin crashed notification received");
+ ok(observerFired, "Observer should have fired first");
+ is(aEvent.type, "PluginCrashed", "event is correct type");
+
+ var pluginElement = document.getElementById("plugin1");
+ is (pluginElement, aEvent.target, "Plugin crashed event target is plugin element");
+
+ ok(aEvent instanceof PluginCrashedEvent,
+ "plugin crashed event has the right interface");
+
+ is(typeof aEvent.pluginDumpID, "string", "pluginDumpID is correct type");
+ isnot(aEvent.pluginDumpID, "", "got a non-empty dump ID");
+ is(typeof aEvent.pluginName, "string", "pluginName is correct type");
+ is(aEvent.pluginName, "Test Plug-in", "got correct plugin name");
+ is(typeof aEvent.pluginFilename, "string", "pluginFilename is correct type");
+ isnot(aEvent.pluginFilename, "", "got a non-empty filename");
+ // The app itself may or may not have decided to submit the report, so
+ // allow either true or false here.
+ ok("submittedCrashReport" in aEvent, "submittedCrashReport is a property of event");
+ is(typeof aEvent.submittedCrashReport, "boolean", "submittedCrashReport is correct type");
+
+ var os = Cc["@mozilla.org/observer-service;1"].
+ getService(Ci.nsIObserverService);
+ os.removeObserver(testObserver, "plugin-crashed");
+
+ SimpleTest.finish();
+}
diff --git a/dom/plugins/test/mochitest/hangui_common.js b/dom/plugins/test/mochitest/hangui_common.js
new file mode 100644
index 000000000..cf0d049f2
--- /dev/null
+++ b/dom/plugins/test/mochitest/hangui_common.js
@@ -0,0 +1,20 @@
+// Plugin Hang UI constants
+const HANGUIOP_NOTHING = 0;
+const HANGUIOP_CANCEL = 1;
+const HANGUIOP_COMMAND = 2;
+const IDC_CONTINUE = 1001;
+const IDC_STOP = 1002;
+const IDC_NOFUTURE = 1003;
+
+// Windows constants
+const WM_CLOSE = 0x0010;
+const WM_COMMAND = 0x0111;
+const BM_GETCHECK = 0x00F0;
+const BM_SETCHECK = 0x00F1;
+const BN_CLICKED = 0;
+const BST_CHECKED = 1;
+
+// Test-specific constants
+const EPSILON_MS = 1000;
+const STALL_DURATION = 2;
+
diff --git a/dom/plugins/test/mochitest/hangui_iface.js b/dom/plugins/test/mochitest/hangui_iface.js
new file mode 100644
index 000000000..853d136bb
--- /dev/null
+++ b/dom/plugins/test/mochitest/hangui_iface.js
@@ -0,0 +1,121 @@
+var user32;
+var sendMessage;
+var getDlgItem;
+var messageBox;
+var watcher;
+
+importScripts("hangui_common.js");
+importScripts("dialog_watcher.js");
+
+function initCTypes() {
+ if (!user32) {
+ user32 = ctypes.open("user32.dll");
+ }
+ if (!getDlgItem) {
+ getDlgItem = user32.declare("GetDlgItem",
+ ctypes.winapi_abi,
+ ctypes.uintptr_t,
+ ctypes.uintptr_t,
+ ctypes.int);
+ }
+ if (!sendMessage) {
+ sendMessage = user32.declare("SendMessageW",
+ ctypes.winapi_abi,
+ ctypes.intptr_t,
+ ctypes.uintptr_t,
+ ctypes.uint32_t,
+ ctypes.uintptr_t,
+ ctypes.intptr_t);
+ }
+ if (!messageBox) {
+ // Handy for debugging the test itself
+ messageBox = user32.declare("MessageBoxW",
+ ctypes.winapi_abi,
+ ctypes.int,
+ ctypes.uintptr_t,
+ ctypes.char16_t.ptr,
+ ctypes.char16_t.ptr,
+ ctypes.uint32_t);
+ }
+ if (!watcher) {
+ watcher = new DialogWatcher("Warning: Unresponsive plugin");
+ }
+}
+
+function postSuccess(params) {
+ self.postMessage({"status": true, "params": params});
+}
+
+function postFail(params, msg) {
+ self.postMessage({"status": false, "params": params, "msg": msg});
+}
+
+function onDialogStart(inparams, hwnd) {
+ var params = Object.create(inparams);
+ params.testName += " (Start)";
+ params.callback = null;
+ if (!params.expectToFind) {
+ postFail(params, "Dialog showed when we weren't expecting it to!");
+ return;
+ }
+ if (params.opCode == HANGUIOP_CANCEL) {
+ sendMessage(hwnd, WM_CLOSE, 0, 0);
+ } else if (params.opCode == HANGUIOP_COMMAND) {
+ if (params.check) {
+ var checkbox = getDlgItem(hwnd, IDC_NOFUTURE);
+ if (!checkbox) {
+ postFail(params, "Couldn't find checkbox");
+ return;
+ }
+ sendMessage(checkbox, BM_SETCHECK, BST_CHECKED, 0);
+ sendMessage(hwnd, WM_COMMAND, (BN_CLICKED << 16) | IDC_NOFUTURE, checkbox);
+ }
+ var button = getDlgItem(hwnd, params.commandId);
+ if (!button) {
+ postFail(params,
+ "GetDlgItem failed to find button with ID " + params.commandId);
+ return;
+ }
+ sendMessage(hwnd, WM_COMMAND, (BN_CLICKED << 16) | params.commandId, button);
+ }
+ postSuccess(params);
+}
+
+function onDialogEnd(inparams) {
+ var params = Object.create(inparams);
+ params.testName += " (End)";
+ params.callback = inparams.callback;
+ postSuccess(params);
+}
+
+self.onmessage = function(event) {
+ initCTypes();
+ watcher.init();
+ var params = event.data;
+ var timeout = params.timeoutMs;
+ if (params.expectToFind) {
+ watcher.onDialogStart = function(hwnd) { onDialogStart(params, hwnd); };
+ if (params.expectToClose) {
+ watcher.onDialogEnd = function() { onDialogEnd(params); };
+ }
+ } else {
+ watcher.onDialogStart = null;
+ watcher.onDialogEnd = null;
+ }
+ var result = watcher.processWindowEvents(timeout);
+ if (result === null) {
+ postFail(params, "Hook failed");
+ } else if (!result) {
+ if (params.expectToFind) {
+ postFail(params, "The dialog didn't show but we were expecting it to");
+ } else {
+ postSuccess(params);
+ }
+ }
+}
+
+self.onerror = function(event) {
+ var msg = "Error: " + event.message + " at " + event.filename + ":" + event.lineno;
+ postFail(null, msg);
+};
+
diff --git a/dom/plugins/test/mochitest/hangui_subpage.html b/dom/plugins/test/mochitest/hangui_subpage.html
new file mode 100644
index 000000000..401912f68
--- /dev/null
+++ b/dom/plugins/test/mochitest/hangui_subpage.html
@@ -0,0 +1,4 @@
+<html>
+<body onload="window.parent.frameLoaded()">
+ <embed id="plugin1" type="application/x-test" width="400" height="400"></embed>
+
diff --git a/dom/plugins/test/mochitest/head.js b/dom/plugins/test/mochitest/head.js
new file mode 100644
index 000000000..42143b84b
--- /dev/null
+++ b/dom/plugins/test/mochitest/head.js
@@ -0,0 +1,133 @@
+
+/**
+ * Waits for a tab switch.
+ */
+function waitTabSwitched() {
+ return new Promise(resolve => {
+ gBrowser.addEventListener("TabSwitchDone", function onSwitch() {
+ gBrowser.removeEventListener("TabSwitchDone", onSwitch);
+ executeSoon(resolve);
+ });
+ });
+}
+
+/**
+ * Waits a specified number of miliseconds.
+ *
+ * Usage:
+ * let wait = yield waitForMs(2000);
+ * ok(wait, "2 seconds should now have elapsed");
+ *
+ * @param aMs the number of miliseconds to wait for
+ * @returns a Promise that resolves to true after the time has elapsed
+ */
+function waitForMs(aMs) {
+ return new Promise((resolve) => {
+ setTimeout(done, aMs);
+ function done() {
+ resolve(true);
+ }
+ });
+}
+
+/**
+ * Platform string helper for nativeVerticalWheelEventMsg
+ */
+function getPlatform() {
+ if (navigator.platform.indexOf("Win") == 0) {
+ return "windows";
+ }
+ if (navigator.platform.indexOf("Mac") == 0) {
+ return "mac";
+ }
+ if (navigator.platform.indexOf("Linux") == 0) {
+ return "linux";
+ }
+ return "unknown";
+}
+
+/**
+ * Returns a native wheel scroll event id for dom window
+ * uitls sendNativeMouseScrollEvent.
+ */
+function nativeVerticalWheelEventMsg() {
+ switch (getPlatform()) {
+ case "windows": return 0x020A; // WM_MOUSEWHEEL
+ case "mac": return 0; // value is unused, can be anything
+ case "linux": return 4; // value is unused, pass GDK_SCROLL_SMOOTH anyway
+ }
+ throw "Native wheel events not supported on platform " + getPlatform();
+}
+
+/**
+ * Waits for the first dom "scroll" event.
+ */
+function waitScrollStart(aTarget) {
+ return new Promise((resolve, reject) => {
+ aTarget.addEventListener("scroll", function listener(event) {
+ aTarget.removeEventListener("scroll", listener, true);
+ resolve(event);
+ }, true);
+ });
+}
+
+/**
+ * Waits for the last dom "scroll" event which generally indicates
+ * a scroll operation is complete. To detect this the helper waits
+ * 1 second intervals checking for scroll events from aTarget. If
+ * a scroll event is not received during that time, it considers
+ * the scroll operation complete. Not super accurate, be careful.
+ */
+function waitScrollFinish(aTarget) {
+ return new Promise((resolve, reject) => {
+ let recent = false;
+ let count = 0;
+ function listener(event) {
+ recent = true;
+ }
+ aTarget.addEventListener("scroll", listener, true);
+ setInterval(function () {
+ // one second passed and we didn't receive a scroll event.
+ if (!recent) {
+ aTarget.removeEventListener("scroll", listener, true);
+ resolve();
+ return;
+ }
+ recent = false;
+ // ten seconds
+ if (count > 10) {
+ aTarget.removeEventListener("scroll", listener, true);
+ reject();
+ }
+ }, 1000);
+ });
+}
+
+/**
+ * Set a plugin activation state. See nsIPluginTag for
+ * supported states. Affected plugin default to the first
+ * test plugin.
+ */
+function setTestPluginEnabledState(aState, aPluginName) {
+ let name = aPluginName || "Test Plug-in";
+ SpecialPowers.setTestPluginEnabledState(aState, name);
+}
+
+/**
+ * Returns the chrome side nsIPluginTag for this plugin, helper for
+ * setTestPluginEnabledState.
+ */
+function getTestPlugin(aName) {
+ let pluginName = aName || "Test Plug-in";
+ let ph = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
+ let tags = ph.getPluginTags();
+
+ // Find the test plugin
+ for (let i = 0; i < tags.length; i++) {
+ if (tags[i].name == pluginName)
+ return tags[i];
+ }
+ ok(false, "Unable to find plugin");
+ return null;
+}
+
diff --git a/dom/plugins/test/mochitest/large-pic.jpg b/dom/plugins/test/mochitest/large-pic.jpg
new file mode 100644
index 000000000..b167f6b9b
--- /dev/null
+++ b/dom/plugins/test/mochitest/large-pic.jpg
Binary files differ
diff --git a/dom/plugins/test/mochitest/loremipsum.txt b/dom/plugins/test/mochitest/loremipsum.txt
new file mode 100644
index 000000000..c5becca59
--- /dev/null
+++ b/dom/plugins/test/mochitest/loremipsum.txt
@@ -0,0 +1,11 @@
+Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
+
+Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
+
+Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+
+Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
+
+Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut laboreet dolore magna aliquyam erat.
+
+Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. \ No newline at end of file
diff --git a/dom/plugins/test/mochitest/loremipsum.xtest b/dom/plugins/test/mochitest/loremipsum.xtest
new file mode 100644
index 000000000..c5becca59
--- /dev/null
+++ b/dom/plugins/test/mochitest/loremipsum.xtest
@@ -0,0 +1,11 @@
+Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
+
+Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
+
+Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+
+Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
+
+Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut laboreet dolore magna aliquyam erat.
+
+Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. \ No newline at end of file
diff --git a/dom/plugins/test/mochitest/loremipsum.xtest^headers^ b/dom/plugins/test/mochitest/loremipsum.xtest^headers^
new file mode 100644
index 000000000..8dd7784af
--- /dev/null
+++ b/dom/plugins/test/mochitest/loremipsum.xtest^headers^
@@ -0,0 +1 @@
+Content-Type: application/x-test
diff --git a/dom/plugins/test/mochitest/loremipsum_file.txt b/dom/plugins/test/mochitest/loremipsum_file.txt
new file mode 100644
index 000000000..c5becca59
--- /dev/null
+++ b/dom/plugins/test/mochitest/loremipsum_file.txt
@@ -0,0 +1,11 @@
+Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
+
+Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
+
+Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+
+Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
+
+Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut laboreet dolore magna aliquyam erat.
+
+Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. \ No newline at end of file
diff --git a/dom/plugins/test/mochitest/loremipsum_nocache.txt b/dom/plugins/test/mochitest/loremipsum_nocache.txt
new file mode 100644
index 000000000..c5becca59
--- /dev/null
+++ b/dom/plugins/test/mochitest/loremipsum_nocache.txt
@@ -0,0 +1,11 @@
+Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
+
+Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
+
+Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
+
+Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
+
+Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut laboreet dolore magna aliquyam erat.
+
+Consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. \ No newline at end of file
diff --git a/dom/plugins/test/mochitest/loremipsum_nocache.txt^headers^ b/dom/plugins/test/mochitest/loremipsum_nocache.txt^headers^
new file mode 100644
index 000000000..12a01c4a2
--- /dev/null
+++ b/dom/plugins/test/mochitest/loremipsum_nocache.txt^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/plugins/test/mochitest/mixed_case_mime.sjs b/dom/plugins/test/mochitest/mixed_case_mime.sjs
new file mode 100644
index 000000000..3c29b8289
--- /dev/null
+++ b/dom/plugins/test/mochitest/mixed_case_mime.sjs
@@ -0,0 +1,8 @@
+function handleRequest(request, response)
+{
+ response.processAsync();
+ response.setHeader("Content-Type", "application/x-Second-Test", false);
+
+ response.write("Hello world.\n");
+ response.finish();
+}
diff --git a/dom/plugins/test/mochitest/mochitest.ini b/dom/plugins/test/mochitest/mochitest.ini
new file mode 100644
index 000000000..0e8587f34
--- /dev/null
+++ b/dom/plugins/test/mochitest/mochitest.ini
@@ -0,0 +1,150 @@
+[DEFAULT]
+subsuite = clipboard
+support-files =
+ 307-xo-redirect.sjs
+ crashing_subpage.html
+ file_authident.js
+ file_bug738396.html
+ file_bug771202.html
+ file_bug863792.html
+ file_bug1245545.js
+ large-pic.jpg
+ loremipsum.txt
+ loremipsum.xtest
+ loremipsum.xtest^headers^
+ loremipsum_file.txt
+ loremipsum_nocache.txt
+ loremipsum_nocache.txt^headers^
+ mixed_case_mime.sjs
+ neverending.sjs
+ npruntime_identifiers_subpage.html
+ plugin-stream-referer.sjs
+ plugin_window.html
+ pluginstream.js
+ post.sjs
+ plugin-utils.js
+ !/toolkit/components/passwordmgr/test/authenticate.sjs
+
+[test_bug406541.html]
+[test_bug532208.html]
+[test_bug539565-1.html]
+[test_bug539565-2.html]
+[test_bug738396.html]
+[test_bug771202.html]
+[test_bug777098.html]
+[test_bug784131.html]
+[test_bug813906.html]
+[test_bug827160.html]
+skip-if = toolkit == 'android' # needs plugin support
+[test_bug852315.html]
+[test_bug854082.html]
+[test_bug863792.html]
+[test_bug967694.html]
+[test_bug985859.html]
+[test_bug986930.html]
+[test_bug1092842.html]
+[test_bug1165981.html]
+skip-if = !(os == "win" && processor == "x86_64")
+[test_bug1245545.html]
+[test_bug1307694.html]
+[test_cocoa_focus.html]
+skip-if = toolkit != "cocoa" || e10s # Bug 1194534
+support-files = cocoa_focus.html
+[test_cocoa_window_focus.html]
+skip-if = toolkit != "cocoa" # Bug 1194534
+support-files = cocoa_window_focus.html
+[test_cookies.html]
+[test_copyText.html]
+skip-if = (toolkit != "gtk2") && (toolkit != "gtk3")
+[test_crash_nested_loop.html]
+skip-if = (toolkit != "gtk2") && (toolkit != "gtk3")
+[test_crashing.html]
+skip-if = !crashreporter
+[test_crashing2.html]
+skip-if = (!crashreporter) || true # Bug 566049
+[test_CrashService_crash.html]
+skip-if = !crashreporter || e10s
+[test_CrashService_hang.html]
+skip-if = !crashreporter || e10s
+[test_defaultValue.html]
+[test_enumerate.html]
+[test_fullpage.html]
+[test_GCrace.html]
+[test_getauthenticationinfo.html]
+[test_hanging.html]
+skip-if = !crashreporter || e10s
+[test_hidden_plugin.html]
+[test_instance_re-parent.html]
+skip-if = release_or_beta # Bug 1172627
+[test_instance_unparent1.html]
+[test_instance_unparent2.html]
+[test_instance_unparent3.html]
+[test_instantiation.html]
+[test_mixed_case_mime.html]
+[test_multipleinstanceobjects.html]
+[test_newstreamondestroy.html]
+[test_npn_asynccall.html]
+[test_npn_timers.html]
+[test_npobject_getters.html]
+[test_NPNVdocumentOrigin.html]
+[test_NPPVpluginWantsAllNetworkStreams.html]
+[test_npruntime_construct.html]
+[test_npruntime_identifiers.html]
+[test_npruntime_npnevaluate.html]
+[test_npruntime_npninvoke.html]
+[test_npruntime_npninvokedefault.html]
+[test_object.html]
+skip-if = toolkit == 'android' # needs plugin support
+[test_painting.html]
+skip-if = (toolkit == "cocoa" && e10s) # bug 1252230
+[test_plugin_scroll_invalidation.html]
+skip-if = toolkit != "gtk2"
+support-files = plugin_scroll_invalidation.html
+[test_plugin_scroll_painting.html]
+skip-if = true # Bug 596491
+[test_pluginstream_3rdparty.html]
+support-files =
+ file_checkcookie.sjs
+ file_setcookie.html
+[test_pluginstream_asfile.html]
+[test_pluginstream_asfileonly.html]
+[test_pluginstream_err.html]
+[test_pluginstream_geturl.html]
+skip-if = true # Bug 1267432
+[test_pluginstream_geturlnotify.html]
+skip-if = true # Bug 1267432
+[test_pluginstream_newstream.html]
+[test_pluginstream_post.html]
+[test_pluginstream_poststream.html]
+[test_pluginstream_referer.html]
+[test_pluginstream_seek.html]
+[test_pluginstream_seek_close.html]
+[test_pluginstream_src.html]
+[test_pluginstream_src_dynamic.html]
+[test_pluginstream_src_referer.html]
+[test_positioning.html]
+skip-if = true # disabled due to oddness, perhaps scrolling of the mochitest window?
+[test_propertyAndMethod.html]
+[test_queryCSSZoomFactor.html]
+[test_queryContentsScaleFactor.html]
+skip-if = (toolkit != "cocoa") || (os != "win")
+[test_queryContentsScaleFactorWindowed.html]
+skip-if = (toolkit != "cocoa") || (os != "win")
+[test_redirect_handling.html]
+[test_secondPlugin.html]
+[test_src_url_change.html]
+[test_streamatclose.html]
+[test_streamNotify.html]
+[test_stringHandling.html]
+[test_twostreams.html]
+[test_visibility.html]
+skip-if = toolkit == "cocoa"
+[test_windowed_invalidate.html]
+skip-if = os != "win"
+[test_windowless_flash.html]
+skip-if = !(os == "win" && processor == "x86_64")
+[test_windowless_ime.html]
+skip-if = os != "win"
+[test_x11_error_crash.html]
+skip-if = !crashreporter || e10s || ((toolkit != "gtk2") && (toolkit != "gtk3"))
+[test_zero_opacity.html]
diff --git a/dom/plugins/test/mochitest/neverending.sjs b/dom/plugins/test/mochitest/neverending.sjs
new file mode 100644
index 000000000..1576ce344
--- /dev/null
+++ b/dom/plugins/test/mochitest/neverending.sjs
@@ -0,0 +1,16 @@
+var timer = null; // declare timer outside to prevent premature GC
+function handleRequest(request, response)
+{
+ response.processAsync();
+ response.setHeader("Content-Type", "text/plain", false);
+
+ for (var i = 0; i < 1000; ++i)
+ response.write("Hello... ");
+
+ timer = Components.classes["@mozilla.org/timer;1"]
+ .createInstance(Components.interfaces.nsITimer);
+ timer.initWithCallback(function() {
+ response.write("world.\n");
+ response.finish();
+ }, 10 * 1000 /* 10 secs */, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+}
diff --git a/dom/plugins/test/mochitest/npruntime_identifiers_subpage.html b/dom/plugins/test/mochitest/npruntime_identifiers_subpage.html
new file mode 100644
index 000000000..38c62e017
--- /dev/null
+++ b/dom/plugins/test/mochitest/npruntime_identifiers_subpage.html
@@ -0,0 +1,4 @@
+<html>
+ <body>
+ <embed id="plugin1" type="application/x-test" width="400" height="100">
+ </embed>
diff --git a/dom/plugins/test/mochitest/plugin-stream-referer.sjs b/dom/plugins/test/mochitest/plugin-stream-referer.sjs
new file mode 100644
index 000000000..a1c9692c9
--- /dev/null
+++ b/dom/plugins/test/mochitest/plugin-stream-referer.sjs
@@ -0,0 +1,12 @@
+function handleRequest(request, response)
+{
+ response.setHeader('Content-Type', 'text/plain', false);
+ response.setHeader('Cache-Control', 'no-cache', false);
+ response.setHeader('Content-Type', 'application/x-test', false);
+ if (request.hasHeader('Referer')) {
+ response.write('Referer found: ' + request.getHeader('Referer'));
+ }
+ else {
+ response.write('No Referer found');
+ }
+}
diff --git a/dom/plugins/test/mochitest/plugin-utils.js b/dom/plugins/test/mochitest/plugin-utils.js
new file mode 100644
index 000000000..90d3c285d
--- /dev/null
+++ b/dom/plugins/test/mochitest/plugin-utils.js
@@ -0,0 +1,95 @@
+function paintCountIs(plugin, expected, msg) {
+ var count = plugin.getPaintCount();
+ var realExpected = expected;
+ ++realExpected; // extra paint at startup for all async-rendering plugins
+ ok(realExpected == count, msg + " (expected " + expected +
+ " independent paints, expected " + realExpected + " logged paints, got " +
+ count + " actual paints)");
+}
+
+function getTestPlugin(pluginName) {
+ var ph = SpecialPowers.Cc["@mozilla.org/plugin/host;1"]
+ .getService(SpecialPowers.Ci.nsIPluginHost);
+ var tags = ph.getPluginTags();
+ var name = pluginName || "Test Plug-in";
+ for (var tag of tags) {
+ if (tag.name == name) {
+ return tag;
+ }
+ }
+
+ ok(false, "Could not find plugin tag with plugin name '" + name + "'");
+ return null;
+}
+
+// call this to set the test plugin(s) initially expected enabled state.
+// it will automatically be reset to it's previous value after the test
+// ends
+function setTestPluginEnabledState(newEnabledState, pluginName) {
+ var oldEnabledState = SpecialPowers.setTestPluginEnabledState(newEnabledState, pluginName);
+ var plugin = getTestPlugin(pluginName);
+ while (plugin.enabledState != newEnabledState) {
+ // Run a nested event loop to wait for the preference change to
+ // propagate to the child. Yuck!
+ SpecialPowers.Services.tm.currentThread.processNextEvent(true);
+ }
+ SimpleTest.registerCleanupFunction(function() {
+ SpecialPowers.setTestPluginEnabledState(oldEnabledState, pluginName);
+ });
+}
+
+function crashAndGetCrashServiceRecord(crashMethodName, callback) {
+ var crashMan =
+ SpecialPowers.Cu.import("resource://gre/modules/Services.jsm").
+ Services.crashmanager;
+
+ // First, clear the crash record store.
+ info("Waiting for pruneOldCrashes");
+ var future = new Date(Date.now() + 1000 * 60 * 60 * 24);
+ crashMan.pruneOldCrashes(future).then(function () {
+
+ var iframe = document.getElementById("iframe1");
+ var p = iframe.contentDocument.getElementById("plugin1");
+
+ var crashDateMS = Date.now();
+ try {
+ p[crashMethodName]();
+ ok(false, "p." + crashMethodName + "() should throw an exception");
+ }
+ catch (e) {
+ ok(true, "p." + crashMethodName + "() should throw an exception");
+ }
+
+ // The crash record store is written and read back asyncly, so poll for
+ // the new record.
+ function tryGetCrash() {
+ info("Waiting for getCrashes");
+ crashMan.getCrashes().then(SpecialPowers.wrapCallback(function (crashes) {
+ if (crashes.length) {
+ is(crashes.length, 1, "There should be only one record");
+ var crash = SpecialPowers.wrap(crashes[0]);
+ ok(!!crash.id, "Record should have an ID");
+ ok(!!crash.crashDate, "Record should have a crash date");
+ var dateMS = crash.crashDate.valueOf();
+ var twoMin = 1000 * 60 * 2;
+ ok(crashDateMS - twoMin <= dateMS &&
+ dateMS <= crashDateMS + twoMin,
+ "Record's crash date should be nowish: " +
+ "now=" + crashDateMS + " recordDate=" + dateMS);
+ callback(crashMan, crash);
+ }
+ else {
+ setTimeout(tryGetCrash, 1000);
+ }
+ }), function (err) {
+ ok(false, "Error getting crashes: " + err);
+ SimpleTest.finish();
+ });
+ }
+ setTimeout(tryGetCrash, 1000);
+
+ }, function () {
+ ok(false, "pruneOldCrashes error");
+ SimpleTest.finish();
+ });
+}
diff --git a/dom/plugins/test/mochitest/plugin_no_scroll_div.html b/dom/plugins/test/mochitest/plugin_no_scroll_div.html
new file mode 100644
index 000000000..b28f6d6ff
--- /dev/null
+++ b/dom/plugins/test/mochitest/plugin_no_scroll_div.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+ <embed id="testplugin" type="application/x-test" drawmode="solid" color="ff00ff00" wmode="window"
+ style="position:absolute; top:5px; left:5px; width:500px; height:250px">
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/plugin_scroll_invalidation.html b/dom/plugins/test/mochitest/plugin_scroll_invalidation.html
new file mode 100644
index 000000000..74a68ff4a
--- /dev/null
+++ b/dom/plugins/test/mochitest/plugin_scroll_invalidation.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test helper for plugin child widgets not being invalidated by scrolling</title>
+ <style>
+ body {
+ background: linear-gradient(red, black);
+ width: 200px;
+ height: 200px;
+ }
+ embed {
+ position:absolute;
+ }
+ embed#paint-waiter {
+ top: 0px;
+ left: 0px;
+ width: 0px;
+ height: 0px;
+ }
+ embed#e0 {
+ top: 70px;
+ left: 70px;
+ width: 10px;
+ height: 10px;
+ }
+ embed#e1 {
+ top: 60px;
+ left: 60px;
+ width: 10px;
+ height: 20px;
+ }
+ embed#e2 {
+ top: 60px;
+ left: 70px;
+ width: 20px;
+ height: 10px;
+ }
+ embed#e3 {
+ top: 70px;
+ left: 80px;
+ width: 10px;
+ height: 20px;
+ }
+ embed#e4 {
+ top: 80px;
+ left: 60px;
+ width: 20px;
+ height: 10px;
+ }
+ </style>
+</head>
+<body>
+ <embed id="paint-waiter" type="application/x-test" wmode="window">
+ <embed id="e0" type="application/x-test" wmode="window" class="scrolling"/>
+ <embed id="e1" type="application/x-test" wmode="window" class="scrolling"/>
+ <embed id="e2" type="application/x-test" wmode="window" class="scrolling"/>
+ <embed id="e3" type="application/x-test" wmode="window" class="scrolling"/>
+ <embed id="e4" type="application/x-test" wmode="window" class="scrolling"/>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/plugin_subframe_test.html b/dom/plugins/test/mochitest/plugin_subframe_test.html
new file mode 100644
index 000000000..598521d57
--- /dev/null
+++ b/dom/plugins/test/mochitest/plugin_subframe_test.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+ <iframe id="subframe" style="width:510px; height:260px;" src="plugin_no_scroll_div.html"></iframe>
+ <div style="display:block; height:3000px;"></div>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/plugin_test.html b/dom/plugins/test/mochitest/plugin_test.html
new file mode 100644
index 000000000..c7eb376cd
--- /dev/null
+++ b/dom/plugins/test/mochitest/plugin_test.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+ <embed id="testplugin" type="application/x-test" drawmode="solid" color="ff00ff00" wmode="window"
+ style="position:absolute; top:50px; left:50px; width:500px; height:250px">
+<div style="display:block; height:3000px;"></div>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/plugin_visibility_loader.html b/dom/plugins/test/mochitest/plugin_visibility_loader.html
new file mode 100644
index 000000000..22802d9a5
--- /dev/null
+++ b/dom/plugins/test/mochitest/plugin_visibility_loader.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body style="background-color: #88AAFF;">
+ <h1>This Page Has a Solid Plugin</h1>
+
+ <p><embed id="p" type="application/x-test" drawmode="solid" color="FFFF0000" width="200" height="200"></embed>
diff --git a/dom/plugins/test/mochitest/plugin_window.html b/dom/plugins/test/mochitest/plugin_window.html
new file mode 100644
index 000000000..d3a298e89
--- /dev/null
+++ b/dom/plugins/test/mochitest/plugin_window.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>NPAPI Stream Tests</title>
+</head>
+<body onload="doTest()">
+<p id="display"></p>
+<div id="content" style="display: none">
+This is a plugin test window.
+</div>
+<div id="test">
+<script class="testbody" type="text/javascript">
+
+function doTest() {
+ window.opener.continueTest();
+}
+
+</script>
+</div>
+</body>
+
+</html>
+
diff --git a/dom/plugins/test/mochitest/pluginstream.js b/dom/plugins/test/mochitest/pluginstream.js
new file mode 100644
index 000000000..9c47cd5f8
--- /dev/null
+++ b/dom/plugins/test/mochitest/pluginstream.js
@@ -0,0 +1,39 @@
+ SimpleTest.waitForExplicitFinish();
+
+ function frameLoaded(finishWhenCalled = true, lastObject = false) {
+ var testframe = document.getElementById('testframe');
+ function getNode(list) {
+ if (list.length === 0)
+ return undefined;
+ return lastObject ? list[list.length - 1] : list[0];
+ }
+ var embed = getNode(document.getElementsByTagName('embed'));
+ if (undefined === embed)
+ embed = getNode(document.getElementsByTagName('object'));
+
+ // In the file:// URI case, this ends up being cross-origin.
+ // Skip these checks in that case.
+ if (testframe.contentDocument) {
+ var content = testframe.contentDocument.body.innerHTML;
+ if (!content.length)
+ return;
+
+ var filename = embed.getAttribute("src") ||
+ embed.getAttribute("geturl") ||
+ embed.getAttribute("geturlnotify") ||
+ embed.getAttribute("data");
+
+ var req = new XMLHttpRequest();
+ req.open('GET', filename, false);
+ req.overrideMimeType('text/plain; charset=x-user-defined');
+ req.send(null);
+ is(req.status, 200, "bad XMLHttpRequest status");
+ is(content, req.responseText.replace(/\r\n/g, "\n"),
+ "content doesn't match");
+ }
+
+ is(embed.getError(), "pass", "plugin reported error");
+ if (finishWhenCalled) {
+ SimpleTest.finish();
+ }
+ }
diff --git a/dom/plugins/test/mochitest/post.sjs b/dom/plugins/test/mochitest/post.sjs
new file mode 100644
index 000000000..b391dbdd8
--- /dev/null
+++ b/dom/plugins/test/mochitest/post.sjs
@@ -0,0 +1,17 @@
+const CC = Components.Constructor;
+const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
+ "nsIBinaryInputStream",
+ "setInputStream");
+
+function handleRequest(request, response)
+{
+ var body = "";
+ var bodyStream = new BinaryInputStream(request.bodyInputStream);
+ var bytes = [], avail = 0;
+ while ((avail = bodyStream.available()) > 0)
+ body += String.fromCharCode.apply(String, bodyStream.readByteArray(avail));
+
+ response.setHeader("Content-Type", "text/html", false);
+ response.write(body);
+}
+
diff --git a/dom/plugins/test/mochitest/privatemode_perwindowpb.xul b/dom/plugins/test/mochitest/privatemode_perwindowpb.xul
new file mode 100644
index 000000000..ab7f06395
--- /dev/null
+++ b/dom/plugins/test/mochitest/privatemode_perwindowpb.xul
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window title="NPAPI Private Mode Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+<body xmlns="http://www.w3.org/1999/xhtml">
+<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+<embed id="plugin2" type="application/x-test" width="200" height="200"></embed>
+</body>
+</window>
diff --git a/dom/plugins/test/mochitest/test_CrashService_crash.html b/dom/plugins/test/mochitest/test_CrashService_crash.html
new file mode 100644
index 000000000..84508a6dc
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_CrashService_crash.html
@@ -0,0 +1,28 @@
+<head>
+ <title>nsICrashService plugin crash</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+
+<body>
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.requestFlakyTimeout(
+ "crashAndGetCrashServiceRecord() polls for async crash recording");
+ SimpleTest.requestCompleteLog();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ window.frameLoaded = function frameLoaded_toCrash() {
+ SimpleTest.expectChildProcessCrash();
+
+ crashAndGetCrashServiceRecord("crash", function (cm, crash) {
+ var isPluginCrash = crash.isOfType(cm.PROCESS_TYPE_PLUGIN, cm.CRASH_TYPE_CRASH);
+ ok(isPluginCrash, "Record should be a plugin crash");
+ if (!isPluginCrash) {
+ dump("Crash type: " + crash.type + "\n");
+ }
+ SimpleTest.finish();
+ });
+
+ }
+ </script>
+ <iframe id="iframe1" src="crashing_subpage.html" width="600" height="600"></iframe>
diff --git a/dom/plugins/test/mochitest/test_CrashService_hang.html b/dom/plugins/test/mochitest/test_CrashService_hang.html
new file mode 100644
index 000000000..6ecf7d419
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_CrashService_hang.html
@@ -0,0 +1,28 @@
+<head>
+ <title>nsICrashService plugin hang</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+
+<body>
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.requestFlakyTimeout(
+ "crashAndGetCrashServiceRecord() polls for async crash recording");
+ SimpleTest.requestCompleteLog();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ window.frameLoaded = function frameLoaded_toCrash() {
+ SimpleTest.expectChildProcessCrash();
+
+ // the default timeout is annoying high for mochitest runs
+ var timeoutPref = "dom.ipc.plugins.timeoutSecs";
+ SpecialPowers.setIntPref(timeoutPref, 5);
+
+ crashAndGetCrashServiceRecord("hang", function (cm, crash) {
+ ok(crash.isOfType(cm.PROCESS_TYPE_PLUGIN, cm.CRASH_TYPE_HANG),
+ "Record should be a plugin hang");
+ SimpleTest.finish();
+ });
+ }
+ </script>
+ <iframe id="iframe1" src="crashing_subpage.html" width="600" height="600"></iframe>
diff --git a/dom/plugins/test/mochitest/test_GCrace.html b/dom/plugins/test/mochitest/test_GCrace.html
new file mode 100644
index 000000000..50b598ef1
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_GCrace.html
@@ -0,0 +1,62 @@
+<head>
+ <title>GC race with actors on the parent</title>
+
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+<body onload="start()">
+ <p id="display"></p>
+
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.requestFlakyTimeout("untriaged");
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function start() {
+ setTimeout(checkGCRace, 1000);
+ }
+
+ var nested = false;
+
+ function cb(f) {
+ ok(!nested, "Callback shouldn't occur in a nested stack frame");
+ try {
+ f(35);
+ ok(true, "Callback was called, no crash");
+ }
+ catch (e) {
+ ok(false, "Exception calling callback object: " + e);
+ }
+ SimpleTest.executeSoon(removePlugin);
+ }
+
+ function removePlugin() {
+ var p = document.getElementById('p');
+ p.parentNode.removeChild(p);
+ p = null;
+ SpecialPowers.Cu.forceGC();
+ SimpleTest.finish();
+ }
+
+ function checkGCRace() {
+ nested = true;
+
+ // The plugin will hand back a function and immediately sleep.
+ // We will lose our only reference to the function and force GC, followed
+ // by calling us with that function object again. We should be able to
+ // call the function and not crash.
+ var p = document.getElementById('p');
+ var f = p.checkGCRace(cb);
+ f = null; // 'f' should be collected next GC
+
+ nested = false;
+
+ setTimeout(function() {
+ SpecialPowers.Cu.forceGC();
+ }, 2000);
+ }
+ </script>
+
+ <embed id="p" type="application/x-test" wmode="window"></embed>
diff --git a/dom/plugins/test/mochitest/test_NPNVdocumentOrigin.html b/dom/plugins/test/mochitest/test_NPNVdocumentOrigin.html
new file mode 100644
index 000000000..75ec66e13
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_NPNVdocumentOrigin.html
@@ -0,0 +1,47 @@
+<html>
+<head>
+ <title>Test NPNVdocumentOrigin</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+</head>
+<body onload="runTest()">
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function runTest() {
+ "use strict";
+ var p1 = document.getElementById("plugin1");
+ var realOrigin = "http://mochi.test:8888";
+
+ // Test with no modifications
+ is(p1.getNPNVdocumentOrigin(), realOrigin, "Checking for expected origin.");
+
+ // This used to test that shadowing window.location.toString didn't confuse
+ // getNPNVdocumentOrigin. But now we explicitly throw when that happens. So
+ // just verify that we throw. There's no reason why getNPNVdocumentOrigin _would_
+ // be confused in this case anyway.
+ try {
+ window.location.toString = function() { return 'http://victim.rckc.at/'; }
+ ok(false, "Should throw when shadowing window.location.toString");
+ }
+ catch (e) {
+ ok(true, "Should throw when shadowing window.location.toString");
+ }
+
+ // Create a plugin in a new window with about:blank
+ var newWindow = window.open("about:blank");
+ newWindow.onload = function() {
+ newWindow.document.writeln('<embed id="plugin2" type="application/x-test" width="200" height="200"></embed>');
+ var p2 = newWindow.document.getElementById("plugin2");
+ is(p2.getNPNVdocumentOrigin(), realOrigin, "Checking for expected origin of plugin in new about:blank window.");
+ newWindow.close();
+
+ SimpleTest.finish();
+ };
+ }
+ </script>
+
+ <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_NPPVpluginWantsAllNetworkStreams.html b/dom/plugins/test/mochitest/test_NPPVpluginWantsAllNetworkStreams.html
new file mode 100644
index 000000000..588e785d3
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_NPPVpluginWantsAllNetworkStreams.html
@@ -0,0 +1,77 @@
+<html>
+<head>
+ <title>Test NPPVpluginWantsAllNetworkStreams</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+</head>
+<body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var p = null;
+
+ var missingDoc = "not-found.html";
+
+ var expectedWriteURL = "";
+ var expectedNotifyStatus = -1;
+
+ var writeHappened = false;
+ var expectedWrite = false;
+
+ function writeCallback(url) {
+ writeHappened = true;
+ }
+
+ function notifyCallback(status, data) {
+ is(writeHappened, expectedWrite, "Test for expected write.");
+ is(status, expectedNotifyStatus, "Test for expected stream notification status.");
+ runNextTest();
+ }
+
+ function test1() {
+ // In this test we do not expect a stream for the missing document.
+ p.setPluginWantsAllStreams(false);
+
+ expectedWriteURL = missingDoc;
+ expectedNotifyStatus = 1;
+
+ writeHappened = false;
+ expectedWrite = false;
+
+ p.streamTest(missingDoc, false, null, writeCallback, notifyCallback, null, false);
+ }
+
+ function test2() {
+ // In this test we expect a stream for the missing document.
+ p.setPluginWantsAllStreams(true);
+
+ expectedWriteURL = missingDoc;
+ expectedNotifyStatus = 0;
+
+ writeHappened = false;
+ expectedWrite = true;
+
+ p.streamTest(missingDoc, false, null, writeCallback, notifyCallback, null, false);
+ }
+
+ var tests = [test1, test2];
+ var currentTest = -1;
+ function runNextTest() {
+ currentTest++;
+ if (currentTest < tests.length) {
+ tests[currentTest]();
+ } else {
+ SimpleTest.finish();
+ }
+ }
+
+ function runTests() {
+ p = document.getElementById("plugin1");
+ runNextTest();
+ }
+ </script>
+
+ <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug1092842.html b/dom/plugins/test/mochitest/test_bug1092842.html
new file mode 100644
index 000000000..e22d0a3b9
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug1092842.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Bug 1092842</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<body onload="startTest()">
+ <script type="application/javascript;version=1.8">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var p = null;
+
+ function startTest() {
+ p = document.getElementById('theplugin');
+ if (!p.hasWidget()) {
+ todo(false, "This test is only relevant for windowed plugins");
+ SimpleTest.finish();
+ return;
+ }
+
+ // Wait for the plugin to have painted once.
+ var interval = setInterval(function() {
+ if (!p.getPaintCount())
+ return;
+
+ clearInterval(interval);
+ doTest();
+ SimpleTest.finish();
+ }, 100);
+ }
+
+ function doTest() {
+ is(p.getClipRegionRectCount(), 1, "getClipRegionRectCount should be a single rect");
+ is(p.getClipRegionRectEdge(0,2) - p.getClipRegionRectEdge(0,0), 100, "width of clip region rect");
+ is(p.getClipRegionRectEdge(0,3) - p.getClipRegionRectEdge(0,1), 26, "height of clip region rect");
+ }
+ </script>
+
+ <div style="position:fixed; z-index:1; left:0; right:0; top:0; height:100px; border-bottom:24px solid blue; background:pink; transform:translateZ(0)"></div>
+ <object id="theplugin" type="application/x-test" drawmode="solid" color="ff00ff00" wmode="window"
+ style="position:absolute; top:50px; left:0; width:100px; height:100px"></object>
+
+ <p id="display"></p>
diff --git a/dom/plugins/test/mochitest/test_bug1165981.html b/dom/plugins/test/mochitest/test_bug1165981.html
new file mode 100644
index 000000000..360d9312a
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug1165981.html
@@ -0,0 +1,81 @@
+<html>
+ <head>
+ <title>Bug 1165981 Test</title>
+
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ </head>
+ <script class="testbody" type="application/javascript">
+ "use strict";
+
+ SimpleTest.waitForExplicitFinish();
+ ok(SpecialPowers.setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED, "Shockwave Flash"), "Should find allowed test flash plugin");
+ ok(SpecialPowers.setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED, "Silverlight Test Plug-in"), "Should find allowed test silverlight plugin");
+ ok(!SpecialPowers.setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED, "Third Test Plug-in"), "Should not find disallowed plugin");
+
+ function findPlugin(pluginName) {
+ for (var i = 0; i < navigator.plugins.length; i++) {
+ var plugin = navigator.plugins[i];
+ if (plugin.name === pluginName) {
+ return plugin;
+ }
+ }
+ return null;
+ }
+
+ function findMimeType(mimeTypeType) {
+ for (var i = 0; i < navigator.mimeTypes.length; i++) {
+ var mimeType = navigator.mimeTypes[i];
+ if (mimeType.type === mimeTypeType) {
+ return mimeType;
+ }
+ }
+ return null;
+ }
+
+ function createNode(id, type) {
+ let obj = document.createElement("object");
+ obj.type = type;
+ obj.id = id;
+ obj.width = 200;
+ obj.height = 200;
+ document.body.appendChild(obj);
+ }
+
+ function run() {
+ createNode("plugin-flash", "application/x-shockwave-flash-test");
+ createNode("plugin-silverlight", "application/x-silverlight-test");
+ createNode("disallowedPlugin", "application/x-third-test");
+ var pluginElement = document.getElementById("plugin-flash");
+ is(pluginElement.identifierToStringTest("foo"), "foo", "Should be able to call a function provided by the plugin");
+
+ pluginElement = document.getElementById("plugin-silverlight");
+ is(pluginElement.identifierToStringTest("foo"), "foo", "Should be able to call a function provided by the plugin");
+
+ pluginElement = document.getElementById("disallowedPlugin");
+ is(typeof pluginElement.identifierToStringTest, "undefined", "Should NOT be able to call a function on a disallowed plugin");
+
+ ok(navigator.plugins["Shockwave Flash"], "Should have queried a plugin named 'Shockwave Flash'");
+ ok(navigator.plugins["Silverlight Test Plug-in"], "Should have queried a plugin named 'Silverlight Test Plug-in'");
+ ok(!navigator.plugins["Third Test Plug-in"], "Should NOT have queried a disallowed plugin named 'Third Test Plug-in'");
+
+ ok(findPlugin("Shockwave Flash"), "Should have found a plugin named 'Shockwave Flash'");
+ ok(findPlugin("Silverlight Test Plug-in"), "Should have found a plugin named 'Silverlight Test Plug-in'");
+ ok(!findPlugin("Third Test Plug-in"), "Should NOT found a disallowed plugin named 'Third Test Plug-in'");
+
+ ok(navigator.mimeTypes["application/x-shockwave-flash-test"], "Should have queried a MIME type named 'application/x-shockwave-flash-test'");
+ ok(navigator.mimeTypes["application/x-silverlight-test"], "Should have queried a MIME type named 'application/x-silverlight-test'");
+ ok(!navigator.mimeTypes["application/x-third-test"], "Should NOT have queried a disallowed type named 'application/x-third-test'");
+
+ ok(findMimeType("application/x-shockwave-flash-test"), "Should have found a MIME type named 'application/x-shockwave-flash-test'");
+ ok(findMimeType("application/x-silverlight-test"), "Should have found a MIME type named 'application/x-silverlight-test'");
+ ok(!findMimeType("application/x-third-test"), "Should NOT have found a disallowed MIME type named 'application/x-third-test'");
+
+ SimpleTest.finish();
+ }
+ </script>
+
+ <body onload="run()">
+ </body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug1245545.html b/dom/plugins/test/mochitest/test_bug1245545.html
new file mode 100644
index 000000000..23e3b21e0
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug1245545.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta><charset="utf-8"/>
+ <title>Test Modifying Plugin click-to-play Flag</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ </head>
+ <body onload="startTest()">
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ SpecialPowers.pushPrefEnv({ "set": [
+ ['dom.ipc.plugins.unloadTimeoutSecs', 0]
+ ] });
+
+ function startTest() {
+ let url = SimpleTest.getTestFileURL("file_bug1245545.js");
+ let script = SpecialPowers.loadChromeScript(url);
+ script.addMessageListener("check-plugin-unload", testChromeUnload);
+ var testPlugin = getTestPlugin();
+ ok(testPlugin, "Should have Test Plug-in");
+ is(testPlugin.loaded, true, "Test plugin should be loaded");
+ var pluginNode = document.getElementById("theplugin");
+ pluginNode.parentNode.removeChild(pluginNode);
+ // Poll for plugin to unload.
+ function testContentUnload() {
+ if (!testPlugin.loaded) {
+ ok(true, "Test plugin unloaded in client process");
+ // Start the chrome unload test
+ testChromeUnload(true);
+ } else {
+ setTimeout(testContentUnload, 0);
+ }
+ }
+
+ function testChromeUnload(isLoaded) {
+ if (!isLoaded) {
+ ok(true, "Test plugin unloaded in chrome process");
+ SimpleTest.finish();
+ } else {
+ var results = script.sendAsyncMessage("check-plugin-unload");
+ }
+ }
+ testContentUnload();
+ }
+ </script>
+ <object id="theplugin" type="application/x-test"></object>
+
+ </body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug1307694.html b/dom/plugins/test/mochitest/test_bug1307694.html
new file mode 100644
index 000000000..97ee1b6ef
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug1307694.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onLoad="addPluginElement()">
+
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ SpecialPowers.setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function addPluginElement() {
+ var p = document.createElement('embed');
+ p.setAttribute('id', 'plugin2');
+ p.setAttribute('type', 'application/x-shockwave-flash-test');
+ p.setAttribute('scale', 'noscale');
+ p.setAttribute('salign', 'lt');
+ document.body.appendChild(p);
+ SimpleTest.executeSoon(function() {
+ runTests();
+ });
+ }
+
+ function runTests() {
+ p = document.getElementById('plugin1');
+ ok(p.setColor != undefined, "Static plugin parameter (salign/scale) ordering were correct");
+ p2 = document.getElementById('plugin2');
+ ok(p2.setColor != undefined, "Dynamic plugin parameter (salign/scale) ordering were correct");
+ SimpleTest.finish();
+ }
+
+ </script>
+ <p id="display"></p>
+
+ <div id="div1">
+ <embed id="plugin1" type="application/x-shockwave-flash-test" width="200" height="200" scale="noscale" salign="lt"></embed>
+ </div>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug406541.html b/dom/plugins/test/mochitest/test_bug406541.html
new file mode 100644
index 000000000..6ce9d4554
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug406541.html
@@ -0,0 +1,100 @@
+<!doctype html>
+<html>
+<head>
+ <title>Test for Bug 406541</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+</head>
+<body>
+<script type="application/x-child-payload" id="child-payload">
+ // This is injected into the file:/// origin iframe, see below.
+
+ // appletA should spawn, appletB, with a codebase outside the temp directory,
+ // should not.
+ var appletA = document.createElement("applet");
+ var appletB = document.createElement("applet");
+ var appletC = document.createElement("applet");
+ appletA.type = appletB.type = appletC.type = "application/x-java-test";
+ appletB.setAttribute("codebase", "file:///");
+ appletC.setAttribute("codebase", "./subdir_bug406541/");
+ document.body.appendChild(appletA);
+ document.body.appendChild(appletB);
+ document.body.appendChild(appletC);
+ function isSpawned(plugin) {
+ try {
+ var x = plugin.getJavaCodebase();
+ return true;
+ } catch (e) {}
+ return false;
+ }
+ window.parent.postMessage({ "A": isSpawned(appletA),
+ "B": isSpawned(appletB),
+ "C": isSpawned(appletC) }, "*");
+</script>
+<script type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED,
+ "Java Test Plug-in");
+ SpecialPowers.pushPrefEnv({ "set": [
+ ['plugin.java.mime', 'application/x-java-test']
+ ] }, runTest);
+
+ function runTest() {
+ // Create a empty file and point an iframe at it
+ var Cc = SpecialPowers.Cc;
+ var Ci = SpecialPowers.Ci;
+ var file = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIProperties)
+ .get("TmpD", Ci.nsIFile);
+ var subdir = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIProperties)
+ .get("TmpD", Ci.nsIFile);
+ file.append("test_bug406541.html");
+ file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
+ subdir.append("subdir_bug406541");
+ subdir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0600);
+
+ var i = document.createElement("iframe");
+ var loaded = false;
+ i.addEventListener("load", function initialLoad() {
+ if (!loaded) {
+ // Once loaded, use special powers to point it at the file
+ SpecialPowers.wrap(i.contentWindow).location.href = "file://" + file.path;
+ loaded = true;
+ } else {
+ // Inject the child-payload script to the file:/// origin. Let it test
+ // applet spawning and send the results in a postMessage. (Because I
+ // couldn't get SpecialPowers to let me touch applets cross-origin, then
+ // gave up.)
+ var innerdoc = SpecialPowers.wrap(i.contentWindow).document;
+ var s = innerdoc.createElement("script");
+ s.type = "text/javascript";
+ s.textContent = document.getElementById("child-payload").textContent;
+ var finished = false;
+ window.onmessage = function(message) {
+ ok(message.data.A, "Plugin A should spawn");
+ ok(!message.data.B, "Plugin B should NOT spawn");
+ ok(message.data.C, "Plugin C should spawn");
+ file.remove(false);
+ subdir.remove(false);
+ finished = true;
+ SimpleTest.finish();
+ };
+ innerdoc.body.appendChild(s);
+
+ SimpleTest.executeSoon(function() {
+ if (!finished) {
+ ok(finished, "Should have received callback by now");
+ SimpleTest.finish();
+ }
+ });
+ }
+ }, false);
+ document.body.appendChild(i);
+ }
+</script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug479979.xul b/dom/plugins/test/mochitest/test_bug479979.xul
new file mode 100644
index 000000000..1f295cbeb
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug479979.xul
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window title="NPAPI Set Undefined Value Test"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+ <script type="application/javascript" src="plugin-utils.js"></script>
+<body xmlns="http://www.w3.org/1999/xhtml" onload="runTests()">
+<script class="testbody" type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+function runTests() {
+ var pluginElement1 = document.getElementById("plugin1");
+
+ var rv = true; // we want !true from the test plugin
+ var exceptionThrown = false;
+ try {
+ rv = pluginElement1.setUndefinedValueTest();
+ } catch (e) {
+ exceptionThrown = true;
+ }
+ is(exceptionThrown, false, "Exception thrown setting undefined variable.");
+ is(rv, false, "Setting undefined variable succeeded.");
+
+ // give the UI a chance to settle with the current enabled plugin state
+ // before we finish the test and reset the state to disabled. Otherwise
+ // the UI shows the plugin infobar!
+ SimpleTest.executeSoon(SimpleTest.finish);
+}
+]]>
+</script>
+<embed id="plugin1" type="application/x-test" width="300" height="300"></embed>
+</body>
+</window>
diff --git a/dom/plugins/test/mochitest/test_bug532208.html b/dom/plugins/test/mochitest/test_bug532208.html
new file mode 100644
index 000000000..0a4cdb985
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug532208.html
@@ -0,0 +1,29 @@
+<head>
+<title>Test for correct async delivery of large streams, bug
+532208</title>
+
+<script type="application/javascript"
+src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript" src="plugin-utils.js"></script>
+
+<body onload="setTimeout(runTests, 2000)">
+
+<script class="testbody" type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+function runTests() {
+ try {
+ document.getElementById('plugin1').getPaintCount();
+ ok(true, "Data delivery didn't crash");
+ }
+ catch (e) {
+ ok(false, "Data delivery crashed");
+ }
+ SimpleTest.finish();
+}
+</script>
+
+<embed id="plugin1" type="application/x-test" width="400"
+ height="400" src="large-pic.jpg" functiontofail="npp_write_rpc" streammode="normal"></embed>
diff --git a/dom/plugins/test/mochitest/test_bug539565-1.html b/dom/plugins/test/mochitest/test_bug539565-1.html
new file mode 100644
index 000000000..022b8cfc6
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug539565-1.html
@@ -0,0 +1,91 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=539565
+-->
+<head>
+ <title>Test #1 for Bug 539565</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <script class="testbody" type="text/javascript">
+function runTests() {
+ var moveBy = 17;
+ var waitedForPaint = 0;
+ function waitForPaint(func) {
+ waitedForPaint = 0;
+ var testplugin = $("plugin1");
+ testplugin.last_paint_count = testplugin.getPaintCount ? testplugin.getPaintCount() : -2;
+ function waitForPaintCountIncrement() {
+ waitedForPaint++;
+ moveBy = -moveBy;
+ $("abs").style.left = ($("abs").offsetLeft + moveBy) + 'px';
+ var x = document.documentElement.offsetHeight;
+ var pc = testplugin.getPaintCount ? testplugin.getPaintCount() : -2;
+ if (waitedForPaint == 20 || (pc != testplugin.last_paint_count && pc >= 0)) {
+ setTimeout(func,0);
+ } else
+ setTimeout(waitForPaintCountIncrement, 50);
+ }
+ waitForPaintCountIncrement();
+ }
+
+ function doClick(x,y,func) {
+ synthesizeMouse($("plugin1"), x, y, {}, window);
+ setTimeout(func,0);
+ }
+
+ function verify(test,x,y,next) {
+ var p = $("plugin1").getLastMouseX();
+ const delta = 2;
+ ok(p-delta <= x && x <= p+delta, "test"+test+" LastMouseX got " + p + " expected " + x +
+ " with fullZoom="+SpecialPowers.getFullZoom(window)+" MozTransform='"+$("container").style.MozTransform+"'");
+ p = $("plugin1").getLastMouseY();
+ ok(p-delta <= y && y <= p+delta, "test"+test+" LastMouseY got " + p + " expected " + y +
+ " with fullZoom="+SpecialPowers.getFullZoom(window)+" MozTransform='"+$("container").style.MozTransform+"'");
+ if (next) next();
+ }
+
+ function click(x,y,next) {
+ waitForPaint(function(){doClick(x,y,next);})
+ }
+ function zoom(factor) {
+ SpecialPowers.setFullZoom(window, factor);
+ }
+
+ function test1() { // fullZoom=1 (sanity check)
+ zoom(1);
+ click(55,136, function(){verify("1",55,136,test2)});
+ }
+ function test2() { // fullZoom=2
+ zoom(2);
+ click(40,108, function(){verify("2",80,216,test2b)})
+ }
+ function test2b() {
+ click(108,112, function(){verify("2c",216,224,endTest)})
+ }
+
+ function endTest() {
+ zoom(1);
+ SimpleTest.finish();
+ }
+
+ setTimeout(function(){waitForPaint(test1)},1000);
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ </script>
+</head>
+
+<body onload="runTests()">
+ <div id="container" style="position:relative;top: 0px; left: 0px; width: 640px; height: 480px;">
+ <div id="abs" style="position:absolute; left:90px; top:90px; width:20px; height:20px; background:blue; pointer-events:none;"></div>
+ <embed id="plugin1" type="application/x-test" wmode="transparent" width="200" height="200"></embed>
+ </div>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug539565-2.html b/dom/plugins/test/mochitest/test_bug539565-2.html
new file mode 100644
index 000000000..7d8d02a42
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug539565-2.html
@@ -0,0 +1,111 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=539565
+-->
+<head>
+ <title>Test #2 for Bug 539565</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <script class="testbody" type="text/javascript">
+function runTests() {
+ var moveBy = 17;
+ var waitedForPaint = 0;
+ function waitForPaint(func) {
+ waitedForPaint = 0;
+ var testplugin = $("plugin1");
+ testplugin.last_paint_count = testplugin.getPaintCount ? testplugin.getPaintCount() : -2;
+ function waitForPaintCountIncrement() {
+ waitedForPaint++;
+ moveBy = -moveBy;
+ $("abs").style.left = ($("abs").offsetLeft + moveBy) + 'px';
+ var x = document.documentElement.offsetHeight;
+ var pc = testplugin.getPaintCount ? testplugin.getPaintCount() : -2;
+ if (waitedForPaint == 20 || (pc != testplugin.last_paint_count && pc >= 0)) {
+ setTimeout(func,0);
+ } else
+ setTimeout(waitForPaintCountIncrement, 50);
+ }
+ waitForPaintCountIncrement();
+ }
+
+ function doClick(x,y,func) {
+ synthesizeMouse($("plugin1"), x, y, {}, window);
+ setTimeout(func,0);
+ }
+
+ function verify(test,x,y,next) {
+ var p = $("plugin1").getLastMouseX();
+ const delta = 2;
+ ok(p-delta <= x && x <= p+delta, "test"+test+" LastMouseX got " + p + " expected " + x +
+ " with fullZoom="+SpecialPowers.getFullZoom(window)+" MozTransform='"+$("container").style.MozTransform+"'");
+ p = $("plugin1").getLastMouseY();
+ ok(p-delta <= y && y <= p+delta, "test"+test+" LastMouseY got " + p + " expected " + y +
+ " with fullZoom="+SpecialPowers.getFullZoom(window)+" MozTransform='"+$("container").style.MozTransform+"'");
+ if (next) next();
+ }
+
+ function click(x,y,next) {
+ waitForPaint(function(){doClick(x,y,next);})
+ }
+ function zoom(factor) {
+ SpecialPowers.setFullZoom(window, factor);
+ }
+
+ function test3() { // fullZoom=1 + scale(2)
+ zoom(1);
+ //
+ // ======================== BUG WARNING =========================================
+ // 'container' already has -moz-transform:scale(2) in its style attribute.
+ // Removing that and setting MozTransform dynamically here (as in test4)
+ // makes the test fail ("getLastMouseX is not a function" in verify() above)
+ // Looks like the plugin instance got destroyed and we never recover from that...
+ // ==============================================================================
+ //
+ click(50,136, function(){verify("3",25,68,test3b)});
+ }
+ function test3b() {
+ click(208,212, function(){verify("3b",104,106,test4)});
+ }
+ function test4() { // fullZoom=2 + scale(0.5)
+ zoom(2);
+ var container = $("container");
+ container.style.MozTransformOrigin = "0px 0px";
+ container.style.MozTransform = "scale(0.5)";
+ var x = document.documentElement.offsetHeight;
+ click(60,52, function(){verify("4",240,208,test5)});
+ }
+ function test5() { // fullZoom=2 + scale(2)
+ zoom(2);
+ var container = $("container");
+ container.style.MozTransformOrigin = "0px 0px";
+ container.style.MozTransform = "scale(2)";
+ var x = document.documentElement.offsetHeight;
+ click(108,112, function(){verify("5",108,112,endTest)});
+ }
+
+ function endTest() {
+ zoom(1);
+ SimpleTest.finish();
+ }
+
+ setTimeout(function(){waitForPaint(test3)},1000);
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ </script>
+</head>
+
+<body onload="runTests()">
+ <div id="container" style="position:relative;top: 0px; left: 0px; width: 640px; height: 480px; -moz-transform:scale(2); -moz-transform-origin:0px 0px;">
+ <div id="abs" style="position:absolute; left:90px; top:90px; width:20px; height:20px; background:blue; pointer-events:none;"></div>
+ <embed id="plugin1" type="application/x-test" wmode="transparent" width="200" height="200"></embed>
+ </div>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug738396.html b/dom/plugins/test/mochitest/test_bug738396.html
new file mode 100644
index 000000000..ead7f5c1a
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug738396.html
@@ -0,0 +1,88 @@
+<!doctype html>
+<html>
+<head>
+ <title>Test for Bug 738396</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+</head>
+<body>
+ <script type="text/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED,
+ "Java Test Plug-in");
+
+ SpecialPowers.pushPrefEnv({ "set": [
+ ['plugin.java.mime', 'application/x-java-test']
+ ] }, loadFrame);
+ SimpleTest.waitForExplicitFinish();
+
+ function loadFrame() {
+ var iframe = document.createElement("iframe");
+ iframe.src = "./file_bug738396.html";
+ iframe.addEventListener("load", function() {
+ runTest(iframe.contentDocument);
+ });
+ document.body.appendChild(iframe);
+ }
+
+ function runTest(doc) {
+ // Check that the canonicalized version of the codebase 'good' was passed
+ // to the plugin in all cases
+ var a = doc.createElement('a');
+ a.href = "good";
+ var goodCodebase = a.href;
+ var codebasevis = doc.getElementById("codebasevis")
+ .querySelectorAll("applet, object, embed");
+ for (var elem of codebasevis) {
+ var codebase = null;
+ try {
+ codebase = elem.getJavaCodebase();
+ } catch (e) {}
+ is(codebase, goodCodebase,
+ "Check that the test plugin sees the proper codebase");
+ }
+ // Check that none of the applets in blockedcodebase were allowed to spawn
+ var blockedcodebase = doc.getElementById("blockedcodebase")
+ .querySelectorAll("applet, object, embed");
+ for (var elem of blockedcodebase) {
+ var spawned = false;
+ try {
+ elem.getObjectValue();
+ spawned = true;
+ } catch (e) {}
+ ok(!spawned, "Plugin should not be allowed to spawn");
+ }
+
+ // With no codebase, the codebase should resolve to "."
+ a.href = ".";
+ goodCodebase = a.href;
+ var nocodebase = doc.getElementById("nocodebase")
+ .querySelectorAll("applet, object, embed");
+ for (var elem of nocodebase) {
+ var codebase = null;
+ try {
+ codebase = elem.getJavaCodebase();
+ } catch (e) {}
+ is(codebase, goodCodebase, "Codebase should resolve to '.'");
+ }
+
+ // With empty codebase, the codebase should resolve to "/"
+ a.href = "/";
+ goodCodebase = a.href;
+ var nocodebase = doc.getElementById("emptycodebase")
+ .querySelectorAll("applet, object, embed");
+ for (var elem of nocodebase) {
+ var codebase = null;
+ try {
+ codebase = elem.getJavaCodebase();
+ } catch (e) {}
+ is(codebase, goodCodebase, "Codebase should resolve to '/'");
+ }
+
+ SimpleTest.finish();
+ }
+</script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug751809.html b/dom/plugins/test/mochitest/test_bug751809.html
new file mode 100644
index 000000000..8f4987a8a
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug751809.html
@@ -0,0 +1,84 @@
+<html>
+<head>
+ <title>Bug 751809</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/paint_listener.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <script type="application/javascript;version=1.7">
+ Components.utils.import("resource://gre/modules/Services.jsm");
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+ </script>
+</head>
+
+<body onload="go();">
+ <embed id="plugin" type="application/x-test" width="400" height="400" drawmode="solid" color="FF00FFFF"></embed>
+
+ <script type="application/javascript;version=1.7">
+
+ SimpleTest.waitForExplicitFinish();
+
+ const Ci = Components.interfaces;
+ const utils = window.QueryInterface(Ci.nsIInterfaceRequestor).
+ getInterface(Ci.nsIDOMWindowUtils);
+
+ function go() {
+ var plugin = document.getElementById('plugin');
+ var objLoadingContent = SpecialPowers.wrap(plugin);
+ ok(!objLoadingContent.activated, "plugin should not be activated");
+
+ SimpleTest.waitForFocus(afterWindowFocus);
+ }
+
+ function afterWindowFocus() {
+ var plugin = document.getElementById('plugin');
+ var objLoadingContent = SpecialPowers.wrap(plugin);
+
+ objLoadingContent.playPlugin();
+ var condition = () => plugin.setColor !== undefined;
+ SimpleTest.waitForCondition(condition, afterPluginActivation,
+ "Waited too long for plugin to activate");
+ }
+
+ function afterPluginActivation() {
+ var plugin = document.getElementById('plugin');
+ var objLoadingContent = SpecialPowers.wrap(plugin);
+ ok(objLoadingContent.activated, "plugin should be activated now");
+
+ // Triggering a paint and waiting for it to be flushed makes sure
+ // that both plugin and platform see the plugin element as visible.
+ // See bug 805330 for details.
+ plugin.setColor("FF000088");
+ waitForAllPaintsFlushed(afterPaintsFlushed);
+ }
+
+ function afterPaintsFlushed() {
+ var plugin = document.getElementById('plugin');
+ try {
+ is(plugin.getMouseUpEventCount(), 0, "Plugin should not have received mouse events yet.");
+ } catch(e) {
+ ok(false, "plugin.getMouseUpEventCount() shouldn't throw");
+ }
+
+ synthesizeMouseAtCenter(plugin, {});
+ var condition = () => plugin.getMouseUpEventCount() > 0;
+ SimpleTest.waitForCondition(condition, afterFirstClick,
+ "Waited too long for plugin to receive the mouse click");
+ }
+
+ function afterFirstClick() {
+ var plugin = document.getElementById('plugin');
+ try {
+ is(plugin.getMouseUpEventCount(), 1, "Plugin should have received 1 mouse up event.");
+ } catch(e) {
+ ok(false, "plugin.getMouseUpEventCount() shouldn't throw");
+ }
+
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ SimpleTest.finish();
+ }
+
+ </script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug771202.html b/dom/plugins/test/mochitest/test_bug771202.html
new file mode 100644
index 000000000..712c11de7
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug771202.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=771202
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 771202</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=771202">Mozilla Bug 771202</a>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for recreating spliced plugin prototype chains after tranplant. **/
+SimpleTest.waitForExplicitFinish();
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+function go() {
+ // Set things up.
+ var win = document.getElementById('ifr').contentWindow;
+ var plugin = win.document.getElementById('pluginElement');
+ var testValue = plugin.getObjectValue();
+
+ function checkPlugin() {
+ dump("About to call checkObjectValue\n");
+ ok(plugin.checkObjectValue(testValue), 'Plugin proto should work correctly');
+ }
+ // First, check things before transplanting.
+ checkPlugin();
+
+ // Adopt the plugin and retest.
+ document.body.appendChild(plugin);
+ checkPlugin();
+
+ // All done.
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+
+<iframe id="ifr" onload="go();" src="file_bug771202.html">
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug777098.html b/dom/plugins/test/mochitest/test_bug777098.html
new file mode 100644
index 000000000..77ba9ed31
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug777098.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=777098
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 777098</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="go();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=777098">Mozilla Bug 777098</a>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for passing dead NPObjects back into plugins. **/
+SimpleTest.waitForExplicitFinish();
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+function go() {
+ var plugin = document.getElementById('plugin');
+
+ // Get wrapped npobject from plugin (plugin.__proto__)
+ var val = plugin.getObjectValue();
+
+ // Force a re-instantiate by re-setting dummy uri,
+ // making val a wrapper for a dead plugin
+ plugin.data = plugin.data;
+
+ // The correct behavior is an exception, if plugin.checkObjectValue succeeds
+ // the plugin wasn't torn down for some reason, and if we crash... that's bad
+ function pluginCheck() {
+ try {
+ plugin.checkObjectValue(val);
+ } catch (e) {
+ return true;
+ }
+ return false;
+ }
+
+ // Spin the event loop so the instantiation can complete
+ window.setTimeout(function () {
+ ok(pluginCheck(), "Shouldn't explode");
+
+ // All done.
+ SimpleTest.finish();
+ }, 0);
+}
+
+</script>
+</pre>
+
+<object data="data:text/plain,a" width=200 height=200 type="application/x-test" id="plugin"></object>
+
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug784131.html b/dom/plugins/test/mochitest/test_bug784131.html
new file mode 100644
index 000000000..ff2dd19c1
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug784131.html
@@ -0,0 +1,85 @@
+<!doctype html>
+<html>
+<head>
+ <title>Test for Bug 784131</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <base href="chrome://browser/content/">
+</head>
+<body>
+
+<script type="text/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+</script>
+
+<embed id="body" type="application/x-test">
+<div>
+ <embed id="nested" type="application/x-test">
+</div>
+
+<script type="application/javascript">
+ function getObjectValue(obj) {
+ try {
+ return obj.getObjectValue();
+ } catch (e) {
+ return null;
+ }
+ }
+ SimpleTest.waitForExplicitFinish();
+
+ var body_embed = document.querySelector("embed#body");
+ var nested_embed = document.querySelector("embed#nested");
+ var nested_parent = nested_embed.parentNode;
+ // Ensure plugins are spawned
+ var body_obj = getObjectValue(body_embed);
+ var nested_obj = getObjectValue(nested_embed);
+ isnot(body_obj, null, "body plugin spawned");
+ isnot(nested_obj, null, "nested plugin spawned");
+ // Display:none the plugin and the nested plugin's parent
+ body_embed.style.display = "none";
+ nested_parent.style.display = "none";
+ body_embed.clientTop;
+ nested_embed.clientTop;
+
+ // Plugins should still be running the same instance
+ ok(body_embed.checkObjectValue(body_obj), "body plugin still running");
+ ok(nested_embed.checkObjectValue(nested_obj), "nested plugin still running");
+ // Spin event loop
+ SimpleTest.executeSoon(function() {
+ // Plugins should be stopped
+ is(getObjectValue(body_embed), null, "body plugin gone");
+ is(getObjectValue(nested_embed), null, "nested plugin gone");
+
+ // Restart plugins...
+ body_embed.style.display = "inherit";
+ nested_parent.style.display = "inherit";
+
+ // Ensure plugins are spawned
+ var body_obj = getObjectValue(body_embed);
+ var nested_obj = getObjectValue(nested_embed);
+ isnot(body_obj, null, "body plugin spawned");
+ isnot(nested_obj, null, "nested plugin spawned");
+
+ // Take away frames again, flush layout, restore frames
+ body_embed.style.display = "none";
+ nested_parent.style.display = "none";
+ body_embed.clientTop;
+ nested_embed.clientTop;
+ body_embed.style.display = "inherit";
+ nested_parent.style.display = "inherit";
+ body_embed.clientTop;
+ nested_embed.clientTop;
+
+ // Spin event loop, ensure plugin remains running
+ SimpleTest.executeSoon(function() {
+ ok(body_embed.checkObjectValue(body_obj), "body plugin still running");
+ ok(nested_embed.checkObjectValue(nested_obj), "nested plugin still running");
+ SimpleTest.finish();
+ });
+ });
+</script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug813906.html b/dom/plugins/test/mochitest/test_bug813906.html
new file mode 100644
index 000000000..04c34daaf
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug813906.html
@@ -0,0 +1,54 @@
+<!doctype html>
+<html>
+<head>
+ <title>Test for Bug 813906</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <base href="chrome://browser/content/">
+</head>
+<body>
+
+<script type="application/javascript">
+function f() {
+ document.getElementsByTagName("base")[0].href = "http://www.safe.com/";
+}
+</script>
+
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+var frameLoadCount = 0;
+function frameLoaded() {
+ frameLoadCount++;
+ if (frameLoadCount == 1) {
+ document.getElementsByTagName("object")[0].type = "application/x-test";
+ document.getElementsByTagName("use")[0].setAttributeNS("http://www.w3.org/1999/xlink", "href", location.href + "#a");
+ } else if (frameLoadCount == 2) {
+ isnot(SpecialPowers.wrap(window.frame1).location.href.indexOf('chrome://'),
+ 0, 'plugin shouldnt be able to cause navigation to chrome URLs');
+ SimpleTest.finish();
+ }
+}
+</script>
+
+<!-- Note that <svg:use> ends up creating an anonymous subtree, which means that the plugin
+ reflector gets hoisted into the XBL scope, and isn't accessible to content. We pass
+ the 'donttouchelement' parameter to the plugin to prevent it from trying to define the
+ 'pluginFoundElement' property on the plugin reflector, since doing so would throw a
+ security exception. -->
+<svg>
+ <symbol id="a">
+ <foreignObject>
+ <object bugmode="813906" frame="frame1"><param name="donttouchelement"></param></object>
+ </foreignObject>
+ </symbol>
+ <use />
+</svg>
+
+<iframe name="frame1" onload="frameLoaded()"></iframe>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug827160.html b/dom/plugins/test/mochitest/test_bug827160.html
new file mode 100644
index 000000000..13cedd62a
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug827160.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=827160
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 827160</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="/tests/SimpleTest/SpecialPowers.js"></script>
+ <script type="application/javascript" src="utils.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=827160">Mozilla Bug 827160</a>
+
+<script type="application/javascript">
+
+// Make sure the test plugin is not click-to-play
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+
+</script>
+
+<!-- Should load test plugin application/x-test -->
+<object id="shouldLoad" data="data:application/x-test,foo"></object>
+<!-- Should load test plugin application/x-test2, ignoring type="" -->
+<object id="shouldIgnoreType" type="application/x-test" data="data:application/x-test2,foo"></object>
+<!-- Should load nothing, channel type does not match type and typeMustMatch is present -->
+<object id="shouldNotLoad" type="application/x-test" data="data:application/x-test2,foo" typemustmatch></object>
+<!-- Should not load test plugin application/x-test2, no type field is present -->
+<object id="shouldNotLoadMissingType" data="data:application/x-test2,foo" typemustmatch></object>
+<!-- Should load, no data field is present -->
+<object id="shouldLoadMissingData" type="application/x-test" typemustmatch></object>
+<pre id="test">
+
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+
+window.addEventListener("load", function () {
+ const OBJLC = SpecialPowers.Ci.nsIObjectLoadingContent;
+ is(SpecialPowers.wrap(document.getElementById("shouldLoad")).displayedType, OBJLC.TYPE_PLUGIN, "Testing object load without type, failed expected load");
+ is(SpecialPowers.wrap(document.getElementById("shouldIgnoreType")).displayedType, OBJLC.TYPE_PLUGIN, "Testing object load with type, failed expected load");
+ is(SpecialPowers.wrap(document.getElementById("shouldNotLoad")).displayedType, OBJLC.TYPE_NULL, "Testing object load with typemustmatch, load success even though failure expected");
+ is(SpecialPowers.wrap(document.getElementById("shouldNotLoadMissingType")).displayedType, OBJLC.TYPE_NULL, "Testing object load with typemustmatch and with type, load success even though failure expected");
+ is(SpecialPowers.wrap(document.getElementById("shouldLoadMissingData")).displayedType, OBJLC.TYPE_PLUGIN, "Testing object load with typemustmatch and without data, failed expected load");
+ SimpleTest.finish();
+}, false);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug852315.html b/dom/plugins/test/mochitest/test_bug852315.html
new file mode 100644
index 000000000..cbbc3d34a
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug852315.html
@@ -0,0 +1,62 @@
+<!doctype html>
+<html>
+<head>
+ <title>Test for Bug 852315</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <base href="chrome://browser/content/">
+</head>
+<body>
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+// Tests that the document-inactive notification stopping plugins does not
+// fatally re-enter when adding other plugins to the document.
+
+var i = document.createElement("iframe");
+var ob = document.body;
+i.addEventListener("load", function loadfunc() {
+ var d = i.contentWindow.document;
+ var e = i.contentDocument.createElement("embed");
+ var destroyran = false;
+ e.type = "application/x-test";
+ i.contentDocument.body.appendChild(e);
+
+ // On despawn, append an embed tag to document.
+ e.callOnDestroy(function() {
+ var e2 = d.createElement("embed");
+ d.body.appendChild(e2);
+ destroyran = true;
+ });
+
+ // Navigate the frame to cause the document with the plugin to go inactive
+ i.removeEventListener("load", loadfunc);
+ i.src = "about:blank";
+
+ const MAX_ATTEMPTS = 50;
+ var attempts = 0;
+ function checkPluginDestroyRan() {
+ // We may need to retry a few times until the plugin stop event makes
+ // its way through the event queue.
+ if (attempts < MAX_ATTEMPTS && !destroyran) {
+ ++attempts;
+ SimpleTest.executeSoon(checkPluginDestroyRan);
+ } else {
+ info("Number of retry attempts: " + attempts);
+ ok(destroyran, "OnDestroy callback ran and did not crash");
+ SimpleTest.finish();
+ }
+ }
+
+ SimpleTest.executeSoon(checkPluginDestroyRan);
+});
+document.body.appendChild(i);
+
+</script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug854082.html b/dom/plugins/test/mochitest/test_bug854082.html
new file mode 100644
index 000000000..ff3d1e1e8
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug854082.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html>
+<head>
+ <title>Test for Bug 854082</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <base href="chrome://browser/content/">
+</head>
+<body>
+<script type="application/javascript">
+ // Tests that destroying the plugin's frame inside NPP_New does not cause a
+ // crash
+
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ // Create an object that will spawn asynchronously
+ var o = document.createElement("object");
+ o.type = "application/x-test";
+
+ // The test plugin sets pluginFoundElement on its element inside NPP_New,
+ // abuse this to run arbitrary script.
+ var setterCalled;
+ o.__defineSetter__("pluginFoundElement", function() {
+ o.style.display = "none";
+ // Access clientTop to force layout flush
+ o.clientTop;
+ ok(true, "Setter called and did not crash");
+ SimpleTest.finish();
+ setterCalled = true;
+ });
+ document.body.appendChild(o);
+</script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug863792.html b/dom/plugins/test/mochitest/test_bug863792.html
new file mode 100644
index 000000000..ccd0fc83c
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug863792.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<html>
+<head>
+ <title>Test for Bug 863792</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+</head>
+<body>
+<script type="application/javascript">
+
+// A plugin that removes itself from the document and inactivates said document
+// inside NPP_New. We should not leak the instance. See also test_bug854082
+
+SimpleTest.waitForExplicitFinish();
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+var i = document.createElement("iframe");
+i.src = "file_bug863792.html";
+i.width = 500;
+i.height = 500;
+document.body.appendChild(i);
+
+i.addEventListener("load", function() {
+ SpecialPowers.forceGC();
+ SpecialPowers.forceCC();
+ SimpleTest.executeSoon(function() {
+ SpecialPowers.forceGC();
+ SpecialPowers.forceCC();
+ SimpleTest.executeSoon(function() {
+ ok(true, "Didn't crash");
+ SimpleTest.finish();
+ });
+ });
+}, false);
+</script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug967694.html b/dom/plugins/test/mochitest/test_bug967694.html
new file mode 100644
index 000000000..8a7602134
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug967694.html
@@ -0,0 +1,78 @@
+<!doctype html>
+<html>
+<head>
+ <title>Test for Bug 967694</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+</head>
+<body>
+<script type="application/javascript">
+
+// Touching a plugin from chrome scope should not spawn it, bug should
+// synchronously spawn it from content scope
+
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+var plugin;
+var spPlugin;
+
+function recreatePlugin() {
+ if (plugin) {
+ document.body.removeChild(plugin);
+ }
+ plugin = document.createElement("embed");
+ plugin.type = "application/x-test";
+
+ document.body.appendChild(plugin);
+ // Plugin should now be queued for async spawning.
+ spPlugin = SpecialPowers.wrap(plugin);
+
+ is(spPlugin.displayedType, spPlugin.TYPE_PLUGIN, "Should be configured as plugin");
+ ok(!spPlugin.hasRunningPlugin, "Should not be spawned yet");
+}
+
+recreatePlugin();
+
+// Try various JS operations with chrome context
+var thrown = false;
+// Get and set non-existent Property
+var hi = spPlugin._testShouldntExist;
+spPlugin._testShouldntExist = 5;
+// Call some test-plugin function
+try {
+ var val = spPlugin.getObjectValue();
+} catch (e) {
+ thrown = true;
+}
+
+ok(thrown, "Function call should have thrown");
+ok(!spPlugin.hasRunningPlugin, "Plugin should not have spawned");
+
+// Try property access from content
+var hi = plugin._testShouldntExistContent;
+ok(spPlugin.hasRunningPlugin, "Should've caused plugin to spawn");
+
+// Property set
+recreatePlugin();
+plugin._testShouldntExistContent = 5;
+ok(spPlugin.hasRunningPlugin, "Should've caused plugin to spawn");
+
+// Call test plugin function. Should succeed.
+recreatePlugin();
+thrown = false;
+try {
+ var value = plugin.getObjectValue();
+} catch (e) {
+ thrown = true;
+}
+
+ok(!thrown, "Call should have succeeded");
+ok(spPlugin.hasRunningPlugin, "Call should have synchronously spawned plugin");
+ok(plugin.checkObjectValue(value), "Plugin should recognize self");
+
+</script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug985859.html b/dom/plugins/test/mochitest/test_bug985859.html
new file mode 100644
index 000000000..1a4329ab4
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug985859.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<html>
+<head>
+ <title>Test for Bug 985859</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <base href="chrome://browser/content/">
+</head>
+<body>
+<script type="application/javascript">
+
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+var testType = navigator.mimeTypes["application/x-test"];
+var testTypeCap = navigator.mimeTypes["Application/x-Test"];
+var testTypeCap2 = navigator.mimeTypes["APPLICATION/X-TEST"];
+
+ok(testType, "Test plugin should be found");
+is(testType, testTypeCap, "navigator.mimeTypes should be case insensitive");
+is(testType, testTypeCap2, "navigator.mimeTypes should be case insensitive");
+
+</script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_bug986930.html b/dom/plugins/test/mochitest/test_bug986930.html
new file mode 100644
index 000000000..f86539e58
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_bug986930.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8"/>
+ <title>Test for Bug 986930</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+</head>
+<body>
+ <script class="testbody" type="application/javascript">
+ var testPlugin = getTestPlugin("Test Plug-in");
+
+ var mimeDescriptions = testPlugin.getMimeDescriptions({});
+
+ is(mimeDescriptions[0], "Test \u2122 mimetype",
+ "Plugin should handle non-ascii mime description");
+ </script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_busy_hang.xul b/dom/plugins/test/mochitest/test_busy_hang.xul
new file mode 100644
index 000000000..824dcbb4d
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_busy_hang.xul
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window title="Basic Plugin Tests"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <title>Plugin Busy Hang Test</title>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+ <script type="application/javascript"
+ src="http://mochi.test:8888/chrome/dom/plugins/test/mochitest/hang_test.js" />
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <script type="application/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+ <body xmlns="http://www.w3.org/1999/xhtml" onload="runTests()">
+ <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+ </body>
+ <script class="testbody" type="application/javascript">
+ <![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+function runTests() {
+ // Default plugin hang timeout is too high for mochitests
+ var prefs = Cc["@mozilla.org/preferences-service;1"]
+ .getService(Ci.nsIPrefBranch);
+ var timeoutPref = "dom.ipc.plugins.timeoutSecs";
+ prefs.setIntPref(timeoutPref, 5);
+
+ var os = Cc["@mozilla.org/observer-service;1"].
+ getService(Ci.nsIObserverService);
+ os.addObserver(testObserver, "plugin-crashed", true);
+
+ testObserver.idleHang = false;
+ document.addEventListener("PluginCrashed", onPluginCrashed, false);
+
+ var pluginElement = document.getElementById("plugin1");
+ try {
+ pluginElement.hang(true);
+ } catch (e) {
+ }
+}
+]]>
+ </script>
+</window>
+
diff --git a/dom/plugins/test/mochitest/test_clear_site_data.html b/dom/plugins/test/mochitest/test_clear_site_data.html
new file mode 100644
index 000000000..88ba937d5
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_clear_site_data.html
@@ -0,0 +1,242 @@
+<html>
+<head>
+ <title>NPAPI ClearSiteData/GetSitesWithData Functionality</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+</head>
+<body>
+ <script type="application/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+
+ <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ const pluginHostIface = Components.interfaces.nsIPluginHost;
+ var pluginHost = Components.classes["@mozilla.org/plugin/host;1"].
+ getService(pluginHostIface);
+ const FLAG_CLEAR_ALL = pluginHostIface.FLAG_CLEAR_ALL;
+ const FLAG_CLEAR_CACHE = pluginHostIface.FLAG_CLEAR_CACHE;
+
+ var p = document.getElementById("plugin1");
+
+ // Since we're running with chrome permissions, accessing the plugin wont
+ // synchronously spawn it -- wait for the async spawning to finish.
+ SimpleTest.executeSoon(function() {
+ // Make sure clearing by timerange is supported.
+ p.setSitesWithDataCapabilities(true);
+ ok(PluginUtils.withTestPlugin(runTest), "Test plugin found");
+ });
+
+ function stored(needles) {
+ var something = pluginHost.siteHasData(this.pluginTag, null);
+ if (!needles)
+ return something;
+
+ if (!something)
+ return false;
+
+ for (var i = 0; i < needles.length; ++i) {
+ if (!pluginHost.siteHasData(this.pluginTag, needles[i]))
+ return false;
+ }
+ return true;
+ }
+
+ function checkThrows(fn, result) {
+ try {
+ fn();
+ throw new Error("bad exception");
+ } catch (e) {
+ is(e.result, result, "Correct exception thrown");
+ }
+ }
+
+ function runTest(pluginTag) {
+ this.pluginTag = pluginTag;
+ p.setSitesWithData(
+ "foo.com:0:5," +
+ "foo.com:0:7," +
+ "bar.com:0:10," +
+ "baz.com:0:10," +
+ "foo.com:1:7," +
+ "qux.com:1:5," +
+ "quz.com:1:8"
+ );
+ ok(stored(["foo.com","bar.com","baz.com","qux.com","quz.com"]),
+ "Data stored for sites");
+
+ // Clear nothing.
+ pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_ALL, 4, {callback: function() { test1(); }});
+ }
+ function test1() {
+ ok(stored(["foo.com","bar.com","baz.com","qux.com","quz.com"]),
+ "Data stored for sites");
+
+ pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 4, {callback: function() { test2(); }});
+ }
+ function test2() {
+ ok(stored(["foo.com","bar.com","baz.com","qux.com","quz.com"]),
+ "Data stored for sites");
+
+ // Clear cache data 5 seconds or older.
+ pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 5, {callback: function() { test3(); }});
+ }
+ function test3() {
+ ok(stored(["foo.com","bar.com","baz.com","quz.com"]),
+ "Data stored for sites");
+ ok(!stored(["qux.com"]), "Data cleared for qux.com");
+ // Clear cache data for foo.com, but leave non-cache data.
+ pluginHost.clearSiteData(pluginTag, "foo.com", FLAG_CLEAR_CACHE, 20, {callback: function() { test4(); }});
+ }
+ function test4() {
+ ok(stored(["foo.com","bar.com","baz.com","quz.com"]),
+ "Data stored for sites");
+
+ // Clear all data 7 seconds or older.
+ pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_ALL, 7, {callback: function() { test5(); }});
+ }
+ function test5() {
+ ok(stored(["bar.com","baz.com","quz.com"]), "Data stored for sites");
+ ok(!stored(["foo.com"]), "Data cleared for foo.com");
+ ok(!stored(["qux.com"]), "Data cleared for qux.com");
+
+ // Clear all cache data.
+ pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 20, {callback: function() { test6(); }});
+ }
+ function test6() {
+ ok(stored(["bar.com","baz.com"]), "Data stored for sites");
+ ok(!stored(["quz.com"]), "Data cleared for quz.com");
+
+ // Clear all data for bar.com.
+ pluginHost.clearSiteData(pluginTag, "bar.com", FLAG_CLEAR_ALL, 20, {callback: function(rv) { test7(rv); }});
+ }
+ function test7(rv) {
+ ok(stored(["baz.com"]), "Data stored for baz.com");
+ ok(!stored(["bar.com"]), "Data cleared for bar.com");
+
+ // Disable clearing by age.
+ p.setSitesWithDataCapabilities(false);
+
+ pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_ALL, 20, {callback: function(rv) {
+ is(rv, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
+ test8(rv);
+ }});
+ }
+ function test8(rv) {
+ pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, 20, {callback: function(rv) {
+ is(rv, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
+ test9(rv);
+ }});
+ }
+ function test9(rv) {
+ pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_ALL, 20, {callback: function(rv) {
+ is(rv, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
+ test10(rv);
+ }});
+ }
+ function test10(rv) {
+ pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_CACHE, 20, {callback: function(rv) {
+ is(rv, Components.results.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED);
+ test11();
+ }});
+ }
+ function test11() {
+ // Clear cache for baz.com and globally for all ages.
+ pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_CACHE, -1, {callback: function(rv) { test12()}});
+ }
+ function test12() {
+ pluginHost.clearSiteData(pluginTag, null, FLAG_CLEAR_CACHE, -1, {callback: function(rv) { test13()}});
+ }
+ function test13() {
+ // Check that all of the above were no-ops.
+ ok(stored(["baz.com"]), "Data stored for baz.com");
+
+ // Clear everything for baz.com.
+ pluginHost.clearSiteData(pluginTag, "baz.com", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test14()}});
+ }
+ function test14() {
+ ok(!stored(["baz.com"]), "Data cleared for baz.com");
+ ok(!stored(null), "All data cleared");
+
+ // Set data to test subdomains, IP literals, and 'localhost'-like hosts.
+ p.setSitesWithData(
+ "foo.com:0:0," +
+ "bar.foo.com:0:0," +
+ "baz.foo.com:0:0," +
+ "bar.com:0:0," +
+ "[192.168.1.1]:0:0," +
+ "localhost:0:0"
+ );
+ ok(stored(["foo.com","nonexistent.foo.com","bar.com","192.168.1.1","localhost"]),
+ "Data stored for sites");
+
+ // Clear data for "foo.com" and its subdomains.
+ pluginHost.clearSiteData(pluginTag, "foo.com", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test15()}});
+ }
+ function test15() {
+ ok(stored(["bar.com","192.168.1.1","localhost"]), "Data stored for sites");
+ ok(!stored(["foo.com"]), "Data cleared for foo.com");
+ ok(!stored(["bar.foo.com"]), "Data cleared for subdomains of foo.com");
+
+ // Clear data for "bar.com" using a subdomain.
+ pluginHost.clearSiteData(pluginTag, "foo.bar.com", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test16()}});
+ }
+ function test16() {
+ ok(!stored(["bar.com"]), "Data cleared for bar.com");
+
+ // Clear data for "192.168.1.1".
+ pluginHost.clearSiteData(pluginTag, "192.168.1.1", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test17()}});
+ }
+ function test17() {
+ ok(!stored(["192.168.1.1"]), "Data cleared for 192.168.1.1");
+
+ // Clear data for "localhost".
+ pluginHost.clearSiteData(pluginTag, "localhost", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test18()}});
+ }
+ function test18() {
+ ok(!stored(null), "All data cleared");
+
+ // Set data to test international domains.
+ p.setSitesWithData(
+ "b\u00FCcher.es:0:0," +
+ "b\u00FCcher.uk:0:0," +
+ "xn--bcher-kva.NZ:0:0"
+ );
+ // Check that both the ACE and UTF-8 representations register.
+ ok(stored(["b\u00FCcher.es","xn--bcher-kva.es","b\u00FCcher.uk","xn--bcher-kva.uk"]),
+ "Data stored for sites");
+
+ // Clear data for the UTF-8 version.
+ pluginHost.clearSiteData(pluginTag, "b\u00FCcher.es", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test19()}});
+ }
+ function test19() {
+ ok(!stored(["b\u00FCcher.es"]), "Data cleared for UTF-8 representation");
+ ok(!stored(["xn--bcher-kva.es"]), "Data cleared for ACE representation");
+
+ // Clear data for the ACE version.
+ pluginHost.clearSiteData(pluginTag, "xn--bcher-kva.uk", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test20()}});
+ }
+ function test20() {
+ ok(!stored(["b\u00FCcher.uk"]), "Data cleared for UTF-8 representation");
+ ok(!stored(["xn--bcher-kva.uk"]), "Data cleared for ACE representation");
+
+ // The NPAPI spec requires that the plugin report sites in normalized
+ // UTF-8. We do happen to normalize the result anyway, so while that's not
+ // strictly required, we test it here.
+ ok(stored(["b\u00FCcher.nz","xn--bcher-kva.nz"]),
+ "Data stored for sites");
+ pluginHost.clearSiteData(pluginTag, "b\u00FCcher.nz", FLAG_CLEAR_ALL, -1, {callback: function(rv) { test21()}});
+ }
+ function test21() {
+ ok(!stored(["b\u00FCcher.nz"]), "Data cleared for UTF-8 representation");
+ ok(!stored(["xn--bcher-kva.nz"]), "Data cleared for ACE representation");
+ ok(!stored(null), "All data cleared");
+ SimpleTest.finish();
+ }
+ </script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_cocoa_focus.html b/dom/plugins/test/mochitest/test_cocoa_focus.html
new file mode 100644
index 000000000..17043ebae
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_cocoa_focus.html
@@ -0,0 +1,28 @@
+<html>
+<head>
+ <title>NPCocoaEventFocusChanged Tests</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var gOtherWindow;
+
+ function runTests() {
+ // We have to have two top-level windows in play in order to run these tests.
+ gOtherWindow = window.open("cocoa_focus.html", "", "width=250,height=250");
+ }
+
+ function testsFinished() {
+ // Tests have finished running, close the new window and end tests.
+ gOtherWindow.close();
+ SimpleTest.finish();
+ }
+ </script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_cocoa_window_focus.html b/dom/plugins/test/mochitest/test_cocoa_window_focus.html
new file mode 100644
index 000000000..3458c24eb
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_cocoa_window_focus.html
@@ -0,0 +1,28 @@
+<html>
+<head>
+ <title>NPCocoaEventWindowFocusChanged Tests</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var gOtherWindow;
+
+ function runTests() {
+ // We have to have two top-level windows in play in order to run these tests.
+ gOtherWindow = window.open("cocoa_window_focus.html", "", "width=200,height=200");
+ }
+
+ function testsFinished() {
+ // Tests have finished running, close the new window and end tests.
+ gOtherWindow.close();
+ SimpleTest.finish();
+ }
+ </script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_convertpoint.xul b/dom/plugins/test/mochitest/test_convertpoint.xul
new file mode 100644
index 000000000..5db01a253
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_convertpoint.xul
@@ -0,0 +1,83 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window title="Basic Plugin Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <script type="application/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+<body xmlns="http://www.w3.org/1999/xhtml" onload="runTests()">
+<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+</body>
+<script class="testbody" type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+function runTests() {
+ var pluginElement = document.getElementById("plugin1");
+ // Poll to see if the plugin is in the right place yet.
+ // Check if x-coordinate 0 in plugin space is 0 in window space. If it is,
+ // the plugin hasn't been placed yet.
+ if (pluginElement.convertPointX(1, 0, 0, 2) == 0) {
+ setTimeout(runTests, 0);
+ return;
+ }
+
+ var domWindowUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindowUtils);
+
+ var pluginRect = pluginElement.getBoundingClientRect();
+ var pluginX = pluginRect.left + (window.mozInnerScreenX - window.screenX);
+ var pluginY = pluginRect.top + (window.mozInnerScreenY - window.screenY);
+
+ var windowX = window.screenX;
+ var windowY = window.screenY;
+ var windowHeight = window.outerHeight;
+
+ var screenHeight = window.screen.height;
+
+ // arbitrary coordinates of test point in plugin top-left origin terms
+ var xOffset = 5;
+ var yOffset = 5;
+
+ var NPCoordinateSpacePluginX = 0 + xOffset;
+ var NPCoordinateSpacePluginY = 0 + yOffset;
+
+ var NPCoordinateSpaceWindowX = pluginX + xOffset;
+ var NPCoordinateSpaceWindowY = (windowHeight - pluginY) - yOffset;
+
+ var NPCoordinateSpaceFlippedWindowX = pluginX + xOffset;
+ var NPCoordinateSpaceFlippedWindowY = pluginY + yOffset;
+
+ var NPCoordinateSpaceScreenX = windowX + pluginX + xOffset;
+ var NPCoordinateSpaceScreenY = ((screenHeight - windowY) - pluginY) - yOffset;
+
+ var NPCoordinateSpaceFlippedScreenX = windowX + pluginX + xOffset;
+ var NPCoordinateSpaceFlippedScreenY = windowY + pluginY + yOffset;
+
+ // these are in coordinate space enumeration order
+ var xValues = new Array(NPCoordinateSpacePluginX, NPCoordinateSpaceWindowX, NPCoordinateSpaceFlippedWindowX, NPCoordinateSpaceScreenX, NPCoordinateSpaceFlippedScreenX);
+ var yValues = new Array(NPCoordinateSpacePluginY, NPCoordinateSpaceWindowY, NPCoordinateSpaceFlippedWindowY, NPCoordinateSpaceScreenY, NPCoordinateSpaceFlippedScreenY);
+
+ var i;
+ for (i = 0; i < 5; i = i + 1) {
+ var sourceCoordSpaceValue = i + 1;
+ var j;
+ for (j = 0; j < 5; j = j + 1) {
+ var destCoordSpaceValue = j + 1;
+ xResult = pluginElement.convertPointX(sourceCoordSpaceValue, xValues[i], yValues[i], destCoordSpaceValue);
+ yResult = pluginElement.convertPointY(sourceCoordSpaceValue, xValues[i], yValues[i], destCoordSpaceValue);
+ is(xResult, xValues[j], "convertPointX: space " + sourceCoordSpaceValue + " to space " + destCoordSpaceValue + " mismatch");
+ is(yResult, yValues[j], "convertPointY: space " + sourceCoordSpaceValue + " to space " + destCoordSpaceValue + " mismatch");
+ }
+ }
+
+ SimpleTest.finish();
+}
+]]>
+</script>
+</window>
diff --git a/dom/plugins/test/mochitest/test_cookies.html b/dom/plugins/test/mochitest/test_cookies.html
new file mode 100644
index 000000000..f52796770
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_cookies.html
@@ -0,0 +1,23 @@
+<html>
+<head>
+ <title>NPAPI Cookie Tests</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+</head>
+
+<body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function runTests() {
+ var pluginElement = document.getElementById("plugin1");
+ pluginElement.setCookie("foo");
+ is(pluginElement.getCookie(), "foo", "Cookie was set and retrieved correctly via NPAPI.");
+ SimpleTest.finish();
+ }
+ </script>
+
+ <embed id="plugin1" type="application/x-test" width="400" height="400"></embed>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_copyText.html b/dom/plugins/test/mochitest/test_copyText.html
new file mode 100644
index 000000000..553207e25
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_copyText.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test copying text from browser to plugin</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+
+ <script class="testbody" type="text/javascript">
+function runTests() {
+ var text = " some text \n to copy 'n paste "
+ var textElt = document.getElementById("input");
+ var plugin = document.getElementById("plugin1");
+
+ // Make sure we wait for the clipboard
+ SimpleTest.waitForClipboard(text, () => {
+ textElt.focus();
+ textElt.value = text;
+ textElt.select();
+ SpecialPowers.wrap(textElt).editor.copy();
+ }, () => {
+ is(plugin.getClipboardText(), text);
+ SimpleTest.finish();
+ }, () => {
+ ok(false, "Failed to set the clipboard text!");
+ SimpleTest.finish();
+ });
+}
+
+SimpleTest.waitForExplicitFinish();
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ </script>
+</head>
+
+<body onload="runTests()">
+ <embed id="plugin1" type="application/x-test" width="400" height="400"></embed>
+ <textarea id="input"></textarea>
+
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_crash_nested_loop.html b/dom/plugins/test/mochitest/test_crash_nested_loop.html
new file mode 100644
index 000000000..379b693e7
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_crash_nested_loop.html
@@ -0,0 +1,46 @@
+<head>
+ <title>Plugin crashing in nested loop</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+
+<body>
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ window.frameLoaded = function frameLoaded_toCrash() {
+ var iframe = document.getElementById('iframe1');
+ var p = iframe.contentDocument.getElementById('plugin1');
+
+ // This test is for bug 550026, which is inherently nondeterministic.
+ // If we hit that bug, the browser process would crash when the plugin
+ // crashes in crashInNestedLoop. If not, we'll pass "spuriously".
+ try {
+ p.crashInNestedLoop();
+ // The plugin didn't crash when expected. This happens sometimes. Give
+ // it longer to crash. If it crashes (but not at the apropriate time),
+ // soft fail with a todo; if it doesn't crash then something went wrong,
+ // so fail.
+ SimpleTest.requestFlakyTimeout("sometimes the plugin takes a little longer to crash");
+ setTimeout(
+ function() {
+ try {
+ p.getPaintCount();
+ ok(false, "plugin should crash");
+ } catch (e) {
+ todo(false, "p.crashInNestedLoop() should throw an exception");
+ }
+
+ SimpleTest.finish();
+ },
+ 1000);
+ }
+ catch (e) {
+ ok(true, "p.crashInNestedLoop() should throw an exception");
+ SimpleTest.finish();
+ }
+
+ }
+
+ </script>
+ <iframe id="iframe1" src="crashing_subpage.html" width="600" height="600"></iframe>
diff --git a/dom/plugins/test/mochitest/test_crash_notify.xul b/dom/plugins/test/mochitest/test_crash_notify.xul
new file mode 100644
index 000000000..fac95b07d
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_crash_notify.xul
@@ -0,0 +1,106 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window title="Basic Plugin Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <script type="application/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+<body xmlns="http://www.w3.org/1999/xhtml" onload="runTests()">
+<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+</body>
+<script class="testbody" type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+var success = false;
+
+var observerFired = false;
+
+var testObserver = {
+ observe: function(subject, topic, data) {
+ observerFired = true;
+ ok(true, "Observer fired");
+ is(topic, "plugin-crashed", "Checking correct topic");
+ is(data, null, "Checking null data");
+ ok((subject instanceof Components.interfaces.nsIPropertyBag2), "got Propbag");
+ ok((subject instanceof Components.interfaces.nsIWritablePropertyBag2), "got writable Propbag");
+
+ var id = subject.getPropertyAsAString("pluginDumpID");
+ isnot(id, "", "got a non-empty crash id");
+ let directoryService =
+ Components.classes["@mozilla.org/file/directory_service;1"].
+ getService(Components.interfaces.nsIProperties);
+ let profD = directoryService.get("ProfD", Components.interfaces.nsIFile);
+ profD.append("minidumps");
+ let dumpFile = profD.clone();
+ dumpFile.append(id + ".dmp");
+ ok(dumpFile.exists(), "minidump exists");
+ let extraFile = profD.clone();
+ extraFile.append(id + ".extra");
+ ok(extraFile.exists(), "extra file exists");
+ // cleanup, to be nice
+ dumpFile.remove(false);
+ extraFile.remove(false);
+ },
+
+ QueryInterface: function(iid) {
+ if (iid.equals(Components.interfaces.nsIObserver) ||
+ iid.equals(Components.interfaces.nsISupportsWeakReference) ||
+ iid.equals(Components.interfaces.nsISupports))
+ return this;
+ throw Components.results.NS_NOINTERFACE;
+ }
+};
+
+
+function onPluginCrashed(aEvent) {
+ ok(true, "Plugin crashed notification received");
+ ok(observerFired, "Observer should have fired first");
+ is(aEvent.type, "PluginCrashed", "event is correct type");
+
+ var pluginElement = document.getElementById("plugin1");
+ is (pluginElement, aEvent.target, "Plugin crashed event target is plugin element");
+
+ ok(aEvent instanceof PluginCrashedEvent,
+ "plugin crashed event has the right interface");
+
+ is(typeof aEvent.pluginDumpID, "string", "pluginDumpID is correct type");
+ isnot(aEvent.pluginDumpID, "", "got a non-empty dump ID");
+ is(typeof aEvent.pluginName, "string", "pluginName is correct type");
+ is(aEvent.pluginName, "Test Plug-in", "got correct plugin name");
+ is(typeof aEvent.pluginFilename, "string", "pluginFilename is correct type");
+ isnot(aEvent.pluginFilename, "", "got a non-empty filename");
+ // The app itself may or may not have decided to submit the report, so
+ // allow either true or false here.
+ ok("submittedCrashReport" in aEvent, "submittedCrashReport is a property of event");
+ is(typeof aEvent.submittedCrashReport, "boolean", "submittedCrashReport is correct type");
+
+ var os = Components.classes["@mozilla.org/observer-service;1"].
+ getService(Components.interfaces.nsIObserverService);
+ os.removeObserver(testObserver, "plugin-crashed");
+
+ SimpleTest.finish();
+}
+
+function runTests() {
+ var os = Components.classes["@mozilla.org/observer-service;1"].
+ getService(Components.interfaces.nsIObserverService);
+ os.addObserver(testObserver, "plugin-crashed", true);
+
+ document.addEventListener("PluginCrashed", onPluginCrashed, false);
+
+ var pluginElement = document.getElementById("plugin1");
+ try {
+ pluginElement.crash();
+ } catch (e) {
+ }
+}
+]]>
+</script>
+</window>
+
diff --git a/dom/plugins/test/mochitest/test_crash_notify_no_report.xul b/dom/plugins/test/mochitest/test_crash_notify_no_report.xul
new file mode 100644
index 000000000..a1344bf0f
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_crash_notify_no_report.xul
@@ -0,0 +1,116 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window title="Basic Plugin Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <script type="application/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+<body xmlns="http://www.w3.org/1999/xhtml" onload="runTests()">
+<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+</body>
+<script class="testbody" type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+var success = false;
+
+var observerFired = false;
+
+var testObserver = {
+ observe: function(subject, topic, data) {
+ observerFired = true;
+ ok(true, "Observer fired");
+ is(topic, "plugin-crashed", "Checking correct topic");
+ is(data, null, "Checking null data");
+ ok((subject instanceof Components.interfaces.nsIPropertyBag2), "got Propbag");
+ ok((subject instanceof Components.interfaces.nsIWritablePropertyBag2),
+"got writable Propbag");
+
+ var id = subject.getPropertyAsAString("pluginDumpID");
+ isnot(id, "", "got a non-empty crash id");
+ let directoryService =
+ Components.classes["@mozilla.org/file/directory_service;1"].
+ getService(Components.interfaces.nsIProperties);
+ let pendingD = directoryService.get("UAppData",
+ Components.interfaces.nsIFile);
+ pendingD.append("Crash Reports");
+ pendingD.append("pending");
+ let dumpFile = pendingD.clone();
+ dumpFile.append(id + ".dmp");
+ ok(dumpFile.exists(), "minidump exists");
+ let extraFile = pendingD.clone();
+ extraFile.append(id + ".extra");
+ ok(extraFile.exists(), "extra file exists");
+ // cleanup, to be nice
+ dumpFile.remove(false);
+ extraFile.remove(false);
+ },
+
+ QueryInterface: function(iid) {
+ if (iid.equals(Components.interfaces.nsIObserver) ||
+ iid.equals(Components.interfaces.nsISupportsWeakReference) ||
+ iid.equals(Components.interfaces.nsISupports))
+ return this;
+ throw Components.results.NS_NOINTERFACE;
+ }
+};
+
+
+function onPluginCrashed(aEvent) {
+ ok(true, "Plugin crashed notification received");
+ ok(observerFired, "Observer should have fired first");
+ is(aEvent.type, "PluginCrashed", "event is correct type");
+
+ var pluginElement = document.getElementById("plugin1");
+ is (pluginElement, aEvent.target, "Plugin crashed event target is plugin element");
+
+ ok(aEvent instanceof PluginCrashedEvent,
+ "plugin crashed event has the right interface");
+
+ is(typeof aEvent.pluginName, "string", "pluginName is correct type");
+ is(aEvent.pluginName, "Test Plug-in");
+ // The app itself may or may not have decided to submit the report, so
+ // allow either true or false here.
+ ok("submittedCrashReport" in aEvent, "submittedCrashReport is a property of event");
+ is(typeof aEvent.submittedCrashReport, "boolean", "submittedCrashReport is correct type");
+
+ var os = Components.classes["@mozilla.org/observer-service;1"].
+ getService(Components.interfaces.nsIObserverService);
+ os.removeObserver(testObserver, "plugin-crashed");
+
+ // re-set MOZ_CRASHREPORTER_NO_REPORT
+ let env = Components.classes["@mozilla.org/process/environment;1"]
+ .getService(Components.interfaces.nsIEnvironment);
+ env.set("MOZ_CRASHREPORTER_NO_REPORT", "1");
+ SimpleTest.finish();
+}
+
+function runTests() {
+ // the test harness will have set MOZ_CRASHREPORTER_NO_REPORT,
+ // ensure that we can change the setting and have our minidumps
+ // wind up in Crash Reports/pending
+ let env = Components.classes["@mozilla.org/process/environment;1"]
+ .getService(Components.interfaces.nsIEnvironment);
+ env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
+
+ var os = Components.classes["@mozilla.org/observer-service;1"].
+ getService(Components.interfaces.nsIObserverService);
+ os.addObserver(testObserver, "plugin-crashed", true);
+
+ document.addEventListener("PluginCrashed", onPluginCrashed, false);
+
+ var pluginElement = document.getElementById("plugin1");
+ try {
+ pluginElement.crash();
+ } catch (e) {
+ }
+}
+]]>
+</script>
+</window>
+
diff --git a/dom/plugins/test/mochitest/test_crash_submit.xul b/dom/plugins/test/mochitest/test_crash_submit.xul
new file mode 100644
index 000000000..22f39384b
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_crash_submit.xul
@@ -0,0 +1,157 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window title="Basic Plugin Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js" />
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <script type="application/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+<body xmlns="http://www.w3.org/1999/xhtml" onload="runTests()">
+<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+</body>
+<script class="testbody" type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+SimpleTest.ignoreAllUncaughtExceptions();
+
+Components.utils.import("resource://gre/modules/NetUtil.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
+Components.utils.import("resource://gre/modules/Task.jsm");
+
+var crashReporter =
+ Components.classes["@mozilla.org/toolkit/crash-reporter;1"]
+ .getService(Components.interfaces.nsICrashReporter);
+var oldServerURL = crashReporter.serverURL;
+
+const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
+
+var testObserver = {
+ observe: function(subject, topic, data) {
+ if (data == "submitting") // not done yet
+ return;
+ is(data, "success", "report should have been submitted successfully");
+ is(topic, "crash-report-status", "Checking correct topic");
+ ok(subject instanceof Components.interfaces.nsIPropertyBag2,
+ "Subject should be a property bag");
+
+ ok(subject.hasKey("minidumpID"), "Should have a local crash ID");
+ let crashID = subject.getPropertyAsAString("minidumpID");
+ isnot(crashID, "", "Local crash ID should not be an empty string");
+
+ ok(subject.hasKey("serverCrashID"), "Should have a server crash ID");
+ let remoteID = subject.getPropertyAsAString("serverCrashID");
+ isnot(remoteID, "", "Server crash ID should not be an empty string");
+
+ // Verify the data. The SJS script will return the data that was POSTed
+ let req = new XMLHttpRequest();
+ req.open("GET", SERVER_URL + "?id=" + remoteID, false);
+ req.send(null);
+ is(req.status, 200, "Server response should be 200 OK");
+ let submitted = JSON.parse(req.responseText);
+ ok(!("Throttleable" in submitted), "Submit request should not be Throttleable");
+ is(submitted.ProcessType, "plugin", "Should specify ProcessType=plugin");
+
+ // Cleanup
+ // First remove our fake submitted report
+ let file = Services.dirsvc.get("UAppData", Components.interfaces.nsILocalFile);
+ file.append("Crash Reports");
+ file.append("submitted");
+ file.append(remoteID + ".txt");
+ file.remove(false);
+
+ // Next unregister our observer
+ var os = Components.classes["@mozilla.org/observer-service;1"].
+ getService(Components.interfaces.nsIObserverService);
+ os.removeObserver(testObserver, "crash-report-status");
+
+ // Then re-set MOZ_CRASHREPORTER_NO_REPORT
+ let env = Components.classes["@mozilla.org/process/environment;1"]
+ .getService(Components.interfaces.nsIEnvironment);
+ env.set("MOZ_CRASHREPORTER_NO_REPORT", "1");
+
+ // Finally re-set crashreporter URL
+ crashReporter.serverURL = oldServerURL;
+
+ // Check and cleanup CrashManager.
+ Task.spawn(function* () {
+ let cm = Services.crashmanager;
+ let store = yield cm._getStore();
+ is(store.crashesCount, 1, "Store should have only 1 item");
+
+ let crash = store.getCrash(crashID);
+ ok(!!crash, "Store should have the crash record");
+ ok(crash.isOfType(cm.PROCESS_TYPE_PLUGIN, cm.CRASH_TYPE_CRASH),
+ "Crash type should be plugin-crash");
+ is(crash.remoteID, remoteID, "Crash remoteID should match");
+
+ is(crash.submissions.size, 1, "Crash should have a submission");
+ let submission = crash.submissions.values().next().value;
+ is(submission.result, cm.SUBMISSION_RESULT_OK,
+ "Submission should be successful");
+
+ store.reset();
+
+ SimpleTest.finish();
+ });
+ },
+
+ QueryInterface: function(iid) {
+ if (iid.equals(Components.interfaces.nsIObserver) ||
+ iid.equals(Components.interfaces.nsISupportsWeakReference) ||
+ iid.equals(Components.interfaces.nsISupports))
+ return this;
+ throw Components.results.NS_NOINTERFACE;
+ }
+};
+
+
+function onPluginCrashed(aEvent) {
+ ok(true, "Plugin crashed notification received");
+ is(aEvent.type, "PluginCrashed", "event is correct type");
+
+ let submitButton = document.getAnonymousElementByAttribute(aEvent.target,
+ "class",
+ "submitButton");
+ // try to submit this report
+ sendMouseEvent({type:'click'}, submitButton, window);
+}
+
+function runTests() {
+ // the test harness will have set MOZ_CRASHREPORTER_NO_REPORT,
+ // ensure that we can change the setting and have our minidumps
+ // wind up in Crash Reports/pending
+ let env = Components.classes["@mozilla.org/process/environment;1"]
+ .getService(Components.interfaces.nsIEnvironment);
+ env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
+
+ // Override the crash reporter URL to send to our fake server
+ crashReporter.serverURL = NetUtil.newURI(SERVER_URL);
+
+ var os = Components.classes["@mozilla.org/observer-service;1"].
+ getService(Components.interfaces.nsIObserverService);
+ os.addObserver(testObserver, "crash-report-status", true);
+
+ document.addEventListener("PluginCrashed", onPluginCrashed, false);
+
+ var pluginElement = document.getElementById("plugin1");
+ try {
+ Task.spawn(function* () {
+ // Clear data in CrashManager in case previous tests caused something
+ // to be added.
+ let store = yield Services.crashmanager._getStore();
+ store.reset();
+
+ pluginElement.crash();
+ });
+ } catch (e) {
+ }
+}
+]]>
+</script>
+</window>
diff --git a/dom/plugins/test/mochitest/test_crashing.html b/dom/plugins/test/mochitest/test_crashing.html
new file mode 100644
index 000000000..eac6e42be
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_crashing.html
@@ -0,0 +1,62 @@
+<head>
+ <title>Plugin crashing</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+
+<body>
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ window.frameLoaded = function frameLoaded_toCrash() {
+ SimpleTest.expectChildProcessCrash();
+
+ var iframe = document.getElementById('iframe1');
+ var p = iframe.contentDocument.getElementById('plugin1');
+
+ p.setColor("FFFF00FF");
+
+ try {
+ p.crash();
+ ok(false, "p.crash() should throw an exception");
+ }
+ catch (e) {
+ ok(true, "p.crash() should throw an exception");
+ }
+
+ // Create random identifiers to test bug 560213
+ for (var i = 0; i < 5; ++i) {
+ var r = 'rid_' + Math.floor(Math.random() * 10000 + 1);
+ try {
+ ok(!(r in p), "unknown identifier in crashed plugin should fail silently");
+ }
+ catch (e) {
+ ok(false, "unknown identifier check threw");
+ }
+ }
+
+ try {
+ p.setColor("FFFF0000");
+ ok(false, "p.setColor should throw after the plugin crashes");
+ }
+ catch (e) {
+ ok(true, "p.setColor should throw after the plugin crashes");
+ }
+
+ window.frameLoaded = function reloaded() {
+ var p = iframe.contentDocument.getElementById('plugin1');
+ try {
+ p.setColor('FF00FF00');
+ ok(true, "Reloading worked");
+ }
+ catch (e) {
+ ok(false, "Reloading didn't give us a usable plugin");
+ }
+ SimpleTest.finish();
+ }
+
+ iframe.contentWindow.location.reload();
+ }
+
+ </script>
+ <iframe id="iframe1" src="crashing_subpage.html" width="600" height="600"></iframe>
diff --git a/dom/plugins/test/mochitest/test_crashing2.html b/dom/plugins/test/mochitest/test_crashing2.html
new file mode 100644
index 000000000..be61f3d50
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_crashing2.html
@@ -0,0 +1,74 @@
+<head>
+ <title>Plugin crashing</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+
+<body onload="mainLoaded()">
+ <iframe id="iframe1" src="about:blank" width="600" height="600"></iframe>
+
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var iframe = document.getElementById('iframe1');
+
+ function mainLoaded() {
+ SimpleTest.expectChildProcessCrash();
+
+ var p = iframe.contentDocument.createElement('embed');
+ p.setAttribute('id', 'plugin1');
+ p.setAttribute('type', 'application/x-test');
+ p.setAttribute('width', '400');
+ p.setAttribute('height', '400');
+ p.setAttribute('drawmode', 'solid');
+ p.setAttribute('color', 'FF00FFFF');
+ p.setAttribute('newCrash', 'true');
+ iframe.contentDocument.body.appendChild(p);
+
+ // The plugin will now crash when it is instantiated, but
+ // that happens asynchronously. HACK: this should use an
+ // event instead of nested pending runnables, but I don't
+ // know of any DOM event that's fired when a plugin is
+ // instantiated.
+ SimpleTest.executeSoon(function() {
+ SimpleTest.executeSoon(function() {
+ ok(p.setColor === undefined,
+ "Plugin should have crashed on creation");
+
+ window.frameLoaded = reloaded1;
+ iframe.contentWindow.location.replace('crashing_subpage.html');
+ })
+ });
+ }
+
+ function reloaded1() {
+ var p = iframe.contentDocument.getElementById('plugin1');
+ try {
+ p.setColor('FF00FF00');
+ ok(true, "Reloading after crash-on-new worked");
+ }
+ catch (e) {
+ ok(false, "Reloading after crash-on-new didn't give us a usable plugin");
+ }
+ p.crashOnDestroy();
+ // the child crash should happen here
+ p.parentNode.removeChild(p);
+
+ window.frameLoaded = reloaded2;
+ SimpleTest.executeSoon(function() {
+ iframe.contentWindow.location.reload();
+ });
+ }
+
+ function reloaded2() {
+ var p = iframe.contentDocument.getElementById('plugin1');
+ try {
+ p.setColor('FF00FF00');
+ ok(true, "Reloading after crash-on-destroy worked");
+ }
+ catch (e) {
+ ok(false, "Reloading after crash-on-destroy didn't give us a usable plugin");
+ }
+ SimpleTest.finish();
+ }
+ </script>
diff --git a/dom/plugins/test/mochitest/test_defaultValue.html b/dom/plugins/test/mochitest/test_defaultValue.html
new file mode 100644
index 000000000..2cbe52efe
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_defaultValue.html
@@ -0,0 +1,38 @@
+<html>
+ <head>
+ <title>NPObject [[DefaultValue]] implementation</title>
+
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ </head>
+
+ <body onload="run()">
+
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function run() {
+ var plugin = document.getElementById("plugin");
+ var pluginProto = Object.getPrototypeOf(plugin);
+
+ plugin.propertyAndMethod = {};
+ plugin.propertyAndMethod + "baz";
+ ok(true, "|plugin.propertyAndMethod + \"baz\"| shouldn't assert");
+ pluginProto.propertyAndMethod = {};
+ pluginProto.propertyAndMethod + "quux";
+ ok(true, "|pluginProto.propertyAndMethod + \"quux\"| shouldn't assert");
+
+ plugin + "foo";
+ ok(true, "|plugin + \"foo\"| shouldn't assert");
+ pluginProto + "bar";
+ ok(true, "|pluginProto + \"bar\"| shouldn't assert");
+
+ SimpleTest.finish();
+ }
+ </script>
+
+ <embed id="plugin" type="application/x-test" wmode="window"></embed>
+ </body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_enumerate.html b/dom/plugins/test/mochitest/test_enumerate.html
new file mode 100644
index 000000000..af8431c7c
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_enumerate.html
@@ -0,0 +1,36 @@
+<html>
+<head>
+ <title>NPAPI Cookie Tests</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+
+<body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function runTests() {
+ var pluginElement = document.getElementById("plugin1");
+ var c = 0;
+ var foundSetColor = false;
+ for (var n in pluginElement) {
+ ++c;
+ ok(n in pluginElement, "Enumerated property which doesn't exist?");
+ if (n == 'setColor')
+ foundSetColor = true;
+ }
+ ok(c > 0, "Should have enumerated some properties");
+ ok(foundSetColor, "Should have enumerated .setColor");
+ SimpleTest.finish();
+ }
+ </script>
+
+ <p id="display"></p>
+
+ <embed id="plugin1" type="application/x-test" width="400" height="400"></embed>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_fullpage.html b/dom/plugins/test/mochitest/test_fullpage.html
new file mode 100644
index 000000000..680eb73a0
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_fullpage.html
@@ -0,0 +1,35 @@
+<head>
+ <title>Full-page seekable stream</title>
+
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css">
+
+<body>
+ <p id="display"></p>
+
+ <script type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function frameLoaded() {
+ var testframe = document.getElementById('testframe');
+ var content = testframe.contentDocument.body.innerHTML;
+ if (!content.length)
+ return;
+
+ var req = new XMLHttpRequest();
+ req.open('GET', 'loremipsum.xtest', false);
+ req.overrideMimeType('text/plain; charset=x-user-defined');
+ req.send(null);
+ is(req.status, 200, "bad XMLHttpRequest");
+ is(content, req.responseText.replace(/\r\n/g, "\n"),
+ "content doesn't match");
+ SimpleTest.finish();
+ }
+ </script>
+
+ <iframe src="loremipsum.xtest" streamtype="seek"></iframe>
+ <iframe id="testframe" name="testframe" onload="frameLoaded()"></iframe>
diff --git a/dom/plugins/test/mochitest/test_getauthenticationinfo.html b/dom/plugins/test/mochitest/test_getauthenticationinfo.html
new file mode 100644
index 000000000..f249386c7
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_getauthenticationinfo.html
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Login Manager</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+Test for NPN_GetAuthenticationInfo
+<p id="display"></p>
+
+<div id="content">
+ <iframe id="iframe"></iframe>
+</div>
+
+<script class="testbody" type="text/javascript">
+
+const Ci = SpecialPowers.Ci;
+const Cc = SpecialPowers.Cc;
+
+function iframeLoad() {
+ var plugin = iframe.contentDocument.getElementById("embedtest");
+ // valid request
+ is(plugin.getAuthInfo("http", "mochi.test", 8888, "basic", "testrealm"),
+ "user1|password1",
+ "correct user/pass retrieved");
+ try {
+ // invalid request -- wrong host
+ is(plugin.getAuthInfo("http", "example.com", 8888, "basic", "testrealm"),
+ "user1|password1",
+ "correct user/pass retrieved");
+ ok(false, "no exception was thrown");
+ }
+ catch (err) {
+ ok(true, "expected exception caught");
+ }
+ try {
+ // invalid request -- wrong port
+ is(plugin.getAuthInfo("http", "mochi.test", 90, "basic", "testrealm"),
+ "user1|password1",
+ "correct user/pass retrieved");
+ ok(false, "no exception was thrown");
+ }
+ catch (err) {
+ ok(true, "expected exception caught");
+ }
+ try {
+ // invalid request -- wrong realm
+ is(plugin.getAuthInfo("http", "mochi.test", 8888, "basic", "wrongrealm"),
+ "user1|password1",
+ "correct user/pass retrieved");
+ ok(false, "no exception was thrown");
+ }
+ catch (err) {
+ ok(true, "expected exception caught");
+ }
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+// Authentication info is added twice here. In the non-e10s case, this does
+// nothing. In the e10s case, we need to add auth info in both the child process,
+// which the plugin checks for auth validity, and the parent process, which the
+// http network objects use.
+// TODO: Clean this up once HTTPAuthManager is made e10s compliant in bug 1249172
+var iframe = document.getElementById("iframe");
+var am = Cc["@mozilla.org/network/http-auth-manager;1"].
+ getService(Ci.nsIHttpAuthManager);
+am.setAuthIdentity("http", "mochi.test", 8888, "basic", "testrealm", "",
+ "mochi.test", "user1", "password1");
+SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL("file_authident.js"));
+iframe.onload = iframeLoad;
+iframe.src = "http://mochi.test:8888/tests/toolkit/components/passwordmgr/" +
+ "test/authenticate.sjs?user=user1&pass=password1&realm=testrealm&plugin=1";
+
+</script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_hang_submit.xul b/dom/plugins/test/mochitest/test_hang_submit.xul
new file mode 100644
index 000000000..6c037ecd4
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_hang_submit.xul
@@ -0,0 +1,165 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window title="Basic Plugin Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js" />
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <script type="application/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+<body xmlns="http://www.w3.org/1999/xhtml" onload="runTests()">
+<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+</body>
+<script class="testbody" type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+SimpleTest.ignoreAllUncaughtExceptions();
+
+Components.utils.import("resource://gre/modules/NetUtil.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
+Components.utils.import("resource://gre/modules/Task.jsm");
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+
+const crashReporter = Cc["@mozilla.org/toolkit/crash-reporter;1"].getService(Ci.nsICrashReporter);
+const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
+
+var oldServerURL = crashReporter.serverURL;
+
+const oldTimeoutPref = Services.prefs.getIntPref("dom.ipc.plugins.timeoutSecs");
+
+var testObserver = {
+ observe: function(subject, topic, data) {
+ if (data == "submitting") // not done yet
+ return;
+ is(data, "success", "report should have been submitted successfully");
+ is(topic, "crash-report-status", "Checking correct topic");
+ ok(subject instanceof Ci.nsIPropertyBag2, "Subject should be a property bag");
+
+ ok(subject.hasKey("minidumpID"), "Should have a local crash ID");
+ let crashID = subject.getPropertyAsAString("minidumpID");
+ isnot(crashID, "", "Local crash ID should not be an empty string");
+
+ ok(subject.hasKey("serverCrashID"), "Should have a server crash ID");
+ let remoteID = subject.getPropertyAsAString("serverCrashID");
+ isnot(remoteID, "", "Server crash ID should not be an empty string");
+
+ // Verify the data. The SJS script will return the data that was POSTed
+ let req = new XMLHttpRequest();
+ req.open("GET", SERVER_URL + "?id=" + remoteID, false);
+ req.send(null);
+ is(req.status, 200, "Server response should be 200 OK");
+ let submitted = JSON.parse(req.responseText);
+
+ ok(!("Throttleable" in submitted), "Submit request should not be Throttleable");
+ is(submitted.ProcessType, "plugin", "Should specify ProcessType=plugin");
+ ok("PluginHang" in submitted, "Request should contain PluginHang field");
+ ok("additional_minidumps" in submitted, "Request should contain additional_minidumps field");
+ let dumpNames = submitted.additional_minidumps.split(',');
+ ok(dumpNames.indexOf("browser") != -1, "additional_minidumps should contain browser");
+ info("additional_minidumps="+submitted.additional_minidumps);
+ ok("upload_file_minidump" in submitted, "Request should contain upload_file_minidump field");
+ ok("upload_file_minidump_browser" in submitted, "Request should contain upload_file_minidump_browser field");
+
+ // Cleanup
+ // First remove our fake submitted report
+ let file = Services.dirsvc.get("UAppData", Ci.nsILocalFile);
+ file.append("Crash Reports");
+ file.append("submitted");
+ file.append(remoteID + ".txt");
+ file.remove(false);
+
+ // Next unregister our observer
+ Services.obs.removeObserver(testObserver, "crash-report-status");
+
+ // Then re-set MOZ_CRASHREPORTER_NO_REPORT
+ let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
+ env.set("MOZ_CRASHREPORTER_NO_REPORT", "1");
+
+ // Finally re-set prefs
+ crashReporter.serverURL = oldServerURL;
+ Services.prefs.setIntPref("dom.ipc.plugins.timeoutSecs", oldTimeoutPref);
+
+ // Check and cleanup CrashManager.
+ Task.spawn(function* () {
+ let cm = Services.crashmanager;
+ let store = yield cm._getStore();
+ is(store.crashesCount, 1, "Store should have only 1 item");
+
+ let crash = store.getCrash(crashID);
+ ok(!!crash, "Store should have the crash record");
+ ok(crash.isOfType(cm.PROCESS_TYPE_PLUGIN, cm.CRASH_TYPE_HANG),
+ "Crash type should be plugin-hang");
+ is(crash.remoteID, remoteID, "Crash remoteID should match");
+
+ is(crash.submissions.size, 1, "Crash should have a submission");
+ let submission = crash.submissions.values().next().value;
+ is(submission.result, cm.SUBMISSION_RESULT_OK,
+ "Submission should be successful");
+
+ store.reset();
+
+ SimpleTest.finish();
+ });
+ },
+
+ QueryInterface: function(iid) {
+ if (iid.equals(Ci.nsIObserver) ||
+ iid.equals(Ci.nsISupportsWeakReference) ||
+ iid.equals(Ci.nsISupports))
+ return this;
+ throw Components.results.NS_NOINTERFACE;
+ }
+};
+
+function onPluginCrashed(aEvent) {
+ ok(true, "Plugin crashed notification received");
+ is(aEvent.type, "PluginCrashed", "event is correct type");
+
+ let submitButton = document.getAnonymousElementByAttribute(aEvent.target,
+ "class",
+ "submitButton");
+ // try to submit this report
+ sendMouseEvent({type:'click'}, submitButton, window);
+}
+
+function runTests() {
+ // Default plugin hang timeout is too high for mochitests
+ Services.prefs.setIntPref("dom.ipc.plugins.timeoutSecs", 1);
+
+ // the test harness will have set MOZ_CRASHREPORTER_NO_REPORT,
+ // ensure that we can change the setting and have our minidumps
+ // wind up in Crash Reports/pending
+ let env = Cc["@mozilla.org/process/environment;1"]
+ .getService(Ci.nsIEnvironment);
+ env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
+
+ // Override the crash reporter URL to send to our fake server
+ crashReporter.serverURL = NetUtil.newURI(SERVER_URL);
+
+ // Hook into plugin crash events
+ Services.obs.addObserver(testObserver, "crash-report-status", true);
+ document.addEventListener("PluginCrashed", onPluginCrashed, false);
+
+ var pluginElement = document.getElementById("plugin1");
+ try {
+ Task.spawn(function* () {
+ // Clear data in CrashManager in case previous tests caused something
+ // to be added.
+ let store = yield Services.crashmanager._getStore();
+ store.reset();
+
+ pluginElement.hang();
+ });
+ } catch (e) {
+ }
+}
+]]>
+</script>
+</window>
diff --git a/dom/plugins/test/mochitest/test_hanging.html b/dom/plugins/test/mochitest/test_hanging.html
new file mode 100644
index 000000000..c8ea936ce
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_hanging.html
@@ -0,0 +1,63 @@
+<head>
+ <title>Plugin hanging</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+
+<body>
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ window.frameLoaded = function frameLoaded_toCrash() {
+ SimpleTest.expectChildProcessCrash();
+
+ // the default timeout is annoying high for mochitest runs
+ var timeoutPref = "dom.ipc.plugins.timeoutSecs";
+ SpecialPowers.setIntPref(timeoutPref, 5);
+
+ var iframe = document.getElementById('iframe1');
+ var p = iframe.contentDocument.getElementById('plugin1');
+
+ p.setColor("FFFF00FF");
+
+ try {
+ p.hang();
+ ok(false, "p.hang() should throw an exception");
+ }
+ catch (e) {
+ ok(true, "p.hang() should throw an exception");
+ }
+
+ try {
+ p.setColor("FFFF0000");
+ ok(false, "p.setColor should throw after the plugin crashes");
+ }
+ catch (e) {
+ ok(true, "p.setColor should throw after the plugin crashes");
+ }
+
+ window.frameLoaded = function reloaded() {
+ var p = iframe.contentDocument.getElementById('plugin1');
+ try {
+ p.setColor('FF00FF00');
+ ok(true, "Reloading worked");
+ }
+ catch (e) {
+ ok(false, "Reloading didn't give us a usable plugin");
+ }
+
+ try {
+ SpecialPowers.clearUserPref(timeoutPref);
+ }
+ catch(e) {
+ ok(false, "Couldn't reset timeout pref");
+ }
+
+ SimpleTest.finish();
+ }
+
+ iframe.contentWindow.location.reload();
+ }
+
+ </script>
+ <iframe id="iframe1" src="crashing_subpage.html" width="600" height="600"></iframe>
diff --git a/dom/plugins/test/mochitest/test_hangui.xul b/dom/plugins/test/mochitest/test_hangui.xul
new file mode 100644
index 000000000..edb90db00
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_hangui.xul
@@ -0,0 +1,262 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window title="Basic Plugin Tests"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <title>Plugin Hang UI Test</title>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+ <script type="application/javascript"
+ src="plugin-utils.js" />
+ <script type="application/javascript"
+ src="http://mochi.test:8888/chrome/dom/plugins/test/mochitest/hang_test.js" />
+ <script type="application/javascript"
+ src="http://mochi.test:8888/chrome/dom/plugins/test/mochitest/hangui_common.js" />
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+ <iframe id="iframe1" src="hangui_subpage.html" width="400" height="400"></iframe>
+</body>
+<script class="testbody" type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+const hangUITimeoutPref = "dom.ipc.plugins.hangUITimeoutSecs";
+const hangUIMinDisplayPref = "dom.ipc.plugins.hangUIMinDisplaySecs";
+const timeoutPref = "dom.ipc.plugins.timeoutSecs";
+
+var worker = new ChromeWorker("hangui_iface.js");
+worker.onmessage = function(event) {
+ var result = event.data;
+ var params = result.params;
+ var output = params.testName;
+ if (result.msg) {
+ output += ": " + result.msg;
+ }
+ ok(result.status, output);
+ if (params.callback) {
+ var cb = eval(params.callback);
+ var timeout = setTimeout(function() { clearTimeout(timeout); cb(); }, 100);
+ }
+};
+worker.onerror = function(event) {
+ var output = "Error: " + event.message + " at " + event.filename + ":" + event.lineno;
+ ok(false, output);
+};
+
+var iframe;
+var p;
+var os = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
+
+function hanguiOperation(testName, timeoutSec, expectFind, expectClose, opCode,
+ commandId, check, cb) {
+ var timeoutMs = timeoutSec * 1000 + EPSILON_MS;
+ worker.postMessage({ "timeoutMs": timeoutMs, "expectToFind": expectFind,
+ "expectToClose": expectClose, "opCode": opCode,
+ "commandId": commandId, "check": check,
+ "testName": testName, "callback": cb });
+}
+
+function hanguiExpect(testName, shouldBeShowing, shouldClose, cb) {
+ var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
+ if (!shouldBeShowing && !timeoutSec) {
+ timeoutSec = Services.prefs.getIntPref(timeoutPref);
+ }
+ hanguiOperation(testName, timeoutSec, shouldBeShowing, shouldClose, HANGUIOP_NOTHING, 0, false, cb);
+}
+
+function hanguiContinue(testName, check, cb) {
+ var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
+ hanguiOperation(testName, timeoutSec, true, true, HANGUIOP_COMMAND, IDC_CONTINUE, check, cb);
+}
+
+function hanguiStop(testName, check, cb) {
+ var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
+ hanguiOperation(testName, timeoutSec, true, true, HANGUIOP_COMMAND, IDC_STOP, check, cb);
+}
+
+function hanguiCancel(testName, cb) {
+ var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
+ hanguiOperation(testName, timeoutSec, true, true, HANGUIOP_CANCEL, 0, false, cb);
+}
+
+function finishTest() {
+ if (obsCount > 0) {
+ os.removeObserver(testObserver, "plugin-crashed");
+ --obsCount;
+ }
+ SpecialPowers.clearUserPref(hangUITimeoutPref);
+ SpecialPowers.clearUserPref(hangUIMinDisplayPref);
+ SpecialPowers.clearUserPref(timeoutPref);
+ SimpleTest.finish();
+}
+
+function runTests() {
+ resetVars();
+
+ hanguiOperation("Prime ChromeWorker", 0, false, false, HANGUIOP_NOTHING, 0,
+ false, "test1");
+}
+
+window.frameLoaded = runTests;
+
+var obsCount = 0;
+
+function onPluginCrashedHangUI(aEvent) {
+ ok(true, "Plugin crashed notification received");
+ is(aEvent.type, "PluginCrashed", "event is correct type");
+
+ is(p, aEvent.target, "Plugin crashed event target is plugin element");
+
+ ok(aEvent instanceof PluginCrashedEvent,
+ "plugin crashed event has the right interface");
+
+ is(typeof aEvent.pluginDumpID, "string", "pluginDumpID is correct type");
+ isnot(aEvent.pluginDumpID, "", "got a non-empty dump ID");
+ is(typeof aEvent.pluginName, "string", "pluginName is correct type");
+ is(aEvent.pluginName, "Test Plug-in", "got correct plugin name");
+ is(typeof aEvent.pluginFilename, "string", "pluginFilename is correct type");
+ isnot(aEvent.pluginFilename, "", "got a non-empty filename");
+ // The app itself may or may not have decided to submit the report, so
+ // allow either true or false here.
+ ok("submittedCrashReport" in aEvent, "submittedCrashReport is a property of event");
+ is(typeof aEvent.submittedCrashReport, "boolean", "submittedCrashReport is correct type");
+
+ os.removeObserver(testObserver, "plugin-crashed");
+ --obsCount;
+}
+
+function resetVars() {
+ iframe = document.getElementById('iframe1');
+ p = iframe.contentDocument.getElementById("plugin1");
+ if (obsCount == 0) {
+ os.addObserver(testObserver, "plugin-crashed", true);
+ ++obsCount;
+ }
+ iframe.contentDocument.addEventListener("PluginCrashed",
+ onPluginCrashedHangUI,
+ false);
+}
+
+function test9b() {
+ hanguiExpect("test9b: Plugin Hang UI is not showing (checkbox)", false);
+ p.stall(STALL_DURATION);
+ hanguiExpect("test9b: Plugin Hang UI is still not showing (checkbox)", false, false, "finishTest");
+ p.stall(STALL_DURATION);
+}
+
+function test9a() {
+ resetVars();
+ SpecialPowers.setIntPref(hangUITimeoutPref, 1);
+ SpecialPowers.setIntPref(hangUIMinDisplayPref, 1);
+ SpecialPowers.setIntPref(timeoutPref, 45);
+ hanguiContinue("test9a: Continue button works with checkbox", true, "test9b");
+ p.stall(STALL_DURATION);
+}
+
+function test9() {
+ window.frameLoaded = test9a;
+ iframe.contentWindow.location.reload();
+}
+
+function test8a() {
+ resetVars();
+ SpecialPowers.setIntPref(hangUITimeoutPref, 1);
+ SpecialPowers.setIntPref(hangUIMinDisplayPref, 4);
+ hanguiExpect("test8a: Plugin Hang UI is not showing (disabled due to hangUIMinDisplaySecs)", false, false, "test9");
+ var exceptionThrown = false;
+ try {
+ p.hang();
+ } catch(e) {
+ exceptionThrown = true;
+ }
+ ok(exceptionThrown, "test8a: Exception thrown from hang() when plugin was terminated");
+}
+
+function test8() {
+ window.frameLoaded = test8a;
+ iframe.contentWindow.location.reload();
+}
+
+function test7a() {
+ resetVars();
+ SpecialPowers.setIntPref(hangUITimeoutPref, 0);
+ hanguiExpect("test7a: Plugin Hang UI is not showing (disabled)", false, false, "test8");
+ var exceptionThrown = false;
+ try {
+ p.hang();
+ } catch(e) {
+ exceptionThrown = true;
+ }
+ ok(exceptionThrown, "test7a: Exception thrown from hang() when plugin was terminated");
+}
+
+function test7() {
+ window.frameLoaded = test7a;
+ iframe.contentWindow.location.reload();
+}
+
+function test6() {
+ SpecialPowers.setIntPref(hangUITimeoutPref, 1);
+ SpecialPowers.setIntPref(hangUIMinDisplayPref, 1);
+ SpecialPowers.setIntPref(timeoutPref, 3);
+ hanguiExpect("test6: Plugin Hang UI is showing", true, true, "test7");
+ var exceptionThrown = false;
+ try {
+ p.hang();
+ } catch(e) {
+ exceptionThrown = true;
+ }
+ ok(exceptionThrown, "test6: Exception thrown from hang() when plugin was terminated (child timeout)");
+}
+
+function test5a() {
+ resetVars();
+ hanguiCancel("test5a: Close button works", "test6");
+ p.stall(STALL_DURATION);
+}
+
+function test5() {
+ window.frameLoaded = test5a;
+ iframe.contentWindow.location.reload();
+}
+
+function test4() {
+ hanguiStop("test4: Stop button works", false, "test5");
+ // We'll get an exception here because the plugin was terminated
+ var exceptionThrown = false;
+ try {
+ p.hang();
+ } catch(e) {
+ exceptionThrown = true;
+ }
+ ok(exceptionThrown, "test4: Exception thrown from hang() when plugin was terminated");
+}
+
+function test3() {
+ hanguiContinue("test3: Continue button works", false, "test4");
+ p.stall(STALL_DURATION);
+}
+
+function test2() {
+ // This test is identical to test1 because there were some bugs where the
+ // Hang UI would show on the first hang but not on subsequent hangs
+ hanguiExpect("test2: Plugin Hang UI is showing", true, true, "test3");
+ p.stall(STALL_DURATION);
+}
+
+function test1() {
+ SpecialPowers.setIntPref(hangUITimeoutPref, 1);
+ SpecialPowers.setIntPref(hangUIMinDisplayPref, 1);
+ SpecialPowers.setIntPref(timeoutPref, 45);
+ hanguiExpect("test1: Plugin Hang UI is showing", true, true, "test2");
+ p.stall(STALL_DURATION);
+}
+
+]]>
+</script>
+</window>
diff --git a/dom/plugins/test/mochitest/test_hidden_plugin.html b/dom/plugins/test/mochitest/test_hidden_plugin.html
new file mode 100644
index 000000000..446d8cbbd
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_hidden_plugin.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Test whether we are adding the dummy plugin correctly when there is only 1 plugin and its hidden</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<body>
+ <script type="application/javascript;version=1.7">
+ "use strict"
+ {
+ SimpleTest.waitForExplicitFinish();
+ let ph = SpecialPowers.Cc["@mozilla.org/plugin/host;1"].getService(SpecialPowers.Ci.nsIPluginHost);
+ let plugins = ph.getPluginTags();
+ let testPluginName = plugins[0].name;
+ let oldPrefVal = null;
+ let prefName = "plugins.navigator.hidden_ctp_plugin";
+ try {
+ oldPrefVal = SpecialPowers.getCharPref(prefName);
+ } catch (ex) {}
+ let promise = SpecialPowers.pushPrefEnv({ set: [[prefName, testPluginName]]});
+ promise.then(function() {
+ for (let i = 0; i < plugins.length; i++) {
+ let plugin = plugins[i];
+ let newState = (plugin.name == testPluginName ? SpecialPowers.Ci.nsIPluginTag.STATE_CLICKTOPLAY :
+ SpecialPowers.Ci.nsIPluginTag.STATE_DISABLED);
+ if (plugin.enabledState != newState) {
+ let oldState = plugin.enabledState;
+ setTestPluginEnabledState(newState, plugin.name);
+ SimpleTest.registerCleanupFunction(function() {
+ if (plugin.enabledState != oldState)
+ setTestPluginEnabledState(oldState, plugin.name);
+ });
+ }
+ }
+ // we have disabled all the plugins except for 1 which is click to play and hidden. The
+ // navigator.plugins list should have only one entry and it should be the dummy plugin.
+ isnot(navigator.plugins.length, 0, "navigator.plugins should not be empty");
+ SimpleTest.finish();
+ });
+ }
+</script>
+</body>
diff --git a/dom/plugins/test/mochitest/test_idle_hang.xul b/dom/plugins/test/mochitest/test_idle_hang.xul
new file mode 100644
index 000000000..83ff28f52
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_idle_hang.xul
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window title="Basic Plugin Tests"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <title>Plugin Idle Hang Test</title>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+ <script type="application/javascript"
+ src="http://mochi.test:8888/chrome/dom/plugins/test/mochitest/hang_test.js" />
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <script type="application/javascript">
+ getTestPlugin().enabledState = Ci.nsIPluginTag.STATE_ENABLED;
+ </script>
+<body xmlns="http://www.w3.org/1999/xhtml" onload="runTests()">
+<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+</body>
+<script class="testbody" type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+function runTests() {
+ // Default plugin hang timeout is too high for mochitests
+ var prefs = Cc["@mozilla.org/preferences-service;1"]
+ .getService(Ci.nsIPrefBranch);
+ var timeoutPref = "dom.ipc.plugins.timeoutSecs";
+ prefs.setIntPref(timeoutPref, 5);
+
+ var os = Cc["@mozilla.org/observer-service;1"].
+ getService(Ci.nsIObserverService);
+ os.addObserver(testObserver, "plugin-crashed", true);
+
+ testObserver.idleHang = true;
+ document.addEventListener("PluginCrashed", onPluginCrashed, false);
+
+ var pluginElement = document.getElementById("plugin1");
+ try {
+ pluginElement.hang(false);
+ } catch (e) {
+ }
+}
+]]>
+</script>
+</window>
+
diff --git a/dom/plugins/test/mochitest/test_instance_re-parent.html b/dom/plugins/test/mochitest/test_instance_re-parent.html
new file mode 100644
index 000000000..1ba87adb5
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_instance_re-parent.html
@@ -0,0 +1,123 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Test re-parentinging an instance's DOM node</title>
+ <script type="text/javascript" src="/MochiKit/packed.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="plugin-utils.js"></script>
+</head>
+<body onload="begin()">
+ <script type="application/javascript;version=1.8">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ const MAX_CHECK_PLUGIN_STOPPED_ATTEMPTS = 50;
+ var numCheckPluginStoppedAttempts = 0;
+ var exceptionThrown = false;
+ var p = null;
+ var d1 = null;
+ var d2 = null;
+
+ var destroyed = false;
+
+ function begin() {
+ runTests(function() {
+ // Callback when finished - set plugin to windowed and repeat the tests
+
+ info("Repeating tests with wmode=window");
+ p.setAttribute("wmode", "window");
+ d1.appendChild(p);
+
+ // Forces the plugin to be respawned
+ p.src = p.src;
+
+ destroyed = false;
+ exceptionThrown = false;
+ runTests(function () {
+ SimpleTest.finish();
+ });
+ });
+ }
+
+ function checkPluginStopped(callback, param) {
+ if (numCheckPluginStoppedAttempts < MAX_CHECK_PLUGIN_STOPPED_ATTEMPTS &&
+ !destroyed) {
+ ++numCheckPluginStoppedAttempts;
+ SimpleTest.executeSoon(function() {
+ checkPluginStopped(callback, param);
+ });
+ } else {
+ info("Number of check plugin stopped attempts: " +
+ numCheckPluginStoppedAttempts);
+ callback(param);
+ }
+ }
+
+ function runTests(callback) {
+ p = document.getElementById('plugin1');
+ d1 = document.getElementById('div1');
+ d2 = document.getElementById('div2');
+
+ // First tests involve moving the instance from one div to another.
+ p.startWatchingInstanceCount();
+ p.callOnDestroy(function() {
+ destroyed = true;
+ });
+
+ try {
+ d1.removeChild(p);
+ } catch (e) {
+ exceptionThrown = true;
+ }
+ is(exceptionThrown, false, "Testing for exception after removeChild.");
+
+ try {
+ d2.appendChild(p);
+ } catch (e) {
+ exceptionThrown = true;
+ }
+ is(exceptionThrown, false, "Testing for exception after appendChild.");
+
+ is(destroyed, false, "No instances should have been destroyed at this point.");
+ is(p.getInstanceCount(), 0, "No new instances should have been created at this point.");
+
+ // Wait for the event loop to spin and ensure the plugin still wasn't touched
+ SimpleTest.executeSoon(function() {
+ is(destroyed, false, "No instances should have been destroyed at this point.");
+ is(p.getInstanceCount(), 0, "No new instances should have been created at this point.");
+
+ d2.removeChild(p);
+ checkPluginStopped(continueTestsAfterPluginDestruction, callback);
+ });
+ }
+
+ function continueTestsAfterPluginDestruction(callback) {
+ d2.appendChild(p);
+ SimpleTest.executeSoon(function() {
+ try {
+ is(p.getInstanceCount(), 1, "One new instance should have been created at this point.");
+ } catch (e) {
+ exceptionThrown = true;
+ }
+ is(exceptionThrown, false, "Testing for exception getting instance count from plugin.");
+
+ p.stopWatchingInstanceCount();
+ callback.apply(null);
+ });
+ }
+ </script>
+
+ <p id="display"></p>
+
+ <div id="div1">
+ <!-- This embed has to have a "src" attribute. Part of this test involves seeing if we
+ properly restart plugins that have been added back to a document without a change
+ in URL. Not re-loading an object when the URL hasn't changed is a shortcut used for
+ some object types. Without a URL, this won't be tested. -->
+ <embed id="plugin1" src="loremipsum.txt" type="application/x-test" width="200" height="200"></embed>
+ </div>
+ <div id="div2">
+ </div>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_instance_unparent1.html b/dom/plugins/test/mochitest/test_instance_unparent1.html
new file mode 100644
index 000000000..5a11dc588
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_instance_unparent1.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Test removing an instance's DOM node</title>
+ <script type="text/javascript" src="/MochiKit/packed.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="startTest()">
+ <script type="application/javascript;version=1.8">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ const MAX_ATTEMPTS = 50;
+ var attempts = 0;
+ var destroyed = false;
+ function onDestroy() {
+ destroyed = true;
+ }
+
+ function checkPluginAlreadyDestroyed() {
+ // We may need to retry a few times until the plugin stop event makes
+ // its way through the event queue.
+ if (attempts < MAX_ATTEMPTS && !destroyed) {
+ ++attempts;
+ SimpleTest.executeSoon(checkPluginAlreadyDestroyed);
+ } else {
+ info("Number of retry attempts: " + attempts);
+ is(destroyed, true, "Plugin instance should have been destroyed.");
+ SimpleTest.finish();
+ }
+ }
+
+ function startTest() {
+ var p1 = document.getElementById('plugin1');
+ var d1 = document.getElementById('div1');
+
+ p1.callOnDestroy(onDestroy);
+ d1.removeChild(p1);
+ SimpleTest.executeSoon(checkPluginAlreadyDestroyed);
+ }
+ </script>
+
+ <p id="display"></p>
+
+ <div id="div1">
+ <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+ </div>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_instance_unparent2.html b/dom/plugins/test/mochitest/test_instance_unparent2.html
new file mode 100644
index 000000000..eedbca8e4
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_instance_unparent2.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Test removing an instance's DOM node</title>
+ <script type="text/javascript" src="/MochiKit/packed.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="startTest()">
+ <script type="application/javascript;version=1.8">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ const MAX_ATTEMPTS = 50;
+ var attempts = 0;
+ var destroyed = false;
+ function onDestroy() {
+ destroyed = true;
+ }
+
+ function checkPluginAlreadyDestroyed() {
+ // We may need to retry a few times until the plugin stop event makes
+ // its way through the event queue.
+ if (attempts < MAX_ATTEMPTS && !destroyed) {
+ ++attempts;
+ SimpleTest.executeSoon(checkPluginAlreadyDestroyed);
+ } else {
+ info("Number of retry attempts: " + attempts);
+ is(destroyed, true, "Plugin instance should have been destroyed.");
+ SimpleTest.finish();
+ }
+ }
+
+ function startTest() {
+ var p1 = document.getElementById('plugin1');
+ var d1 = document.getElementById('div1');
+
+ p1.callOnDestroy(onDestroy);
+
+ // Get two parent check events to run.
+ d1.removeChild(p1);
+ d1.appendChild(p1);
+ d1.removeChild(p1);
+
+ SimpleTest.executeSoon(checkPluginAlreadyDestroyed);
+ }
+ </script>
+
+ <p id="display"></p>
+
+ <div id="div1">
+ <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+ </div>
+
+ <div id="div2">
+ <div id="div3">
+ <embed id="plugin2" type="application/x-test" width="200" height="200"></embed>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_instance_unparent3.html b/dom/plugins/test/mochitest/test_instance_unparent3.html
new file mode 100644
index 000000000..9e55c7ed9
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_instance_unparent3.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Test removing an instance's DOM node</title>
+ <script type="text/javascript" src="/MochiKit/packed.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="startTest()">
+ <script type="application/javascript;version=1.8">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ const MAX_ATTEMPTS = 50;
+ var attempts = 0;
+ var destroyed = false;
+ function onDestroy() {
+ destroyed = true;
+ }
+
+ function checkPluginAlreadyDestroyed() {
+ // We may need to retry a few times until the plugin stop event makes
+ // its way through the event queue.
+ if (attempts < MAX_ATTEMPTS && !destroyed) {
+ ++attempts;
+ SimpleTest.executeSoon(checkPluginAlreadyDestroyed);
+ } else {
+ info("Number of retry attempts: " + attempts);
+ is(destroyed, true, "Plugin instance should have been destroyed.");
+ SimpleTest.finish();
+ }
+ }
+
+ function startTest() {
+ var p1 = document.getElementById('plugin1');
+ var d1 = document.getElementById('div1');
+ var d2 = document.getElementById('div2');
+
+ p1.callOnDestroy(onDestroy);
+ d1.removeChild(d2);
+ SimpleTest.executeSoon(checkPluginAlreadyDestroyed);
+ }
+ </script>
+
+ <p id="display"></p>
+
+ <div id="div1">
+ <div id="div2">
+ <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+ </div<
+ </div>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_instantiation.html b/dom/plugins/test/mochitest/test_instantiation.html
new file mode 100644
index 000000000..e8fc07745
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_instantiation.html
@@ -0,0 +1,33 @@
+<head>
+ <title>Plugin instantiation</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+
+<body onload="mainLoaded()">
+ <iframe id="iframe1" src="about:blank" width="600" height="600"></iframe>
+
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var iframe = document.getElementById('iframe1');
+
+ function mainLoaded() {
+ var p = iframe.contentDocument.createElement('embed');
+ p.setAttribute('id', 'plugin1');
+ p.setAttribute('type', 'application/x-test');
+ p.setAttribute('width', '400');
+ p.setAttribute('height', '400');
+ p.setAttribute('drawmode', 'solid');
+ p.setAttribute('color', 'FF00FFFF');
+ iframe.contentDocument.body.appendChild(p);
+
+ // Plugin instantiation happens asynchronously
+ SimpleTest.executeSoon(function() {
+ SimpleTest.executeSoon(function() {
+ ok(p.setColor !== undefined, "Dynamic plugin instantiation.");
+ SimpleTest.finish();
+ })
+ });
+ }
+ </script>
diff --git a/dom/plugins/test/mochitest/test_mixed_case_mime.html b/dom/plugins/test/mochitest/test_mixed_case_mime.html
new file mode 100644
index 000000000..9258541bb
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_mixed_case_mime.html
@@ -0,0 +1,29 @@
+<body>
+<head>
+ <title>Test mixed case mimetype for plugins</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script>
+ SimpleTest.expectAssertions(0, 1);
+
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
+
+ function frameLoaded() {
+ var contentDocument = document.getElementById('testframe').contentDocument;
+ ok(contentDocument.body.innerHTML.length > 0, "Frame content shouldn't be empty.");
+ ok(contentDocument.plugins.length > 0, "Frame content should have a plugin.");
+ var plugin = contentDocument.plugins[0];
+ is(plugin.type.toLowerCase(), "application/x-second-test", "Should have loaded the second test plugin.");
+ SimpleTest.finish();
+ }
+</script>
+</head>
+<body>
+ <p id="display"></p>
+
+ <iframe id="testframe" name="testframe" onload="frameLoaded()" src="mixed_case_mime.sjs"></iframe>
+
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_multipleinstanceobjects.html b/dom/plugins/test/mochitest/test_multipleinstanceobjects.html
new file mode 100644
index 000000000..74749e019
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_multipleinstanceobjects.html
@@ -0,0 +1,24 @@
+<head>
+ <title>NPNV*NPObject accessibility tests</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+
+<body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function runTests() {
+ var p1 = document.getElementById('plugin1');
+ var p2 = document.getElementById('plugin2');
+
+ var o = p1.getObjectValue();
+ ok(p1.checkObjectValue(o), "Plugin objects passed to the same instance are identical.");
+ ok(!p2.checkObjectValue(o), "Plugin objects passed to another instance are double-wrapped.");
+
+ SimpleTest.finish();
+ }
+ </script>
+
+ <embed id="plugin1" type="application/x-test" width="400" height="400"></embed>
+ <embed id="plugin2" type="application/x-test" width="400" height="400"></embed>
diff --git a/dom/plugins/test/mochitest/test_newstreamondestroy.html b/dom/plugins/test/mochitest/test_newstreamondestroy.html
new file mode 100644
index 000000000..26c4709af
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_newstreamondestroy.html
@@ -0,0 +1,36 @@
+<head>
+ <title>NPN_GetURL called from NPP_Destroy</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css">
+
+<body onload="runTest()">
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.requestFlakyTimeout("untriaged");
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function runTest() {
+ var p = document.getElementById('plugin1');
+ var destroyed = false;
+ p.callOnDestroy(function() {
+ destroyed = true;
+ ok(!p.streamTest('loremipsum.txt', false, null, null,
+ function(r, t) {
+ ok(false, "get-during-destroy should have failed");
+ }, null, true), "NPN_GetURLNotify should fail during NPP_Destroy");
+ });
+ document.body.removeChild(p);
+
+ setTimeout(function() {
+ ok(destroyed, "callback was fired as expected");
+ SimpleTest.finish();
+ }, 1000);
+ }
+ </script>
+
+ <p id="display"></p>
+
+ <embed id="plugin1" type="application/x-test"></embed>
diff --git a/dom/plugins/test/mochitest/test_npn_asynccall.html b/dom/plugins/test/mochitest/test_npn_asynccall.html
new file mode 100644
index 000000000..4f007aacb
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_npn_asynccall.html
@@ -0,0 +1,33 @@
+<html>
+<head>
+ <title>NPN_AsyncCallback Tests</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function asyncTestsComplete(result) {
+ ok(result, "asyncCallback tests completed");
+ SimpleTest.finish();
+ }
+
+ function runTests() {
+ var plugin = document.getElementById("plugin1");
+ plugin.asyncCallbackTest("asyncTestsComplete");
+ }
+ </script>
+
+ <p id="display"></p>
+
+ <embed id="plugin1" type="application/x-test" width="400" height="100">
+ </embed>
+
+ </body>
+ </html>
diff --git a/dom/plugins/test/mochitest/test_npn_timers.html b/dom/plugins/test/mochitest/test_npn_timers.html
new file mode 100644
index 000000000..64d5aebbd
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_npn_timers.html
@@ -0,0 +1,33 @@
+<html>
+<head>
+ <title>NPN_Timer Tests</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function pluginTimerTestFinish(result) {
+ ok(result, "timer tests completed");
+ SimpleTest.finish();
+ }
+
+ function runTests() {
+ var plugin = document.getElementById("plugin1");
+ plugin.timerTest("pluginTimerTestFinish");
+ }
+ </script>
+
+ <p id="display"></p>
+
+ <embed id="plugin1" type="application/x-test" width="400" height="100">
+ </embed>
+
+ </body>
+ </html>
diff --git a/dom/plugins/test/mochitest/test_npobject_getters.html b/dom/plugins/test/mochitest/test_npobject_getters.html
new file mode 100644
index 000000000..5a9a47081
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_npobject_getters.html
@@ -0,0 +1,21 @@
+<head>
+ <title>NPNV*NPObject accessibility tests</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+
+<body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+ dump('lastScript\n');
+
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function runTests() {
+ ok(document.getElementById('plugin1').pluginFoundElement, "plugin1.pluginFoundElement (NPNVPluginElementNPObject)", document.getElementById('plugin1').pluginFoundElement);
+ ok(window.pluginFoundWindow, "window.pluginFoundWindow (NPNVWindowNPObject)", window.pluginFoundWindow);
+
+ SimpleTest.finish();
+ }
+ </script>
+
+ <embed id="plugin1" type="application/x-test" width="400" height="400"></embed>
diff --git a/dom/plugins/test/mochitest/test_npruntime.xul b/dom/plugins/test/mochitest/test_npruntime.xul
new file mode 100644
index 000000000..7e5cc087f
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_npruntime.xul
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window title="Basic Plugin Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <script type="application/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+<body xmlns="http://www.w3.org/1999/xhtml" onload="runTests()">
+<embed id="plugin1" type="application/x-test" width="400" height="400"></embed>
+</body>
+<script class="testbody" type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+function runTests() {
+ var pluginElement = document.getElementById("plugin1");
+
+ ok(pluginElement.identifierToStringTest('foo') == "foo", "identifierToStringTest failed");
+
+ SimpleTest.finish();
+}
+]]>
+</script>
+</window>
diff --git a/dom/plugins/test/mochitest/test_npruntime_construct.html b/dom/plugins/test/mochitest/test_npruntime_construct.html
new file mode 100644
index 000000000..bd85930a4
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_npruntime_construct.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Test whether windowless plugins receive correct visible/invisible notifications.</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<body>
+ <script type="text/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+
+ <p id="display"></p>
+
+ <embed id="theplugin" type="application/x-test"></embed>
+
+ <script type="application/javascript">
+ function MyFunc(arg) {
+ is(arg, "hi", "Argument passed to constructor function");
+ this.localProp = 'local';
+ }
+ MyFunc.prototype.protoProp = 't';
+
+ var theplugin = document.getElementById('theplugin');
+
+ ok(theplugin.constructObject(Array) instanceof Array, "Constructed Array");
+ var o = theplugin.constructObject(MyFunc, "hi");
+ ok(o instanceof MyFunc, "Constructed MyFunc");
+ is(o.localProp, 'local', "this property correct");
+ is(o.protoProp, 't', "prototype property correct");
+ </script>
diff --git a/dom/plugins/test/mochitest/test_npruntime_identifiers.html b/dom/plugins/test/mochitest/test_npruntime_identifiers.html
new file mode 100644
index 000000000..a19a59be5
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_npruntime_identifiers.html
@@ -0,0 +1,67 @@
+<html>
+<head>
+ <title>NPN_Invoke Tests</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+
+ <script class="testbody" type="application/javascript">
+ ////
+ // This test exercises NP identifiers by querying the reflector to make sure
+ // that identifiers are translated to values correctly.
+
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var testsRun = 0;
+
+ function doTest() {
+ SpecialPowers.gc();
+
+ var reflector = document.getElementById("subframe").contentDocument.getElementById("plugin1").getReflector();
+
+ var i, prop, randomnumber;
+
+ for (i = 0; i < 20; ++i) {
+ randomnumber=Math.floor(Math.random()*1001);
+ prop = "prop" + randomnumber;
+ is(reflector[prop], prop, "Property " + prop);
+ }
+
+ for (i = -10; i < 0; ++i) {
+ is(reflector[i], String(i), "Property " + i);
+ prop = "prop" + i;
+ is(reflector[prop], prop, "Property " + prop);
+ }
+
+ for (i = 0; i < 10; ++i) {
+ is(reflector[i], i, "Property " + i);
+ prop = "prop" + i;
+ is(reflector[prop], prop, "Property " + prop);
+ }
+
+ is(reflector.a, 'a', "Property .a");
+ is(reflector['a'], 'a', "Property ['a']");
+ reflector = null;
+
+ SpecialPowers.gc();
+
+ ++testsRun;
+ if (testsRun == 3) {
+ SimpleTest.finish();
+ }
+ else {
+ document.getElementById('subframe').contentWindow.location.reload(true);
+ }
+ }
+ </script>
+
+ <iframe id="subframe" src="npruntime_identifiers_subpage.html" onload="doTest()"></iframe>
+
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_npruntime_npnevaluate.html b/dom/plugins/test/mochitest/test_npruntime_npnevaluate.html
new file mode 100644
index 000000000..4a1c22978
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_npruntime_npnevaluate.html
@@ -0,0 +1,101 @@
+<html>
+<head>
+ <title>NPN_Evaluate Tests</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ // global test function
+ function testMe(arg) {
+ var result = arg+arg;
+ for (var i = 1; i < arguments.length; i++) {
+ result += arguments[i] + arguments[i];
+ }
+ return result;
+ }
+
+ ////
+ // This test exercises NPN_Evaluate using the test plugin's
+ // npnEvaluateTest method. This method calls NPN_Evaluate on
+ // a string argument passed to it, and returns the eval result.
+ // The array below drives the tests; each array member has two
+ // members: the first is a string to eval, and the second is
+ // the expected result of the eval.
+ //
+
+ function runTests() {
+ var tests = [
+ ["3", 3],
+ ["3 + 3", 6],
+ ["'3'", "3"],
+ ["function test() { return 3; } test();", 3],
+ ["testMe(3)", 6],
+ ["testMe(new Object(3))", 6],
+ ["new Object(3)", new Object(3)],
+ ["new Array(1, 2, 3, 4)", [1, 2, 3, 4]],
+ ["document.getElementById('display')",
+ document.getElementById("display")],
+ ["encodeURI('a = b')", "a%20=%20b"],
+ ["document.getElementById('testdiv').innerHTML = 'Hello world!'",
+ "Hello world!"],
+ ["function test2() { var x = {a: '1', b: '2'}; return x; } test2();",
+ {a: '1', b: '2'}],
+ ["(function() { var ret; try { win = window.open(); win.document.writeln('wibble'); ret = 'no error' } catch(e) { ret = e.name; } win.close(); return ret; })()", "no error"],
+ ];
+
+ var plugin = document.getElementById("plugin1");
+
+ // Test calling NPN_Evaluate from within plugin code.
+ for (var test of tests) {
+ var expected = test[1];
+ var result = plugin.npnEvaluateTest(test[0]);
+ // serialize the two values for easy comparison
+ var json_expected = JSON.stringify(expected);
+ var json_result = JSON.stringify(result);
+ if (typeof(result) == "function")
+ json_result = result.toString();
+ if (typeof(expected) == "function")
+ json_expected = expected.toString();
+ is(json_result, json_expected,
+ "npnEvaluateTest returned an unexpected value");
+ is(typeof(result), typeof(expected),
+ "npnEvaluateTest return value was of unexpected type");
+ var success = (json_result == json_expected &&
+ typeof(result) == typeof(expected));
+ $("verbose").appendChild(
+ createEl('span',null, (success ? "pass" : "fail") + ": eval(" + test[0] + ")"));
+ $("verbose").appendChild(
+ createEl('span', null," == " + json_result + "(" +
+ typeof(result) + "), expected " + json_expected + "(" +
+ typeof(expected) + ")"));
+ $("verbose").appendChild(
+ createEl('br')
+ );
+ }
+
+ is(document.getElementById('testdiv').innerHTML, "Hello world!",
+ "innerHTML not set correctly via NPN_Evaluate");
+
+ SimpleTest.finish();
+ }
+ </script>
+
+ <p id="display"></p>
+
+ <embed id="plugin1" type="application/x-test" width="400" height="100">
+ </embed>
+
+ <div id="verbose">
+ </div>
+ <div id="testdiv">
+ </div>
+ </body>
+ </html>
diff --git a/dom/plugins/test/mochitest/test_npruntime_npninvoke.html b/dom/plugins/test/mochitest/test_npruntime_npninvoke.html
new file mode 100644
index 000000000..ff4c92a6d
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_npruntime_npninvoke.html
@@ -0,0 +1,162 @@
+<html>
+<head>
+ <title>NPN_Invoke Tests</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="runTests()">
+
+ <script class="testbody" type="application/javascript">
+ ////
+ // This test exercises NPN_Invoke by calling the plugin's npnInvokeTest
+ // method, which in turn invokes a script method with 1 or more parameters,
+ // and then compares the return vale with an expected value. This is good
+ // for verifying various NPVariant values and types moving between
+ // the browser and the plugin.
+ //
+
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ // This function returns all the arguments passed to it, either as a
+ // single variable (in the caes of 1 argument), or as an array.
+ function returnArgs() {
+ if (arguments.length == 1)
+ return arguments[0];
+ var arr = new Array();
+ for (i = 0; i < arguments.length; i++) {
+ arr.push(arguments[i]);
+ }
+ return arr;
+ }
+
+ // Same as above but explicitly expects two arguments.
+ function returnTwoArgs(arg1, arg2) {
+ return [arg1, arg2];
+ }
+
+ // some objects and arrays used in the tests...
+ var obj = {"key1": "string", "key2": 0, "key3": true, "key4": undefined,
+ "key5": null, "key6": -551235.12552, "key7": false};
+ var arr = ["string", 0, true, false, undefined, null, -1, 55512.1252];
+ var obj2 = {"key1": "string", "key2": 0, "key3": true, "key4": undefined,
+ "key5": null, "key6": -551235.12552, "key7": false, "array": arr};
+ var arr2 = ["string", false, undefined, null, -1, 55512.1252,
+ {"a": "apple", "b": true, "c": undefined}];
+
+ ////
+ // A list of tests to run. Each member of the main array contains
+ // two members: the first contains the arguments passed to npnInvokeTest,
+ // and the second is the expected result.
+ //
+ var tests = [
+ // numeric values
+ [["returnArgs", 0, 0], true],
+ [["returnArgs", 1, 1], true],
+ [["returnArgs", 32768, 32768], true],
+ [["returnArgs", -32768, -32768], true],
+ [["returnArgs", 2147483648, 2147483648], true],
+ [["returnArgs", -2147483648, -2147483648], true],
+ [["returnArgs", 1.0, 1.0], true],
+ [["returnArgs", 1.592786, 1.592786], true],
+ [["returnArgs", 1.592786837, 1.592786837], true],
+ [["returnArgs", -1.592786, -1.592786], true],
+ [["returnArgs", -1.592786837, -1.592786837], true],
+ [["returnArgs", 15235.592786, 15235.592786], true],
+ // null, void, bool
+ [["returnArgs", null, null], true],
+ [["returnArgs", undefined, undefined], true],
+ [["returnArgs", undefined, null], false],
+ [["returnArgs", null, undefined], false],
+ [["returnArgs", 0, undefined], false],
+ [["returnArgs", 0, null], false],
+ [["returnArgs", 0, false], false],
+ [["returnArgs", 1, true], false],
+ [["returnArgs", true, true], true],
+ [["returnArgs", false, false], true],
+ // strings
+ [["returnArgs", "", ""], true],
+ [["returnArgs", "test", "test"], true],
+ [["returnArgs", "test", "testing"], false],
+ [["returnArgs", "test\n", "test\n"], true],
+ [["returnArgs", "test\nline2", "test\nline2"], true],
+ [["returnArgs", "test\nline2", "testline2"], false],
+ [["returnArgs", "test\u000aline2", "test\u000aline2"], true],
+ [["returnArgs", "test\u0020line2", "test line2"], true],
+ [["returnArgs", "test line2", "test\u0020line2"], true],
+ // objects and arrays
+ [["returnArgs", obj, obj], true],
+ [["returnArgs", arr, arr], true],
+ [["returnArgs", obj2, obj2], true],
+ [["returnArgs", arr2, arr2], true],
+ // multiple arguments
+ [["returnArgs", [0, 1, 2], 0, 1, 2], true],
+ [["returnArgs", [5, "a", true, false, null],
+ 5, "a", true, false, null], true],
+ [["returnArgs", [-1500.583, "test string\n",
+ [5, 10, 15, 20], {"a": 1, "b": 2}],
+ -1500.583, "test string\n", [5, 10, 15, 20], {"a": 1, "b": 2}], true],
+ [["returnArgs", [undefined, 0, null, "yes"],
+ undefined, 0, null, "yes"], true],
+ [["returnArgs", [0, undefined, null, "yes"],
+ 0, undefined, null, "yes"], true],
+ // too many/too few args
+ [["returnTwoArgs", ["a", "b"], "a", "b", "c"], true],
+ [["returnTwoArgs", ["a", undefined], "a"], true],
+ [["returnTwoArgs", [undefined, undefined]], true],
+ ];
+
+ function runTests() {
+ var plugin = document.getElementById("plugin1");
+
+ var result;
+ for (var test of tests) {
+ switch (test[0].length) {
+ case 2:
+ result = plugin.npnInvokeTest(test[0][0], test[0][1]);
+ break;
+ case 3:
+ result = plugin.npnInvokeTest(test[0][0], test[0][1], test[0][2]);
+ break;
+ case 4:
+ result = plugin.npnInvokeTest(test[0][0], test[0][1], test[0][2],
+ test[0][3]);
+ break;
+ case 5:
+ result = plugin.npnInvokeTest(test[0][0], test[0][1], test[0][2],
+ test[0][3], test[0][4]);
+ case 6:
+ result = plugin.npnInvokeTest(test[0][0], test[0][1], test[0][2],
+ test[0][3], test[0][4], test[0][5]);
+ break;
+ case 7:
+ result = plugin.npnInvokeTest(test[0][0], test[0][1], test[0][2],
+ test[0][3], test[0][4], test[0][5], test[0][6]);
+ break;
+ default:
+ is(false, "bad number of test arguments");
+ }
+ is(result, test[1], "npnInvokeTestFailed: " + plugin.getError());
+ $("verbose").appendChild(
+ createEl('span', null, ((result == test[1] ? "pass" : "fail") + ": " + test[0])));
+ if (result != test[1])
+ $("verbose").appendChild(createEl("span", null, (" " + plugin.getError())));
+ $("verbose").appendChild(createEl('br'));
+ }
+
+ SimpleTest.finish();
+ }
+ </script>
+
+ <p id="display"></p>
+
+ <embed id="plugin1" type="application/x-test" width="400" height="100">
+ </embed>
+
+ <div id="verbose">
+ </div>
+ </body>
+ </html>
diff --git a/dom/plugins/test/mochitest/test_npruntime_npninvokedefault.html b/dom/plugins/test/mochitest/test_npruntime_npninvokedefault.html
new file mode 100644
index 000000000..79a75e755
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_npruntime_npninvokedefault.html
@@ -0,0 +1,153 @@
+<html>
+<head>
+ <title>NPN_Invoke_Default Tests</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ // global test function
+ function testMe(arg) {
+ var result = arg+arg;
+ for (var i = 1; i < arguments.length; i++) {
+ result += arguments[i] + arguments[i];
+ }
+ return result;
+ }
+
+ ////
+ // This test exercises NPN_InvokeDefault using the test plugin's
+ // npnInvokeDefaultTest method. This method invokes an object
+ // with a single parameter, and returns the result of the invocation.
+ // The test list below is used to drive the tests. Each member of the
+ // array contains three members: the object to invoke, an argument to
+ // invoke it with, and the expected result of the invocation.
+ //
+ var tests = [
+ // Number object
+ ["Number", 3, 3],
+ ["Number", "3", 3],
+ ["Number", "0x20", 32],
+ ["Number", "three", Number.NaN],
+ ["Number", "1e+3", 1000],
+ ["Number", 5.6612, 5.6612],
+ // Array object
+ ["Array", 3, Array(3)],
+ // Boolean object
+ ["Boolean", 0, false],
+ ["Boolean", null, false],
+ ["Boolean", "", false],
+ ["Boolean", false, false],
+ ["Boolean", true, true],
+ ["Boolean", "true", true],
+ ["Boolean", "false", true],
+ ["Boolean", new Boolean(false), true],
+ ["Boolean", { "value": false }, true],
+ // Function object
+ ["Function", "return 3", Function("return 3")],
+ ["Function", "window.alert('test')", Function("window.alert('test')")],
+ // Object object
+ ["Object", undefined, Object()],
+ ["Object", null, Object()],
+ ["Object", true, new Boolean(true)],
+ ["Object", Boolean(), new Boolean(false)],
+ ["Object", "a string", new String("a string")],
+ ["Object", 3.14, new Number(3.14)],
+ ["Object", { "key1": "test", "key2": 15 }, { "key1": "test", "key2": 15 }],
+ ["Object", [1, 3, 5, 7, 9, 11, 13, 17], [1, 3, 5, 7, 9, 11, 13, 17]],
+ // RegExp object
+ ["RegExp", "...", RegExp("...")],
+ // String object
+ ["String", "testing", "testing"],
+ ["String", "test\u0020me", "test me"],
+ ["String", "314", "314"],
+ ["String", "true", "true"],
+ ["String", "null", "null"],
+ ["String", "2 + 2", String("2 + 2")],
+ ["String", ""],
+ // global functions
+ ["testMe", 3, 6],
+ ["testMe", "string", [1,2], "stringstring1,21,2"],
+ ["testMe", "me", "meme"],
+ ["testMe", undefined, Number.NaN],
+ ["testMe", [1, 2], "1,21,2"],
+ ["testMe", 3, 4, 14],
+ ["isNaN", "junk", true],
+ ["parseInt", "156", 156],
+ ["encodeURI", "a = b", "a%20=%20b"],
+ ];
+
+ function runTests() {
+ var plugin = document.getElementById("plugin1");
+
+ // Test calling NPN_InvokeDefault from within plugin code.
+ for (var test of tests) {
+ var result;
+ var expected = test[test.length - 1];
+ switch (test.length) {
+ case 2:
+ result = plugin.npnInvokeDefaultTest(test[0]);
+ break;
+ case 3:
+ result = plugin.npnInvokeDefaultTest(test[0], test[1]);
+ break;
+ case 4:
+ result = plugin.npnInvokeDefaultTest(test[0], test[1], test[2]);
+ break;
+ }
+ // serialize the two values for easy
+ var json_expected = JSON.stringify(expected);
+ var json_result = JSON.stringify(result);
+ if (typeof(result) == "function")
+ json_result = result.toString();
+ if (typeof(test[2]) == "function")
+ json_expected = expected.toString();
+ is(json_result, json_expected,
+ "npnInvokeDefault returned an unexpected value");
+ is(typeof(result), typeof(expected),
+ "npnInvokeDefaultTest return value was of unexpected type");
+ var success = (json_result == json_expected &&
+ typeof(result) == typeof(expected));
+ $("verbose").appendChild(
+ createEl('span', null, ((success ? "pass" : "fail") + ": " + test[0] + "(")));
+ for (var i = 1; i < test.length - 1; i++) {
+ $("verbose").appendChild(
+ createEl('span', null, (JSON.stringify(test[i]) + (i < test.length - 2 ? "," : ""))));
+ }
+ $("verbose").appendChild(
+ createEl('span', null, (") == " + json_result + "(" +
+ typeof(result) + "), expected " + json_expected + "(" +
+ typeof(expected) + ")")));
+ $("verbose").appendChild(createEl('br'));
+ }
+
+ // Test calling the invokedefault method of plugin-defined object
+ is(plugin(), "Test Plug-in",
+ "calling NPN_InvokeDefault on plugin-defined Object doesn't work");
+ is(plugin(1), "Test Plug-in;1",
+ "calling NPN_InvokeDefault on plugin-defined Object doesn't work");
+ is(plugin("test"), "Test Plug-in;test",
+ "calling NPN_InvokeDefault on plugin-defined Object doesn't work");
+ is(plugin(undefined, -1, null), "Test Plug-in;undefined;-1;null",
+ "calling NPN_InvokeDefault on plugin-defined Object doesn't work");
+
+ SimpleTest.finish();
+ }
+ </script>
+
+ <p id="display"></p>
+
+ <embed id="plugin1" type="application/x-test" width="400" height="100">
+ </embed>
+
+ <div id="verbose">
+ </div>
+ </body>
+ </html>
diff --git a/dom/plugins/test/mochitest/test_object.html b/dom/plugins/test/mochitest/test_object.html
new file mode 100644
index 000000000..093333ea5
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_object.html
@@ -0,0 +1,510 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Plugin instantiation</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="/tests/SimpleTest/SpecialPowers.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <meta charset="utf-8">
+ <body onload="onLoad()">
+ <script class="testbody" type="text/javascript;version=1.8">
+
+ "use strict";
+ SimpleTest.waitForExplicitFinish();
+
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
+
+ // This can go away once embed also is on WebIDL
+ let OBJLC = SpecialPowers.Ci.nsIObjectLoadingContent;
+
+ // Use string modes in this test to make the test easier to read/debug.
+ // nsIObjectLoadingContent refers to this as "type", but I am using "mode"
+ // in the test to avoid confusing with content-type.
+ let prettyModes = {};
+ prettyModes[OBJLC.TYPE_LOADING] = "loading";
+ prettyModes[OBJLC.TYPE_IMAGE] = "image";
+ prettyModes[OBJLC.TYPE_PLUGIN] = "plugin";
+ prettyModes[OBJLC.TYPE_DOCUMENT] = "document";
+ prettyModes[OBJLC.TYPE_NULL] = "none";
+
+ let body = document.body;
+ // A single-pixel white png
+ let testPNG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AoIFiETNqbNRQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAACklEQVQIHWP4DwABAQEANl9ngAAAAABJRU5ErkJggg==';
+ // An empty, but valid, SVG
+ let testSVG = 'data:image/svg+xml,<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"></svg>';
+ // executeSoon wrapper to count pending callbacks
+ let pendingCalls = 0;
+ let afterPendingCalls = false;
+
+ function runWhenDone(func) {
+ if (!pendingCalls)
+ func();
+ else
+ afterPendingCalls = func;
+ }
+ function runSoon(func) {
+ pendingCalls++;
+ SimpleTest.executeSoon(function() {
+ func();
+ if (--pendingCalls < 1 && afterPendingCalls)
+ afterPendingCalls();
+ });
+ }
+ function src(obj, state, uri) {
+ // If we have a running plugin, src changing should always throw it out,
+ // even if it causes us to load the same plugin again.
+ if (uri && runningPlugin(obj, state)) {
+ if (!state.oldPlugins)
+ state.oldPlugins = [];
+ try {
+ state.oldPlugins.push(obj.getObjectValue());
+ } catch (e) {
+ ok(false, "Running plugin but cannot call getObjectValue?");
+ }
+ }
+
+ var srcattr;
+ if (state.tagName == "object")
+ srcattr = "data";
+ else if (state.tagName == "embed")
+ srcattr = "src";
+ else
+ ok(false, "Internal test fail: Why are we setting the src of an applet");
+
+ // Plugins should always go away immediately on src/data change
+ state.initialPlugin = false;
+ if (uri === null) {
+ removeAttr(obj, srcattr);
+ // TODO Bug 767631 - we don't trigger loadObject on UnsetAttr :(
+ forceReload(obj, state);
+ } else {
+ setAttr(obj, srcattr, uri);
+ }
+ }
+ // We have to be careful not to reach past the nsObjectLoadingContent
+ // prototype to touch generic element attributes, as this will try to
+ // spawn the plugin, breaking our ability to test for that.
+ function getAttr(obj, attr) {
+ return document.body.constructor.prototype.getAttribute.call(obj, attr);
+ }
+ function setAttr(obj, attr, val) {
+ return document.body.constructor.prototype.setAttribute.call(obj, attr, val);
+ }
+ function hasAttr(obj, attr) {
+ return document.body.constructor.prototype.hasAttribute.call(obj, attr);
+ }
+ function removeAttr(obj, attr) {
+ return document.body.constructor.prototype.removeAttribute.call(obj, attr);
+ }
+ function setDisplayed(obj, display) {
+ if (display)
+ removeAttr(obj, 'style');
+ else
+ setAttr(obj, 'style', "display: none;");
+ }
+ function displayed(obj) {
+ // Hacky, but that's all we use style for.
+ return !hasAttr(obj, 'style');
+ }
+ function actualType(obj, state) {
+ return state.getActualType.call(obj);
+ }
+ function getMode(obj, state) {
+ return prettyModes[state.getDisplayedType.call(obj)];
+ }
+ function runningPlugin(obj, state) {
+ return state.getHasRunningPlugin.call(obj);
+ }
+
+ // TODO this is hacky and might hide some failures, but is needed until
+ // Bug 767635 lands -- which itself will probably mean tweaking this test.
+ function forceReload(obj, state) {
+ let attr;
+ if (state.tagName == "object")
+ attr = "data";
+ else if (state.tagName == "embed")
+ attr = "src";
+
+ if (attr && hasAttr(obj, attr)) {
+ src(obj, state, getAttr(obj, attr));
+ } else if (body.contains(obj)) {
+ body.appendChild(obj);
+ } else {
+ // Out of document nodes without data attributes simply can't be
+ // reloaded currently. Bug 767635
+ }
+ };
+
+ // Make a list of combinations of sub-lists, e.g.:
+ // [ [a, b], [c, d] ]
+ // ->
+ // [ [a, c], [a, d], [b, c], [b, d] ]
+ function eachList() {
+ let all = [];
+ if (!arguments.length)
+ return all;
+ let list = Array.prototype.slice.call(arguments, 0);
+ for (let c of list[0]) {
+ if (list.length > 1) {
+ for (let x of eachList.apply(this,list.slice(1))) {
+ all.push((c.length ? [c] : []).concat(x));
+ }
+ } else if (c.length) {
+ all.push([c]);
+ }
+ }
+ return all;
+ }
+
+ let states = {
+ svg: function(obj, state) {
+ removeAttr(obj, "type");
+ src(obj, state, testSVG);
+ state.noChannel = false;
+ state.expectedType = "image/svg";
+ // SVGs are actually image-like subdocuments
+ state.expectedMode = "document";
+ },
+ image: function(obj, state) {
+ removeAttr(obj, "type");
+ src(obj, state, testPNG);
+ state.noChannel = false;
+ state.expectedMode = "image";
+ state.expectedType = "image/png";
+ },
+ plugin: function(obj, state) {
+ removeAttr(obj, "type");
+ src(obj, state, "data:application/x-test,foo");
+ state.noChannel = false;
+ state.expectedType = "application/x-test";
+ state.expectedMode = "plugin";
+ },
+ pluginExtension: function(obj, state) {
+ src(obj, state, "./fake_plugin.tst");
+ state.expectedMode = "plugin";
+ state.pluginExtension = true;
+ state.noChannel = false;
+ },
+ document: function(obj, state) {
+ removeAttr(obj, "type");
+ src(obj, state, "data:text/plain,I am a document");
+ state.noChannel = false;
+ state.expectedType = "text/plain";
+ state.expectedMode = "document";
+ },
+ fallback: function(obj, state) {
+ removeAttr(obj, "type");
+ state.expectedType = "application/x-unknown";
+ state.expectedMode = "none";
+ state.noChannel = true;
+ src(obj, state, null);
+ },
+ addToDoc: function(obj, state) {
+ body.appendChild(obj);
+ },
+ removeFromDoc: function(obj, state) {
+ if (body.contains(obj))
+ body.removeChild(obj);
+ },
+ // Set the proper type
+ setType: function(obj, state) {
+ if (state.expectedType) {
+ state.badType = false;
+ setAttr(obj, 'type', state.expectedType);
+ forceReload(obj, state);
+ }
+ },
+ // Set an improper type
+ setWrongType: function(obj, state) {
+ // This should break no-channel-plugins but nothing else
+ state.badType = true;
+ setAttr(obj, 'type', "application/x-unknown");
+ forceReload(obj, state);
+ },
+ // Set a plugin type
+ setPluginType: function(obj, state) {
+ // If an object/embed has a type set to a plugin type, it should not
+ // use the channel type.
+ state.badType = false;
+ setAttr(obj, 'type', 'application/x-test');
+ state.expectedType = "application/x-test";
+ state.expectedMode = "plugin";
+ forceReload(obj, state);
+ },
+ noChannel: function(obj, state) {
+ src(obj, state, null);
+ state.noChannel = true;
+ state.pluginExtension = false;
+ },
+ displayNone: function(obj, state) {
+ setDisplayed(obj, false);
+ },
+ displayInherit: function(obj, state) {
+ setDisplayed(obj, true);
+ }
+ };
+
+
+ function testObject(obj, state) {
+ // If our test combination both sets noChannel but no explicit type
+ // it shouldn't load ever.
+ let expectedMode = state.expectedMode;
+ let actualMode = getMode(obj, state);
+
+ if (state.noChannel && !getAttr(obj, 'type')) {
+ // Some combinations of test both set no type and no channel. This is
+ // worth testing with the various combinations, but shouldn't load.
+ expectedMode = "none";
+ }
+
+ // Embed tags should always try to load a plugin by type or extension
+ // before falling back to opening a channel. See bug 803159
+ if (state.tagName == "embed" &&
+ (getAttr(obj, 'type') == "application/x-test" || state.pluginExtension)) {
+ state.noChannel = true;
+ }
+
+ // with state.loading, unless we're loading with no channel, these types
+ // should still be in loading state pending a channel.
+ if (state.loading && (expectedMode == "image" || expectedMode == "document" ||
+ (expectedMode == "plugin" && !state.initialPlugin && !state.noChannel))) {
+ expectedMode = "loading";
+ }
+
+ // With the exception of plugins with a proper type, nothing should
+ // load without a channel
+ if (state.noChannel && (expectedMode != "plugin" || state.badType) &&
+ body.contains(obj)) {
+ expectedMode = "none";
+ }
+
+ // embed tags should reject documents, except for SVG images which
+ // render as such
+ if (state.tagName == "embed" && expectedMode == "document" &&
+ actualType(obj, state) != "image/svg+xml") {
+ expectedMode = "none";
+ }
+
+ // Embeds with a plugin type should skip opening a channel prior to
+ // loading, taking only type into account.
+ if (state.tagName == 'embed' && getAttr(obj, 'type') == 'application/x-test' &&
+ body.contains(obj)) {
+ expectedMode = "plugin";
+ }
+
+ if (!body.contains(obj)
+ && (!state.loading || expectedMode != "image")
+ && (!state.initialPlugin || expectedMode != "plugin")) {
+ // Images are handled by nsIImageLoadingContent so we dont track
+ // their state change as they're detached and reattached. All other
+ // types switch to state "loading", and are completely unloaded
+ expectedMode = "loading";
+ }
+
+ is(actualMode, expectedMode, "check loaded mode");
+
+ // If we're a plugin, check that we spawned successfully. state.loading
+ // is set if we haven't had an event loop since applying state, in which
+ // case the plugin would not have stopped yet if it was initially a
+ // plugin.
+ let shouldBeSpawnable = expectedMode == "plugin" && displayed(obj);
+ let shouldSpawn = shouldBeSpawnable && (!state.loading || state.initialPlugin);
+ let didSpawn = runningPlugin(obj, state);
+ is(didSpawn, !!shouldSpawn, "check plugin spawned is " + !!shouldSpawn);
+
+ // If we are a plugin, scripting should work. If we're not spawned we
+ // should spawn synchronously.
+ let scripted = false;
+ try {
+ let x = obj.getObjectValue();
+ scripted = true;
+ } catch(e) {}
+ is(scripted, shouldBeSpawnable, "check plugin scriptability");
+
+ // If this tag previously had other spawned plugins, make sure it
+ // respawned between then and now
+ if (state.oldPlugins && didSpawn) {
+ let didRespawn = false;
+ for (let oldp of state.oldPlugins) {
+ // If this returns false or throws, it's not the same plugin
+ try {
+ didRespawn = !obj.checkObjectValue(oldp);
+ } catch (e) {
+ didRespawn = true;
+ }
+ }
+ is(didRespawn, true, "Plugin should have re-spawned since old state ("+state.oldPlugins.length+")");
+ }
+ }
+
+ let total = 0;
+ let test_modes = {
+ // Just apply from_state then to_state
+ "immediate": function(obj, from_state, to_state, state) {
+ for (let from of from_state)
+ states[from](obj, state);
+ for (let to of to_state)
+ states[to](obj, state);
+
+ // We don't spin the event loop between applying to_state and
+ // running tests, so some types are still loading
+ state.loading = true;
+ info("["+(++total)+"] Testing [ " + from_state + " ] -> [ " + to_state + " ] / " + state.tagName + " / immediate");
+ testObject(obj, state);
+
+ if (body.contains(obj))
+ body.removeChild(obj);
+
+ },
+ // Apply states, spin event loop, run tests.
+ "cycle": function(obj, from_state, to_state, state) {
+ for (let from of from_state)
+ states[from](obj, state);
+ for (let to of to_state)
+ states[to](obj, state);
+ // Because re-appending to the document creates a script blocker, but
+ // plugins spawn asynchronously, we need to return to the event loop
+ // twice to ensure the plugin has been given a chance to lazily spawn.
+ runSoon(function() { runSoon(function() {
+ info("["+(++total)+"] Testing [ " + from_state + " ] -> [ " + to_state + " ] / " + state.tagName + " / cycle");
+ testObject(obj, state);
+
+ if (body.contains(obj))
+ body.removeChild(obj);
+ }); });
+ },
+ // Apply initial state, spin event loop, apply final state, spin event
+ // loop again.
+ "cycleboth": function(obj, from_state, to_state, state) {
+ for (let from of from_state) {
+ states[from](obj, state);
+ }
+ runSoon(function() {
+ for (let to of to_state) {
+ states[to](obj, state);
+ }
+ // Because re-appending to the document creates a script blocker,
+ // but plugins spawn asynchronously, we need to return to the event
+ // loop twice to ensure the plugin has been given a chance to lazily
+ // spawn.
+ runSoon(function() { runSoon(function() {
+ info("["+(++total)+"] Testing [ " + from_state + " ] -> [ " + to_state + " ] / " + state.tagName + " / cycleboth");
+ testObject(obj, state);
+
+ if (body.contains(obj))
+ body.removeChild(obj);
+ }); });
+ });
+ },
+ // Apply initial state, spin event loop, apply later state, test
+ // immediately
+ "cyclefirst": function(obj, from_state, to_state, state) {
+ for (let from of from_state) {
+ states[from](obj, state);
+ }
+ runSoon(function() {
+ state.initialPlugin = runningPlugin(obj, state);
+ for (let to of to_state) {
+ states[to](obj, state);
+ }
+ info("["+(++total)+"] Testing [ " + from_state + " ] -> [ " + to_state + " ] / " + state.tagName + " / cyclefirst");
+ // We don't spin the event loop between applying to_state and
+ // running tests, so some types are still loading
+ state.loading = true;
+ testObject(obj, state);
+
+ if (body.contains(obj))
+ body.removeChild(obj);
+ });
+ },
+ };
+
+ function test(testdat) {
+ // FIXME bug 1291854: Change back to lets when the test is fixed.
+ for (var from_state of testdat['from_states']) {
+ for (var to_state of testdat['to_states']) {
+ for (var mode of testdat['test_modes']) {
+ for (var type of testdat['tag_types']) {
+ runSoon(function () {
+ let obj = document.createElement(type);
+ obj.width = 1; obj.height = 1;
+ let state = {};
+ state.noChannel = true;
+ state.tagName = type;
+ // Part of the test checks whether a plugin spawned or not,
+ // but touching the object prototype will attempt to
+ // synchronously spawn a plugin! We use this terrible hack to
+ // get a privileged getter for the attributes we want to touch
+ // prior to applying any attributes.
+ // TODO when embed goes away we wont need to check for
+ // QueryInterface any longer.
+ var lookup_on = obj.QueryInterface ? obj.QueryInterface(OBJLC): obj;
+ state.getDisplayedType = SpecialPowers.do_lookupGetter(lookup_on, 'displayedType');
+ state.getHasRunningPlugin = SpecialPowers.do_lookupGetter(lookup_on, 'hasRunningPlugin');
+ state.getActualType = SpecialPowers.do_lookupGetter(lookup_on, 'actualType');
+ test_modes[mode](obj, from_state, to_state, state);
+ });
+ }
+ }
+ }
+ }
+ }
+
+ function onLoad() {
+ // Generic tests
+ test({
+ 'tag_types': [ 'embed', 'object' ],
+ // In all three modes
+ 'test_modes': [ 'immediate', 'cycle', 'cyclefirst', 'cycleboth' ],
+ // Starting from a blank tag in and out of the document, a loading
+ // plugin, and no-channel plugin (initial types only really have
+ // odd cases with plugins)
+ 'from_states': [
+ [ 'addToDoc' ],
+ [ 'plugin' ],
+ [ 'plugin', 'addToDoc' ],
+ [ 'plugin', 'noChannel', 'setType', 'addToDoc' ],
+ [],
+ ],
+ // To various combinations of loaded objects
+ 'to_states': eachList(
+ [ 'svg', 'image', 'plugin', 'document', '' ],
+ [ 'setType', 'setWrongType', 'setPluginType', '' ],
+ [ 'noChannel', '' ],
+ [ 'displayNone', 'displayInherit', '' ]
+ )});
+ // Special case test for embed tags with plugin-by-extension
+ // TODO object tags should be tested here too -- they have slightly
+ // different behavior, but waiting on a file load requires a loaded
+ // event handler and wont work with just our event loop spinning.
+ test({
+ 'tag_types': [ 'embed' ],
+ 'test_modes': [ 'immediate', 'cyclefirst', 'cycle', 'cycleboth' ],
+ 'from_states': eachList(
+ [ 'svg', 'plugin', 'image', 'document' ],
+ [ 'addToDoc' ]
+ ),
+ // Set extension along with valid ty
+ 'to_states': [
+ [ 'pluginExtension' ]
+ ]});
+ // Test plugin add/remove from document with adding/removing frame, with
+ // and without a channel.
+ test({
+ 'tag_types': [ 'embed', 'object' ], // Ideally we'd test object too, but this gets exponentially long.
+ 'test_modes': [ 'immediate', 'cyclefirst', 'cycle' ],
+ 'from_states': [ [ 'displayNone', 'plugin', 'addToDoc' ],
+ [ 'displayNone', 'plugin', 'noChannel', 'addToDoc' ],
+ [ 'plugin', 'noChannel', 'addToDoc' ],
+ [ 'plugin', 'noChannel' ] ],
+ 'to_states': eachList(
+ [ 'displayNone', '' ],
+ [ 'removeFromDoc' ],
+ [ 'image', 'displayNone', '' ],
+ [ 'image', 'displayNone', '' ],
+ [ 'addToDoc' ],
+ [ 'displayInherit' ]
+ )});
+ runWhenDone(() => SimpleTest.finish());
+ }
+ </script>
diff --git a/dom/plugins/test/mochitest/test_painting.html b/dom/plugins/test/mochitest/test_painting.html
new file mode 100644
index 000000000..08ebd4675
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_painting.html
@@ -0,0 +1,121 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for windowless plugin invalidation and expose events in clips</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <style>
+ div#container {
+ position: relative;
+ height: 30px;
+ background: blue;
+ }
+ div#clip {
+ overflow:hidden;
+ position:absolute;
+ left: 10.3px;
+ top: 9.7px;
+ width: 10px;
+ height: 0px;
+ background: red;
+ }
+ embed {
+ position:absolute;
+ }
+ embed#paint-waiter {
+ top: 0px;
+ left: 0px;
+ width: 1px;
+ height: 0px;
+ }
+ embed#clipped {
+ left: -5.3px;
+ top: -4.7px;
+ width: 20px;
+ height: 20px;
+ }
+ </style>
+</head>
+<body onload="initialize()">
+
+<script type="application/javascript" src="plugin-utils.js"></script>
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+var paint_waiter;
+var clip;
+var clipped;
+
+function initialize() {
+ paint_waiter = document.getElementById("paint-waiter");
+ clip = document.getElementById("clip");
+ clipped = document.getElementById("clipped");
+
+ waitForPaint(show);
+}
+
+function show() {
+ paintCountIs(clipped, 0, "fully clipped plugin not painted");
+
+ clip.style.height = "10px";
+
+ // Capturing an image (as in a reftest) would force a repaint and use
+ // different paths for the image surface, so instead check the plugin's
+ // paint count.
+ waitForPaint(invalidate);
+}
+
+function invalidate() {
+ paintCountIs(clipped, 1, "partially clipped plugin painted once");
+
+ clipped.setColor("FF00FF00"); // plugin invalidates
+
+ waitForPaint(done);
+}
+
+function done() {
+ paintCountIs(clipped, 2, "painted after invalidate");
+
+ SimpleTest.finish();
+}
+
+function waitForPaint(func) {
+ paint_waiter.last_paint_count = paint_waiter.getPaintCount();
+ // Ensure the waiter has had a style change, so that this will
+ // change its size and cause a paint.
+ paint_waiter.style.backgroundColor = paint_waiter.style.backgroundColor == "blue" ? "yellow" : "blue";
+ var flush = paint_waiter.offsetHeight;
+ paint_waiter.style.height = "1px";
+ waitForPaintHelper(func);
+}
+
+function waitForPaintHelper(func) {
+ if (paint_waiter.getPaintCount() != paint_waiter.last_paint_count) {
+ // hide the paint waiter
+ paint_waiter.style.height = "0px";
+ setTimeout(func, 0);
+ return;
+ }
+ setTimeout(function() { waitForPaintHelper(func); }, 1000);
+}
+
+</script>
+
+<p id="display"></p>
+<div id="container">
+ <embed id="paint-waiter" type="application/x-test"/>
+ <div id="clip">
+ <embed id="clipped" type="application/x-test"
+ drawmode="solid" color="FF808080"/>
+ </div>
+</div>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_plugin_scroll_invalidation.html b/dom/plugins/test/mochitest/test_plugin_scroll_invalidation.html
new file mode 100644
index 000000000..65ea3498a
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_plugin_scroll_invalidation.html
@@ -0,0 +1,109 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for plugin child widgets not being invalidated by scrolling</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="initialize()">
+<script type="application/javascript">
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED,
+ "Test Plug-in");
+</script>
+
+<p id="display">
+ <iframe id="i" src="plugin_scroll_invalidation.html"
+ width="50" height="50" scrolling="no"></iframe>
+</p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var scrolling;
+var scrolling_plugins = [];
+var paint_waiter;
+var last_paint_counts;
+
+function initialize() {
+ scrolling = document.getElementById("i").contentWindow;
+ scrolling_plugins = scrolling.document.querySelectorAll("embed.scrolling");
+ paint_waiter = scrolling.document.getElementById("paint-waiter");
+
+ scrolling.scrollTo(50, 45);
+
+ is(paint_waiter.getPaintCount(), 0, "zero-sized plugin not painted");
+
+ waitForPaint(scrollAround);
+}
+
+function scrollAround() {
+ var paints = getPaintCounts();
+
+ for (var i = 0; i < paints.length; ++i) {
+ isnot(paints[i], 0, "embed " + scrolling_plugins[i].id + " is painted");
+ }
+
+ last_paint_counts = paints;
+
+ scrolling.scrollBy(-5, 5);
+ scrolling.scrollBy(5, 5);
+ scrolling.scrollBy(5, -5);
+ scrolling.scrollBy(-5, -5);
+
+ scrolling.scrollTo(45, 45);
+ scrolling.scrollBy(10, 0);
+ scrolling.scrollBy(0, 10);
+ scrolling.scrollBy(-10, 0);
+ scrolling.scrollBy(0, -10);
+
+ waitForPaint(done);
+}
+
+function done() {
+ var paints = getPaintCounts();
+ for (var i = 0; i < paints.length; ++i) {
+ is(paints[i], last_paint_counts[i], "embed " + scrolling_plugins[i].id + " is not painted on scroll");
+ }
+ SimpleTest.finish();
+}
+
+// Waits for the paint_waiter plugin to be repainted and then
+// calls 'func' to continue.
+function waitForPaint(func) {
+ paint_waiter.last_paint_count = paint_waiter.getPaintCount();
+
+ paint_waiter.style.left = scrolling.scrollX + "px";
+ paint_waiter.style.top = scrolling.scrollY + "px";
+
+ // Fiddle with the style in a way that should force some repainting
+ paint_waiter.style.width =
+ (paint_waiter.getBoundingClientRect().width + 1) + "px";
+ paint_waiter.style.height = "1px";
+
+ function waitForPaintHelper() {
+ if (paint_waiter.getPaintCount() != paint_waiter.last_paint_count) {
+ setTimeout(func, 0);
+ return;
+ }
+ setTimeout(waitForPaintHelper, 0);
+ }
+ waitForPaintHelper();
+}
+
+function getPaintCounts() {
+ var result = [];
+ for (var i = 0; i < scrolling_plugins.length; ++i) {
+ result[i] = scrolling_plugins[i].getPaintCount();
+ }
+ return result;
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_plugin_scroll_painting.html b/dom/plugins/test/mochitest/test_plugin_scroll_painting.html
new file mode 100644
index 000000000..9626156b6
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_plugin_scroll_painting.html
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test that scrolling a windowless plugin doesn't force us to repaint it</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <script type="text/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="runTest()">
+<p id="display"></p>
+ <embed id="plugin" type="application/x-test" style="width:50px; height:10px; margin-top:20px;"></embed>
+</div>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+
+<script type="application/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var container = document.documentElement;
+container.scrollTop = 0;
+var plugin = document.getElementById("plugin");
+var pluginTop;
+var beforeScrollPaintCount;
+
+function waitForScroll() {
+ if (plugin.getEdge(1) >= pluginTop) {
+ setTimeout(waitForScroll, 0);
+ return;
+ }
+
+ is(plugin.getPaintCount(), beforeScrollPaintCount, "plugin should not paint due to scrolling");
+ SimpleTest.finish();
+}
+
+function waitForInitialScroll() {
+ if (plugin.getEdge(1) >= pluginTop) {
+ setTimeout(waitForInitialScroll, 0);
+ return;
+ }
+
+ pluginTop = plugin.getEdge(1);
+ beforeScrollPaintCount = plugin.getPaintCount();
+ container.scrollTop = 20;
+ waitForScroll();
+}
+
+function runTest() {
+ document.body.offsetTop;
+ pluginTop = plugin.getEdge(1);
+ container.scrollTop = 10;
+ waitForInitialScroll();
+}
+</script>
+
+<div style="height:4000px;"></div>
+
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_plugin_tag_clicktoplay.html b/dom/plugins/test/mochitest/test_plugin_tag_clicktoplay.html
new file mode 100644
index 000000000..0679e6795
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_plugin_tag_clicktoplay.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta><charset="utf-8"/>
+ <title>Test Modifying Plugin click-to-play Flag</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ </head>
+ <body>
+ <script class="testbody" type="application/javascript">
+ Components.utils.import("resource://gre/modules/Services.jsm");
+ Services.prefs.setBoolPref("plugins.click_to_play", true);
+ var pluginHost = Components.classes["@mozilla.org/plugin/host;1"]
+ .getService(Components.interfaces.nsIPluginHost);
+
+ var testPlugin = getTestPlugin();
+ var secondTestPlugin = getTestPlugin("Second Test Plug-in");
+ ok(testPlugin, "Should have Test Plug-in");
+ ok(secondTestPlugin, "Should have Second Test Plug-in");
+
+ // make sure both start off as click-to-play
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
+
+ testPlugin.enabledState = Components.interfaces.nsIPluginTag.STATE_ENABLED;
+ is(pluginHost.getStateForType("application/x-test"), Components.interfaces.nsIPluginTag.STATE_ENABLED, "click-to-play should be off for Test Plug-in now");
+ is(pluginHost.getStateForType("application/x-second-test"), Components.interfaces.nsIPluginTag.STATE_CLICKTOPLAY, "click-to-play should still be on for the Second Test Plug-in");
+
+ testPlugin.enabledState = Components.interfaces.nsIPluginTag.STATE_CLICKTOPLAY;
+ is(pluginHost.getStateForType("application/x-test"), Components.interfaces.nsIPluginTag.STATE_CLICKTOPLAY, "click-to-play should be on for Test Plug-in now");
+
+ Services.prefs.clearUserPref("plugins.click_to_play");
+ </script>
+ </body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_pluginstream_3rdparty.html b/dom/plugins/test/mochitest/test_pluginstream_3rdparty.html
new file mode 100644
index 000000000..aa7dbb5a1
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_pluginstream_3rdparty.html
@@ -0,0 +1,76 @@
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html>
+<head>
+ <title>NPAPI NPN_GetURL NPStream Test</title>
+ <meta charset=UTF-8>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript"
+ src="pluginstream.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+ <script type="text/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+
+ <iframe id="testframe" name="testframe"></iframe>
+
+ <script>
+ /**
+ * Tests that we still properly do or don't send cookies for requests from
+ * plugins when the user has disabled 3rd-party cookies. See
+ * pluginstream.js where we verify that we get the same content as for XHR
+ * requests.
+ */
+ SimpleTest.waitForExplicitFinish();
+ function get_embed_elt() {
+ var e = document.createElement("embed");
+ e.setAttribute("streammode", "normal");
+ e.setAttribute("streamchunksize", "1024");
+ e.setAttribute("frame", "testframe");
+ e.setAttribute("id", "embedtest");
+ e.setAttribute("style", "width: 400px; height: 100px;");
+ e.setAttribute("type", "application/x-test");
+ return e;
+ }
+
+ function* test_runner() {
+ function create_embed(host) {
+ var e = get_embed_elt();
+
+ const url =
+ `http://${host}/tests/dom/plugins/test/mochitest/file_checkcookie.sjs`;
+ e.setAttribute('geturl', url);
+ document.body.appendChild(e);
+
+ return new Promise(resolve => {
+ $('testframe').addEventListener("load", function loaded() {
+ $('testframe').removeEventListener("load", loaded);
+ resolve();
+ });
+ });
+ }
+
+ // Same origin
+ yield create_embed("mochi.test:8888");
+ yield create_embed("example.org");
+ }
+
+ document.cookie = "found=a_cookie";
+ var example_iframe = document.createElement("iframe");
+ example_iframe.src = "http://example.org/tests/dom/plugins/test/mochitest/file_setcookie.html";
+ example_iframe.addEventListener("load", () => {
+ $('testframe').addEventListener("load", () => frameLoaded(false, true));
+ SpecialPowers.pushPrefEnv({ set: [[ 'network.cookie.cookieBehavior', 1 ]] },
+ () => (spawn_task(test_runner).then(SimpleTest.finish)));
+ });
+ document.body.appendChild(example_iframe);
+ </script>
+ </body>
+ </html>
diff --git a/dom/plugins/test/mochitest/test_pluginstream_asfile.html b/dom/plugins/test/mochitest/test_pluginstream_asfile.html
new file mode 100644
index 000000000..b021a74ce
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_pluginstream_asfile.html
@@ -0,0 +1,33 @@
+<html>
+<head>
+ <title>NPAPI NP_ASFILE NPStream Test</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript"
+ src="pluginstream.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <script type="text/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+
+ <iframe id="testframe" name="testframe" onload="frameLoaded()"></iframe>
+
+ <!--
+ - Similar to the above tests, but NPP_NewStream sets the stream mode
+ - to NP_ASFILE. In this test, stream data is written in a series of
+ - NPP_Write calls, as per NP_NORMAL, and also written to a file whose
+ - path is passed to NPP_StreamAsFile. The plugin compares the file
+ - and the stream to verify they're indentical, then passes the stream
+ - back to the browser via NPN_GetURL as above.
+ -->
+ <embed src="loremipsum_file.txt" streammode="asfile"
+ frame="testframe"
+ id="embedtest" style="width: 400px; height: 100px;"
+ type="application/x-test"></embed>
+ </body>
+ </html>
diff --git a/dom/plugins/test/mochitest/test_pluginstream_asfileonly.html b/dom/plugins/test/mochitest/test_pluginstream_asfileonly.html
new file mode 100644
index 000000000..96c9b85dc
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_pluginstream_asfileonly.html
@@ -0,0 +1,30 @@
+<html>
+<head>
+ <title>NPAPI NP_ASFILEONLY NPStream Test</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript"
+ src="pluginstream.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <script type="text/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+
+ <iframe id="testframe" name="testframe" onload="frameLoaded()"></iframe>
+
+ <!--
+ - Similar to above, but NPP_NewStream sets to the stream mode
+ - to NP_ASFILEONLY, so the entire stream is written to a file
+ - and the file is read by the plugin when NPP_StreamAsFile is called.
+ -->
+ <embed src="loremipsum_file.txt" streammode="asfileonly"
+ frame="testframe"
+ id="embedtest" style="width: 400px; height: 100px;"
+ type="application/x-test"></embed>
+ </body>
+ </html>
diff --git a/dom/plugins/test/mochitest/test_pluginstream_err.html b/dom/plugins/test/mochitest/test_pluginstream_err.html
new file mode 100644
index 000000000..0ac2a5efc
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_pluginstream_err.html
@@ -0,0 +1,165 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=517078
+
+Tests for plugin stream error conditions.
+-->
+<head>
+ <title>NPAPI Stream Error Tests</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="runNextTest()">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=517078">
+ Mozilla Bug 517078</a> - Plugin Stream Error Tests
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<div id="test">
+<script class="testbody" type="text/javascript">
+////
+// These tests verify that nothing "bad" happens when a plugin returns an
+// error from one of the NPP_ stream functions. "Bad" is defined here
+// as the plugin being terminated, or NPP_ stream functions being
+// called inappropriately by the browser after the plugin has returned
+// a stream error.
+//
+
+function $(id) { return document.getElementById(id); }
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+
+var tests = [
+ {
+ "src": "loremipsum.txt",
+ "streammode": "normal",
+ "functiontofail": "npp_newstream",
+ "failurecode": "1",
+ "frame": "testframe"
+ },
+ {
+ "src": "loremipsum.txt",
+ "streammode": "normal",
+ "functiontofail": "npp_newstream",
+ "failurecode": "3",
+ "frame": "testframe"
+ },
+ {
+ "src": "loremipsum.txt",
+ "streammode": "normal",
+ "functiontofail": "npp_newstream",
+ "failurecode": "5",
+ "frame": "testframe"
+ },
+ {
+ "geturl": "loremipsum.txt",
+ "streammode": "normal",
+ "functiontofail": "npp_newstream",
+ "failurecode": "1",
+ "frame": "testframe"
+ },
+ {
+ "src": "loremipsum.txt",
+ "streammode": "normal",
+ "functiontofail": "npp_write",
+ "frame": "testframe"
+ },
+ {
+ "src": "loremipsum.txt",
+ "streammode": "asfile",
+ "functiontofail": "npp_write",
+ "frame": "testframe"
+ },
+ {
+ "src": "loremipsum.txt",
+ "streammode": "normal",
+ "functiontofail": "npp_destroystream",
+ "failurecode": "1",
+ "frame": "testframe"
+ },
+];
+
+function iframeonload(evt) {
+ var contentLength = evt.target.contentDocument.body.innerHTML.length;
+ var plugin = gTestWindow.document.getElementById("embedtest");
+ var functionToFail = plugin.getAttribute("functiontofail");
+ if (contentLength > 0) {
+ is(evt.target.contentDocument.body.innerHTML, "pass",
+ "test frame has unexpected content");
+ setTimeout(function() {
+ // This verifies that the plugin hasn't been unloaded, and that
+ // no calls to NPP_ functions have been made unexpectedly.
+ is(plugin.getError(), "pass", "plugin reported an error");
+ gTestWindow.close();
+ setTimeout(runNextTest, 10);
+ }, functionToFail == "npp_newstream" ? 500 : 10);
+ }
+}
+
+var index = 0;
+var gTestWindow;
+function runNextTest() {
+ if (index == tests.length * 2) {
+ SimpleTest.finish();
+ return;
+ }
+
+ gTestWindow = window.open("plugin_window.html",
+ "",
+ "width=620,height=320");
+}
+
+function continueTest() {
+ // We run each test as an embed and an object, as their initial stream
+ // handling differs.
+ var tag = index % 2 ? "embed" : "object";
+ var test = tests[Math.floor(index / 2)];
+
+ var p = gTestWindow.document.createElement("p");
+ p.innerHTML = "Plugin Stream Test " + index;
+ gTestWindow.document.getElementById("test").appendChild(p);
+
+ if (test.frame) {
+ var iframe = gTestWindow.document.createElement("iframe");
+ iframe.name = test.frame;
+ iframe.onload = iframeonload;
+ gTestWindow.document.getElementById("test").appendChild(iframe);
+ }
+
+ var plugin = gTestWindow.document.createElement(tag);
+ plugin.setAttribute("id", "embedtest");
+ plugin.setAttribute("style", "width: 400px; height: 100px;");
+ plugin.setAttribute("type", "application/x-test");
+ for (var name in test) {
+ if (tag == "embed") {
+ plugin.setAttribute(name, test[name]);
+ } else if (name == "src") {
+ plugin.setAttribute("data", test[name]);
+ } else {
+ var param = document.createElement("param");
+ param.name = name;
+ param.value = test[name];
+ plugin.appendChild(param);
+ }
+ }
+ gTestWindow.document.getElementById("test").appendChild(plugin);
+
+ gTestWindow.document.getElementById("test")
+ .appendChild(document.createElement("br"));
+
+ index++;
+}
+
+</script>
+</div>
+</body>
+</html>
+
diff --git a/dom/plugins/test/mochitest/test_pluginstream_geturl.html b/dom/plugins/test/mochitest/test_pluginstream_geturl.html
new file mode 100644
index 000000000..fe69427a4
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_pluginstream_geturl.html
@@ -0,0 +1,31 @@
+<html>
+<head>
+ <title>NPAPI NPN_GetURL NPStream Test</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript"
+ src="pluginstream.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <script type="text/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+
+ <iframe id="testframe" name="testframe" onload="frameLoaded()"></iframe>
+
+ <!--
+ - The plugin reports that data can be sent to
+ - it in 1024-byte chunks, and the stream is initiated by a call to
+ - NPN_GetURL.
+ -->
+ <embed geturl="loremipsum.txt" streammode="normal"
+ streamchunksize="1024" frame="testframe"
+ id="embedtest" style="width: 400px; height: 100px;"
+ type="application/x-test"></embed>
+ </body>
+ </html>
+ \ No newline at end of file
diff --git a/dom/plugins/test/mochitest/test_pluginstream_geturlnotify.html b/dom/plugins/test/mochitest/test_pluginstream_geturlnotify.html
new file mode 100644
index 000000000..ee4c2b119
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_pluginstream_geturlnotify.html
@@ -0,0 +1,30 @@
+<body>
+<head>
+ <title>NPAPI NPN_GetURLNotify Test</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript"
+ src="pluginstream.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <script type="text/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+
+ <iframe id="testframe" name="testframe" onload="frameLoaded()"></iframe>
+
+ <!--
+ - The stream is requested by
+ - the plugin using NPN_GetURLNotify, and the plugin does not send the
+ - stream back to the browser until NPP_URLNotify is called.
+ -->
+ <embed geturlnotify="loremipsum.txt" streammode="normal"
+ streamchunksize="1024" frame="testframe"
+ id="embedtest" style="width: 400px; height: 100px;"
+ type="application/x-test"></embed>
+ </body>
+ </html>
diff --git a/dom/plugins/test/mochitest/test_pluginstream_newstream.html b/dom/plugins/test/mochitest/test_pluginstream_newstream.html
new file mode 100644
index 000000000..3972fd7ed
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_pluginstream_newstream.html
@@ -0,0 +1,32 @@
+<html>
+<head>
+ <title>NPAPI NPN_NewStream NPStream Test</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript"
+ src="pluginstream.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <script type="text/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+
+ <iframe id="testframe" name="testframe" onload="frameLoaded()"></iframe>
+
+ <!--
+ - A stream is sent to the browser via NPP_NewStream, NP_NORMAL.
+ - When NPP_DestroyStream is called, the plugin sends the stream
+ - content back to the browser by calling NPN_NewStream and
+ - NPN_Write. The stream content should be displayed in the specified
+ - frame.
+ -->
+ <embed src="loremipsum.txt" streammode="normal"
+ newstream="true" frame="testframe"
+ id="embedtest" style="width: 400px; height: 100px;"
+ type="application/x-test"></embed>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_pluginstream_post.html b/dom/plugins/test/mochitest/test_pluginstream_post.html
new file mode 100644
index 000000000..da12ff3b0
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_pluginstream_post.html
@@ -0,0 +1,33 @@
+<html>
+<head>
+ <title>NPAPI NPN_PostURL NPStream Test</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript"
+ src="pluginstream.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <script type="text/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+
+ <iframe id="testframe" name="testframe" onload="frameLoaded()"></iframe>
+
+ <!--
+ - In this test, a stream is sent to the plugin via NPP_NewStream,
+ - NP_NORMAL. When the stream is destroyed, the plugin posts the
+ - stream content to post.sjs via NPN_PostURL, with a frame specified
+ - to display the post's response. Post.sjs just reflects
+ - the body of the post back in the HTTP response, so the original
+ - stream content should end up being displayed in the frame.
+ -->
+ <embed src="loremipsum.txt" streammode="normal"
+ frame="testframe" posturl="post.sjs" postmode="frame"
+ id="embedtest" style="width: 400px; height: 100px;"
+ type="application/x-test"></embed>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_pluginstream_poststream.html b/dom/plugins/test/mochitest/test_pluginstream_poststream.html
new file mode 100644
index 000000000..ed2e8ce2c
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_pluginstream_poststream.html
@@ -0,0 +1,31 @@
+<html>
+<head>
+ <title>NPAPI NPN_PostURL NPStream Test</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript"
+ src="pluginstream.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <script type="text/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+
+ <iframe id="testframe" name="testframe" onload="frameLoaded()"></iframe>
+
+ <!--
+ - Same as test_pluginstream_post.html, except NULL is passed to NPN_PostURL
+ - as the frame parameter, so the HTTP response to the post is passed to the
+ - plugin via NPP_NewStream. Once this stream is received, it's displayed
+ - in a frame in the browser via a call to NPN_GetURL.
+ -->
+ <embed src="loremipsum.txt" streammode="normal"
+ frame="testframe" posturl="post.sjs" postmode="stream"
+ id="embedtest" style="width: 400px; height: 100px;"
+ type="application/x-test"></embed>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_pluginstream_referer.html b/dom/plugins/test/mochitest/test_pluginstream_referer.html
new file mode 100644
index 000000000..e1b63fb95
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_pluginstream_referer.html
@@ -0,0 +1,55 @@
+<head>
+ <title>Do plugin stream requests send the Referer header correctly?</title>
+ <script type="application/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+
+<body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var pending = 3;
+ function testDone() {
+ --pending;
+ if (0 == pending)
+ SimpleTest.finish()
+ }
+
+ function runTests() {
+ var p = document.getElementById('plugin1');
+ var p2 = document.getElementById('plugin2');
+
+ ok(p.streamTest('plugin-stream-referer.sjs', false, null, null,
+ function(r, t) {
+ is(r, 0, "GET plugin-stream-referer.sjs");
+ is(t, "Referer found: " + window.location,
+ "GET Referer correct");
+ testDone();
+ }, null, true), "referer GET");
+
+ ok(p.streamTest('plugin-stream-referer.sjs', true, "Dummy Data", null,
+ function(r, t) {
+ is(r, 0, "POST plugin-stream-referer.sjs");
+ is(t, "No Referer found", "POST Referer absent");
+ testDone();
+ }, null, true), "referer POST");
+
+ ok(p2.streamTest('plugin-stream-referer.sjs', false, null, null,
+ function(r, t) {
+ is(r, 0, "GET plugin-stream-referer.sjs (2)");
+ var expectedreferer = String(window.location).replace("test_pluginstream_referer.html", "loremipsum.xtest");
+ is(t, "Referer found: " + expectedreferer,
+ "GET Referer correct with plugin src");
+ testDone();
+ }, null, true), "referer GET (2)");
+
+ }
+ </script>
+
+ <p id="display"></p>
+
+ <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+ <embed id="plugin2" type="application/x-test" src="loremipsum.xtest" width="200" height="200"></embed>
diff --git a/dom/plugins/test/mochitest/test_pluginstream_seek.html b/dom/plugins/test/mochitest/test_pluginstream_seek.html
new file mode 100644
index 000000000..6915a766e
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_pluginstream_seek.html
@@ -0,0 +1,33 @@
+<body>
+<head>
+ <title>NPAPI Seekable NPStream Test</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript"
+ src="pluginstream.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <script type="text/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+
+ <iframe id="testframe" name="testframe" onload="frameLoaded()"></iframe>
+
+ <!--
+ - Tests a seekable stream. Calls NPN_RequestRead with the specified
+ - range, and verifies that an NPP_Write call is made with the correct
+ - parameters, including the buffer data for the byte range. Once all
+ - calls to NPP_Write have finished, the plugin calls NPN_DestroyStream
+ - and then displays the entire stream's content in a browser frame via
+ - NPN_GetURL.
+ -->
+ <embed src="loremipsum.txt" streammode="seek"
+ frame="testframe" streamchunksize="1024" range="100,100"
+ id="embedtest" style="width: 400px; height: 100px;"
+ type="application/x-test"></embed>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/plugins/test/mochitest/test_pluginstream_seek_close.html b/dom/plugins/test/mochitest/test_pluginstream_seek_close.html
new file mode 100644
index 000000000..46fd3962a
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_pluginstream_seek_close.html
@@ -0,0 +1,45 @@
+<body>
+<head>
+ <title>NPAPI Seekable NPStream Test</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+<script>
+ SimpleTest.expectAssertions(0, 1);
+
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function frameLoaded() {
+ var testframe = document.getElementById('testframe');
+ var content = testframe.contentDocument.body.innerHTML;
+ if (!content.length)
+ return;
+
+ ok(true, "We didn't crash");
+ SimpleTest.finish();
+ }
+</script>
+</head>
+<body>
+ <p id="display"></p>
+
+ <iframe id="testframe" name="testframe" onload="frameLoaded()"></iframe>
+
+ <!--
+ - Tests a seekable stream. Calls NPN_RequestRead with the specified
+ - range, and verifies that an NPP_Write call is made with the correct
+ - parameters, including the buffer data for the byte range. Once all
+ - calls to NPP_Write have finished, the plugin calls NPN_DestroyStream
+ - and then displays the entire stream's content in a browser frame via
+ - NPN_GetURL.
+ -->
+ <embed src="neverending.sjs" streammode="seek" closestream
+ frame="testframe" streamchunksize="1024" range="100,100"
+ id="embedtest" style="width: 400px; height: 100px;"
+ type="application/x-test"></embed>
+
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_pluginstream_src.html b/dom/plugins/test/mochitest/test_pluginstream_src.html
new file mode 100644
index 000000000..cf934d022
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_pluginstream_src.html
@@ -0,0 +1,33 @@
+<html>
+<head>
+ <title>NPAPI src="" NPStream Test</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript"
+ src="pluginstream.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <script type="text/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+
+ <iframe id="testframe" name="testframe" onload="frameLoaded()"></iframe>
+
+ <!--
+ - A stream is sent to the browser via NPP_NewStream, NP_NORMAL.
+ - The plugin reports that data can only be sent to it in 100-byte
+ - chunks. When NPP_DestroyStream is called, the plugin sends the stream
+ - content back to the browser by passing it as a data: url to
+ - NPN_GetURL, using a frame, so that the stream content should
+ - be displayed in the frame in the browser.
+ -->
+ <embed src="loremipsum.txt" streammode="normal"
+ streamchunksize="100" frame="testframe"
+ id="embedtest" style="width: 400px; height: 100px;"
+ type="application/x-test"></embed>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/plugins/test/mochitest/test_pluginstream_src_dynamic.html b/dom/plugins/test/mochitest/test_pluginstream_src_dynamic.html
new file mode 100644
index 000000000..2a7db9916
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_pluginstream_src_dynamic.html
@@ -0,0 +1,43 @@
+<html>
+<head>
+ <title>NPAPI src="" NPStream Test</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript"
+ src="pluginstream.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <script type="text/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+
+ <iframe id="testframe" name="testframe" onload="frameLoaded()"></iframe>
+
+ <!--
+ - A stream is sent to the browser via NPP_NewStream, NP_NORMAL.
+ - The plugin reports that data can only be sent to it in 100-byte
+ - chunks. When NPP_DestroyStream is called, the plugin sends the stream
+ - content back to the browser by passing it as a data: url to
+ - NPN_GetURL, using a frame, so that the stream content should
+ - be displayed in the frame in the browser.
+ -
+ - We create the object element dynamically, which in some cases has caused us to deliver the data=""
+ - stream twice. This verifies that we only deliver the data="" stream once.
+ -->
+
+ <script type="text/javascript">
+ var e = document.createElement('object');
+ e.setAttribute('data', 'loremipsum.xtest');
+ e.setAttribute('type', 'application/x-test');
+ e.setAttribute('streammode', 'normal');
+ e.setAttribute('streamchunksize', '100');
+ e.setAttribute('frame', 'testframe');
+ e.setAttribute('style', 'width: 400px; height: 100px;');
+ document.body.appendChild(e);
+ </script>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_pluginstream_src_referer.html b/dom/plugins/test/mochitest/test_pluginstream_src_referer.html
new file mode 100644
index 000000000..9e96016ff
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_pluginstream_src_referer.html
@@ -0,0 +1,30 @@
+<head>
+ <title>Do plugin stream src requests send the Referer header correctly?</title>
+ <script type="application/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+
+<body>
+ <p id="display"></p>
+
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function frameLoaded() {
+ var testframe = document.getElementById('pluginframe');
+ var content = testframe.contentDocument.body.innerHTML;
+ if (!content.length)
+ return;
+
+ is(content, "Referer found: " + window.location);
+ SimpleTest.finish();
+ }
+ </script>
+
+ <iframe name="pluginframe" id="pluginframe" onload="frameLoaded()"></iframe>
+
+ <embed id="plugin" type="application/x-test" src="plugin-stream-referer.sjs" width="200" height="200" frame="pluginframe"></embed>
+
diff --git a/dom/plugins/test/mochitest/test_positioning.html b/dom/plugins/test/mochitest/test_positioning.html
new file mode 100644
index 000000000..4a4fc1d3d
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_positioning.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Test whether windowless plugins receive correct visible/invisible notifications.</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <style type="text/css">
+ body {
+ height: 10000px;
+ }
+ </style>
+
+<body onload="startTest()">
+ <p id="display"></p>
+
+ <script type="application/javascript;version=1.8">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var p = null;
+
+ function startTest() {
+ p = document.getElementById('theplugin');
+
+ // Wait for the plugin to have painted once
+ var interval = setInterval(function() {
+ if (!p.getPaintCount())
+ return;
+
+ clearInterval(interval);
+ doScroll();
+ }, 100);
+ }
+
+ const kScrollAmount = 1000;
+ var startY;
+
+ function doScroll() {
+ let [x, y, w, h] = p.getWindowPosition();
+ startY = y;
+
+ scrollBy(0, kScrollAmount);
+ setTimeout(checkScroll, 500);
+ }
+
+ function checkScroll() {
+ let [x, y, w, h] = p.getWindowPosition();
+
+ is(y, startY - kScrollAmount, "Window should be informed of its new position.");
+ SimpleTest.finish();
+ }
+ </script>
+
+ <embed id="theplugin" type="application/x-test" width="200" height="200"></embed>
diff --git a/dom/plugins/test/mochitest/test_privatemode_perwindowpb.xul b/dom/plugins/test/mochitest/test_privatemode_perwindowpb.xul
new file mode 100644
index 000000000..ae6c9d292
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_privatemode_perwindowpb.xul
@@ -0,0 +1,120 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window title="NPAPI Private Mode Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+ <script type="application/javascript"
+ src="chrome://mochikit/content/chrome-harness.js" />
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <script type="application/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+<body xmlns="http://www.w3.org/1999/xhtml" onload="runTests()">
+<embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+<embed id="plugin2" type="application/x-test" width="200" height="200"></embed>
+</body>
+<script class="testbody" type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+
+function runTests() {
+ // Allow all cookies, then run the actual tests
+ SpecialPowers.pushPrefEnv({"set": [["network.cookie.cookieBehavior", 0]]}, runTestsCallback);
+}
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+function whenDelayedStartupFinished(aWindow, aCallback) {
+ Services.obs.addObserver(function observer(aSubject, aTopic) {
+ if (aWindow == aSubject) {
+ Services.obs.removeObserver(observer, aTopic);
+ SimpleTest.executeSoon(aCallback);
+ }
+ }, "browser-delayed-startup-finished", false);
+}
+
+function runTestsCallback() {
+ var pluginElement1 = document.getElementById("plugin1");
+ var pluginElement2 = document.getElementById("plugin2");
+
+ var state1 = false;
+ var state2 = false;
+ var exceptionThrown = false;
+
+ try {
+ state1 = pluginElement1.queryPrivateModeState();
+ state2 = pluginElement2.queryPrivateModeState();
+ } catch (e) {
+ exceptionThrown = true;
+ }
+ is(exceptionThrown, false, "Exception thrown getting private mode state.");
+ is(state1, false, "Browser returned incorrect private mode state.");
+ is(state2, false, "Browser returned incorrect private mode state.");
+
+ pluginElement1.setCookie("foo");
+ is(pluginElement1.getCookie(), "foo", "Cookie was set and retrieved correctly in public mode.");
+
+ // open a window with private mode and get the references of the elements.
+ var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShellTreeItem)
+ .rootTreeItem
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow);
+ var contentPage = getRootDirectory(window.location.href) + "privatemode_perwindowpb.xul";
+
+ function testOnWindow(aIsPrivate, aCallback) {
+ var win = mainWindow.OpenBrowserWindow({private: aIsPrivate});
+ whenDelayedStartupFinished(win, function () {
+ win.addEventListener("DOMContentLoaded", function onInnerLoad() {
+ if (win.content.location.href == "about:privatebrowsing") {
+ win.gBrowser.loadURI(contentPage);
+ return;
+ }
+ win.removeEventListener("DOMContentLoaded", onInnerLoad, true);
+ win.gBrowser.selectedBrowser.focus();
+ SimpleTest.executeSoon(function() { aCallback(win); });
+ }, true);
+ SimpleTest.executeSoon(function() { win.gBrowser.loadURI(contentPage); });
+ });
+ }
+
+ testOnWindow(true, function(aWin) {
+ pluginElement1 = aWin.gBrowser.contentDocument.getElementById("plugin1");
+ pluginElement2 = aWin.gBrowser.contentDocument.getElementById("plugin2");
+
+ var officialState1, officialState2;
+ try {
+ officialState1 = pluginElement1.queryPrivateModeState();
+ officialState2 = pluginElement2.queryPrivateModeState();
+ } catch (e) {
+ exceptionThrown = true;
+ }
+ is(exceptionThrown, false, "Exception thrown getting private mode state.");
+ is(officialState1, true, "Querying private mode reported incorrectly");
+ is(officialState2, true, "Querying private mode reported incorrectly");
+
+ // It would be nice to assert that we don't see the public cookie in private mode,
+ // but the NPAPI complains when the resulting string is empty.
+ // is(pluginElement1.getCookie(), "", "Public cookie was not retrieved in private mode.");
+ pluginElement1.setCookie("bar");
+ is(pluginElement1.getCookie(), "bar", "Cookie was set and retrieved correctly in private mode.");
+
+ aWin.close();
+
+ pluginElement1 = document.getElementById("plugin1");
+ is(pluginElement1.getCookie(), "foo", "Private cookie was not retrieved in public mode.");
+
+ SimpleTest.finish();
+ });
+}
+]]>
+</script>
+</window>
diff --git a/dom/plugins/test/mochitest/test_propertyAndMethod.html b/dom/plugins/test/mochitest/test_propertyAndMethod.html
new file mode 100644
index 000000000..6e638e419
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_propertyAndMethod.html
@@ -0,0 +1,51 @@
+<html>
+ <head>
+ <title>NPObject with property and method with the same name</title>
+
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ </head>
+
+ <body onload="run()">
+
+ <script class="testbody" type="application/javascript">
+ if (typeof Object.getPrototypeOf !== "function") {
+ if (typeof "test".__proto__ === "object") {
+ Object.getPrototypeOf = function(object) {
+ return object.__proto__;
+ };
+ } else {
+ Object.getPrototypeOf = function(object) {
+ // May break if the constructor has been tampered with
+ return object.constructor.prototype;
+ };
+ }
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function run() {
+ var plugin = document.getElementById("plugin");
+ var pluginProto = Object.getPrototypeOf(plugin);
+
+ delete pluginProto.propertyAndMethod;
+ ok(isNaN(plugin.propertyAndMethod + 0), "Shouldn't be set yet!");
+
+ plugin.propertyAndMethod = 5;
+ is(+plugin.propertyAndMethod, 5, "Should be set to 5!");
+
+ delete pluginProto.propertyAndMethod;
+ ok(isNaN(plugin.propertyAndMethod + 0), "Shouldn't be set any more!");
+
+ var res = plugin.propertyAndMethod();
+ is(res, 5, "Method invocation should return 5!");
+
+ SimpleTest.finish();
+ }
+ </script>
+
+ <embed id="plugin" type="application/x-test" wmode="window"></embed>
+ </body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_queryCSSZoomFactor.html b/dom/plugins/test/mochitest/test_queryCSSZoomFactor.html
new file mode 100644
index 000000000..682d23ae6
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_queryCSSZoomFactor.html
@@ -0,0 +1,48 @@
+<html>
+ <head>
+ <title>NPAPI NPNVcontentsScaleFactor Test</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ </head>
+
+ <body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function checkZoomFactor(zoomFactor, expectedValue) {
+ // Done as if/ok instead of is() so we don't spam test results
+ if (isNaN(zoomFactor)) {
+ ok(false, "Return should be valid when getting CSS zoom factor");
+ }
+ return (expectedValue - zoomFactor) < 0.00001;
+ }
+
+ function testZoom() {
+ var pluginElement = document.getElementById("plugin");
+ // setTimeout loop on value checks, as zoom value updates can take some
+ // time and we don't have a good event to listen for.
+ if (!checkZoomFactor(pluginElement.queryCSSZoomFactorGetValue(), 2.0) ||
+ !checkZoomFactor(pluginElement.queryCSSZoomFactorSetValue(), 2.0)) {
+ setTimeout(testZoom, 0);
+ return;
+ }
+ ok(true, "Zoom values set to 2.0 as expected");
+ // set back to 1 when we're done otherwise later tests can fail
+ SpecialPowers.setFullZoom(window, 1.0);
+ SimpleTest.finish();
+ }
+
+ function runTests() {
+ var pluginElement = document.getElementById("plugin");
+ // Don't check SetValue yet, needs to happen after zoom has been explicitly set.
+ ok(checkZoomFactor(pluginElement.queryCSSZoomFactorGetValue(), 1.0), "Zoom values set to 1.0 as expected");
+ SpecialPowers.setFullZoom(window, 2.0);
+ // Check for new zoom value sometime after we've spun event loop to repaint.
+ setTimeout(testZoom, 0);
+ }
+ </script>
+
+ <embed id="plugin" type="application/x-test" width="400" height="400"></embed>
+ </body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_queryContentsScaleFactor.html b/dom/plugins/test/mochitest/test_queryContentsScaleFactor.html
new file mode 100644
index 000000000..c1f8919ab
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_queryContentsScaleFactor.html
@@ -0,0 +1,31 @@
+<html>
+<head>
+ <title>NPAPI NPNVcontentsScaleFactor Test</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+</head>
+
+<body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function runTests() {
+ var pluginElement = document.getElementById("plugin");
+ var contentsScaleFactor;
+ var exceptionThrown = false;
+ try {
+ contentsScaleFactor = pluginElement.queryContentsScaleFactor();
+ } catch (e) {
+ exceptionThrown = true;
+ }
+ is(exceptionThrown, false, "Exception thrown getting contents scale factor.");
+ is(isNaN(contentsScaleFactor), false, "Invalid return getting contents scale factor");
+ ok(true, "Got Scale Factor of " + contentsScaleFactor);
+ SimpleTest.finish();
+ }
+ </script>
+
+ <embed id="plugin" type="application/x-test" width="400" height="400"></embed>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_queryContentsScaleFactorWindowed.html b/dom/plugins/test/mochitest/test_queryContentsScaleFactorWindowed.html
new file mode 100644
index 000000000..6f11332cb
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_queryContentsScaleFactorWindowed.html
@@ -0,0 +1,31 @@
+<html>
+<head>
+ <title>NPAPI NPNVcontentsScaleFactor Test</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="utils.js"></script>
+</head>
+
+<body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function runTests() {
+ var pluginElement = document.getElementById("plugin");
+ var contentsScaleFactor;
+ var exceptionThrown = false;
+ try {
+ contentsScaleFactor = pluginElement.queryContentsScaleFactor();
+ } catch (e) {
+ exceptionThrown = true;
+ }
+ is(exceptionThrown, false, "Exception thrown getting contents scale factor.");
+ is(isNaN(contentsScaleFactor), false, "Invalid return getting contents scale factor");
+ ok(true, "Got Scale Factor of " + contentsScaleFactor);
+ SimpleTest.finish();
+ }
+ </script>
+
+ <embed id="plugin" type="application/x-test" width="400" height="400" wmode="window"></embed>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_redirect_handling.html b/dom/plugins/test/mochitest/test_redirect_handling.html
new file mode 100644
index 000000000..7d60ec06e
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_redirect_handling.html
@@ -0,0 +1,67 @@
+<html>
+<head>
+ <title>Basic NPAPI Redirect Handling</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+</head>
+<body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var p = null;
+
+ var redirectingURL = "307-xo-redirect.sjs";
+ var redirectTargetURL = "http://example.org/tests/dom/plugins/test/mochitest/loremipsum.txt";
+
+ var expectedWriteURL = "";
+ var expectedNotifyStatus = -1;
+
+ function redirectCallback(url, httpStatus) {
+ is(url, redirectTargetURL, "Test for expected redirect notify URL.");
+ is(httpStatus, 307, "Test for expected http redirect status.");
+ }
+
+ function writeCallback(url) {
+ is(url, expectedWriteURL, "Test for expected stream write URL.");
+ }
+
+ function notifyCallback(status, data) {
+ is(status, expectedNotifyStatus, "Test for expected stream notification status.");
+ runNextTest();
+ }
+
+ function test1() {
+ expectedWriteURL = "";
+ expectedNotifyStatus = 2;
+
+ p.streamTest(redirectingURL, false, null, writeCallback, notifyCallback, redirectCallback, false);
+ }
+
+ function test2() {
+ expectedWriteURL = redirectTargetURL;
+ expectedNotifyStatus = 0;
+
+ p.streamTest(redirectingURL, false, null, writeCallback, notifyCallback, redirectCallback, true);
+ }
+
+ var tests = [test1, test2];
+ var currentTest = -1;
+ function runNextTest() {
+ currentTest++;
+ if (currentTest < tests.length) {
+ tests[currentTest]();
+ } else {
+ SimpleTest.finish();
+ }
+ }
+
+ function runTests() {
+ p = document.getElementById("plugin1");
+ runNextTest();
+ }
+ </script>
+
+ <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_refresh_navigator_plugins.html b/dom/plugins/test/mochitest/test_refresh_navigator_plugins.html
new file mode 100644
index 000000000..e39b3217a
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_refresh_navigator_plugins.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<!-- bug 820708 -->
+<html>
+ <head>
+ <meta><charset="utf-8"/>
+ <title>Test Refreshing navigator.plugins (bug 820708)</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ </head>
+ <body>
+ <script class="testbody" type="application/javascript">
+ "use strict";
+
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var pluginHost = Components.classes["@mozilla.org/plugin/host;1"]
+ .getService(Components.interfaces.nsIPluginHost);
+ var pluginTags = pluginHost.getPluginTags();
+ var nextTest = null;
+ var obsService = Components.classes["@mozilla.org/observer-service;1"]
+ .getService(Components.interfaces.nsIObserverService);
+ var observer = {
+ observe: function(aSubject, aTopic, aData) {
+ if (aTopic == "plugin-info-updated") {
+ SimpleTest.executeSoon(nextTest);
+ }
+ }
+ };
+ obsService.addObserver(observer, "plugin-info-updated", false);
+
+ var navTestPlugin1 = navigator.plugins.namedItem("Test Plug-in");
+ ok(navTestPlugin1, "navigator.plugins should have Test Plug-in");
+ var tagTestPlugin = null;
+ for (var plugin of pluginTags) {
+ if (plugin.name == navTestPlugin1.name) {
+ tagTestPlugin = plugin;
+ break;
+ }
+ }
+ ok(tagTestPlugin, "plugin tags should have Test Plug-in");
+ var mimeType = tagTestPlugin.getMimeTypes()[0];
+ ok(mimeType, "should have a MIME type for Test Plug-in");
+ ok(navigator.mimeTypes[mimeType], "navigator.mimeTypes should have an entry for '" + mimeType + "'");
+ ok(!tagTestPlugin.disabled, "test plugin should not be disabled");
+
+ nextTest = testPart2;
+ tagTestPlugin.enabledState = Components.interfaces.nsIPluginTag.STATE_DISABLED;
+
+ function testPart2() {
+ var navTestPlugin2 = navigator.plugins.namedItem("Test Plug-in");
+ ok(!navTestPlugin2, "now navigator.plugins should not have Test Plug-in");
+ ok(!navigator.mimeTypes[mimeType], "now navigator.mimeTypes should not have an entry for '" + mimeType + "'");
+
+ nextTest = testPart3;
+ tagTestPlugin.enabledState = Components.interfaces.nsIPluginTag.STATE_ENABLED;
+ }
+
+ function testPart3() {
+ var navTestPlugin3 = navigator.plugins.namedItem("Test Plug-in");
+ ok(navTestPlugin3, "now navigator.plugins should have Test Plug-in again");
+ ok(navigator.mimeTypes[mimeType], "now navigator.mimeTypes should have an entry for '" + mimeType + "' again");
+ obsService.removeObserver(observer, "plugin-info-updated");
+ SimpleTest.finish();
+ }
+ </script>
+ </body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_secondPlugin.html b/dom/plugins/test/mochitest/test_secondPlugin.html
new file mode 100644
index 000000000..4c1f051ca
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_secondPlugin.html
@@ -0,0 +1,73 @@
+<html>
+ <head>
+ <title>Second Test Plug-in Test</title>
+
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ </head>
+
+ <body onload="run()">
+ <script class="testbody" type="application/javascript">
+ "use strict";
+
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_DISABLED, "Second Test Plug-in");
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Java Test Plug-in");
+
+ function findPlugin(pluginName) {
+ for (var i = 0; i < navigator.plugins.length; i++) {
+ var plugin = navigator.plugins[i];
+ if (plugin.name === pluginName) {
+ return plugin;
+ }
+ }
+ return null;
+ }
+
+ function findMimeType(mimeTypeType) {
+ for (var i = 0; i < navigator.mimeTypes.length; i++) {
+ var mimeType = navigator.mimeTypes[i];
+ if (mimeType.type === mimeTypeType) {
+ return mimeType;
+ }
+ }
+ return null;
+ }
+
+ function run() {
+ var pluginElement = document.getElementById("plugin");
+ is(pluginElement.identifierToStringTest("foo"), "foo", "Should be able to call a function provided by the plugin");
+
+ pluginElement = document.getElementById("disabledPlugin");
+ is(typeof pluginElement.identifierToStringTest, "undefined", "Should NOT be able to call a function on a disabled plugin");
+
+ pluginElement = document.getElementById("clickToPlayPlugin");
+ is(typeof pluginElement.identifierToStringTest, "undefined", "Should NOT be able to call a function on a click-to-play plugin");
+
+ ok(navigator.plugins["Test Plug-in"], "Should have queried a plugin named 'Test Plug-in'");
+ ok(!navigator.plugins["Second Test Plug-in"], "Should NOT have queried a disabled plugin named 'Second Test Plug-in'");
+ ok(navigator.plugins["Java Test Plug-in"], "Should have queried a click-to-play plugin named 'Java Test Plug-in'");
+
+ ok(findPlugin("Test Plug-in"), "Should have found a plugin named 'Test Plug-in'");
+ ok(!findPlugin("Second Test Plug-in"), "Should NOT found a disabled plugin named 'Second Test Plug-in'");
+ ok(findPlugin("Java Test Plug-in"), "Should have found a click-to-play plugin named 'Java Test Plug-in'");
+
+ ok(navigator.mimeTypes["application/x-test"], "Should have queried a MIME type named 'application/x-test'");
+ ok(!navigator.mimeTypes["application/x-second-test"], "Should NOT have queried a disabled type named 'application/x-second-test'");
+ ok(navigator.mimeTypes["application/x-java-test"], "Should have queried a click-to-play MIME type named 'application/x-java-test'");
+
+ ok(findMimeType("application/x-test"), "Should have found a MIME type named 'application/x-test'");
+ ok(!findMimeType("application/x-second-test"), "Should NOT have found a disabled MIME type named 'application/x-second-test'");
+ ok(findMimeType("application/x-java-test"), "Should have found a click-to-play MIME type named 'application/x-java-test'");
+
+ SimpleTest.finish();
+ }
+ </script>
+
+ <object id="plugin" type="application/x-test" width=200 height=200></object>
+ <object id="disabledPlugin" type="application/x-second-test" width=200 height=200></object>
+ <object id="clickToPlayPlugin" type="application/x-java-test" width=200 height=200></object>
+ </body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_src_url_change.html b/dom/plugins/test/mochitest/test_src_url_change.html
new file mode 100644
index 000000000..8e8f4d326
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_src_url_change.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Test changing src attribute</title>
+ <script type="text/javascript" src="/MochiKit/packed.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="runTests()">
+ <script type="application/javascript;version=1.8">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var destroyed = false;
+ function onDestroy() {
+ destroyed = true;
+ }
+
+ function runTests() {
+ p = document.getElementById('plugin1');
+
+ p.startWatchingInstanceCount();
+ p.callOnDestroy(onDestroy);
+
+ p.setAttribute("src", "loremipsum.txt");
+
+ is(destroyed, true, "Instance should have been destroyed.");
+ is(p.getInstanceCount(), 1, "One new instance should have been created.");
+
+ p.stopWatchingInstanceCount();
+
+ SimpleTest.finish();
+ }
+ </script>
+
+ <p id="display"></p>
+
+ <embed id="plugin1" src="about:blank" type="application/x-test" width="200" height="200"></embed>
+</body>
+</html>
+
diff --git a/dom/plugins/test/mochitest/test_streamNotify.html b/dom/plugins/test/mochitest/test_streamNotify.html
new file mode 100644
index 000000000..d1aa8be8d
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_streamNotify.html
@@ -0,0 +1,89 @@
+<head>
+ <title>NPN_Get/PostURLNotify tests</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+
+<body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.requestFlakyTimeout("untriaged");
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var pending = 5;
+ function testDone() {
+ dump("testDone: " + pending + "\n")
+ --pending;
+
+ // Wait for a bit so that any unexpected notifications from the
+ // malformed data or null-post tests are received.
+ if (0 == pending)
+ window.setTimeout(SimpleTest.finish, 2000);
+ }
+
+ function runTests() {
+ var p = document.getElementById('plugin1');
+
+ ok(p.streamTest("loremipsum.txt", false, null, null,
+ function(r, t) {
+ is(r, 0, "GET loremipsum.txt");
+ is(t.substr(0, 11), "Lorem ipsum",
+ "GET loremipsum.txt correct");
+ testDone();
+ }, null, true), "streamTest GET");
+
+ ok(!p.streamTest("post.sjs", true, null, null,
+ function(r, t) {
+ ok(false, "Shouldn't get callback from null post");
+ }, null, true), "streamTest POST null postdata");
+
+ ok(p.streamTest("post.sjs", true, "Something good", null,
+ function(r, t) {
+ is(r, 0, "POST something good");
+ is(t, "Something good", "POST non-null correct");
+ testDone();
+ }, null, true), "streamTest POST valid postdata");
+
+ ok(p.streamTest("http://example.invalid/", false, null, null,
+ function(r, t) {
+ is(r, 1, "Shouldn't load example.invalid DNS name");
+ testDone();
+ }, null, true), "streamTest GET bad DNS");
+
+ ok(!p.streamTest("http://localhost:-8/", false, null, null,
+ function(r, t) {
+ ok(false, "Shouldn't get callback from malformed URI");
+ }, null, true), "streamTest GET invalid URL");
+
+ ok(p.streamTest("javascript:'Hello';", false, null, null,
+ function(r, t) {
+ is(r, 0, "GET javascript: URI");
+ is(t, "Hello", "GET javascript: URI correct");
+ testDone();
+ }, null, true), "streamTest GET javascript: URI");
+
+/*
+ * XXX/cjones: disabled for now because it appears to be hard to make
+ * mochitest ignore the malformed javascript
+
+ ok(!p.streamTest("javascript:syntax##$&*@error-*", false, null,
+ function(r, t) {
+ is(r, 1, "Shouldn't load invalid javascript: URI");
+ testDone();
+ }), "streamTest GET bad javascript: URI");
+*/
+
+ ok(p.streamTest("data:text/plain,World", false, null, null,
+ function(r, t) {
+ is(r, 0, "GET data: URI");
+ is(t, "World", "GET data: URI correct");
+ testDone();
+ }, null, true), "streamTest GET data: URI");
+
+ ok(!p.streamTest("data:malformed?", false, null, null,
+ function(r, t) {
+ todo(false, "Shouldn't get callback for invalid data: URI");
+ }, null, true), "streamTest GET bad data: URI");
+ }
+ </script>
+
+ <embed id="plugin1" type="application/x-test" width="400" height="400"></embed>
diff --git a/dom/plugins/test/mochitest/test_streamatclose.html b/dom/plugins/test/mochitest/test_streamatclose.html
new file mode 100644
index 000000000..f308d7d79
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_streamatclose.html
@@ -0,0 +1,46 @@
+<html>
+<head>
+ <title>Stream open at NPP_Destroy</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css">
+
+<body onload="startTest()">
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.requestFlakyTimeout("untriaged");
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var urlnotified = false;
+
+ var p = null;
+
+ function startTest() {
+ p = document.getElementById('embedtest');
+ ok(p.streamTest("neverending.sjs", false, null, null,
+ function(r, t) {
+ is(r, 2, "Stream should have failed");
+ urlnotified = true;
+ }, null, true), "neverending.sjs started successfully");
+
+ setTimeout(removePlugin, 500);
+ }
+
+ function removePlugin() {
+ document.body.removeChild(p); // Fires NPP_Destroy immediately
+ SimpleTest.executeSoon(done);
+ }
+
+ function done() {
+ ok(urlnotified, "NPP_URLNotify should be called if streams are active at NPP_Destroy");
+ SimpleTest.finish();
+ }
+
+ </script>
+
+ <p id="display"></p>
+
+ <embed id="embedtest"
+ style="width: 400px; height: 100px;" type="application/x-test"></embed>
diff --git a/dom/plugins/test/mochitest/test_stringHandling.html b/dom/plugins/test/mochitest/test_stringHandling.html
new file mode 100644
index 000000000..023fcfcb0
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_stringHandling.html
@@ -0,0 +1,35 @@
+<html>
+<head>
+ <title>NPAPI string test</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+
+<body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function runTests() {
+ try {
+ var plugin = document.getElementById("plugin1");
+ var badData = 'foo ' + '\x00'.repeat(260000);
+ var ret = plugin.echoString(badData);
+ ok(true, "Did not crash.");
+ is(ret, badData, "Returned string should equal what we passed in.");
+ } catch (e) {
+ ok(false, "Failed to call plugin.echoString() properly.");
+ } finally {
+ SimpleTest.finish();
+ }
+ }
+ </script>
+
+ <p id="display"></p>
+
+ <embed id="plugin1" type="application/x-test" width="400" height="400"></embed>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_twostreams.html b/dom/plugins/test/mochitest/test_twostreams.html
new file mode 100644
index 000000000..c2b3672c8
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_twostreams.html
@@ -0,0 +1,46 @@
+<html>
+<head>
+ <title>Dual NPAPI NP_ASFILEONLY NPStream Test</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+
+ <script type="text/javascript">
+ SimpleTest.expectAssertions(0, 2);
+
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var framesToLoad = 2;
+ function frameLoaded(id) {
+ var frame = document.getElementById('testframe' + id);
+ if (!frame.contentDocument.body.innerHTML.length)
+ return;
+
+ --framesToLoad;
+ if (0 == framesToLoad) {
+ is(document.getElementById('testframe1').contentDocument.body.innerHTML,
+ document.getElementById('testframe2').contentDocument.body.innerHTML,
+ "Frame contents should match");
+ SimpleTest.finish();
+ }
+ }
+ </script>
+
+ <iframe id="testframe1" name="testframe1" onload="frameLoaded(1)"></iframe>
+ <iframe id="testframe2" name="testframe2" onload="frameLoaded(2)"></iframe>
+
+ <embed src="loremipsum_nocache.txt" streammode="asfileonly"
+ frame="testframe1"
+ id="embedtest" style="width: 400px; height: 100px;"
+ type="application/x-test"></embed>
+ <embed src="loremipsum_nocache.txt" streammode="asfileonly"
+ frame="testframe2"
+ id="embedtest2" style="width: 400px; height: 100px;"
+ type="application/x-test"></embed>
+
diff --git a/dom/plugins/test/mochitest/test_visibility.html b/dom/plugins/test/mochitest/test_visibility.html
new file mode 100644
index 000000000..943fddaf4
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_visibility.html
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Test whether windowless plugins receive correct visible/invisible notifications.</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <style>
+ .hidden { visibility: hidden; }
+ </style>
+
+<body onload="startTest()">
+ <p id="display"></p>
+
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <script type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.requestFlakyTimeout("untriaged");
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var didPaint = function() {};
+
+ function startTest() {
+ if (p.getPaintCount() < 1) {
+ setTimeout(startTest, 0);
+ return;
+ }
+
+ didPaint = function() {
+ ok(false, "Plugin should not paint until it is visible!");
+ };
+
+ ok(!p.isVisible(), "Plugin should not be visible.");
+ paintCountIs(p, 0, "Plugin should not have painted.");
+
+ didPaint = part2;
+
+ p.style.visibility = 'visible';
+ }
+
+ function part2() {
+ ok(p.isVisible(), "Plugin should now be visible.");
+ paintCountIs(p, 1, "Plugin should have painted once.");
+
+ didPaint = part3;
+
+ p.setColor('FF0000FF'); // this causes an invalidate/repaint
+ }
+
+ const kTimeout = 5000; // 5 seconds
+ var part4GiveUp;
+ var part4Interval;
+
+ function part3() {
+ ok(p.isVisible(), "Plugin should still be visible.");
+ paintCountIs(p, 2, "Plugin should have painted twice.");
+
+ didPaint = function() {
+ ok(false, "Plugin should not paint when it is invisible.");
+ };
+
+ p.style.visibility = 'hidden';
+
+ part4GiveUp = Date.now() + kTimeout;
+ part4Interval = setInterval(part4, 100);
+ }
+
+ function part4() {
+ if (p.isVisible()) {
+ if (Date.now() < part4GiveUp)
+ return;
+
+ ok(false, "Plugin never became invisible in part4.");
+ SimpleTest.finish();
+ return;
+ }
+
+ clearInterval(part4Interval);
+
+ ok(true, "Plugin became invisible again.");
+ p.setColor('FF00FF00');
+ setTimeout(SimpleTest.finish, 500);
+ // wait to make sure we don't actually paint
+ }
+
+ function inPaint() {
+ // We're actually in the middle of painting the plugin so don't do anything
+ // complex here, for the sake of cases where async plugin painting isn't
+ // enabled yet
+ setTimeout(didPaint, 0);
+ // Don't run that didPaint callback again
+ didPaint = function() {};
+ }
+ </script>
+
+ <embed id="theplugin" class="hidden" type="application/x-test" drawmode="solid" color="FFFF0000" paintscript="inPaint()"></embed>
+
+ <script type="application/javascript">
+ var p = document.getElementById('theplugin');
+ </script>
diff --git a/dom/plugins/test/mochitest/test_windowed_invalidate.html b/dom/plugins/test/mochitest/test_windowed_invalidate.html
new file mode 100644
index 000000000..a19e4c8c5
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_windowed_invalidate.html
@@ -0,0 +1,66 @@
+<html>
+<head>
+ <title>Test NPN_Invalidate working for a windowed plugin</title>
+ <script type="text/javascript"
+ src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="runTests()">
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.requestFlakyTimeout("untriaged");
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var lastPaintCount;
+ var p = null;
+
+ function checkPainted() {
+ if (p.getPaintCount() > lastPaintCount) {
+ ok(true, "Plugin did repaint");
+ SimpleTest.finish();
+ } else {
+ setTimeout(checkPainted, 100);
+ }
+ }
+
+ function doTest() {
+ // Cause the plugin to invalidate itself using NPN_Invalidate,
+ // and then wait for the plugin's paintCount to increase. This is the
+ // simplest way to check that a windowed plugin has repainted.
+ p.setColor("FF00FF00");
+ checkPainted();
+ }
+
+ function checkPaintCountStabilized() {
+ // Wait for the paint count to stabilize (i.e. doesn't change for a full
+ // second), so that all buffered-up painting is hopefully finished,
+ // before running the test
+ lastPaintCount = p.getPaintCount();
+ setTimeout(function() {
+ var newCount = p.getPaintCount();
+ if (newCount == lastPaintCount) {
+ doTest();
+ } else {
+ checkPaintCountStabilized();
+ }
+ }, 1000);
+ }
+
+ function runTests() {
+ p = document.getElementById("p");
+ checkPaintCountStabilized();
+ }
+ </script>
+
+ <p id="display"></p>
+
+ <embed id="p" type="application/x-test" wmode="window" drawmode="solid"
+ color="FFFF0000">
+ </embed>
+
+ <div id="verbose">
+ </div>
+ </body>
+ </html>
diff --git a/dom/plugins/test/mochitest/test_windowless_flash.html b/dom/plugins/test/mochitest/test_windowless_flash.html
new file mode 100644
index 000000000..8274a78ae
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_windowless_flash.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="runTests()">
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ SpecialPowers.setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ function runTests() {
+ var p1 = document.getElementById('plugin1');
+ var p2 = document.getElementById('plugin2');
+ var p3 = document.getElementById('plugin3');
+ is(p1.hasWidget(), false, "Flash is always windowless mode even if wmode=window");
+ is(p2.hasWidget(), false, "Flash is always windowless mode even if wmode=anything");
+ is(p3.hasWidget(), false, "Flash is always windowless mode even if no wmode");
+ SimpleTest.finish();
+ }
+
+ </script>
+ <p id="display"></p>
+
+ <div id="div1">
+ <embed id="plugin1" type="application/x-shockwave-flash-test" width="200" height="200" wmode="window"></embed>
+ <embed id="plugin2" type="application/x-shockwave-flash-test" width="200" height="200" wmode="test"></embed>
+ <embed id="plugin3" type="application/x-shockwave-flash-test" width="200" height="200"></embed>
+ </div>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_windowless_ime.html b/dom/plugins/test/mochitest/test_windowless_ime.html
new file mode 100644
index 000000000..edc994052
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_windowless_ime.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=539565
+-->
+<head>
+ <title>Test #1 for Bug 539565</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+ <script class="testbody" type="text/javascript">
+function runTests() {
+ var plugin = document.getElementById("plugin1");
+
+ plugin.focus();
+ synthesizeComposition({ type: "compositionstart", data: "" });
+ let data = "composition";
+ synthesizeCompositionChange({
+ composition: {
+ string: data,
+ clauses: [
+ { length: data.length, attr: COMPOSITION_ATTR_RAW_CLAUSE }
+ ]
+ },
+ caret: {start: data.length, length: 0}
+ });
+ is(plugin.getLastCompositionText(), data, "can get composition string");
+ synthesizeComposition({ type: "compositioncommit", data: "" });
+
+ synthesizeComposition({ type: "compositionstart", data: "" });
+ is(plugin.getLastCompositionText(), "", "can get empty composition string");
+ synthesizeComposition({ type: "compositioncommit", data: "" });
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+</head>
+
+<body onload="runTests()">
+ <embed id="plugin1" type="application/x-test" wmode="transparent" width="200" height="200"></embed>
+</body>
+</html>
diff --git a/dom/plugins/test/mochitest/test_wmode.xul b/dom/plugins/test/mochitest/test_wmode.xul
new file mode 100644
index 000000000..b45038835
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_wmode.xul
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+<window title="WMode Tests"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+ <script type="application/javascript" src="plugin-utils.js"></script>
+ <script type="application/javascript">
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+ </script>
+<body xmlns="http://www.w3.org/1999/xhtml" onload="runTests()">
+<embed id="plugin2" type="application/x-test" width="400" height="400" wmode="window"></embed>
+<embed id="plugin1" type="application/x-test" width="400" height="400"></embed>
+</body>
+<script class="testbody" type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+function runTests() {
+ var p1 = document.getElementById("plugin1");
+ is(p1.hasWidget(), false, "Plugin should be windowless by default");
+
+ var p2 = document.getElementById("plugin2");
+ if (navigator.platform.indexOf("Mac") >= 0) {
+ is(p2.hasWidget(), false, "Mac does not support windowed plugins");
+ } else if (navigator.platform.indexOf("Win") >= 0) {
+ is(p2.hasWidget(), true, "Windows supports windowed plugins");
+ } else if (navigator.platform.indexOf("Linux") >= 0) {
+ is(p2.hasWidget(), true, "Linux supports windowed plugins");
+ }
+
+ SimpleTest.finish();
+}
+]]>
+</script>
+</window>
diff --git a/dom/plugins/test/mochitest/test_x11_error_crash.html b/dom/plugins/test/mochitest/test_x11_error_crash.html
new file mode 100644
index 000000000..1b52d1e6f
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_x11_error_crash.html
@@ -0,0 +1,27 @@
+<head>
+ <title>Plugin terminating on X11 error</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="plugin-utils.js"></script>
+
+<body>
+ <script class="testbody" type="application/javascript">
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.requestFlakyTimeout(
+ "crashAndGetCrashServiceRecord() polls for async crash recording");
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ window.frameLoaded = function frameLoaded_toCrash() {
+ SimpleTest.expectChildProcessCrash();
+
+ crashAndGetCrashServiceRecord("triggerXError", function (cm, crash) {
+ var isPluginCrash = crash.isOfType(cm.PROCESS_TYPE_PLUGIN, cm.CRASH_TYPE_CRASH);
+ ok(isPluginCrash, "Record should be a plugin crash");
+ if (!isPluginCrash) {
+ dump("Crash type: " + crash.type + "\n");
+ }
+ SimpleTest.finish();
+ });
+
+ }
+ </script>
+ <iframe id="iframe1" src="crashing_subpage.html" width="600" height="600"></iframe>
diff --git a/dom/plugins/test/mochitest/test_xulbrowser_plugin_visibility.xul b/dom/plugins/test/mochitest/test_xulbrowser_plugin_visibility.xul
new file mode 100644
index 000000000..8cccb8bf7
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_xulbrowser_plugin_visibility.xul
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+ <script type="application/javascript" src="plugin-utils.js"></script>
+
+ <script>
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var w = window.open('xulbrowser_plugin_visibility.xul', '_blank', 'chrome,resizable=yes,width=400,height=600');
+
+ function done()
+ {
+ w.close();
+ SimpleTest.finish();
+ }
+ </script>
+
+ <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;" />
+</window>
diff --git a/dom/plugins/test/mochitest/test_zero_opacity.html b/dom/plugins/test/mochitest/test_zero_opacity.html
new file mode 100644
index 000000000..c768cafd5
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_zero_opacity.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Test whether windowed plugins with opacity:0 get their window set correctly</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="plugin-utils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<body onload="startTest()">
+ <script type="application/javascript;version=1.8">
+ SimpleTest.waitForExplicitFinish();
+ setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+ var p = null;
+
+ function startTest() {
+ p = document.getElementById('theplugin');
+ if (!p.hasWidget()) {
+ todo(false, "This test is only relevant for windowed plugins");
+ SimpleTest.finish();
+ return;
+ }
+
+ // Wait for the plugin to have painted once.
+ var interval = setInterval(function() {
+ if (!p.getPaintCount())
+ return;
+
+ clearInterval(interval);
+ doTest();
+ SimpleTest.finish();
+ }, 100);
+ }
+
+ function doTest() {
+ is(p.getClipRegionRectCount(), 1, "getClipRegionRectCount should be a single rect");
+ is(p.getClipRegionRectEdge(0,2) - p.getClipRegionRectEdge(0,0), 100, "width of clip region rect");
+ is(p.getClipRegionRectEdge(0,3) - p.getClipRegionRectEdge(0,1), 50, "height of clip region rect");
+ }
+ </script>
+
+ <p id="display"></p>
+
+ <embed id="theplugin" type="application/x-test" width="100" height="50" style="opacity:0" wmode="window"></embed> \ No newline at end of file
diff --git a/dom/plugins/test/mochitest/xulbrowser_plugin_visibility.xul b/dom/plugins/test/mochitest/xulbrowser_plugin_visibility.xul
new file mode 100644
index 000000000..d08730520
--- /dev/null
+++ b/dom/plugins/test/mochitest/xulbrowser_plugin_visibility.xul
@@ -0,0 +1,139 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ orient="vertical">
+
+ <tabbox id="tabbox" flex="1">
+ <tabs>
+ <tab id="tab1" label="Tab 1" />
+ <tab id="tab2" label="Tab 2" />
+ </tabs>
+ <tabpanels flex="1">
+ <browser id="browser1" type="content-primary" flex="1" src="about:blank"/>
+ <browser id="browser2" type="content-primary" flex="1" src="about:blank"/>
+ </tabpanels>
+ </tabbox>
+ <script type="application/javascript" src="plugin-utils.js"/>
+ <script type="application/javascript"><![CDATA[
+ const ok = window.opener.wrappedJSObject.ok;
+ const is = window.opener.wrappedJSObject.is;
+ const done = window.opener.wrappedJSObject.done;
+ const SimpleTest = window.opener.wrappedJSObject.SimpleTest;
+
+ const nsIWebProgress = Components.interfaces.nsIWebProgress;
+ const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
+
+ const kURI = 'http://mochi.test:8888/chrome/dom/plugins/test/mochitest/plugin_visibility_loader.html';
+
+ function ProgressListener() {
+ }
+ ProgressListener.prototype.onStateChange =
+ function(progress, req, flags, status) {
+ if ((flags & nsIWebProgressListener.STATE_IS_WINDOW) &&
+ (flags & nsIWebProgressListener.STATE_STOP))
+ browserLoaded();
+ };
+ ProgressListener.prototype.QueryInterface = function(iid) {
+ if (iid.equals(nsIWebProgressListener) ||
+ iid.equals(Components.interfaces.nsISupportsWeakReference))
+ return this;
+ throw Components.results.NS_ERROR_NO_INTERFACE;
+ };
+
+ var loadCount = 0;
+ function browserLoaded() {
+ ++loadCount;
+ if (2 == loadCount)
+ startTest();
+ }
+
+ var tabbox = document.getElementById('tabbox');
+ var browser1 = document.getElementById('browser1');
+ var browser2 = document.getElementById('browser2');
+
+ var progressListener1, progressListener2;
+
+ function setup() {
+ progressListener1 = new ProgressListener();
+ browser1.addProgressListener(progressListener1, nsIWebProgress.NOTIFY_STATE_WINDOW);
+ browser1.loadURI(kURI, null, null);
+ progressListener2 = new ProgressListener();
+ browser2.addProgressListener(progressListener2, nsIWebProgress.NOTIFY_STATE_WINDOW);
+ browser2.loadURI(kURI, null, null);
+ }
+
+ window.addEventListener("load", setup, false);
+
+ var plugin1, plugin2;
+
+ const kTimeout = 5000; // 5 seconds
+ var paintGiveUp;
+ var paintInterval;
+
+ function startTest() {
+ plugin1 = browser1.contentDocument.getElementById('p').wrappedJSObject;
+ plugin2 = browser2.contentDocument.getElementById('p').wrappedJSObject;
+
+ paintGiveUp = Date.now() + kTimeout;
+ paintInterval = setInterval(waitForPaint, 100);
+ }
+
+ function waitForPaint() {
+ if (!plugin1.isVisible()) {
+ if (Date.now() < paintGiveUp)
+ return;
+
+ ok(false, "Plugin in tab 1 never became visible.");
+ done();
+ return;
+ }
+
+ clearInterval(paintInterval);
+
+ ok(true, "Plugin in tab 1 should be visible.");
+ paintCountIs(plugin1, 1, "Plugin in tab 1 should have painted once.");
+
+ ok(!plugin2.isVisible(), "Plugin in tab 2 should not be visible.");
+ paintCountIs(plugin2, 0, "Plugin in tab 2 should not have painted.");
+
+ tabbox.selectedIndex = 1;
+ paintGiveUp = Date.now() + kTimeout;
+ paintInterval = setInterval(part2, 100);
+ }
+
+ function part2() {
+ if (!plugin2.isVisible()) {
+ if (Date.now() < paintGiveUp)
+ return;
+
+ ok(false, "Plugin in tab 2 never became visible.");
+ done();
+ return;
+ }
+
+ clearInterval(paintInterval);
+
+ ok(true, "Plugin in tab 2 became visible.");
+ paintCountIs(plugin2, 1, "Plugin in tab 2 should have painted once.");
+
+ ok(!plugin1.isVisible(), "Plugin in tab 1 should have become invisible.");
+ paintCountIs(plugin1, 1, "Plugin in tab 1 should have painted once.");
+
+ // Setcolor invalidates
+ plugin1.setColor('FF00FF00');
+ plugin2.setColor('FF00FF00');
+
+ setTimeout(part3, 500);
+ }
+
+ function part3() {
+ paintCountIs(plugin1, 1,
+ "Plugin in tab 1 should not have repainted after invalidate.");
+ paintCountIs(plugin2, 2,
+ "Plugin in tab 2 should have repainted after invalidate.");
+ done();
+ }
+ ]]></script>
+
+</window>