Bug 1214148 - patch 1 - propagation from the nested iframe back to the toplevel iframe, r=alwu

This commit is contained in:
Andrea Marchesini 2015-12-09 16:46:25 -05:00
parent f0f60b7dff
commit 09dc802de5
15 changed files with 280 additions and 25 deletions

View File

@ -5,6 +5,7 @@
#include "nsISupports.idl"
interface mozIApplication;
interface nsFrameLoader;
interface nsIDocShell;
interface nsIURI;
@ -214,7 +215,7 @@ class nsFrameLoader;
native alreadyAddRefed_nsFrameLoader(already_AddRefed<nsFrameLoader>);
[scriptable, uuid(c4abebcf-55f3-47d4-af15-151311971255)]
[scriptable, uuid(adc1b3ba-8deb-4943-8045-e6de0044f2ce)]
interface nsIFrameLoaderOwner : nsISupports
{
/**
@ -223,6 +224,12 @@ interface nsIFrameLoaderOwner : nsISupports
readonly attribute nsIFrameLoader frameLoader;
[noscript, notxpcom] alreadyAddRefed_nsFrameLoader GetFrameLoader();
/**
* The principal of parent mozIApplication in case of nested mozbrowser
* iframes.
*/
readonly attribute mozIApplication parentApplication;
/**
* Puts the FrameLoaderOwner in prerendering mode.
*/

View File

@ -1215,6 +1215,17 @@ nsObjectLoadingContent::GetFrameLoader()
return loader.forget();
}
NS_IMETHODIMP
nsObjectLoadingContent::GetParentApplication(mozIApplication** aApplication)
{
if (!aApplication) {
return NS_ERROR_FAILURE;
}
*aApplication = nullptr;
return NS_OK;
}
NS_IMETHODIMP
nsObjectLoadingContent::SetIsPrerendered()
{

View File

@ -7,6 +7,8 @@
#include "mozilla/Services.h"
#include "mozilla/dom/BrowserElementAudioChannelBinding.h"
#include "mozilla/dom/DOMRequest.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseNativeHandler.h"
#include "mozilla/dom/ToJSValue.h"
@ -23,16 +25,6 @@
#include "nsPIDOMWindow.h"
#include "nsServiceManagerUtils.h"
namespace {
void
AssertIsInMainProcess()
{
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
}
} // anonymous namespace
namespace mozilla {
namespace dom {
@ -89,7 +81,6 @@ BrowserElementAudioChannel::BrowserElementAudioChannel(
, mState(eStateUnknown)
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsInMainProcess();
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
@ -107,7 +98,6 @@ BrowserElementAudioChannel::BrowserElementAudioChannel(
BrowserElementAudioChannel::~BrowserElementAudioChannel()
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsInMainProcess();
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
@ -173,8 +163,6 @@ AudioChannel
BrowserElementAudioChannel::Name() const
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsInMainProcess();
return mAudioChannel;
}
@ -361,7 +349,6 @@ already_AddRefed<dom::DOMRequest>
BrowserElementAudioChannel::GetVolume(ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsInMainProcess();
if (!mFrameWindow) {
nsCOMPtr<nsIDOMDOMRequest> request;
@ -387,7 +374,6 @@ already_AddRefed<dom::DOMRequest>
BrowserElementAudioChannel::SetVolume(float aVolume, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsInMainProcess();
if (!mFrameWindow) {
nsCOMPtr<nsIDOMDOMRequest> request;
@ -420,7 +406,6 @@ already_AddRefed<dom::DOMRequest>
BrowserElementAudioChannel::GetMuted(ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsInMainProcess();
if (!mFrameWindow) {
nsCOMPtr<nsIDOMDOMRequest> request;
@ -446,7 +431,6 @@ already_AddRefed<dom::DOMRequest>
BrowserElementAudioChannel::SetMuted(bool aMuted, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsInMainProcess();
if (!mFrameWindow) {
nsCOMPtr<nsIDOMDOMRequest> request;
@ -479,7 +463,6 @@ already_AddRefed<dom::DOMRequest>
BrowserElementAudioChannel::IsActive(ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsInMainProcess();
if (mState != eStateUnknown) {
RefPtr<DOMRequest> domRequest = new DOMRequest(GetOwner());
@ -593,8 +576,29 @@ BrowserElementAudioChannel::Observe(nsISupports* aSubject, const char* aTopic,
}
nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
if (NS_WARN_IF(!wrapper)) {
return NS_ERROR_FAILURE;
// This can be a nested iframe.
if (!wrapper) {
nsCOMPtr<nsITabParent> iTabParent = do_QueryInterface(aSubject);
if (!iTabParent) {
return NS_ERROR_FAILURE;
}
RefPtr<TabParent> tabParent = TabParent::GetFrom(iTabParent);
if (!tabParent) {
return NS_ERROR_FAILURE;
}
Element* element = tabParent->GetOwnerElement();
if (!element) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsPIDOMWindow> window = element->OwnerDoc()->GetWindow();
if (window == mFrameWindow) {
ProcessStateChanged(aData);
}
return NS_OK;
}
uint64_t windowID;

View File

@ -0,0 +1,76 @@
/* Any copyright is dedicated to the public domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Bug 1113086 - tests for AudioChannel API into BrowserElement
"use strict";
SimpleTest.waitForExplicitFinish();
browserElementTestHelpers.setEnabledPref(true);
browserElementTestHelpers.addPermission();
function runTests() {
var iframe = document.createElement('iframe');
iframe.setAttribute('mozbrowser', 'true');
iframe.setAttribute('mozapp', 'http://example.org/manifest.webapp');
var listener = function(e) {
var message = e.detail.message;
if (/^OK/.exec(message)) {
ok(true, "Message from app: " + message);
} else if (/^KO/.exec(message)) {
ok(false, "Message from app: " + message);
} else if (/DONE/.exec(message)) {
ok(true, "Messaging from app complete");
iframe.removeEventListener('mozbrowsershowmodalprompt', listener);
}
}
function audio_loadend() {
ok("mute" in iframe, "iframe.mute exists");
ok("unmute" in iframe, "iframe.unmute exists");
ok("getMuted" in iframe, "iframe.getMuted exists");
ok("getVolume" in iframe, "iframe.getVolume exists");
ok("setVolume" in iframe, "iframe.setVolume exists");
ok("allowedAudioChannels" in iframe, "allowedAudioChannels exist");
var channels = iframe.allowedAudioChannels;
is(channels.length, 1, "1 audio channel by default");
var ac = channels[0];
ok(ac instanceof BrowserElementAudioChannel, "Correct class");
ok("getVolume" in ac, "ac.getVolume exists");
ok("setVolume" in ac, "ac.setVolume exists");
ok("getMuted" in ac, "ac.getMuted exists");
ok("setMuted" in ac, "ac.setMuted exists");
ok("isActive" in ac, "ac.isActive exists");
info("Setting the volume...");
ac.setVolume(0.5);
ac.onactivestatechanged = function() {
ok(true, "activestatechanged event received.");
ac.onactivestatechanged = null;
SimpleTest.finish();
}
}
iframe.addEventListener('mozbrowserloadend', audio_loadend);
iframe.addEventListener('mozbrowsershowmodalprompt', listener, false);
document.body.appendChild(iframe);
var context = { 'url': 'http://example.org',
'appId': SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
'isInBrowserElement': true };
SpecialPowers.pushPermissions([
{'type': 'browser', 'allow': 1, 'context': context},
{'type': 'embed-apps', 'allow': 1, 'context': context}
], function() {
iframe.src = 'http://example.org/tests/dom/browser-element/mochitest/file_browserElement_AudioChannel_nested.html';
});
}
addEventListener('testready', function() {
SimpleTest.executeSoon(runTests);
});

View File

@ -0,0 +1,63 @@
<html>
<head>
<script type="text/javascript">
function ok(a, msg) {
alert((!!a ? "OK" : "KO") + " " + msg);
}
function is(a, b, msg) {
ok(a === b, msg);
}
function finish(a, b, msg) {
alert("DONE");
}
addEventListener('load', function(e) {
var iframe = document.createElement('iframe');
iframe.setAttribute('mozbrowser', 'true');
// set 'remote' to true here will make the the iframe remote in _inproc_
// test and in-process in _oop_ test.
iframe.setAttribute('remote', 'true');
iframe.setAttribute('mozapp', 'http://example.org/manifest.webapp');
iframe.addEventListener('mozbrowserloadend', function(e) {
ok("mute" in iframe, "iframe.mute exists");
ok("unmute" in iframe, "iframe.unmute exists");
ok("getMuted" in iframe, "iframe.getMuted exists");
ok("getVolume" in iframe, "iframe.getVolume exists");
ok("setVolume" in iframe, "iframe.setVolume exists");
ok("allowedAudioChannels" in iframe, "allowedAudioChannels exist");
var channels = iframe.allowedAudioChannels;
is(channels.length, 1, "1 audio channel by default");
var ac = channels[0];
ok(ac instanceof BrowserElementAudioChannel, "Correct class");
ok("getVolume" in ac, "ac.getVolume exists");
ok("setVolume" in ac, "ac.setVolume exists");
ok("getMuted" in ac, "ac.getMuted exists");
ok("setMuted" in ac, "ac.setMuted exists");
ok("isActive" in ac, "ac.isActive exists");
ac.onactivestatechanged = function() {
ok("activestatechanged event received.");
ac.getVolume().onsuccess = function(e) {
ok(e.target.result, 1, "Default volume is 1");
};
finish();
}
});
document.body.appendChild(iframe);
iframe.src = 'http://example.org/tests/dom/browser-element/mochitest/file_audio.html';
});
</script>
</head>
<body>
</body>
</html>

View File

@ -121,6 +121,7 @@ disabled = bug 924771
disabled = bug 924771
[test_browserElement_oop_GetContentDimensions.html]
[test_browserElement_oop_AudioChannel.html]
[test_browserElement_oop_AudioChannel_nested.html]
[test_browserElement_oop_SetNFCFocus.html]
[test_browserElement_oop_getWebManifest.html]
[test_browserElement_oop_OpenWindowEmpty.html]

View File

@ -83,11 +83,13 @@ support-files =
browserElement_XFrameOptionsSameOrigin.js
browserElement_GetContentDimensions.js
browserElement_AudioChannel.js
browserElement_AudioChannel_nested.js
file_browserElement_AlertInFrame.html
file_browserElement_AlertInFrame_Inner.html
file_browserElement_AllowEmbedAppsInNestedOOIframe.html
file_browserElement_AppFramePermission.html
file_browserElement_AppWindowNamespace.html
file_browserElement_AudioChannel_nested.html
file_browserElement_Viewmode.html
file_browserElement_ThemeColor.html
file_browserElement_BrowserWindowNamespace.html
@ -250,6 +252,7 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 936226
disabled = bug 774100
[test_browserElement_inproc_GetContentDimensions.html]
[test_browserElement_inproc_AudioChannel.html]
[test_browserElement_inproc_AudioChannel_nested.html]
[test_browserElement_inproc_SetNFCFocus.html]
[test_browserElement_inproc_getStructuredData.html]
[test_browserElement_inproc_OpenWindowEmpty.html]

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test of browser element audioChannel in nested mozbrowser iframes.</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7" src="browserElement_AudioChannel_nested.js">
</script>
</body>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test of browser element audioChannel.</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7" src="browserElement_AudioChannel_nested.js">
</script>
</body>
</html>

View File

@ -563,12 +563,18 @@ nsBrowserElement::GetAllowedAudioChannels(
return;
}
nsCOMPtr<mozIApplication> parentApp;
aRv = GetParentApplication(getter_AddRefs(parentApp));
if (NS_WARN_IF(aRv.Failed())) {
return;
}
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
("nsBrowserElement, GetAllowedAudioChannels, this = %p\n", this));
GenerateAllowedAudioChannels(window, frameLoader, mBrowserElementAPI,
manifestURL, mBrowserElementAudioChannels,
aRv);
manifestURL, parentApp,
mBrowserElementAudioChannels, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
@ -583,6 +589,7 @@ nsBrowserElement::GenerateAllowedAudioChannels(
nsIFrameLoader* aFrameLoader,
nsIBrowserElementAPI* aAPI,
const nsAString& aManifestURL,
mozIApplication* aParentApp,
nsTArray<RefPtr<BrowserElementAudioChannel>>& aAudioChannels,
ErrorResult& aRv)
{
@ -625,6 +632,19 @@ nsBrowserElement::GenerateAllowedAudioChannels(
permissionName.AssignASCII("audio-channel-");
permissionName.AppendASCII(audioChannelTable[i].tag);
// In case of nested iframes we want to check if the parent has the
// permission to use this AudioChannel.
if (aParentApp) {
aRv = aParentApp->HasPermission(permissionName.get(), &allowed);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
if (!allowed) {
continue;
}
}
aRv = app->HasPermission(permissionName.get(), &allowed);
if (NS_WARN_IF(aRv.Failed())) {
return;

View File

@ -125,11 +125,14 @@ public:
nsIFrameLoader* aFrameLoader,
nsIBrowserElementAPI* aAPI,
const nsAString& aManifestURL,
mozIApplication* aParentApp,
nsTArray<RefPtr<dom::BrowserElementAudioChannel>>& aAudioChannels,
ErrorResult& aRv);
protected:
NS_IMETHOD_(already_AddRefed<nsFrameLoader>) GetFrameLoader() = 0;
NS_IMETHOD GetParentApplication(mozIApplication** aApplication) = 0;
void InitBrowserElementAPI();
nsCOMPtr<nsIBrowserElementAPI> mBrowserElementAPI;
nsTArray<RefPtr<dom::BrowserElementAudioChannel>> mBrowserElementAudioChannels;

View File

@ -191,6 +191,35 @@ nsGenericHTMLFrameElement::GetFrameLoader()
return loader.forget();
}
NS_IMETHODIMP
nsGenericHTMLFrameElement::GetParentApplication(mozIApplication** aApplication)
{
if (!aApplication) {
return NS_ERROR_FAILURE;
}
*aApplication = nullptr;
uint32_t appId;
nsIPrincipal *principal = NodePrincipal();
nsresult rv = principal->GetAppId(&appId);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
if (NS_WARN_IF(!appsService)) {
return NS_ERROR_FAILURE;
}
rv = appsService->GetAppByLocalId(appId, aApplication);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
NS_IMETHODIMP
nsGenericHTMLFrameElement::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner)
{

View File

@ -5,7 +5,7 @@
#include "domstubs.idl"
[scriptable, uuid(7615408c-1fb3-4128-8dd5-a3e2f3fa8842)]
[builtinclass, scriptable, uuid(8e49f7b0-1f98-4939-bf91-e9c39cd56434)]
interface nsITabParent : nsISupports
{
void injectTouchEvent(in AString aType,

View File

@ -1616,6 +1616,17 @@ nsXULElement::GetFrameLoader()
return loader.forget();
}
nsresult
nsXULElement::GetParentApplication(mozIApplication** aApplication)
{
if (!aApplication) {
return NS_ERROR_FAILURE;
}
*aApplication = nullptr;
return NS_OK;
}
nsresult
nsXULElement::SetIsPrerendered()
{

View File

@ -412,6 +412,7 @@ public:
virtual mozilla::EventStates IntrinsicState() const override;
nsresult GetFrameLoader(nsIFrameLoader** aFrameLoader);
nsresult GetParentApplication(mozIApplication** aApplication);
nsresult SetIsPrerendered();
nsresult SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner);