зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1595491 - Part 1: Make <embed> and <object> behave more like <iframe>. r=smaug,emilio
By making image loading in <embed> and <object> behave more like when an <iframe> loads an image, we can make sure that the synthetic document generated is process switched if the image is cross origin. This is done by making image loading in nsObjectLoadingContent follow the document loading path. We also make sure that we pass the image size back to the embedder element to not get stuck with the intrinsic size. To avoid named targeting being able to target these synthetic documents, as well as showing up in `Window.frames` and being counted in `Window.length`, we keep a filtered list of non-synthetic browsing contexts for that use-case. This feature is controlled by two prefs: * browser.opaqueResponseBlocking.syntheticBrowsingContext This triggers the creation of synthetic documents for images loaded in <object> or embed. * browser.opaqueResponseBlocking.syntheticBrowsingContext.filter This turns on the filtering of synthetic browsing contexts in named targeting, `Window.length` and `Window.frames`. Differential Revision: https://phabricator.services.mozilla.com/D148117
This commit is contained in:
Родитель
90178fe177
Коммит
ec3d91462e
|
@ -737,9 +737,22 @@ void BrowsingContext::SetEmbedderElement(Element* aEmbedder) {
|
|||
obs->NotifyWhenScriptSafe(ToSupports(this),
|
||||
"browsing-context-did-set-embedder", nullptr);
|
||||
}
|
||||
|
||||
if (IsEmbedderTypeObjectOrEmbed()) {
|
||||
if (WindowContext* context = GetParentWindowContext()) {
|
||||
Unused << SetSyntheticDocumentContainer(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BrowsingContext::IsEmbedderTypeObjectOrEmbed() {
|
||||
if (const Maybe<nsString>& type = GetEmbedderElementType()) {
|
||||
return nsGkAtoms::object->Equals(*type) || nsGkAtoms::embed->Equals(*type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BrowsingContext::Embed() {
|
||||
if (auto* frame = HTMLIFrameElement::FromNode(mEmbedderElement)) {
|
||||
frame->BindToBrowsingContext(this);
|
||||
|
@ -1059,6 +1072,13 @@ void BrowsingContext::GetChildren(
|
|||
aChildren.AppendElements(Children());
|
||||
}
|
||||
|
||||
Span<RefPtr<BrowsingContext>> BrowsingContext::NonSyntheticChildren() const {
|
||||
if (WindowContext* current = mCurrentWindowContext) {
|
||||
return current->NonSyntheticChildren();
|
||||
}
|
||||
return Span<RefPtr<BrowsingContext>>();
|
||||
}
|
||||
|
||||
void BrowsingContext::GetWindowContexts(
|
||||
nsTArray<RefPtr<WindowContext>>& aWindows) {
|
||||
aWindows.AppendElements(mWindowContexts);
|
||||
|
@ -1209,7 +1229,7 @@ BrowsingContext* BrowsingContext::FindWithName(
|
|||
found = parent;
|
||||
break;
|
||||
} else {
|
||||
siblings = parent->Children();
|
||||
siblings = parent->NonSyntheticChildren();
|
||||
}
|
||||
|
||||
for (BrowsingContext* sibling : siblings) {
|
||||
|
@ -1244,7 +1264,7 @@ BrowsingContext* BrowsingContext::FindChildWithName(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
for (BrowsingContext* child : Children()) {
|
||||
for (BrowsingContext* child : NonSyntheticChildren()) {
|
||||
if (child->NameEquals(aName) && aRequestingContext.CanAccess(child) &&
|
||||
child->IsTargetable()) {
|
||||
return child;
|
||||
|
@ -1288,7 +1308,7 @@ BrowsingContext* BrowsingContext::FindWithNameInSubtree(
|
|||
return this;
|
||||
}
|
||||
|
||||
for (BrowsingContext* child : Children()) {
|
||||
for (BrowsingContext* child : NonSyntheticChildren()) {
|
||||
if (BrowsingContext* found =
|
||||
child->FindWithNameInSubtree(aName, aRequestingContext)) {
|
||||
return found;
|
||||
|
@ -2966,6 +2986,13 @@ void BrowsingContext::DidSet(FieldIndex<IDX_IsInBFCache>) {
|
|||
}
|
||||
}
|
||||
|
||||
void BrowsingContext::DidSet(FieldIndex<IDX_SyntheticDocumentContainer>) {
|
||||
if (WindowContext* parentWindowContext = GetParentWindowContext()) {
|
||||
parentWindowContext->UpdateChildSynthetic(this,
|
||||
GetSyntheticDocumentContainer());
|
||||
}
|
||||
}
|
||||
|
||||
void BrowsingContext::SetCustomPlatform(const nsAString& aPlatform,
|
||||
ErrorResult& aRv) {
|
||||
Top()->SetPlatformOverride(aPlatform, aRv);
|
||||
|
|
|
@ -234,7 +234,10 @@ enum class ExplicitActiveStatus : uint8_t {
|
|||
/* This field only gets incrememented when we start navigations in the \
|
||||
* parent process. This is used for keeping track of the racing navigations \
|
||||
* between the parent and content processes. */ \
|
||||
FIELD(ParentInitiatedNavigationEpoch, uint64_t)
|
||||
FIELD(ParentInitiatedNavigationEpoch, uint64_t) \
|
||||
/* This browsing context is for a synthetic image document wrapping an \
|
||||
* image embedded in <object> or <embed>. */ \
|
||||
FIELD(SyntheticDocumentContainer, bool)
|
||||
|
||||
// BrowsingContext, in this context, is the cross process replicated
|
||||
// environment in which information about documents is stored. In
|
||||
|
@ -366,6 +369,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
|||
Element* GetEmbedderElement() const { return mEmbedderElement; }
|
||||
void SetEmbedderElement(Element* aEmbedder);
|
||||
|
||||
// Return true if the type of the embedder element is either object
|
||||
// or embed, false otherwise.
|
||||
bool IsEmbedderTypeObjectOrEmbed();
|
||||
|
||||
// Called after the BrowingContext has been embedded in a FrameLoader. This
|
||||
// happens after `SetEmbedderElement` is called on the BrowsingContext and
|
||||
// after the BrowsingContext has been set on the FrameLoader.
|
||||
|
@ -488,6 +495,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
|||
Span<RefPtr<BrowsingContext>> Children() const;
|
||||
void GetChildren(nsTArray<RefPtr<BrowsingContext>>& aChildren);
|
||||
|
||||
Span<RefPtr<BrowsingContext>> NonSyntheticChildren() const;
|
||||
|
||||
const nsTArray<RefPtr<WindowContext>>& GetWindowContexts() {
|
||||
return mWindowContexts;
|
||||
}
|
||||
|
@ -1194,6 +1203,8 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
|||
bool CanSet(FieldIndex<IDX_IsInBFCache>, bool, ContentParent* aSource);
|
||||
void DidSet(FieldIndex<IDX_IsInBFCache>);
|
||||
|
||||
void DidSet(FieldIndex<IDX_SyntheticDocumentContainer>);
|
||||
|
||||
// Allow if the process attemping to set field is the same as the owning
|
||||
// process. Deprecated. New code that might use this should generally be moved
|
||||
// to WindowContext or be settable only by the parent process.
|
||||
|
|
|
@ -122,6 +122,9 @@ void WindowContext::AppendChildBrowsingContext(
|
|||
MOZ_DIAGNOSTIC_ASSERT(!mChildren.Contains(aBrowsingContext));
|
||||
|
||||
mChildren.AppendElement(aBrowsingContext);
|
||||
if (!aBrowsingContext->IsEmbedderTypeObjectOrEmbed()) {
|
||||
mNonSyntheticChildren.AppendElement(aBrowsingContext);
|
||||
}
|
||||
|
||||
// If we're the current WindowContext in our BrowsingContext, make sure to
|
||||
// clear any cached `children` value.
|
||||
|
@ -136,6 +139,7 @@ void WindowContext::RemoveChildBrowsingContext(
|
|||
"Mismatched groups?");
|
||||
|
||||
mChildren.RemoveElement(aBrowsingContext);
|
||||
mNonSyntheticChildren.RemoveElement(aBrowsingContext);
|
||||
|
||||
// If we're the current WindowContext in our BrowsingContext, make sure to
|
||||
// clear any cached `children` value.
|
||||
|
@ -144,6 +148,19 @@ void WindowContext::RemoveChildBrowsingContext(
|
|||
}
|
||||
}
|
||||
|
||||
void WindowContext::UpdateChildSynthetic(BrowsingContext* aBrowsingContext,
|
||||
bool aIsSynthetic) {
|
||||
if (aIsSynthetic) {
|
||||
mNonSyntheticChildren.RemoveElement(aBrowsingContext);
|
||||
} else {
|
||||
// The same BrowsingContext will be reused for error pages, so it can be in
|
||||
// the list already.
|
||||
if (!mNonSyntheticChildren.Contains(aBrowsingContext)) {
|
||||
mNonSyntheticChildren.AppendElement(aBrowsingContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WindowContext::SendCommitTransaction(ContentParent* aParent,
|
||||
const BaseTransaction& aTxn,
|
||||
uint64_t aEpoch) {
|
||||
|
@ -569,12 +586,14 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WindowContext)
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildren)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mNonSyntheticChildren)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WindowContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildren)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNonSyntheticChildren)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(WindowContext)
|
||||
|
|
|
@ -147,6 +147,12 @@ class WindowContext : public nsISupports, public nsWrapperCache {
|
|||
|
||||
Span<RefPtr<BrowsingContext>> Children() { return mChildren; }
|
||||
|
||||
// The filtered version of `Children()`, which contains no browsing contexts
|
||||
// for synthetic documents as created by object loading content.
|
||||
Span<RefPtr<BrowsingContext>> NonSyntheticChildren() {
|
||||
return mNonSyntheticChildren;
|
||||
}
|
||||
|
||||
// Cast this object to it's parent-process canonical form.
|
||||
WindowGlobalParent* Canonical();
|
||||
|
||||
|
@ -219,6 +225,12 @@ class WindowContext : public nsISupports, public nsWrapperCache {
|
|||
void AppendChildBrowsingContext(BrowsingContext* aBrowsingContext);
|
||||
void RemoveChildBrowsingContext(BrowsingContext* aBrowsingContext);
|
||||
|
||||
// Update non-synthetic children based on whether `aBrowsingContext`
|
||||
// is synthetic or not. Regardless the synthetic of `aBrowsingContext`, it is
|
||||
// kept in this WindowContext's all children list.
|
||||
void UpdateChildSynthetic(BrowsingContext* aBrowsingContext,
|
||||
bool aIsSynthetic);
|
||||
|
||||
// Send a given `BaseTransaction` object to the correct remote.
|
||||
void SendCommitTransaction(ContentParent* aParent,
|
||||
const BaseTransaction& aTxn, uint64_t aEpoch);
|
||||
|
@ -331,6 +343,15 @@ class WindowContext : public nsISupports, public nsWrapperCache {
|
|||
// `AppendChildBrowsingContext` and `RemoveChildBrowsingContext` methods.
|
||||
nsTArray<RefPtr<BrowsingContext>> mChildren;
|
||||
|
||||
// --- NEVER CHANGE `mNonSyntheticChildren` DIRECTLY! ---
|
||||
// Same reason as for mChildren.
|
||||
// mNonSyntheticChildren contains the same browsing contexts except browsing
|
||||
// contexts created by the synthetic document for object loading contents
|
||||
// loading images. This is used to discern browsing contexts created when
|
||||
// loading images in <object> or <embed> elements, so that they can be hidden
|
||||
// from named targeting, `Window.frames` etc.
|
||||
nsTArray<RefPtr<BrowsingContext>> mNonSyntheticChildren;
|
||||
|
||||
bool mIsDiscarded = false;
|
||||
bool mIsInProcess = false;
|
||||
|
||||
|
|
|
@ -16519,6 +16519,16 @@ Selection* Document::GetSelection(ErrorResult& aRv) {
|
|||
return nsGlobalWindowInner::Cast(window)->GetSelection(aRv);
|
||||
}
|
||||
|
||||
void Document::MakeBrowsingContextNonSynthetic() {
|
||||
if (nsContentUtils::ShouldHideObjectOrEmbedImageDocument()) {
|
||||
if (BrowsingContext* bc = GetBrowsingContext()) {
|
||||
if (bc->GetSyntheticDocumentContainer()) {
|
||||
Unused << bc->SetSyntheticDocumentContainer(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult Document::HasStorageAccessSync(bool& aHasStorageAccess) {
|
||||
// Step 1: check if cookie permissions are available or denied to this
|
||||
// document's principal
|
||||
|
|
|
@ -270,6 +270,7 @@ class SVGDocument;
|
|||
class SVGElement;
|
||||
class SVGSVGElement;
|
||||
class SVGUseElement;
|
||||
class ImageDocument;
|
||||
class Touch;
|
||||
class TouchList;
|
||||
class TreeWalker;
|
||||
|
@ -1255,6 +1256,7 @@ class Document : public nsINode,
|
|||
|
||||
Selection* GetSelection(ErrorResult& aRv);
|
||||
|
||||
void MakeBrowsingContextNonSynthetic();
|
||||
nsresult HasStorageAccessSync(bool& aHasStorageAccess);
|
||||
already_AddRefed<Promise> HasStorageAccess(ErrorResult& aRv);
|
||||
|
||||
|
@ -2200,6 +2202,9 @@ class Document : public nsINode,
|
|||
*/
|
||||
bool IsHTMLDocument() const { return mType == eHTML; }
|
||||
bool IsHTMLOrXHTML() const { return mType == eHTML || mType == eXHTML; }
|
||||
bool IsImageDocument() const {
|
||||
return MediaDocumentKind() == MediaDocumentKind::Image;
|
||||
}
|
||||
bool IsXMLDocument() const { return !IsHTMLDocument(); }
|
||||
bool IsSVGDocument() const { return mType == eSVG; }
|
||||
bool IsUnstyledDocument() { return IsLoadedAsData(); }
|
||||
|
@ -3575,6 +3580,13 @@ class Document : public nsINode,
|
|||
inline SVGDocument* AsSVGDocument();
|
||||
inline const SVGDocument* AsSVGDocument() const;
|
||||
|
||||
/**
|
||||
* Asserts IsImageDocument, and can't return null.
|
||||
* Defined inline in ImageDocument.h
|
||||
*/
|
||||
inline ImageDocument* AsImageDocument();
|
||||
inline const ImageDocument* AsImageDocument() const;
|
||||
|
||||
/*
|
||||
* Given a node, get a weak reference to it and append that reference to
|
||||
* mBlockedNodesByClassifier. Can be used later on to look up a node in it.
|
||||
|
|
|
@ -109,6 +109,7 @@
|
|||
#include "mozilla/ScrollbarPreferences.h"
|
||||
#include "mozilla/Span.h"
|
||||
#include "mozilla/StaticAnalysisFunctions.h"
|
||||
#include "mozilla/StaticPrefs_browser.h"
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
#ifdef FUZZING
|
||||
# include "mozilla/StaticPrefs_fuzzing.h"
|
||||
|
@ -10251,7 +10252,7 @@ uint32_t nsContentUtils::HtmlObjectContentTypeForMIMEType(
|
|||
}
|
||||
|
||||
if (imgLoader::SupportImageWithMimeType(aMIMEType)) {
|
||||
return nsIObjectLoadingContent::TYPE_IMAGE;
|
||||
return ResolveObjectType(nsIObjectLoadingContent::TYPE_IMAGE);
|
||||
}
|
||||
|
||||
// Faking support of the PDF content as a document for EMBED tags
|
||||
|
@ -10970,6 +10971,28 @@ nsresult nsContentUtils::AnonymizeId(nsAString& aId,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool nsContentUtils::ShouldHideObjectOrEmbedImageDocument() {
|
||||
return StaticPrefs::
|
||||
browser_opaqueResponseBlocking_syntheticBrowsingContext_AtStartup() &&
|
||||
StaticPrefs::
|
||||
browser_opaqueResponseBlocking_syntheticBrowsingContext_filter_AtStartup_DoNotUseDirectly();
|
||||
}
|
||||
|
||||
/* static */
|
||||
uint32_t nsContentUtils::ResolveObjectType(uint32_t aType) {
|
||||
if (!StaticPrefs::
|
||||
browser_opaqueResponseBlocking_syntheticBrowsingContext_AtStartup()) {
|
||||
return aType;
|
||||
}
|
||||
|
||||
if (aType != nsIObjectLoadingContent::TYPE_IMAGE) {
|
||||
return aType;
|
||||
}
|
||||
|
||||
return nsIObjectLoadingContent::TYPE_DOCUMENT;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
std::ostream& operator<<(std::ostream& aOut,
|
||||
const PreventDefaultResult aPreventDefaultResult) {
|
||||
|
|
|
@ -3359,6 +3359,19 @@ class nsContentUtils {
|
|||
static nsresult AnonymizeId(nsAString& aId, const nsACString& aOriginKey,
|
||||
OriginFormat aFormat = OriginFormat::Base64);
|
||||
|
||||
/**
|
||||
* Return true if we should hide the synthetic browsing context for <object>
|
||||
* or <embed> images in synthetic documents.
|
||||
*/
|
||||
static bool ShouldHideObjectOrEmbedImageDocument();
|
||||
|
||||
/**
|
||||
* Returns the object type that the object loading content will actually use
|
||||
* to load the resource. Used for ORB and loading images into synthetic
|
||||
* documents.
|
||||
*/
|
||||
static uint32_t ResolveObjectType(uint32_t aType);
|
||||
|
||||
private:
|
||||
static bool InitializeEventTable();
|
||||
|
||||
|
|
|
@ -2495,6 +2495,15 @@ void nsFrameLoader::PropagateIsUnderHiddenEmbedderElement(
|
|||
}
|
||||
}
|
||||
|
||||
void nsFrameLoader::UpdateRemoteStyle(
|
||||
mozilla::StyleImageRendering aImageRendering) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(IsRemoteFrame());
|
||||
|
||||
if (auto* browserBridgeChild = GetBrowserBridgeChild()) {
|
||||
browserBridgeChild->SendUpdateRemoteStyle(aImageRendering);
|
||||
}
|
||||
}
|
||||
|
||||
void nsFrameLoader::UpdateBaseWindowPositionAndSize(
|
||||
nsSubDocumentFrame* aIFrame) {
|
||||
nsCOMPtr<nsIBaseWindow> baseWindow = GetDocShell(IgnoreErrors());
|
||||
|
|
|
@ -147,6 +147,8 @@ class nsFrameLoader final : public nsStubMutationObserver,
|
|||
void PropagateIsUnderHiddenEmbedderElement(
|
||||
bool aIsUnderHiddenEmbedderElement);
|
||||
|
||||
void UpdateRemoteStyle(mozilla::StyleImageRendering aImageRendering);
|
||||
|
||||
// When creating a nsFrameLoaderOwner which is a static clone, a
|
||||
// `nsFrameLoader` is not immediately attached to it. Instead, it is added to
|
||||
// the static clone document's `PendingFrameStaticClones` list.
|
||||
|
|
|
@ -3366,7 +3366,8 @@ Nullable<WindowProxyHolder> nsGlobalWindowOuter::IndexedGetterOuter(
|
|||
BrowsingContext* bc = GetBrowsingContext();
|
||||
NS_ENSURE_TRUE(bc, nullptr);
|
||||
|
||||
Span<RefPtr<BrowsingContext>> children = bc->Children();
|
||||
Span<RefPtr<BrowsingContext>> children = bc->NonSyntheticChildren();
|
||||
|
||||
if (aIndex < children.Length()) {
|
||||
return WindowProxyHolder(children[aIndex]);
|
||||
}
|
||||
|
@ -3994,7 +3995,7 @@ double nsGlobalWindowOuter::GetScrollYOuter() { return GetScrollXY(false).y; }
|
|||
|
||||
uint32_t nsGlobalWindowOuter::Length() {
|
||||
BrowsingContext* bc = GetBrowsingContext();
|
||||
return bc ? bc->Children().Length() : 0;
|
||||
return bc ? bc->NonSyntheticChildren().Length() : 0;
|
||||
}
|
||||
|
||||
Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetTopOuter() {
|
||||
|
|
|
@ -391,7 +391,8 @@ nsObjectLoadingContent::nsObjectLoadingContent()
|
|||
mIsStopping(false),
|
||||
mIsLoading(false),
|
||||
mScriptRequested(false),
|
||||
mRewrittenYoutubeEmbed(false) {}
|
||||
mRewrittenYoutubeEmbed(false),
|
||||
mLoadingSyntheticDocument(false) {}
|
||||
|
||||
nsObjectLoadingContent::~nsObjectLoadingContent() {
|
||||
// Should have been unbound from the tree at this point, and
|
||||
|
@ -820,11 +821,17 @@ ElementState nsObjectLoadingContent::ObjectState() const {
|
|||
case eType_Image:
|
||||
return ImageState();
|
||||
case eType_FakePlugin:
|
||||
case eType_Document:
|
||||
case eType_Document: {
|
||||
// These are OK. If documents start to load successfully, they display
|
||||
// something, and are thus not broken in this sense. The same goes for
|
||||
// plugins.
|
||||
return ElementState();
|
||||
ElementState states = ElementState();
|
||||
if (mLoadingSyntheticDocument) {
|
||||
states |= ElementState::LOADING;
|
||||
states |= ImageState();
|
||||
}
|
||||
return states;
|
||||
}
|
||||
case eType_Fallback:
|
||||
// This may end up handled as TYPE_NULL or as a "special" type, as
|
||||
// chosen by the layout.use-plugin-fallback pref.
|
||||
|
@ -1299,6 +1306,12 @@ nsObjectLoadingContent::UpdateObjectParameters() {
|
|||
LOG(("OBJLC [%p]: NewType #4: %u", this, newType));
|
||||
}
|
||||
|
||||
mLoadingSyntheticDocument =
|
||||
newType == eType_Document &&
|
||||
StaticPrefs::
|
||||
browser_opaqueResponseBlocking_syntheticBrowsingContext_AtStartup() &&
|
||||
imgLoader::SupportImageWithMimeType(newMime);
|
||||
|
||||
///
|
||||
/// Handle existing channels
|
||||
///
|
||||
|
@ -1408,7 +1421,7 @@ nsresult nsObjectLoadingContent::LoadObject(bool aNotify, bool aForceLoad,
|
|||
ObjectType oldType = mType;
|
||||
mType = eType_Fallback;
|
||||
ConfigureFallback();
|
||||
NotifyStateChanged(oldType, ObjectState(), true);
|
||||
NotifyStateChanged(oldType, ObjectState(), true, false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1695,7 +1708,7 @@ nsresult nsObjectLoadingContent::LoadObject(bool aNotify, bool aForceLoad,
|
|||
}
|
||||
|
||||
// Notify of our final state
|
||||
NotifyStateChanged(oldType, oldState, aNotify);
|
||||
NotifyStateChanged(oldType, oldState, aNotify, false);
|
||||
NS_ENSURE_TRUE(mIsLoading, NS_OK);
|
||||
|
||||
//
|
||||
|
@ -1725,7 +1738,7 @@ nsresult nsObjectLoadingContent::LoadObject(bool aNotify, bool aForceLoad,
|
|||
}
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv) && mIsLoading) {
|
||||
if ((NS_FAILED(rv) && rv != NS_ERROR_PARSED_DATA_CACHED) && mIsLoading) {
|
||||
// Since we've already notified of our transition, we can just Unload and
|
||||
// call ConfigureFallback (which will notify again)
|
||||
oldType = mType;
|
||||
|
@ -1734,7 +1747,7 @@ nsresult nsObjectLoadingContent::LoadObject(bool aNotify, bool aForceLoad,
|
|||
NS_ENSURE_TRUE(mIsLoading, NS_OK);
|
||||
CloseChannel();
|
||||
ConfigureFallback();
|
||||
NotifyStateChanged(oldType, ObjectState(), true);
|
||||
NotifyStateChanged(oldType, ObjectState(), true, false);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -1964,7 +1977,7 @@ void nsObjectLoadingContent::Unlink(nsObjectLoadingContent* tmp) {
|
|||
|
||||
void nsObjectLoadingContent::UnloadObject(bool aResetState) {
|
||||
// Don't notify in CancelImageRequests until we transition to a new loaded
|
||||
// state
|
||||
// state, but not if we've loaded the image in a synthetic browsing context.
|
||||
CancelImageRequests(false);
|
||||
if (mFrameLoader) {
|
||||
mFrameLoader->Destroy();
|
||||
|
@ -1997,14 +2010,14 @@ void nsObjectLoadingContent::UnloadObject(bool aResetState) {
|
|||
|
||||
void nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
|
||||
ElementState aOldState,
|
||||
bool aNotify) {
|
||||
bool aNotify,
|
||||
bool aForceRestyle) {
|
||||
LOG(("OBJLC [%p]: NotifyStateChanged: (%u, %" PRIx64 ") -> (%u, %" PRIx64 ")"
|
||||
" (notify %i)",
|
||||
this, aOldType, aOldState.GetInternalValue(), mType,
|
||||
ObjectState().GetInternalValue(), aNotify));
|
||||
|
||||
nsCOMPtr<dom::Element> thisEl =
|
||||
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
||||
nsCOMPtr<dom::Element> thisEl = AsContent()->AsElement();
|
||||
MOZ_ASSERT(thisEl, "must be an element");
|
||||
|
||||
// XXX(johns): A good bit of the code below replicates UpdateState(true)
|
||||
|
@ -2012,7 +2025,7 @@ void nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
|
|||
// Unfortunately, we do some state changes without notifying
|
||||
// (e.g. in Fallback when canceling image requests), so we have to
|
||||
// manually notify object state changes.
|
||||
thisEl->UpdateState(false);
|
||||
thisEl->UpdateState(aForceRestyle);
|
||||
|
||||
if (!aNotify) {
|
||||
// We're done here
|
||||
|
@ -2030,6 +2043,12 @@ void nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
|
|||
}
|
||||
|
||||
RefPtr<PresShell> presShell = doc->GetPresShell();
|
||||
// If there is no PresShell or it hasn't been initialized there isn't much to
|
||||
// do.
|
||||
if (!presShell || !presShell->DidInitialize()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (presShell && (aOldType != mType)) {
|
||||
presShell->PostRecreateFramesFor(thisEl);
|
||||
}
|
||||
|
@ -2046,13 +2065,13 @@ nsObjectLoadingContent::ObjectType nsObjectLoadingContent::GetTypeOfContent(
|
|||
(eSupportImages | eSupportDocuments | eSupportPlugins));
|
||||
|
||||
LOG(
|
||||
("OBJLC[%p]: calling HtmlObjectContentTypeForMIMEType: aMIMEType: %s - "
|
||||
("OBJLC [%p]: calling HtmlObjectContentTypeForMIMEType: aMIMEType: %s - "
|
||||
"thisContent: %p\n",
|
||||
this, aMIMEType.get(), thisContent.get()));
|
||||
auto ret =
|
||||
static_cast<ObjectType>(nsContentUtils::HtmlObjectContentTypeForMIMEType(
|
||||
aMIMEType, aNoFakePlugin));
|
||||
LOG(("OBJLC[%p]: called HtmlObjectContentTypeForMIMEType\n", this));
|
||||
LOG(("OBJLC [%p]: called HtmlObjectContentTypeForMIMEType\n", this));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2359,14 +2378,29 @@ void nsObjectLoadingContent::SubdocumentIntrinsicSizeOrRatioChanged(
|
|||
mSubdocumentIntrinsicSize = aIntrinsicSize;
|
||||
mSubdocumentIntrinsicRatio = aIntrinsicRatio;
|
||||
|
||||
nsCOMPtr<nsIContent> thisContent =
|
||||
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
||||
|
||||
if (nsSubDocumentFrame* sdf = do_QueryFrame(thisContent->GetPrimaryFrame())) {
|
||||
if (nsSubDocumentFrame* sdf = do_QueryFrame(AsContent()->GetPrimaryFrame())) {
|
||||
sdf->SubdocumentIntrinsicSizeOrRatioChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void nsObjectLoadingContent::SubdocumentImageLoadComplete(nsresult aResult) {
|
||||
ElementState oldState = ObjectState();
|
||||
ObjectType oldType = mType;
|
||||
mLoadingSyntheticDocument = false;
|
||||
|
||||
if (NS_FAILED(aResult)) {
|
||||
UnloadObject();
|
||||
mType = eType_Fallback;
|
||||
ConfigureFallback();
|
||||
NotifyStateChanged(oldType, oldState, true, false);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(mType == eType_Document);
|
||||
|
||||
NotifyStateChanged(oldType, oldState, true, true);
|
||||
}
|
||||
|
||||
void nsObjectLoadingContent::MaybeStoreCrossOriginFeaturePolicy() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mFrameLoader);
|
||||
|
||||
|
|
|
@ -189,6 +189,8 @@ class nsObjectLoadingContent : public nsImageLoadingContent,
|
|||
const mozilla::Maybe<mozilla::IntrinsicSize>& aIntrinsicSize,
|
||||
const mozilla::Maybe<mozilla::AspectRatio>& aIntrinsicRatio);
|
||||
|
||||
void SubdocumentImageLoadComplete(nsresult aResult);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Begins loading the object when called
|
||||
|
@ -448,7 +450,8 @@ class nsObjectLoadingContent : public nsImageLoadingContent,
|
|||
* @param aNotify if false, only need to update the state of our element.
|
||||
*/
|
||||
void NotifyStateChanged(ObjectType aOldType,
|
||||
mozilla::dom::ElementState aOldState, bool aNotify);
|
||||
mozilla::dom::ElementState aOldState, bool aNotify,
|
||||
bool aForceRestyle);
|
||||
|
||||
/**
|
||||
* Returns a ObjectType value corresponding to the type of content we would
|
||||
|
@ -574,6 +577,8 @@ class nsObjectLoadingContent : public nsImageLoadingContent,
|
|||
// videos.
|
||||
bool mRewrittenYoutubeEmbed : 1;
|
||||
|
||||
bool mLoadingSyntheticDocument : 1;
|
||||
|
||||
nsTArray<mozilla::dom::MozPluginParameter> mCachedAttributes;
|
||||
nsTArray<mozilla::dom::MozPluginParameter> mCachedParameters;
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "ImageDocument.h"
|
||||
#include "mozilla/AutoRestore.h"
|
||||
#include "mozilla/ComputedStyle.h"
|
||||
#include "mozilla/dom/BrowserChild.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/ImageDocumentBinding.h"
|
||||
|
@ -16,6 +17,8 @@
|
|||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/StaticPrefs_browser.h"
|
||||
#include "mozilla/StaticPrefs_privacy.h"
|
||||
#include "nsICSSDeclaration.h"
|
||||
#include "nsObjectLoadingContent.h"
|
||||
#include "nsRect.h"
|
||||
#include "nsIImageLoadingContent.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
|
@ -137,6 +140,7 @@ ImageDocument::ImageDocument()
|
|||
mObservingImageLoader(false),
|
||||
mTitleUpdateInProgress(false),
|
||||
mHasCustomTitle(false),
|
||||
mIsInObjectOrEmbed(false),
|
||||
mOriginalZoomLevel(1.0),
|
||||
mOriginalResolution(1.0) {}
|
||||
|
||||
|
@ -175,6 +179,10 @@ nsresult ImageDocument::StartDocumentLoad(
|
|||
mOriginalZoomLevel = IsSiteSpecific() ? 1.0 : GetZoomLevel();
|
||||
mOriginalResolution = GetResolution();
|
||||
|
||||
if (BrowsingContext* context = GetBrowsingContext()) {
|
||||
mIsInObjectOrEmbed = context->IsEmbedderTypeObjectOrEmbed();
|
||||
}
|
||||
|
||||
NS_ASSERTION(aDocListener, "null aDocListener");
|
||||
*aDocListener = new ImageListener(this);
|
||||
NS_ADDREF(*aDocListener);
|
||||
|
@ -344,7 +352,9 @@ void ImageDocument::RestoreImage() {
|
|||
imageContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::width, true);
|
||||
imageContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::height, true);
|
||||
|
||||
if (ImageIsOverflowing()) {
|
||||
if (mIsInObjectOrEmbed) {
|
||||
SetModeClass(eIsInObjectOrEmbed);
|
||||
} else if (ImageIsOverflowing()) {
|
||||
if (!ImageIsOverflowingVertically()) {
|
||||
SetModeClass(eOverflowingHorizontalOnly);
|
||||
} else {
|
||||
|
@ -422,6 +432,10 @@ void ImageDocument::SetModeClass(eModeClasses mode) {
|
|||
} else {
|
||||
classList->Remove(u"overflowingHorizontalOnly"_ns, IgnoreErrors());
|
||||
}
|
||||
|
||||
if (mode == eIsInObjectOrEmbed) {
|
||||
classList->Add(u"isInObjectOrEmbed"_ns, IgnoreErrors());
|
||||
}
|
||||
}
|
||||
|
||||
void ImageDocument::OnSizeAvailable(imgIRequest* aRequest,
|
||||
|
@ -462,6 +476,8 @@ void ImageDocument::OnLoadComplete(imgIRequest* aRequest, nsresult aStatus) {
|
|||
|
||||
mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::alt, errorMsg, false);
|
||||
}
|
||||
|
||||
MaybeSendResultToEmbedder(aStatus);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -471,7 +487,8 @@ ImageDocument::HandleEvent(Event* aEvent) {
|
|||
if (eventType.EqualsLiteral("resize")) {
|
||||
CheckOverflowing(false);
|
||||
} else if (eventType.EqualsLiteral("click") &&
|
||||
StaticPrefs::browser_enable_click_image_resizing()) {
|
||||
StaticPrefs::browser_enable_click_image_resizing() &&
|
||||
!mIsInObjectOrEmbed) {
|
||||
ResetZoomLevel();
|
||||
mShouldResize = true;
|
||||
if (mImageIsResized) {
|
||||
|
@ -526,6 +543,31 @@ void ImageDocument::UpdateSizeFromLayout() {
|
|||
}
|
||||
}
|
||||
|
||||
void ImageDocument::UpdateRemoteStyle(StyleImageRendering aImageRendering) {
|
||||
if (!mImageContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsICSSDeclaration> style = mImageContent->Style();
|
||||
switch (aImageRendering) {
|
||||
case StyleImageRendering::Auto:
|
||||
case StyleImageRendering::Smooth:
|
||||
case StyleImageRendering::Optimizequality:
|
||||
style->SetProperty("image-rendering"_ns, "auto"_ns, ""_ns,
|
||||
IgnoreErrors());
|
||||
break;
|
||||
case StyleImageRendering::Optimizespeed:
|
||||
case StyleImageRendering::Pixelated:
|
||||
style->SetProperty("image-rendering"_ns, "pixelated"_ns, ""_ns,
|
||||
IgnoreErrors());
|
||||
break;
|
||||
case StyleImageRendering::CrispEdges:
|
||||
style->SetProperty("image-rendering"_ns, "crisp-edges"_ns, ""_ns,
|
||||
IgnoreErrors());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult ImageDocument::CreateSyntheticDocument() {
|
||||
// Synthesize an html document that refers to the image
|
||||
nsresult rv = MediaDocument::CreateSyntheticDocument();
|
||||
|
@ -591,7 +633,9 @@ nsresult ImageDocument::CheckOverflowing(bool changeState) {
|
|||
|
||||
if (changeState || mShouldResize || mFirstResize || windowBecameBigEnough ||
|
||||
verticalOverflowChanged) {
|
||||
if (ImageIsOverflowing() && (changeState || mShouldResize)) {
|
||||
if (mIsInObjectOrEmbed) {
|
||||
SetModeClass(eIsInObjectOrEmbed);
|
||||
} else if (ImageIsOverflowing() && (changeState || mShouldResize)) {
|
||||
ShrinkToFit();
|
||||
} else if (mImageIsResized || mFirstResize || windowBecameBigEnough) {
|
||||
RestoreImage();
|
||||
|
@ -694,6 +738,37 @@ float ImageDocument::GetResolution() {
|
|||
return mOriginalResolution;
|
||||
}
|
||||
|
||||
void ImageDocument::MaybeSendResultToEmbedder(nsresult aResult) {
|
||||
if (!mIsInObjectOrEmbed) {
|
||||
return;
|
||||
}
|
||||
|
||||
BrowsingContext* context = GetBrowsingContext();
|
||||
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->GetParent() && context->GetParent()->IsInProcess()) {
|
||||
if (Element* embedder = context->GetEmbedderElement()) {
|
||||
if (nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent =
|
||||
do_QueryInterface(embedder)) {
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"nsObjectLoadingContent::SubdocumentImageLoadComplete",
|
||||
[objectLoadingContent, aResult]() {
|
||||
static_cast<nsObjectLoadingContent*>(objectLoadingContent.get())
|
||||
->SubdocumentImageLoadComplete(aResult);
|
||||
}));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (BrowserChild* browserChild =
|
||||
BrowserChild::GetFrom(context->GetDocShell())) {
|
||||
browserChild->SendImageLoadComplete(aResult);
|
||||
}
|
||||
}
|
||||
} // namespace mozilla::dom
|
||||
|
||||
nsresult NS_NewImageDocument(mozilla::dom::Document** aResult) {
|
||||
|
|
|
@ -8,11 +8,15 @@
|
|||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "imgINotificationObserver.h"
|
||||
#include "MediaDocument.h"
|
||||
#include "mozilla/dom/MediaDocument.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
|
||||
namespace mozilla::dom {
|
||||
namespace mozilla {
|
||||
enum class StyleImageRendering : uint8_t;
|
||||
struct IntrinsicSize;
|
||||
} // namespace mozilla
|
||||
|
||||
namespace mozilla::dom {
|
||||
class HTMLImageElement;
|
||||
|
||||
class ImageDocument final : public MediaDocument,
|
||||
|
@ -73,6 +77,8 @@ class ImageDocument final : public MediaDocument,
|
|||
|
||||
void NotifyPossibleTitleChange(bool aBoundTitleElement) override;
|
||||
|
||||
void UpdateRemoteStyle(StyleImageRendering aImageRendering);
|
||||
|
||||
protected:
|
||||
virtual ~ImageDocument();
|
||||
|
||||
|
@ -98,7 +104,8 @@ class ImageDocument final : public MediaDocument,
|
|||
eNone,
|
||||
eShrinkToFit,
|
||||
eOverflowingVertical, // And maybe horizontal too.
|
||||
eOverflowingHorizontalOnly
|
||||
eOverflowingHorizontalOnly,
|
||||
eIsInObjectOrEmbed
|
||||
};
|
||||
void SetModeClass(eModeClasses mode);
|
||||
|
||||
|
@ -106,6 +113,8 @@ class ImageDocument final : public MediaDocument,
|
|||
void OnLoadComplete(imgIRequest* aRequest, nsresult aStatus);
|
||||
void OnHasTransparency();
|
||||
|
||||
void MaybeSendResultToEmbedder(nsresult aResult);
|
||||
|
||||
RefPtr<HTMLImageElement> mImageContent;
|
||||
|
||||
float mVisibleWidth;
|
||||
|
@ -125,10 +134,23 @@ class ImageDocument final : public MediaDocument,
|
|||
bool mTitleUpdateInProgress;
|
||||
bool mHasCustomTitle;
|
||||
|
||||
// True iff embedder is either <object> or <embed>.
|
||||
bool mIsInObjectOrEmbed;
|
||||
|
||||
float mOriginalZoomLevel;
|
||||
float mOriginalResolution;
|
||||
};
|
||||
|
||||
inline ImageDocument* Document::AsImageDocument() {
|
||||
MOZ_ASSERT(IsImageDocument());
|
||||
return static_cast<ImageDocument*>(this);
|
||||
}
|
||||
|
||||
inline const ImageDocument* Document::AsImageDocument() const {
|
||||
MOZ_ASSERT(IsImageDocument());
|
||||
return static_cast<const ImageDocument*>(this);
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif /* mozilla_dom_ImageDocument_h */
|
||||
|
|
|
@ -114,6 +114,7 @@ EXPORTS.mozilla.dom += [
|
|||
"HTMLUnknownElement.h",
|
||||
"HTMLVideoElement.h",
|
||||
"ImageDocument.h",
|
||||
"MediaDocument.h",
|
||||
"MediaError.h",
|
||||
"nsBrowserElement.h",
|
||||
"PlayPromise.h",
|
||||
|
|
|
@ -3,6 +3,7 @@ support-files =
|
|||
bug592641_img.jpg
|
||||
dummy_page.html
|
||||
file_fullscreen-api-keys.html
|
||||
image.png
|
||||
submission_flush.html
|
||||
post_action_page.html
|
||||
form_data_file.bin
|
||||
|
@ -82,6 +83,7 @@ support-files =
|
|||
file_fullscreen-iframe-top.html
|
||||
file_fullscreen-iframe-middle.html
|
||||
file_fullscreen-iframe-inner.html
|
||||
[browser_containerLoadingContent.js]
|
||||
[browser_submission_flush.js]
|
||||
[browser_refresh_after_document_write.js]
|
||||
support-files =
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const syntheticBrowsingContexts = SpecialPowers.getBoolPref(
|
||||
"browser.opaqueResponseBlocking.syntheticBrowsingContext",
|
||||
false
|
||||
);
|
||||
|
||||
const DIRPATH = getRootDirectory(gTestPath).replace(
|
||||
"chrome://mochitests/content/",
|
||||
""
|
||||
);
|
||||
|
||||
const ORIGIN = "https://example.com";
|
||||
const CROSSORIGIN = "https://example.org";
|
||||
|
||||
const TABURL = `${ORIGIN}/${DIRPATH}dummy_page.html`;
|
||||
|
||||
const IMAGEURL = `${ORIGIN}/${DIRPATH}image.png`;
|
||||
const CROSSIMAGEURL = `${CROSSORIGIN}/${DIRPATH}image.png`;
|
||||
|
||||
const DOCUMENTURL = `${ORIGIN}/${DIRPATH}dummy_page.html`;
|
||||
const CROSSDOCUMENTURL = `${CROSSORIGIN}/${DIRPATH}dummy_page.html`;
|
||||
|
||||
async function createElements({ element, attribute }, url1, url2) {
|
||||
for (let url of [url1, url2]) {
|
||||
const object = content.document.createElement(element);
|
||||
object[attribute] = url;
|
||||
const onloadPromise = new Promise(res => {
|
||||
object.onload = res;
|
||||
});
|
||||
content.document.body.appendChild(object);
|
||||
await onloadPromise;
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
function getPids(browser) {
|
||||
return browser.browsingContext.children.map(
|
||||
child => child.currentWindowContext.osPid
|
||||
);
|
||||
}
|
||||
|
||||
async function runTest(spec, tabUrl, imageurl, crossimageurl, check) {
|
||||
await BrowserTestUtils.withNewTab(tabUrl, async browser => {
|
||||
await SpecialPowers.spawn(
|
||||
browser,
|
||||
[spec, imageurl, crossimageurl],
|
||||
async ({ element, attribute }, url1, url2) => {
|
||||
for (let url of [url1, url2]) {
|
||||
const object = content.document.createElement(element);
|
||||
object[attribute] = url;
|
||||
const onloadPromise = new Promise(res => {
|
||||
object.onload = res;
|
||||
});
|
||||
content.document.body.appendChild(object);
|
||||
await onloadPromise;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
await check(browser);
|
||||
});
|
||||
}
|
||||
|
||||
let iframe = { element: "iframe", attribute: "src" };
|
||||
let embed = { element: "embed", attribute: "src" };
|
||||
let object = { element: "object", attribute: "data" };
|
||||
|
||||
async function checkImage(browser) {
|
||||
let pids = getPids(browser);
|
||||
is(pids.length, 2, "There should be two browsing contexts");
|
||||
ok(pids[0], "The first pid should have a sane value");
|
||||
ok(pids[1], "The second pid should have a sane value");
|
||||
isnot(pids[0], pids[1], "The two pids should be different");
|
||||
|
||||
let images = [];
|
||||
for (let context of browser.browsingContext.children) {
|
||||
images.push(
|
||||
await SpecialPowers.spawn(context, [], async () => {
|
||||
let img = new URL(content.document.querySelector("img").src);
|
||||
is(
|
||||
`${img.protocol}//${img.host}`,
|
||||
`${content.location.protocol}//${content.location.host}`,
|
||||
"Images should be loaded in the same domain as the document"
|
||||
);
|
||||
return img.href;
|
||||
})
|
||||
);
|
||||
}
|
||||
isnot(images[0], images[1], "The images should have different sources");
|
||||
}
|
||||
|
||||
function checkDocument(browser) {
|
||||
let pids = getPids(browser);
|
||||
is(pids.length, 2, "There should be two browsing contexts");
|
||||
ok(pids[0], "The first pid should have a sane value");
|
||||
ok(pids[1], "The second pid should have a sane value");
|
||||
isnot(pids[0], pids[1], "The two pids should be different");
|
||||
}
|
||||
|
||||
add_task(async function test_iframeImageDocument() {
|
||||
await runTest(iframe, TABURL, IMAGEURL, CROSSIMAGEURL, checkImage);
|
||||
});
|
||||
|
||||
if (syntheticBrowsingContexts) {
|
||||
add_task(async function test_embedImageDocument() {
|
||||
await runTest(embed, TABURL, IMAGEURL, CROSSIMAGEURL, checkImage);
|
||||
});
|
||||
|
||||
add_task(async function test_objectImageDocument() {
|
||||
await runTest(object, TABURL, IMAGEURL, CROSSIMAGEURL, checkImage);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(async function test_iframeDocument() {
|
||||
await runTest(iframe, TABURL, DOCUMENTURL, CROSSDOCUMENTURL, checkDocument);
|
||||
});
|
||||
|
||||
if (syntheticBrowsingContexts) {
|
||||
add_task(async function test_embedDocument() {
|
||||
await runTest(embed, TABURL, DOCUMENTURL, CROSSDOCUMENTURL, checkDocument);
|
||||
});
|
||||
|
||||
add_task(async function test_objectDocument() {
|
||||
await runTest(object, TABURL, DOCUMENTURL, CROSSDOCUMENTURL, checkDocument);
|
||||
});
|
||||
}
|
|
@ -623,3 +623,4 @@ skip-if = toolkit == "android" # test does not function on android due to aggre
|
|||
support-files =
|
||||
file_window_close_and_open.html
|
||||
file_broadcast_load.html
|
||||
[test_frame_count_with_synthetic_doc.html]
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
function getWindowLength() {
|
||||
setTimeout(function() {
|
||||
if (window.length > 0) {
|
||||
ok(false, "Synthetic document shouldn't be exposed");
|
||||
}
|
||||
|
||||
// Keep running this check until the test stops
|
||||
getWindowLength();
|
||||
});
|
||||
}
|
||||
|
||||
function addObject() {
|
||||
const object = document.createElement("object");
|
||||
object.data = 'file_bug417760.png';
|
||||
document.body.appendChild(object);
|
||||
|
||||
object.onload = function() {
|
||||
ok(true, "Test passes");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
getWindowLength();
|
||||
addObject();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -251,4 +251,15 @@ mozilla::ipc::IPCResult BrowserBridgeChild::RecvIntrinsicSizeOrRatioChanged(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserBridgeChild::RecvImageLoadComplete(
|
||||
const nsresult& aResult) {
|
||||
if (RefPtr<Element> owner = mFrameLoader->GetOwnerContent()) {
|
||||
if (nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(owner)) {
|
||||
static_cast<nsObjectLoadingContent*>(olc.get())
|
||||
->SubdocumentImageLoadComplete(aResult);
|
||||
}
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
|
|
@ -96,6 +96,8 @@ class BrowserBridgeChild : public PBrowserBridgeChild {
|
|||
const Maybe<IntrinsicSize>& aIntrinsicSize,
|
||||
const Maybe<AspectRatio>& aIntrinsicRatio);
|
||||
|
||||
mozilla::ipc::IPCResult RecvImageLoadComplete(const nsresult& aResult);
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
mozilla::ipc::IPCResult RecvScrollRectIntoView(
|
||||
const nsRect& aRect, const ScrollAxis& aVertical,
|
||||
|
|
|
@ -257,6 +257,12 @@ IPCResult BrowserBridgeParent::RecvSetIsUnderHiddenEmbedderElement(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserBridgeParent::RecvUpdateRemoteStyle(
|
||||
const StyleImageRendering& aImageRendering) {
|
||||
Unused << mBrowserParent->SendUpdateRemoteStyle(aImageRendering);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
a11y::DocAccessibleParent* BrowserBridgeParent::GetDocAccessibleParent() {
|
||||
auto* embeddedBrowser = GetBrowserParent();
|
||||
|
|
|
@ -101,6 +101,9 @@ class BrowserBridgeParent : public PBrowserBridgeParent {
|
|||
mozilla::ipc::IPCResult RecvSetIsUnderHiddenEmbedderElement(
|
||||
const bool& aIsUnderHiddenEmbedderElement);
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateRemoteStyle(
|
||||
const StyleImageRendering& aImageRendering);
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
mozilla::ipc::IPCResult RecvSetEmbedderAccessible(PDocAccessibleParent* aDoc,
|
||||
uint64_t aID);
|
||||
|
|
|
@ -62,7 +62,9 @@
|
|||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/JSWindowActorChild.h"
|
||||
#include "mozilla/dom/ImageDocument.h"
|
||||
#include "mozilla/dom/LoadURIOptionsBinding.h"
|
||||
#include "mozilla/dom/MediaDocument.h"
|
||||
#include "mozilla/dom/MessageManagerBinding.h"
|
||||
#include "mozilla/dom/MouseEventBinding.h"
|
||||
#include "mozilla/dom/Nullable.h"
|
||||
|
@ -1328,6 +1330,25 @@ mozilla::ipc::IPCResult BrowserChild::RecvSetIsUnderHiddenEmbedderElement(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserChild::RecvUpdateRemoteStyle(
|
||||
const StyleImageRendering& aImageRendering) {
|
||||
BrowsingContext* context = GetBrowsingContext();
|
||||
if (!context) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
Document* document = context->GetDocument();
|
||||
if (!document) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
if (document->IsImageDocument()) {
|
||||
document->AsImageDocument()->UpdateRemoteStyle(aImageRendering);
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserChild::RecvDynamicToolbarMaxHeightChanged(
|
||||
const ScreenIntCoord& aHeight) {
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
|
|
|
@ -416,6 +416,9 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
|
|||
|
||||
mozilla::ipc::IPCResult RecvInsertText(const nsAString& aStringToInsert);
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateRemoteStyle(
|
||||
const StyleImageRendering& aImageRendering);
|
||||
|
||||
mozilla::ipc::IPCResult RecvNormalPriorityInsertText(
|
||||
const nsAString& aStringToInsert);
|
||||
|
||||
|
|
|
@ -3120,6 +3120,18 @@ mozilla::ipc::IPCResult BrowserParent::RecvIntrinsicSizeOrRatioChanged(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult BrowserParent::RecvImageLoadComplete(
|
||||
const nsresult& aResult) {
|
||||
BrowserBridgeParent* bridge = GetBrowserBridgeParent();
|
||||
if (!bridge || !bridge->CanSend()) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
Unused << bridge->SendImageLoadComplete(aResult);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool BrowserParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent) {
|
||||
nsCOMPtr<nsIWidget> textInputHandlingWidget = GetTextInputHandlingWidget();
|
||||
if (!textInputHandlingWidget) {
|
||||
|
|
|
@ -324,6 +324,8 @@ class BrowserParent final : public PBrowserParent,
|
|||
const Maybe<IntrinsicSize>& aIntrinsicSize,
|
||||
const Maybe<AspectRatio>& aIntrinsicRatio);
|
||||
|
||||
mozilla::ipc::IPCResult RecvImageLoadComplete(const nsresult& aResult);
|
||||
|
||||
mozilla::ipc::IPCResult RecvSyncMessage(
|
||||
const nsString& aMessage, const ClonedMessageData& aData,
|
||||
nsTArray<ipc::StructuredCloneData>* aRetVal);
|
||||
|
|
|
@ -106,6 +106,7 @@ using mozilla::dom::EmbedderElementEventType from "mozilla/dom/TabMessageTypes.h
|
|||
using mozilla::IntrinsicSize from "nsIFrame.h";
|
||||
using mozilla::AspectRatio from "mozilla/AspectRatio.h";
|
||||
using mozilla::NativeKeyBindingsType from "mozilla/NativeKeyBindingsType.h";
|
||||
using mozilla::StyleImageRendering from "mozilla/ServoStyleConsts.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -574,6 +575,8 @@ parent:
|
|||
async IntrinsicSizeOrRatioChanged(IntrinsicSize? aIntrinsicSize,
|
||||
AspectRatio? aIntrinsicRatio);
|
||||
|
||||
async ImageLoadComplete(nsresult aResult);
|
||||
|
||||
/**
|
||||
* Child informs the parent that a pointer lock has requested/released.
|
||||
*/
|
||||
|
@ -711,6 +714,8 @@ child:
|
|||
|
||||
async SetIsUnderHiddenEmbedderElement(bool aIsUnderHiddenEmbedderElement);
|
||||
|
||||
async UpdateRemoteStyle(StyleImageRendering aImageRendering);
|
||||
|
||||
async DynamicToolbarMaxHeightChanged(ScreenIntCoord height);
|
||||
|
||||
async DynamicToolbarOffsetChanged(ScreenIntCoord height);
|
||||
|
|
|
@ -30,6 +30,7 @@ using mozilla::dom::EmbedderElementEventType from "mozilla/dom/TabMessageTypes.h
|
|||
[RefCounted] using class nsDocShellLoadState from "nsDocShellLoadState.h";
|
||||
using mozilla::IntrinsicSize from "nsIFrame.h";
|
||||
using mozilla::AspectRatio from "mozilla/AspectRatio.h";
|
||||
using mozilla::StyleImageRendering from "mozilla/ServoStyleConsts.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -78,6 +79,8 @@ child:
|
|||
async IntrinsicSizeOrRatioChanged(IntrinsicSize? aIntrinsicSize,
|
||||
AspectRatio? aIntrinsicRatio);
|
||||
|
||||
async ImageLoadComplete(nsresult aResult);
|
||||
|
||||
both:
|
||||
|
||||
// Destroy the remote web browser due to the nsFrameLoader going away.
|
||||
|
@ -121,6 +124,8 @@ parent:
|
|||
|
||||
async SetIsUnderHiddenEmbedderElement(bool aIsUnderHiddenEmbedderElement);
|
||||
|
||||
async UpdateRemoteStyle(StyleImageRendering aImageRendering);
|
||||
|
||||
async WillChangeProcess();
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/ServoBindings.h"
|
||||
#include "mozilla/ServoStyleSetInlines.h"
|
||||
#include "mozilla/StaticPrefs_browser.h"
|
||||
#include "mozilla/StaticPrefs_layout.h"
|
||||
#include "mozilla/StaticPrefs_mathml.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
@ -3610,6 +3611,14 @@ nsCSSFrameConstructor::FindInputData(const Element& aElement,
|
|||
ArrayLength(sInputData));
|
||||
}
|
||||
|
||||
static nsIFrame* NS_NewSubDocumentOrImageFrame(mozilla::PresShell* aPresShell,
|
||||
mozilla::ComputedStyle* aStyle) {
|
||||
return StaticPrefs::
|
||||
browser_opaqueResponseBlocking_syntheticBrowsingContext_AtStartup()
|
||||
? NS_NewSubDocumentFrame(aPresShell, aStyle)
|
||||
: NS_NewImageFrame(aPresShell, aStyle);
|
||||
}
|
||||
|
||||
/* static */
|
||||
const nsCSSFrameConstructor::FrameConstructionData*
|
||||
nsCSSFrameConstructor::FindObjectData(const Element& aElement,
|
||||
|
@ -3640,7 +3649,8 @@ nsCSSFrameConstructor::FindObjectData(const Element& aElement,
|
|||
NS_NewEmptyFrame),
|
||||
SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_FALLBACK,
|
||||
ToCreationFunc(NS_NewBlockFrame)),
|
||||
SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_IMAGE, NS_NewImageFrame),
|
||||
SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_IMAGE,
|
||||
NS_NewSubDocumentOrImageFrame),
|
||||
SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_DOCUMENT,
|
||||
NS_NewSubDocumentFrame),
|
||||
// Fake plugin handlers load as documents
|
||||
|
|
|
@ -117,10 +117,12 @@ nsContentDLF::CreateInstance(const char* aCommand, nsIChannel* aChannel,
|
|||
contentType = TEXT_PLAIN;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
bool imageDocument = false;
|
||||
// Try html or plaintext; both use the same document CID
|
||||
if (IsTypeInList(contentType, gHTMLTypes) ||
|
||||
nsContentUtils::IsPlainTextType(contentType)) {
|
||||
return CreateDocument(
|
||||
rv = CreateDocument(
|
||||
aCommand, aChannel, aLoadGroup, aContainer,
|
||||
[]() -> already_AddRefed<Document> {
|
||||
RefPtr<Document> doc;
|
||||
|
@ -129,11 +131,9 @@ nsContentDLF::CreateInstance(const char* aCommand, nsIChannel* aChannel,
|
|||
return doc.forget();
|
||||
},
|
||||
aDocListener, aDocViewer);
|
||||
}
|
||||
|
||||
// Try XML
|
||||
if (IsTypeInList(contentType, gXMLTypes)) {
|
||||
return CreateDocument(
|
||||
} // Try XML
|
||||
else if (IsTypeInList(contentType, gXMLTypes)) {
|
||||
rv = CreateDocument(
|
||||
aCommand, aChannel, aLoadGroup, aContainer,
|
||||
[]() -> already_AddRefed<Document> {
|
||||
RefPtr<Document> doc;
|
||||
|
@ -142,11 +142,9 @@ nsContentDLF::CreateInstance(const char* aCommand, nsIChannel* aChannel,
|
|||
return doc.forget();
|
||||
},
|
||||
aDocListener, aDocViewer);
|
||||
}
|
||||
|
||||
// Try SVG
|
||||
if (IsTypeInList(contentType, gSVGTypes)) {
|
||||
return CreateDocument(
|
||||
} // Try SVG
|
||||
else if (IsTypeInList(contentType, gSVGTypes)) {
|
||||
rv = CreateDocument(
|
||||
aCommand, aChannel, aLoadGroup, aContainer,
|
||||
[]() -> already_AddRefed<Document> {
|
||||
RefPtr<Document> doc;
|
||||
|
@ -155,12 +153,10 @@ nsContentDLF::CreateInstance(const char* aCommand, nsIChannel* aChannel,
|
|||
return doc.forget();
|
||||
},
|
||||
aDocListener, aDocViewer);
|
||||
}
|
||||
|
||||
if (mozilla::DecoderTraits::ShouldHandleMediaType(
|
||||
contentType.get(),
|
||||
/* DecoderDoctorDiagnostics* */ nullptr)) {
|
||||
return CreateDocument(
|
||||
} else if (mozilla::DecoderTraits::ShouldHandleMediaType(
|
||||
contentType.get(),
|
||||
/* DecoderDoctorDiagnostics* */ nullptr)) {
|
||||
rv = CreateDocument(
|
||||
aCommand, aChannel, aLoadGroup, aContainer,
|
||||
[]() -> already_AddRefed<Document> {
|
||||
RefPtr<Document> doc;
|
||||
|
@ -169,11 +165,10 @@ nsContentDLF::CreateInstance(const char* aCommand, nsIChannel* aChannel,
|
|||
return doc.forget();
|
||||
},
|
||||
aDocListener, aDocViewer);
|
||||
}
|
||||
|
||||
// Try image types
|
||||
if (IsImageContentType(contentType)) {
|
||||
return CreateDocument(
|
||||
} // Try image types
|
||||
else if (IsImageContentType(contentType)) {
|
||||
imageDocument = true;
|
||||
rv = CreateDocument(
|
||||
aCommand, aChannel, aLoadGroup, aContainer,
|
||||
[]() -> already_AddRefed<Document> {
|
||||
RefPtr<Document> doc;
|
||||
|
@ -182,10 +177,18 @@ nsContentDLF::CreateInstance(const char* aCommand, nsIChannel* aChannel,
|
|||
return doc.forget();
|
||||
},
|
||||
aDocListener, aDocViewer);
|
||||
} else {
|
||||
// If we get here, then we weren't able to create anything. Sorry!
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// If we get here, then we weren't able to create anything. Sorry!
|
||||
return NS_ERROR_FAILURE;
|
||||
if (NS_SUCCEEDED(rv) && !imageDocument) {
|
||||
Document* doc = (*aDocViewer)->GetDocument();
|
||||
MOZ_ASSERT(doc);
|
||||
doc->MakeBrowsingContextNonSynthetic();
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
#ifndef LAYOUT_GENERIC_LAYOUTMESSAGEUTILS_H_
|
||||
#define LAYOUT_GENERIC_LAYOUTMESSAGEUTILS_H_
|
||||
|
||||
#include "ipc/EnumSerializer.h"
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "mozilla/AspectRatio.h"
|
||||
#include "mozilla/webrender/WebRenderTypes.h"
|
||||
|
||||
namespace IPC {
|
||||
|
||||
|
@ -41,6 +43,12 @@ struct ParamTraits<mozilla::AspectRatio> {
|
|||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::StyleImageRendering>
|
||||
: public ContiguousEnumSerializerInclusive<
|
||||
mozilla::StyleImageRendering, mozilla::StyleImageRendering::Auto,
|
||||
mozilla::StyleImageRendering::Optimizequality> {};
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif // LAYOUT_GENERIC_LAYOUTMESSAGEUTILS_H_
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "nsIImageLoadingContent.h"
|
||||
#include "nsImageLoadingContent.h"
|
||||
#include "nsImageRenderer.h"
|
||||
#include "nsObjectLoadingContent.h"
|
||||
#include "nsString.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsPresContext.h"
|
||||
|
@ -355,6 +356,8 @@ void nsImageFrame::DisconnectMap() {
|
|||
|
||||
void nsImageFrame::DestroyFrom(nsIFrame* aDestructRoot,
|
||||
PostDestroyData& aPostDestroyData) {
|
||||
MaybeSendIntrinsicSizeAndRatioToEmbedder(Nothing(), Nothing());
|
||||
|
||||
if (mReflowCallbackPosted) {
|
||||
PresShell()->CancelReflowCallback(this);
|
||||
mReflowCallbackPosted = false;
|
||||
|
@ -513,6 +516,11 @@ void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
|
|||
// We have a PresContext now, so we need to notify the image content node
|
||||
// that it can register images.
|
||||
imageLoader->FrameCreated(this);
|
||||
if (nsIDocShell* docShell = PresContext()->GetDocShell()) {
|
||||
RefPtr<BrowsingContext> bc = docShell->GetBrowsingContext();
|
||||
mIsInObjectOrEmbed = bc->IsEmbedderTypeObjectOrEmbed() &&
|
||||
PresContext()->Document()->IsImageDocument();
|
||||
}
|
||||
} else {
|
||||
const StyleImage* image = GetImageFromStyle();
|
||||
MOZ_ASSERT(mKind == Kind::ListStyleImage || image->IsImageRequestType(),
|
||||
|
@ -538,6 +546,8 @@ void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
|
|||
|
||||
currentRequest->BoostPriority(categoryToBoostPriority);
|
||||
}
|
||||
|
||||
MaybeSendIntrinsicSizeAndRatioToEmbedder();
|
||||
}
|
||||
|
||||
void nsImageFrame::SetupForContentURLRequest() {
|
||||
|
@ -950,6 +960,13 @@ void nsImageFrame::UpdateImage(imgIRequest* aRequest, imgIContainer* aImage) {
|
|||
bool intrinsicRatioChanged = UpdateIntrinsicRatio();
|
||||
return intrinsicSizeChanged || intrinsicRatioChanged;
|
||||
}();
|
||||
|
||||
if (intrinsicSizeOrRatioChanged) {
|
||||
// Our aspect-ratio property value changed, and an embedding <object> or
|
||||
// <embed> might care about that.
|
||||
MaybeSendIntrinsicSizeAndRatioToEmbedder();
|
||||
}
|
||||
|
||||
if (!GotInitialReflow()) {
|
||||
return;
|
||||
}
|
||||
|
@ -1022,6 +1039,47 @@ void nsImageFrame::InvalidateSelf(const nsIntRect* aLayerInvalidRect,
|
|||
}
|
||||
}
|
||||
|
||||
void nsImageFrame::MaybeSendIntrinsicSizeAndRatioToEmbedder() {
|
||||
MaybeSendIntrinsicSizeAndRatioToEmbedder(Some(GetIntrinsicSize()),
|
||||
Some(GetAspectRatio()));
|
||||
}
|
||||
|
||||
void nsImageFrame::MaybeSendIntrinsicSizeAndRatioToEmbedder(
|
||||
Maybe<IntrinsicSize> aIntrinsicSize, Maybe<AspectRatio> aIntrinsicRatio) {
|
||||
if (!mIsInObjectOrEmbed || !mImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShell> docShell = PresContext()->GetDocShell();
|
||||
if (!docShell) {
|
||||
return;
|
||||
}
|
||||
|
||||
BrowsingContext* bc = docShell->GetBrowsingContext();
|
||||
if (!bc) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(bc->IsContentSubframe());
|
||||
|
||||
if (bc->GetParent()->IsInProcess()) {
|
||||
if (Element* embedder = bc->GetEmbedderElement()) {
|
||||
if (nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(embedder)) {
|
||||
static_cast<nsObjectLoadingContent*>(olc.get())
|
||||
->SubdocumentIntrinsicSizeOrRatioChanged(aIntrinsicSize,
|
||||
aIntrinsicRatio);
|
||||
} else {
|
||||
MOZ_ASSERT_UNREACHABLE("Got out of sync?");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (BrowserChild* browserChild = BrowserChild::GetFrom(docShell)) {
|
||||
Unused << browserChild->SendIntrinsicSizeOrRatioChanged(aIntrinsicSize,
|
||||
aIntrinsicRatio);
|
||||
}
|
||||
}
|
||||
|
||||
void nsImageFrame::OnLoadComplete(imgIRequest* aRequest, nsresult aStatus) {
|
||||
NotifyNewCurrentRequest(aRequest, aStatus);
|
||||
}
|
||||
|
@ -1039,6 +1097,10 @@ void nsImageFrame::ResponsiveContentDensityChanged() {
|
|||
return;
|
||||
}
|
||||
|
||||
// Our aspect-ratio property value changed, and an embedding <object> or
|
||||
// <embed> might care about that.
|
||||
MaybeSendIntrinsicSizeAndRatioToEmbedder();
|
||||
|
||||
PresShell()->FrameNeedsReflow(this, IntrinsicDirty::StyleChange,
|
||||
NS_FRAME_IS_DIRTY);
|
||||
}
|
||||
|
@ -1151,8 +1213,15 @@ void nsImageFrame::EnsureIntrinsicSizeAndRatio() {
|
|||
return;
|
||||
}
|
||||
|
||||
UpdateIntrinsicSize();
|
||||
UpdateIntrinsicRatio();
|
||||
bool intrinsicSizeOrRatioChanged = UpdateIntrinsicSize();
|
||||
intrinsicSizeOrRatioChanged =
|
||||
UpdateIntrinsicRatio() || intrinsicSizeOrRatioChanged;
|
||||
|
||||
if (intrinsicSizeOrRatioChanged) {
|
||||
// Our aspect-ratio property value changed, and an embedding <object> or
|
||||
// <embed> might care about that.
|
||||
MaybeSendIntrinsicSizeAndRatioToEmbedder();
|
||||
}
|
||||
}
|
||||
|
||||
nsIFrame::SizeComputationResult nsImageFrame::ComputeSize(
|
||||
|
|
|
@ -370,6 +370,10 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
|
|||
void InvalidateSelf(const nsIntRect* aLayerInvalidRect,
|
||||
const nsRect* aFrameInvalidRect);
|
||||
|
||||
void MaybeSendIntrinsicSizeAndRatioToEmbedder();
|
||||
void MaybeSendIntrinsicSizeAndRatioToEmbedder(Maybe<mozilla::IntrinsicSize>,
|
||||
Maybe<mozilla::AspectRatio>);
|
||||
|
||||
RefPtr<nsImageMap> mImageMap;
|
||||
|
||||
RefPtr<nsImageListener> mListener;
|
||||
|
@ -397,6 +401,8 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
|
|||
bool mReflowCallbackPosted;
|
||||
bool mForceSyncDecoding;
|
||||
|
||||
bool mIsInObjectOrEmbed = false;
|
||||
|
||||
/* loading / broken image icon support */
|
||||
|
||||
// XXXbz this should be handled by the prescontext, I think; that
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/HTMLFrameElement.h"
|
||||
#include "mozilla/dom/ImageDocument.h"
|
||||
#include "mozilla/dom/BrowserParent.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
@ -73,7 +74,8 @@ nsSubDocumentFrame::nsSubDocumentFrame(ComputedStyle* aStyle,
|
|||
mIsInline(false),
|
||||
mPostedReflowCallback(false),
|
||||
mDidCreateDoc(false),
|
||||
mCallingShow(false) {}
|
||||
mCallingShow(false),
|
||||
mIsInObjectOrEmbed(false) {}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
a11y::AccType nsSubDocumentFrame::AccessibleType() {
|
||||
|
@ -145,8 +147,14 @@ void nsSubDocumentFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
|
|||
frameloader->Hide();
|
||||
}
|
||||
}
|
||||
|
||||
if (RefPtr<BrowsingContext> bc = frameloader->GetExtantBrowsingContext()) {
|
||||
mIsInObjectOrEmbed = bc->IsEmbedderTypeObjectOrEmbed();
|
||||
}
|
||||
}
|
||||
|
||||
MaybeUpdateRemoteStyle();
|
||||
|
||||
PropagateIsUnderHiddenEmbedderElementToSubView(
|
||||
PresShell()->IsUnderHiddenEmbedderElement() ||
|
||||
!StyleVisibility()->IsVisible());
|
||||
|
@ -181,7 +189,7 @@ void nsSubDocumentFrame::ShowViewer() {
|
|||
}
|
||||
|
||||
RefPtr<nsFrameLoader> frameloader = FrameLoader();
|
||||
if (!frameloader) {
|
||||
if (!frameloader || frameloader->IsDead()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -845,11 +853,51 @@ void nsSubDocumentFrame::MaybeUpdateEmbedderColorScheme() {
|
|||
Unused << bc->SetEmbedderColorScheme(value);
|
||||
}
|
||||
|
||||
void nsSubDocumentFrame::MaybeUpdateRemoteStyle(
|
||||
ComputedStyle* aOldComputedStyle) {
|
||||
if (!mIsInObjectOrEmbed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aOldComputedStyle &&
|
||||
aOldComputedStyle->StyleVisibility()->mImageRendering ==
|
||||
Style()->StyleVisibility()->mImageRendering) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mFrameLoader) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFrameLoader->IsRemoteFrame()) {
|
||||
mFrameLoader->UpdateRemoteStyle(
|
||||
Style()->StyleVisibility()->mImageRendering);
|
||||
return;
|
||||
}
|
||||
|
||||
BrowsingContext* context = mFrameLoader->GetExtantBrowsingContext();
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
Document* document = context->GetDocument();
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (document->IsImageDocument()) {
|
||||
document->AsImageDocument()->UpdateRemoteStyle(
|
||||
Style()->StyleVisibility()->mImageRendering);
|
||||
}
|
||||
}
|
||||
|
||||
void nsSubDocumentFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
|
||||
nsAtomicContainerFrame::DidSetComputedStyle(aOldComputedStyle);
|
||||
|
||||
MaybeUpdateEmbedderColorScheme();
|
||||
|
||||
MaybeUpdateRemoteStyle(aOldComputedStyle);
|
||||
|
||||
// If this presshell has invisible ancestors, we don't need to propagate the
|
||||
// visibility style change to the subdocument since the subdocument should
|
||||
// have already set the IsUnderHiddenEmbedderElement flag in
|
||||
|
@ -1235,11 +1283,6 @@ nsPoint nsSubDocumentFrame::GetExtraOffset() const {
|
|||
}
|
||||
|
||||
void nsSubDocumentFrame::SubdocumentIntrinsicSizeOrRatioChanged() {
|
||||
if (MOZ_UNLIKELY(HasAllStateBits(NS_FRAME_IS_DIRTY))) {
|
||||
// We will be reflowed soon anyway.
|
||||
return;
|
||||
}
|
||||
|
||||
const nsStylePosition* pos = StylePosition();
|
||||
bool dependsOnIntrinsics =
|
||||
!pos->mWidth.ConvertsToLength() || !pos->mHeight.ConvertsToLength();
|
||||
|
@ -1248,6 +1291,7 @@ void nsSubDocumentFrame::SubdocumentIntrinsicSizeOrRatioChanged() {
|
|||
auto dirtyHint = dependsOnIntrinsics ? IntrinsicDirty::StyleChange
|
||||
: IntrinsicDirty::Resize;
|
||||
PresShell()->FrameNeedsReflow(this, dirtyHint, NS_FRAME_IS_DIRTY);
|
||||
InvalidateFrame();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -135,6 +135,8 @@ class nsSubDocumentFrame final : public nsAtomicContainerFrame,
|
|||
void ClearRetainedPaintData();
|
||||
|
||||
void MaybeUpdateEmbedderColorScheme();
|
||||
|
||||
void MaybeUpdateRemoteStyle(ComputedStyle* aOldComputedStyle = nullptr);
|
||||
void PropagateIsUnderHiddenEmbedderElementToSubView(
|
||||
bool aIsUnderHiddenEmbedderElement);
|
||||
|
||||
|
@ -193,6 +195,7 @@ class nsSubDocumentFrame final : public nsAtomicContainerFrame,
|
|||
bool mPostedReflowCallback : 1;
|
||||
bool mDidCreateDoc : 1;
|
||||
bool mCallingShow : 1;
|
||||
bool mIsInObjectOrEmbed : 1;
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
|
|
|
@ -25,6 +25,11 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
.isInObjectOrEmbed {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
}
|
||||
|
|
|
@ -1617,6 +1617,23 @@
|
|||
value: @IS_NIGHTLY_BUILD@
|
||||
mirror: always
|
||||
|
||||
# When this pref is enabled, <object> and <embed> elements will create
|
||||
# synthetic documents when the resource type they're loading is an image.
|
||||
- name: browser.opaqueResponseBlocking.syntheticBrowsingContext
|
||||
type: bool
|
||||
value: @IS_NIGHTLY_BUILD@
|
||||
mirror: once
|
||||
|
||||
# When this pref is enabled, <object> and <embed> elements will filter the
|
||||
# browsing contexts created for the synthetic browsing contexts for the
|
||||
# synthetic documents when browser.opaqueResponseBlocking.syntheticBrowsingContext
|
||||
# is enabled from `Window.frames`, `Window.length` and named targeting.
|
||||
- name: browser.opaqueResponseBlocking.syntheticBrowsingContext.filter
|
||||
type: bool
|
||||
value: @IS_NIGHTLY_BUILD@
|
||||
mirror: once
|
||||
do_not_use_directly: true
|
||||
|
||||
# When true, zooming will be enabled on all sites, even ones that declare
|
||||
# user-scalable=no.
|
||||
- name: browser.ui.zoom.force-user-scalable
|
||||
|
|
Загрузка…
Ссылка в новой задаче