Bug 1196834 - Add a test that confirms plugin windows are hidden after switching from a remote to local tab. r=roc

This commit is contained in:
Jim Mathies 2015-08-24 16:45:39 -05:00
parent db0b03b6ae
commit 391cbdd913
7 changed files with 200 additions and 0 deletions

View File

@ -0,0 +1,6 @@
[DEFAULT]
support-files =
plugin_test.html
[browser_bug1163570.js]
skip-if = (!e10s || os != "win")

View File

@ -0,0 +1,140 @@
let gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
// Returns the chrome side nsIPluginTag for this plugin
function getTestPlugin(aName) {
let pluginName = aName || "Test Plug-in";
let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.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;
}
// Set the test plugin state, disabling features like click-to-play
function setTestPluginEnabledState(newEnabledState, pluginName) {
let name = pluginName || "Test Plug-in";
let plugin = getTestPlugin(name);
plugin.enabledState = newEnabledState;
}
// simple tab load helper, pilfered from browser plugin tests
function promiseTabLoad(tab, url, eventType="load") {
return new Promise((resolve, reject) => {
function handle(event) {
if (event.originalTarget != tab.linkedBrowser.contentDocument ||
event.target.location.href == "about:blank" ||
(url && event.target.location.href != url)) {
return;
}
clearTimeout(timeout);
tab.linkedBrowser.removeEventListener(eventType, handle, true);
resolve(event);
}
let timeout = setTimeout(() => {
tab.linkedBrowser.removeEventListener(eventType, handle, true);
reject(new Error("Timed out while waiting for a '" + eventType + "'' event"));
}, 30000);
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 () {
Services.prefs.clearUserPref("browser.uiCustomization.disableAnimation");
window.focus();
});
});
add_task(function* () {
Services.prefs.setBoolPref("browser.uiCustomization.disableAnimation", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
let pluginTab = gBrowser.selectedTab = gBrowser.addTab();
let customizeTab = gBrowser.addTab();
yield promiseTabLoad(pluginTab, gTestRoot + "plugin_test.html");
yield promiseTabLoad(customizeTab, "about:customizing");
let result = yield ContentTask.spawn(gBrowser.selectedBrowser, null, function*() {
let doc = content.document;
let plugin = doc.getElementById("testplugin");
return !!plugin;
});
is(result, true, "plugin is loaded");
let cpromise = promiseWaitForEvent(window.gNavToolbox, "customizationready");
let ppromise = promiseWaitForEvent(window, "MozAfterPaint");
gBrowser.selectedTab = customizeTab;
yield cpromise;
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); // customize tab
for (let iteration = 0; iteration < 5; iteration++) {
cpromise = promiseWaitForEvent(window.gNavToolbox, "aftercustomization");
ppromise = promiseWaitForEvent(window, "MozAfterPaint");
EventUtils.synthesizeMouseAtCenter(tabStripContainer.childNodes[1], {}, window);
yield cpromise;
yield ppromise;
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");
cpromise = promiseWaitForEvent(window.gNavToolbox, "customizationready");
ppromise = promiseWaitForEvent(window, "MozAfterPaint");
EventUtils.synthesizeMouseAtCenter(tabStripContainer.childNodes[2], {}, window);
yield cpromise;
yield ppromise;
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");
}
// wait for customize view to shutdown cleanly otherwise we get
// a ton of error spew on shutdown.
cpromise = promiseWaitForEvent(window.gNavToolbox, "aftercustomization");
gBrowser.removeTab(customizeTab);
yield cpromise;
gBrowser.removeTab(pluginTab);
});

View File

@ -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:50px; left:50px; width:500px; height:250px">
</body>
</html>

View File

@ -11,4 +11,5 @@ XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'cocoa', 'windows'):
MOCHITEST_MANIFESTS += ['mochitest/mochitest.ini']
MOCHITEST_CHROME_MANIFESTS += ['mochitest/chrome.ini']
BROWSER_CHROME_MANIFESTS += ['mochitest/browser.ini']

View File

@ -171,6 +171,7 @@ static bool echoString(NPObject* npobj, const NPVariant* args, uint32_t argCount
static bool startAudioPlayback(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool stopAudioPlayback(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool getAudioMuted(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool nativeWidgetIsVisible(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static const NPUTF8* sPluginMethodIdentifierNames[] = {
"npnEvaluateTest",
@ -240,6 +241,7 @@ static const NPUTF8* sPluginMethodIdentifierNames[] = {
"startAudioPlayback",
"stopAudioPlayback",
"audioMuted",
"nativeWidgetIsVisible",
};
static NPIdentifier sPluginMethodIdentifiers[MOZ_ARRAY_LENGTH(sPluginMethodIdentifierNames)];
static const ScriptableFunction sPluginMethodFunctions[] = {
@ -310,6 +312,7 @@ static const ScriptableFunction sPluginMethodFunctions[] = {
startAudioPlayback,
stopAudioPlayback,
getAudioMuted,
nativeWidgetIsVisible,
};
static_assert(MOZ_ARRAY_LENGTH(sPluginMethodIdentifierNames) ==
@ -3321,6 +3324,27 @@ destroySharedGfxStuff(NPObject* npobj, const NPVariant* args,
}
#endif
#if defined(XP_WIN)
bool
nativeWidgetIsVisible(NPObject* npobj, const NPVariant* args,
uint32_t argCount, NPVariant* result)
{
NPP npp = static_cast<TestNPObject*>(npobj)->npp;
InstanceData* id = static_cast<InstanceData*>(npp->pdata);
bool visible = pluginNativeWidgetIsVisible(id);
BOOLEAN_TO_NPVARIANT(visible, *result);
return true;
}
#else
bool
nativeWidgetIsVisible(NPObject* npobj, const NPVariant* args,
uint32_t argCount, NPVariant* result)
{
// XXX Not implemented!
return false;
}
#endif
bool
callOnDestroy(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
{

View File

@ -145,4 +145,11 @@ bool pluginCrashInNestedLoop(InstanceData* instanceData);
*/
bool pluginDestroySharedGfxStuff(InstanceData* instanceData);
/**
* Checks to see if the native widget is marked as visible. Works
* in e10s and non-e10s. Useful in testing e10s related compositor
* plugin window functionality. Supported on Windows.
*/
bool pluginNativeWidgetIsVisible(InstanceData* instanceData);
#endif // nptest_platform_h_

View File

@ -591,3 +591,15 @@ void pluginDoInternalConsistencyCheck(InstanceData* instanceData, string& error)
checkEquals(childRect.bottom, childRect.top + CHILD_WIDGET_SIZE, "Child widget height", error);
}
}
bool pluginNativeWidgetIsVisible(InstanceData* instanceData)
{
HWND hWnd = (HWND)instanceData->window.window;
wchar_t className[60];
if (::GetClassNameW(hWnd, className, sizeof(className) / sizeof(char16_t)) &&
!wcsicmp(className, L"GeckoPluginWindow")) {
return ::IsWindowVisible(hWnd);
}
// something isn't right, fail the check
return false;
}