Bug 1606660 - Move allowfullscreen checks to the browsing context. r=nika

So that they work properly on fission iframes.

Differential Revision: https://phabricator.services.mozilla.com/D78702
This commit is contained in:
Emilio Cobos Álvarez 2020-06-08 23:49:31 +00:00
Родитель 9890093d16
Коммит 6b709b5f55
9 изменённых файлов: 76 добавлений и 88 удалений

Просмотреть файл

@ -16,6 +16,7 @@
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLEmbedElement.h"
#include "mozilla/dom/HTMLIFrameElement.h"
#include "mozilla/dom/Location.h"
#include "mozilla/dom/LocationBinding.h"
@ -293,6 +294,10 @@ already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
context->mFields.SetWithoutSyncing<IDX_AllowContentRetargetingOnChildren>(
allowContentRetargeting);
// Assume top allows fullscreen for its children unless otherwise stated.
// Subframes start with it false unless otherwise noted in SetEmbedderElement.
context->mFields.SetWithoutSyncing<IDX_FullscreenAllowedByOwner>(!aParent);
const bool allowPlugins = inherit ? inherit->GetAllowPlugins() : true;
context->mFields.SetWithoutSyncing<IDX_AllowPlugins>(allowPlugins);
@ -470,11 +475,34 @@ void BrowsingContext::CleanUpDanglingRemoteOuterWindowProxies(
js::RemapRemoteWindowProxies(aCx, &cb, aOuter);
}
bool BrowsingContext::FullscreenAllowed() const {
for (auto* current = this; current; current = current->GetParent()) {
if (!current->GetFullscreenAllowedByOwner()) {
return false;
}
}
return true;
}
static bool OwnerAllowsFullscreen(const Element& aEmbedder) {
if (aEmbedder.IsXULElement()) {
return !aEmbedder.HasAttr(nsGkAtoms::disablefullscreen);
}
if (const auto* iframe = HTMLIFrameElement::FromNode(aEmbedder)) {
return iframe->AllowFullscreen();
}
if (const auto* embed = HTMLEmbedElement::FromNode(aEmbedder)) {
return embed->AllowFullscreen();
}
return false;
}
void BrowsingContext::SetEmbedderElement(Element* aEmbedder) {
mEmbeddedByThisProcess = true;
// Update embedder-element-specific fields in a shared transaction.
// this when clearing our embedder, as we're being destroyed either way.
// Don't do this when clearing our embedder, as we're being destroyed either
// way.
if (aEmbedder) {
Transaction txn;
txn.SetEmbedderElementType(Some(aEmbedder->LocalName()));
@ -482,6 +510,7 @@ void BrowsingContext::SetEmbedderElement(Element* aEmbedder) {
do_QueryInterface(aEmbedder->GetOwnerGlobal())) {
txn.SetEmbedderInnerWindowId(inner->WindowID());
}
txn.SetFullscreenAllowedByOwner(OwnerAllowsFullscreen(*aEmbedder));
if (XRE_IsParentProcess() && IsTopContent()) {
nsAutoString messageManagerGroup;
if (aEmbedder->IsXULElement()) {
@ -2024,6 +2053,11 @@ bool BrowsingContext::CanSet(FieldIndex<IDX_AllowPlugins>,
return CheckOnlyOwningProcessCanSet(aSource);
}
bool BrowsingContext::CanSet(FieldIndex<IDX_FullscreenAllowedByOwner>,
const bool& aAllowed, ContentParent* aSource) {
return CheckOnlyEmbedderCanSet(aSource);
}
// We map `watchedByDevTools` WebIDL attribute to `watchedByDevToolsInternal`
// BC field. And we map it to the top level BrowsingContext.
bool BrowsingContext::WatchedByDevTools() {

Просмотреть файл

@ -116,6 +116,7 @@ class WindowProxyHolder;
FIELD(AllowContentRetargetingOnChildren, bool) \
FIELD(ForceEnableTrackingProtection, bool) \
FIELD(UseGlobalHistory, bool) \
FIELD(FullscreenAllowedByOwner, bool) \
/* These field are used to store the states of autoplay media request on \
* GeckoView only, and it would only be modified on the top level browsing \
* context. */ \
@ -388,6 +389,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
bool WatchedByDevTools();
void SetWatchedByDevTools(bool aWatchedByDevTools, ErrorResult& aRv);
bool FullscreenAllowed() const;
float FullZoom() const { return GetFullZoom(); }
float TextZoom() const { return GetTextZoom(); }
@ -746,6 +749,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
ContentParent* aSource);
bool CanSet(FieldIndex<IDX_AllowPlugins>, const bool& aAllowPlugins,
ContentParent* aSource);
bool CanSet(FieldIndex<IDX_FullscreenAllowedByOwner>, const bool&,
ContentParent*);
bool CanSet(FieldIndex<IDX_WatchedByDevToolsInternal>,
const bool& aWatchedByDevToolsInternal, ContentParent* aSource);

Просмотреть файл

@ -1743,74 +1743,6 @@ nsDocShell::SetAllowContentRetargetingOnChildren(
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed) {
NS_ENSURE_ARG_POINTER(aFullscreenAllowed);
// Assume false until we determine otherwise...
*aFullscreenAllowed = false;
nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
if (!win) {
return NS_OK;
}
// FIXME(emilio, bug 1606660): What makes this work in fission?
if (nsCOMPtr<Element> frameElement = win->GetFrameElementInternal()) {
if (frameElement->IsXULElement()) {
if (frameElement->HasAttr(kNameSpaceID_None,
nsGkAtoms::disablefullscreen)) {
// Document inside this frame is explicitly disabled.
return NS_OK;
}
} else {
// We do not allow document inside any containing element other
// than iframe to enter fullscreen.
if (auto* iframe = HTMLIFrameElement::FromNode(*frameElement)) {
// If any ancestor iframe does not have allowfullscreen attribute
// set, then fullscreen is not allowed.
if (!iframe->AllowFullscreen()) {
return NS_OK;
}
} else if (frameElement->IsHTMLElement(nsGkAtoms::embed)) {
// Respect allowfullscreen only if this is a rewritten YouTube embed.
nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent =
do_QueryInterface(frameElement);
if (!objectLoadingContent) {
return NS_OK;
}
nsObjectLoadingContent* olc =
static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
if (!olc->IsRewrittenYoutubeEmbed()) {
return NS_OK;
}
// We don't have to check prefixed attributes because Flash does not
// support them.
if (!frameElement->HasAttr(kNameSpaceID_None,
nsGkAtoms::allowfullscreen)) {
return NS_OK;
}
} else {
// neither iframe nor embed
return NS_OK;
}
}
}
// If we have no parent then we're the root docshell; no ancestor of the
// original docshell doesn't have a allowfullscreen attribute, so
// report fullscreen as allowed.
RefPtr<nsDocShell> parent = GetInProcessParentDocshell();
if (!parent) {
*aFullscreenAllowed = true;
return NS_OK;
}
// Otherwise, we have a parent, continue the checking for
// mozFullscreenAllowed in the parent docshell's ancestors.
return parent->GetFullscreenAllowed(aFullscreenAllowed);
}
NS_IMETHODIMP
nsDocShell::GetMayEnableCharacterEncodingMenu(
bool* aMayEnableCharacterEncodingMenu) {

Просмотреть файл

@ -698,19 +698,6 @@ interface nsIDocShell : nsIDocShellTreeItem
*/
[noscript, notxpcom] bool pluginsAllowedInCurrentDoc();
/**
* Attribute that determines whether fullscreen is allowed to be entered for
* this subtree of the docshell tree. This is true when all iframes containing
* this docshell have their "allowfullscreen" attribute set to "true".
* fullscreenAllowed is only writable at content boundaries, where it is used
* to propagate the value of the cross process parent's iframe's
* "allowfullscreen" attribute to the child process. Setting
* fullscreenAllowed on docshells which aren't content boundaries throws an
* exception.
*/
[infallible] readonly attribute boolean fullscreenAllowed;
[noscript, infallible] attribute boolean affectPrivateSessionLifetime;
/**

Просмотреть файл

@ -13587,12 +13587,13 @@ static const char* GetFullscreenError(Document* aDoc, CallerType aCallerType) {
return "FullscreenDeniedHidden";
}
// Ensure that all containing elements are <iframe> and have
// allowfullscreen attribute set.
nsCOMPtr<nsIDocShell> docShell(aDoc->GetDocShell());
if (!docShell || !docShell->GetFullscreenAllowed()) {
// Ensure that all containing elements are <iframe> and have allowfullscreen
// attribute set.
BrowsingContext* bc = aDoc->GetBrowsingContext();
if (!bc || !bc->FullscreenAllowed()) {
return "FullscreenDeniedContainerNotAllowed";
}
return nullptr;
}

Просмотреть файл

@ -15,6 +15,7 @@
#include "nsThreadUtils.h"
#include "nsIWidget.h"
#include "nsContentUtils.h"
#include "nsFrameLoader.h"
#ifdef XP_MACOSX
# include "mozilla/EventDispatcher.h"
# include "mozilla/dom/Event.h"
@ -119,6 +120,13 @@ nsresult HTMLEmbedElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
NS_ENSURE_SUCCESS(rv, rv);
}
if (aNamespaceID == kNameSpaceID_None &&
aName == nsGkAtoms::allowfullscreen && mFrameLoader) {
if (auto* bc = mFrameLoader->GetExtantBrowsingContext()) {
bc->SetFullscreenAllowedByOwner(AllowFullscreen());
}
}
return nsGenericHTMLElement::AfterSetAttr(
aNamespaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
}

Просмотреть файл

@ -32,6 +32,12 @@ class HTMLEmbedElement final : public nsGenericHTMLElement,
NS_IMETHOD PostHandleEvent(EventChainPostVisitor& aVisitor) override;
#endif
bool AllowFullscreen() const {
// We don't need to check prefixed attributes because Flash does not support
// them.
return IsRewrittenYoutubeEmbed() && GetBoolAttr(nsGkAtoms::allowfullscreen);
}
// EventTarget
virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;

Просмотреть файл

@ -169,6 +169,15 @@ nsresult HTMLIFrameElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
// alreay been updated.
mFrameLoader->ApplySandboxFlags(GetSandboxFlags());
}
} else if (aName == nsGkAtoms::allowfullscreen ||
aName == nsGkAtoms::mozallowfullscreen) {
if (mFrameLoader) {
if (auto* bc = mFrameLoader->GetExtantBrowsingContext()) {
// This could be simpler if we didn't support the prefixed
// attribute, then it could just use !!aValue.
bc->SetFullscreenAllowedByOwner(AllowFullscreen());
}
}
}
if (StaticPrefs::dom_security_featurePolicy_enabled()) {

Просмотреть файл

@ -172,8 +172,14 @@ nsresult XULFrameElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
const nsAttrValue* aOldValue,
nsIPrincipal* aSubjectPrincipal,
bool aNotify) {
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::src && aValue) {
LoadSrc();
if (aNamespaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::src && aValue) {
LoadSrc();
} else if (aName == nsGkAtoms::disablefullscreen && mFrameLoader) {
if (auto* bc = mFrameLoader->GetExtantBrowsingContext()) {
bc->SetFullscreenAllowedByOwner(!aValue);
}
}
}
return nsXULElement::AfterSetAttr(aNamespaceID, aName, aValue, aOldValue,