From 3118636b0dec29b04a6b637004fdd492adc1d580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 5 Aug 2024 12:23:44 +0000 Subject: [PATCH] Bug 1076583 - Make src attribute not load sync. r=smaug,extension-reviewers,devtools-reviewers,robwu,nchevobbe This fixes src loads to be consistent with srcset/picture loads, modulo the special synchronous case in the spec (https://html.spec.whatwg.org/#update-the-image-data step 7), which requires src loads to be sync if the image is available. We now avoid triggering the load from the parser consistently for src / srcset / picture, and unify the codepath with BindToTree. That should avoid some useless task allocations. Only the sync load code-path needs a script runner (mostly to deal with anonymous content like the video poster and such, but it also helps not trigger sync loads at unexpected times like on adoption). About the HTMLImageElement::Complete() getter change, we need to also return false if there's an existing load task. That is the proposal in https://github.com/whatwg/html/issues/4884, and prevents some failures in the-img-element/{update-src-complete,img.complete}.html WPTs. It technically changes our behavior on .srcset changes, but it makes it consistent with .src changes and other browsers, so seems fine. There are a couple regressions in CSP tests and the networkEvent stubs, but these are really a pre-existing issue. What happens is that, since the loads are now async, CSP can't figure out the script that triggered the load anymore. I need to look if there's an easy way to propagate that information in the image load tasks, but this is trivially reproducible by changing these tests to use srcset rather than src. The rest of the test changes are as expected: either new passes, or expected test changes from this. Differential Revision: https://phabricator.services.mozilla.com/D215519 --- .../test/node/fixtures/stubs/networkEvent.js | 18 +- ...resources_network_events_parent_process.js | 13 +- dom/base/DOMIntersectionObserver.cpp | 2 +- dom/base/nsImageLoadingContent.cpp | 22 - dom/base/nsImageLoadingContent.h | 23 +- dom/base/test/browser_blocking_image.js | 3 +- dom/html/HTMLImageElement.cpp | 389 +++++++----------- dom/html/HTMLImageElement.h | 29 +- dom/html/HTMLPictureElement.cpp | 8 +- .../mochitest/general/test_img_mutations.html | 56 +-- ...ross-origin-image-from-script.sub.html.ini | 4 +- ...tion-block-cross-origin-image.sub.html.ini | 3 + ...ation-block-image-from-script.sub.html.ini | 4 +- ...typolicyviolation-block-image.sub.html.ini | 3 + ...f-available-images-matching.https.html.ini | 6 - .../current-request-microtask.html.ini | 5 - .../test_ext_web_accessible_incognito.html | 2 +- 17 files changed, 216 insertions(+), 374 deletions(-) create mode 100644 testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html.ini create mode 100644 testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html.ini delete mode 100644 testing/web-platform/meta/html/semantics/embedded-content/the-img-element/update-the-image-data/current-request-microtask.html.ini diff --git a/devtools/client/webconsole/test/node/fixtures/stubs/networkEvent.js b/devtools/client/webconsole/test/node/fixtures/stubs/networkEvent.js index d5af9db00df78..b599fee7c6c0b 100644 --- a/devtools/client/webconsole/test/node/fixtures/stubs/networkEvent.js +++ b/devtools/client/webconsole/test/node/fixtures/stubs/networkEvent.js @@ -29,14 +29,7 @@ rawPackets.set(`GET request`, { "cause": { "loadingDocumentUri": "https://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html", "type": "img", - "stacktraceAvailable": true, - "lastFrame": { - "filename": "https://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html", - "lineNumber": 3, - "columnNumber": 1, - "functionName": "triggerPacket", - "asyncCause": null - } + "stacktraceAvailable": false }, "httpVersion": "HTTP/1.1", "status": "404", @@ -68,14 +61,7 @@ rawPackets.set(`GET request update`, { "cause": { "loadingDocumentUri": "https://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html", "type": "img", - "stacktraceAvailable": true, - "lastFrame": { - "filename": "https://example.com/browser/devtools/client/webconsole/test/browser/stub-generators/test-network-event.html", - "lineNumber": 3, - "columnNumber": 1, - "functionName": "triggerPacket", - "asyncCause": null - } + "stacktraceAvailable": false }, "httpVersion": "HTTP/1.1", "status": "404", diff --git a/devtools/shared/commands/resource/tests/browser_resources_network_events_parent_process.js b/devtools/shared/commands/resource/tests/browser_resources_network_events_parent_process.js index dc92354f3635f..ad03ac015828c 100644 --- a/devtools/shared/commands/resource/tests/browser_resources_network_events_parent_process.js +++ b/devtools/shared/commands/resource/tests/browser_resources_network_events_parent_process.js @@ -21,8 +21,8 @@ const createParentProcessRequests = async () => { const EXPECTED_METHOD_NAME = "createParentProcessRequests"; const EXPECTED_REQUEST_LINE_1 = 12; const EXPECTED_REQUEST_COL_1 = 9; -const EXPECTED_REQUEST_LINE_2 = 17; -const EXPECTED_REQUEST_COL_2 = 3; +// const EXPECTED_REQUEST_LINE_2 = 17; +// const EXPECTED_REQUEST_COL_2 = 3; // Test the ResourceCommand API around NETWORK_EVENT for the parent process @@ -133,13 +133,20 @@ add_task(async function testParentProcessRequests() { ok(!firstImageRequest.fromCache, "The first image request isn't cached"); ok(firstImageRequest.chromeContext, "The first image request is privileged"); - const firstImageStacktrace = receivedStacktraces[1].lastFrame; is(receivedStacktraces[1].resourceId, firstImageRequest.stacktraceResourceId); + const firstImageStacktrace = receivedStacktraces[1].lastFrame; + // TODO(bug 1911435). + todo( + !!firstImageStacktrace, + "After bug 1076583, image load is async and we can't get a stack trace" + ); + /* is(firstImageStacktrace.filename, gTestPath); is(firstImageStacktrace.lineNumber, EXPECTED_REQUEST_LINE_2); is(firstImageStacktrace.columnNumber, EXPECTED_REQUEST_COL_2); is(firstImageStacktrace.functionName, EXPECTED_METHOD_NAME); is(firstImageStacktrace.asyncCause, null); + */ info("Assert the second image request"); const secondImageRequest = receivedNetworkEvents[2]; diff --git a/dom/base/DOMIntersectionObserver.cpp b/dom/base/DOMIntersectionObserver.cpp index 863061f452b12..9fd6488850064 100644 --- a/dom/base/DOMIntersectionObserver.cpp +++ b/dom/base/DOMIntersectionObserver.cpp @@ -149,7 +149,7 @@ static void LazyLoadCallback( Element* target = entry->Target(); if (entry->IsIntersecting()) { if (auto* image = HTMLImageElement::FromNode(target)) { - image->StopLazyLoading(HTMLImageElement::StartLoading::Yes); + image->StopLazyLoading(); } else if (auto* iframe = HTMLIFrameElement::FromNode(target)) { iframe->StopLazyLoading(); } else { diff --git a/dom/base/nsImageLoadingContent.cpp b/dom/base/nsImageLoadingContent.cpp index fa1798ce3532e..c12a0e343b7c5 100644 --- a/dom/base/nsImageLoadingContent.cpp +++ b/dom/base/nsImageLoadingContent.cpp @@ -105,7 +105,6 @@ nsImageLoadingContent::nsImageLoadingContent() mRequestGeneration(0), mLoadingEnabled(true), mLoading(false), - mNewRequestsWillNeedAnimationReset(false), mUseUrgentStartForChannel(false), mLazyLoading(false), mStateChangerDepth(0), @@ -971,7 +970,6 @@ nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel, if (NS_SUCCEEDED(rv)) { CloneScriptedRequests(req); TrackImage(req); - ResetAnimationIfNeeded(); return NS_OK; } @@ -1167,7 +1165,6 @@ nsresult nsImageLoadingContent::LoadImage(nsIURI* aNewURI, bool aForce, CloneScriptedRequests(req); TrackImage(req); - ResetAnimationIfNeeded(); // Handle cases when we just ended up with a request but it's already done. // In that situation we have to synchronously switch that request to being @@ -1483,10 +1480,6 @@ RefPtr& nsImageLoadingContent::PrepareCurrentRequest( // Get rid of anything that was there previously. ClearCurrentRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DiscardImages)); - if (mNewRequestsWillNeedAnimationReset) { - mCurrentRequestFlags |= REQUEST_NEEDS_ANIMATION_RESET; - } - if (aImageLoadType == eImageLoadType_Imageset) { mCurrentRequestFlags |= REQUEST_IS_IMAGESET; } @@ -1500,10 +1493,6 @@ RefPtr& nsImageLoadingContent::PreparePendingRequest( // Get rid of anything that was there previously. ClearPendingRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DiscardImages)); - if (mNewRequestsWillNeedAnimationReset) { - mPendingRequestFlags |= REQUEST_NEEDS_ANIMATION_RESET; - } - if (aImageLoadType == eImageLoadType_Imageset) { mPendingRequestFlags |= REQUEST_IS_IMAGESET; } @@ -1562,7 +1551,6 @@ void nsImageLoadingContent::MakePendingRequestCurrent() { mPendingRequestFlags = 0; mCurrentRequestRegistered = mPendingRequestRegistered; mPendingRequestRegistered = false; - ResetAnimationIfNeeded(); } void nsImageLoadingContent::ClearCurrentRequest( @@ -1606,16 +1594,6 @@ void nsImageLoadingContent::ClearPendingRequest( mPendingRequestFlags = 0; } -void nsImageLoadingContent::ResetAnimationIfNeeded() { - if (mCurrentRequest && - (mCurrentRequestFlags & REQUEST_NEEDS_ANIMATION_RESET)) { - nsCOMPtr container; - mCurrentRequest->GetImage(getter_AddRefs(container)); - if (container) container->ResetAnimation(); - mCurrentRequestFlags &= ~REQUEST_NEEDS_ANIMATION_RESET; - } -} - bool nsImageLoadingContent::HaveSize(imgIRequest* aImage) { // Handle the null case if (!aImage) return false; diff --git a/dom/base/nsImageLoadingContent.h b/dom/base/nsImageLoadingContent.h index 2b6dac53fb91f..a84836d3561bf 100644 --- a/dom/base/nsImageLoadingContent.h +++ b/dom/base/nsImageLoadingContent.h @@ -424,13 +424,6 @@ class nsImageLoadingContent : public nsIImageLoadingContent { nsresult aReason, const Maybe& aNonvisibleAction = Nothing()); - /** - * Reset animation of the current request if - * |mNewRequestsWillNeedAnimationReset| was true when the request was - * prepared. - */ - void ResetAnimationIfNeeded(); - /** * Static helper method to tell us if we have the size of a request. The * image may be null. @@ -467,13 +460,11 @@ class nsImageLoadingContent : public nsIImageLoadingContent { uint8_t mPendingRequestFlags = 0; enum { - // Set if the request needs ResetAnimation called on it. - REQUEST_NEEDS_ANIMATION_RESET = 1 << 0, // Set if the request is currently tracked with the document. - REQUEST_IS_TRACKED = 1 << 1, + REQUEST_IS_TRACKED = 1 << 0, // Set if this is an imageset request, such as from or // - REQUEST_IS_IMAGESET = 1 << 2, + REQUEST_IS_IMAGESET = 1 << 1, }; // If the image was blocked or if there was an error loading, it's nice to @@ -565,16 +556,6 @@ class nsImageLoadingContent : public nsIImageLoadingContent { */ bool mLoading : 1; - /** - * A hack to get animations to reset, see bug 594771. On requests - * that originate from setting .src, we mark them for needing their animation - * reset when they are ready. mNewRequestsWillNeedAnimationReset is set to - * true while preparing such requests (as a hack around needing to change an - * interface), and the other two booleans store which of the current - * and pending requests are of the sort that need their animation restarted. - */ - bool mNewRequestsWillNeedAnimationReset : 1; - /** * Flag to indicate whether the channel should be mark as urgent-start. * It should be set in *Element and passed to nsContentUtils::LoadImage. diff --git a/dom/base/test/browser_blocking_image.js b/dom/base/test/browser_blocking_image.js index 5749937f07a8d..5dec9a586a928 100644 --- a/dom/base/test/browser_blocking_image.js +++ b/dom/base/test/browser_blocking_image.js @@ -158,8 +158,6 @@ add_task(async function block_pending_request_test() { let img = content.document.createElement("img"); img.src = "https://example.com/tests/image/test/mochitest/shaver.png"; - - let req = img.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST); img.addObserver(observer); content.document.body.appendChild(img); @@ -169,6 +167,7 @@ add_task(async function block_pending_request_test() { info("Size Available now!"); img.removeObserver(observer); + let req = img.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST); // Now we change to load from http:// site, which will be blocked. img.src = "http://example.com/tests/image/test/mochitest/shaver.png"; diff --git a/dom/html/HTMLImageElement.cpp b/dom/html/HTMLImageElement.cpp index 597d7f4b22bbe..4024846211427 100644 --- a/dom/html/HTMLImageElement.cpp +++ b/dom/html/HTMLImageElement.cpp @@ -77,7 +77,7 @@ namespace mozilla::dom { // Calls LoadSelectedImage on host element unless it has been superseded or // canceled -- this is the synchronous section of "update the image data". -// https://html.spec.whatwg.org/multipage/embedded-content.html#update-the-image-data +// https://html.spec.whatwg.org/#update-the-image-data class ImageLoadTask final : public MicroTaskRunnable { public: ImageLoadTask(HTMLImageElement* aElement, bool aAlwaysLoad, @@ -93,7 +93,7 @@ class ImageLoadTask final : public MicroTaskRunnable { if (mElement->mPendingImageLoadTask == this) { mElement->mPendingImageLoadTask = nullptr; mElement->mUseUrgentStartForChannel = mUseUrgentStartForChannel; - mElement->LoadSelectedImage(true, true, mAlwaysLoad); + mElement->LoadSelectedImage(mAlwaysLoad); } mDocument->UnblockOnload(false); } @@ -165,12 +165,11 @@ bool HTMLImageElement::Draggable() const { bool HTMLImageElement::Complete() { // It is still not clear what value should img.complete return in various // cases, see https://github.com/whatwg/html/issues/4884 - if (!HasAttr(nsGkAtoms::srcset) && !HasNonEmptyAttr(nsGkAtoms::src)) { return true; } - if (!mCurrentRequest || mPendingRequest) { + if (!mCurrentRequest || mPendingRequest || mPendingImageLoadTask) { return false; } @@ -321,32 +320,24 @@ void HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName, } bool forceReload = false; - if (aName == nsGkAtoms::loading && !mLoading) { if (aValue && Loading(aValue->GetEnumValue()) == Loading::Lazy) { SetLazyLoading(); } else if (aOldValue && Loading(aOldValue->GetEnumValue()) == Loading::Lazy) { - StopLazyLoading(StartLoading::Yes); + StopLazyLoading(StartLoad(aNotify)); } } else if (aName == nsGkAtoms::src && !aValue) { + // AfterMaybeChangeAttr handles setting src since it needs to catch + // img.src = img.src, so we only need to handle the unset case // NOTE: regular src value changes are handled in AfterMaybeChangeAttr, so // this only needs to handle unsetting the src attribute. // Mark channel as urgent-start before load image if the image load is - // initaiated by a user interaction. - mUseUrgentStartForChannel = UserActivation::IsHandlingUserInput(); - - // AfterMaybeChangeAttr handles setting src since it needs to catch - // img.src = img.src, so we only need to handle the unset case - if (InResponsiveMode()) { - if (mResponsiveSelector && mResponsiveSelector->Content() == this) { - mResponsiveSelector->SetDefaultSource(VoidString()); - } - UpdateSourceSyncAndQueueImageTask(true); - } else { - // Bug 1076583 - We still behave synchronously in the non-responsive case - CancelImageRequests(aNotify); + // initiated by a user interaction. + if (mResponsiveSelector && mResponsiveSelector->Content() == this) { + mResponsiveSelector->SetDefaultSource(VoidString()); } + forceReload = true; } else if (aName == nsGkAtoms::srcset) { // Mark channel as urgent-start before load image if the image load is // initaiated by a user interaction. @@ -368,37 +359,20 @@ void HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName, ImageDecodingType::Sync); } else if (aName == nsGkAtoms::referrerpolicy) { ReferrerPolicy referrerPolicy = GetReferrerPolicyAsEnum(); - // FIXME(emilio): Why only when not in responsive mode? Also see below for - // aNotify. - forceReload = aNotify && !InResponsiveMode() && - referrerPolicy != ReferrerPolicy::_empty && + forceReload = referrerPolicy != ReferrerPolicy::_empty && referrerPolicy != ReferrerPolicyFromAttr(aOldValue); } else if (aName == nsGkAtoms::crossorigin) { - // FIXME(emilio): The aNotify bit seems a bit suspicious, but it is useful - // to avoid extra sync loads, specially in non-responsive mode. Ideally we - // can unify the responsive and non-responsive code paths (bug 1076583), and - // simplify this a bit. - forceReload = aNotify && GetCORSMode() != AttrValueToCORSMode(aOldValue); + forceReload = GetCORSMode() != AttrValueToCORSMode(aOldValue); } - if (forceReload) { - // Because we load image synchronously in non-responsive-mode, we need to do - // reload after the attribute has been set if the reload is triggered by - // cross origin / referrer policy changing. - // - // Mark channel as urgent-start before load image if the image load is - // initiated by a user interaction. + // NOTE(emilio): When not notifying, we come from the parser or some other + // internal caller, in which cases we can skip the load since we are about to + // get bound to a tree. + if (forceReload && aNotify) { + // Per spec, full selection runs when this changes, even though it doesn't + // directly affect the source selection. mUseUrgentStartForChannel = UserActivation::IsHandlingUserInput(); - if (InResponsiveMode()) { - // Per spec, full selection runs when this changes, even though - // it doesn't directly affect the source selection - UpdateSourceSyncAndQueueImageTask(true); - } else if (ShouldLoadImage()) { - // Bug 1076583 - We still use the older synchronous algorithm in - // non-responsive mode. Force a new load of the image with the - // new cross origin policy - ForceReload(aNotify, IgnoreErrors()); - } + UpdateSourceSyncAndQueueImageTask(true); } return nsGenericHTMLElement::AfterSetAttr( @@ -427,47 +401,19 @@ void HTMLImageElement::AfterMaybeChangeAttr( // being set to its existing value, which is normally optimized away as a // no-op. // - // If we are in responsive mode, we drop the forced reload behavior, - // but still trigger a image load task for img.src = img.src per - // spec. + // If we are in responsive mode, we drop the forced reload behavior, but still + // trigger a image load task for img.src = img.src per spec. // // Both cases handle unsetting src in AfterSetAttr - // Mark channel as urgent-start before load image if the image load is - // initaiated by a user interaction. - mUseUrgentStartForChannel = UserActivation::IsHandlingUserInput(); - mSrcTriggeringPrincipal = nsContentUtils::GetAttrTriggeringPrincipal( this, aValue.String(), aMaybeScriptedPrincipal); - if (InResponsiveMode()) { - if (mResponsiveSelector && mResponsiveSelector->Content() == this) { - mResponsiveSelector->SetDefaultSource(mSrcURI, mSrcTriggeringPrincipal); - } + if (mResponsiveSelector && mResponsiveSelector->Content() == this) { + mResponsiveSelector->SetDefaultSource(mSrcURI, mSrcTriggeringPrincipal); + } + if (aNotify) { + mUseUrgentStartForChannel = UserActivation::IsHandlingUserInput(); UpdateSourceSyncAndQueueImageTask(true); - } else if (aNotify && ShouldLoadImage()) { - // If aNotify is false, we are coming from the parser or some such place; - // we'll get bound after all the attributes have been set, so we'll do the - // sync image load from BindToTree. Skip the LoadImage call in that case. - - // Note that this sync behavior is partially removed from the spec, bug - // 1076583 - - // A hack to get animations to reset. See bug 594771. - mNewRequestsWillNeedAnimationReset = true; - - // Force image loading here, so that we'll try to load the image from - // network if it's set to be not cacheable. - // Potentially, false could be passed here rather than aNotify since - // UpdateState will be called by SetAttrAndNotify, but there are two - // obstacles to this: 1) LoadImage will end up calling - // UpdateState(aNotify), and we do not want it to call UpdateState(false) - // when aNotify is true, and 2) When this function is called by - // OnAttrSetButNotChanged, SetAttrAndNotify will not subsequently call - // UpdateState. - LoadSelectedImage(/* aForce = */ true, aNotify, - /* aAlwaysLoad = */ true); - - mNewRequestsWillNeedAnimationReset = false; } } @@ -513,59 +459,31 @@ bool HTMLImageElement::IsHTMLFocusable(IsFocusableFlags aFlags, } nsresult HTMLImageElement::BindToTree(BindContext& aContext, nsINode& aParent) { - nsresult rv = nsGenericHTMLElement::BindToTree(aContext, aParent); - NS_ENSURE_SUCCESS(rv, rv); + MOZ_TRY(nsGenericHTMLElement::BindToTree(aContext, aParent)); nsImageLoadingContent::BindToTree(aContext, aParent); UpdateFormOwner(); - if (HaveSrcsetOrInPicture()) { - if (IsInComposedDoc() && !mInDocResponsiveContent) { - aContext.OwnerDoc().AddResponsiveContent(this); - mInDocResponsiveContent = true; - } - - // Mark channel as urgent-start before load image if the image load is - // initaiated by a user interaction. - mUseUrgentStartForChannel = UserActivation::IsHandlingUserInput(); - - // Run selection algorithm when an img element is inserted into a document - // in order to react to changes in the environment. See note of - // https://html.spec.whatwg.org/multipage/embedded-content.html#img-environment-changes - // - // We also do this in PictureSourceAdded() if it is in , so here - // we only need to do if its parent is not , even if there is no - // . - if (!IsInPicture()) { - UpdateSourceSyncAndQueueImageTask(false); - } - } else if (!InResponsiveMode() && HasAttr(nsGkAtoms::src)) { - // We skip loading when our attributes were set from parser land, - // so trigger a aForce=false load now to check if things changed. - // This isn't necessary for responsive mode, since creating the - // image load task is asynchronous we don't need to take special - // care to avoid doing so when being filled by the parser. - - // Mark channel as urgent-start before load image if the image load is - // initaiated by a user interaction. - mUseUrgentStartForChannel = UserActivation::IsHandlingUserInput(); - - // We still act synchronously for the non-responsive case (Bug - // 1076583), but still need to delay if it is unsafe to run - // script. - - // If loading is temporarily disabled, don't even launch MaybeLoadImage. - // Otherwise MaybeLoadImage may run later when someone has reenabled - // loading. - if (LoadingEnabled() && ShouldLoadImage()) { - nsContentUtils::AddScriptRunner( - NewRunnableMethod("dom::HTMLImageElement::MaybeLoadImage", this, - &HTMLImageElement::MaybeLoadImage, false)); - } + const bool srcsetOrPicture = HaveSrcsetOrInPicture(); + if (srcsetOrPicture && aContext.InComposedDoc() && !mInDocResponsiveContent) { + aContext.OwnerDoc().AddResponsiveContent(this); + mInDocResponsiveContent = true; } - return rv; + // Mark channel as urgent-start before load image if the image load is + // initiated by a user interaction. + mUseUrgentStartForChannel = UserActivation::IsHandlingUserInput(); + // Run selection algorithm when an img element is inserted into a document + // in order to react to changes in the environment. See note of + // https://html.spec.whatwg.org/#img-environment-changes + // + // We skip loading when our attributes were set from parser land (see the + // aNotify checks in the various attribute mutation functions), so trigger a + // aAlwaysLoad=false load now to check if things changed. + UpdateSourceSyncAndQueueImageTask(false); + + return NS_OK; } void HTMLImageElement::UnbindFromTree(UnbindContext& aContext) { @@ -611,21 +529,6 @@ void HTMLImageElement::UpdateFormOwner() { } } -void HTMLImageElement::MaybeLoadImage(bool aAlwaysForceLoad) { - // Our base URI may have changed, or we may have had responsive parameters - // change while not bound to the tree. However, at this moment, we should have - // updated the responsive source in other places, so we don't have to re-parse - // src/srcset here. Just need to LoadImage. - - // Note, check LoadingEnabled() after LoadImage call. - - LoadSelectedImage(aAlwaysForceLoad, /* aNotify */ true, aAlwaysForceLoad); - - if (!LoadingEnabled()) { - CancelImageRequests(true); - } -} - void HTMLImageElement::NodeInfoChanged(Document* aOldDoc) { nsGenericHTMLElement::NodeInfoChanged(aOldDoc); @@ -644,19 +547,12 @@ void HTMLImageElement::NodeInfoChanged(Document* aOldDoc) { SetLazyLoading(); } - // Run selection algorithm synchronously when an img element's adopting steps - // are run, in order to react to changes in the environment, per spec, - // https://html.spec.whatwg.org/multipage/images.html#reacting-to-dom-mutations, - // and - // https://html.spec.whatwg.org/multipage/images.html#reacting-to-environment-changes. - if (InResponsiveMode()) { - UpdateResponsiveSource(); - } - - // Force reload image if adoption steps are run. - // If loading is temporarily disabled, don't even launch script runner. - // Otherwise script runner may run later when someone has reenabled loading. - StartLoadingIfNeeded(); + // Run selection algorithm synchronously and reload when an img element's + // adopting steps are run, in order to react to changes in the environment, + // per spec, + // https://html.spec.whatwg.org/#reacting-to-dom-mutations, and + // https://html.spec.whatwg.org/#reacting-to-environment-changes. + UpdateSourceSyncAndQueueImageTask(true); } // static @@ -727,26 +623,13 @@ nsIntSize HTMLImageElement::NaturalSize() { } nsresult HTMLImageElement::CopyInnerTo(HTMLImageElement* aDest) { - nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest); - if (NS_FAILED(rv)) { - return rv; - } + MOZ_TRY(nsGenericHTMLElement::CopyInnerTo(aDest)); // In SetAttr (called from nsGenericHTMLElement::CopyInnerTo), aDest skipped // doing the image load because we passed in false for aNotify. But we // really do want it to do the load, so set it up to happen once the cloning // reaches a stable state. - if (!aDest->InResponsiveMode() && aDest->HasAttr(nsGkAtoms::src) && - aDest->ShouldLoadImage()) { - // Mark channel as urgent-start before load image if the image load is - // initaiated by a user interaction. - mUseUrgentStartForChannel = UserActivation::IsHandlingUserInput(); - - nsContentUtils::AddScriptRunner( - NewRunnableMethod("dom::HTMLImageElement::MaybeLoadImage", aDest, - &HTMLImageElement::MaybeLoadImage, false)); - } - + aDest->UpdateSourceSyncAndQueueImageTask(false); return NS_OK; } @@ -799,6 +682,7 @@ void HTMLImageElement::ClearForm(bool aRemoveFromForm) { mForm = nullptr; } +// Roughly corresponds to https://html.spec.whatwg.org/#update-the-image-data void HTMLImageElement::UpdateSourceSyncAndQueueImageTask( bool aAlwaysLoad, const HTMLSourceElement* aSkippedSource) { // Per spec, when updating the image data or reacting to environment @@ -809,45 +693,77 @@ void HTMLImageElement::UpdateSourceSyncAndQueueImageTask( // However, in the spec of updating the image data, the selection of image // source URL is in the asynchronous part (i.e. in a microtask), and so this // doesn't guarantee that the image style is correct after we flush the style - // synchornously. So here we update the responsive source synchronously always + // synchronously. So here we update the responsive source synchronously always // to make sure the image source is always up-to-date after each DOM mutation. // Spec issue: https://github.com/whatwg/html/issues/8207. - const bool changed = UpdateResponsiveSource(aSkippedSource); + UpdateResponsiveSource(aSkippedSource); - // If loading is temporarily disabled, we don't want to queue tasks - // that may then run when loading is re-enabled. + // If loading is temporarily disabled, we don't want to queue tasks that may + // then run when loading is re-enabled. + // Roughly step 1 and 2. + // FIXME(emilio): Would be great to do this more per-spec. We don't cancel + // existing loads etc. if (!LoadingEnabled() || !ShouldLoadImage()) { return; } // Ensure that we don't overwrite a previous load request that requires // a complete load to occur. - bool alwaysLoad = aAlwaysLoad; - if (mPendingImageLoadTask) { - alwaysLoad = alwaysLoad || mPendingImageLoadTask->AlwaysLoad(); - } + const bool alwaysLoad = aAlwaysLoad || (mPendingImageLoadTask && + mPendingImageLoadTask->AlwaysLoad()); - if (!changed && !alwaysLoad) { + // Steps 5 and 7 (sync cache check for src). + const bool shouldLoadSync = [&] { + if (HaveSrcsetOrInPicture()) { + return false; + } + if (!mSrcURI) { + // NOTE(emilio): we need to also do a sync check for empty / invalid src, + // see https://github.com/whatwg/html/issues/2429 + return true; + } + return nsContentUtils::IsImageAvailable( + this, mSrcURI, mSrcTriggeringPrincipal, GetCORSMode()); + }(); + + if (shouldLoadSync) { + if (!nsContentUtils::IsSafeToRunScript()) { + // If not safe to run script, we should do the sync load task as soon as + // possible instead. This prevents unsound state changes from frame + // construction and such. + nsContentUtils::AddScriptRunner( + NewRunnableMethod( + "HTMLImageElement::UpdateSourceSyncAndQueueImageTask", this, + &HTMLImageElement::UpdateSourceSyncAndQueueImageTask, aAlwaysLoad, + nullptr)); + return; + } + + if (mLazyLoading && mSrcURI) { + StopLazyLoading(StartLoad::No); + } + mPendingImageLoadTask = nullptr; + LoadSelectedImage(alwaysLoad); return; } - QueueImageLoadTask(alwaysLoad); -} - -bool HTMLImageElement::HaveSrcsetOrInPicture() { - if (HasAttr(nsGkAtoms::srcset)) { - return true; + if (mLazyLoading) { + // This check is not in the spec, but it is just a performance optimization. + // The reasoning for why it is sound is that we early-return from the image + // task when lazy loading, and that StopLazyLoading makes us queue a new + // task (which will implicitly cancel all the pre-existing tasks). + return; } - return IsInPicture(); + RefPtr task = new ImageLoadTask(this, alwaysLoad, mUseUrgentStartForChannel); + mPendingImageLoadTask = task; + // The task checks this to determine if it was the last queued event, and so + // earlier tasks are implicitly canceled. + CycleCollectedJSContext::Get()->DispatchToMicroTask(task.forget()); } -bool HTMLImageElement::InResponsiveMode() { - // When we lose srcset or leave a element, the fallback to img.src - // will happen from the microtask, and we should behave responsively in the - // interim - return mResponsiveSelector || mPendingImageLoadTask || - HaveSrcsetOrInPicture(); +bool HTMLImageElement::HaveSrcsetOrInPicture() const { + return HasAttr(nsGkAtoms::srcset) || IsInPicture(); } bool HTMLImageElement::SelectedSourceMatchesLast(nsIURI* aSelectedSource) { @@ -861,10 +777,9 @@ bool HTMLImageElement::SelectedSourceMatchesLast(nsIURI* aSelectedSource) { equal; } -nsresult HTMLImageElement::LoadSelectedImage(bool aForce, bool aNotify, - bool aAlwaysLoad) { - // In responsive mode, we have to make sure we ran the full selection algrithm - // before loading the selected image. +void HTMLImageElement::LoadSelectedImage(bool aAlwaysLoad) { + // In responsive mode, we have to make sure we ran the full selection + // algorithm before loading the selected image. // Use this assertion to catch any cases we missed. MOZ_ASSERT(!UpdateResponsiveSource(), "The image source should be the same because we update the " @@ -908,33 +823,30 @@ nsresult HTMLImageElement::LoadSelectedImage(bool aForce, bool aNotify, // to nsImageFrame::NotifyNewCurrentRequest, which takes care of that for // us. SetDensity(currentDensity); - return NS_OK; + return; } - // Before we actually defer the lazy-loading if (mLazyLoading) { - if (!selectedSource || - !nsContentUtils::IsImageAvailable(this, selectedSource, - triggeringPrincipal, GetCORSMode())) { - return NS_OK; - } - StopLazyLoading(StartLoading::No); + return; } nsresult rv = NS_ERROR_FAILURE; + const bool kNotify = true; // src triggers an error event on invalid URI, unlike other loads. if (selectedSource || hasSrc) { - rv = LoadImage(selectedSource, aForce, aNotify, type, triggeringPrincipal); + // We can pass true for aForce because we already do a manual check for + // SelectedSourceMatchesLast. + rv = LoadImage(selectedSource, /* aForce = */ true, kNotify, type, + triggeringPrincipal); } mLastSelectedSource = selectedSource; mCurrentDensity = currentDensity; if (NS_FAILED(rv)) { - CancelImageRequests(aNotify); + CancelImageRequests(kNotify); } - return rv; } void HTMLImageElement::PictureSourceSrcsetChanged(nsIContent* aSourceNode, @@ -963,9 +875,11 @@ void HTMLImageElement::PictureSourceSrcsetChanged(nsIContent* aSourceNode, mInDocResponsiveContent = true; } - // This always triggers the image update steps per the spec, even if - // we are not using this source. - UpdateSourceSyncAndQueueImageTask(true); + // This always triggers the image update steps per the spec, even if we are + // not using this source. + if (aNotify) { + UpdateSourceSyncAndQueueImageTask(true); + } } void HTMLImageElement::PictureSourceSizesChanged(nsIContent* aSourceNode, @@ -985,7 +899,9 @@ void HTMLImageElement::PictureSourceSizesChanged(nsIContent* aSourceNode, // This always triggers the image update steps per the spec, even if // we are not using this source. - UpdateSourceSyncAndQueueImageTask(true); + if (aNotify) { + UpdateSourceSyncAndQueueImageTask(true); + } } void HTMLImageElement::PictureSourceMediaOrTypeChanged(nsIContent* aSourceNode, @@ -995,7 +911,9 @@ void HTMLImageElement::PictureSourceMediaOrTypeChanged(nsIContent* aSourceNode, // This always triggers the image update steps per the spec, even if // we are not switching to/from this source - UpdateSourceSyncAndQueueImageTask(true); + if (aNotify) { + UpdateSourceSyncAndQueueImageTask(true); + } } void HTMLImageElement::PictureSourceDimensionChanged( @@ -1012,18 +930,24 @@ void HTMLImageElement::PictureSourceDimensionChanged( } } -void HTMLImageElement::PictureSourceAdded(HTMLSourceElement* aSourceNode) { +void HTMLImageElement::PictureSourceAdded(bool aNotify, + HTMLSourceElement* aSourceNode) { MOZ_ASSERT(!aSourceNode || IsPreviousSibling(aSourceNode, this), "Should not be getting notifications for non-previous-siblings"); - UpdateSourceSyncAndQueueImageTask(true); + if (aNotify) { + UpdateSourceSyncAndQueueImageTask(true); + } } -void HTMLImageElement::PictureSourceRemoved(HTMLSourceElement* aSourceNode) { +void HTMLImageElement::PictureSourceRemoved(bool aNotify, + HTMLSourceElement* aSourceNode) { MOZ_ASSERT(!aSourceNode || IsPreviousSibling(aSourceNode, this), "Should not be getting notifications for non-previous-siblings"); - UpdateSourceSyncAndQueueImageTask(true, aSourceNode); + if (aNotify) { + UpdateSourceSyncAndQueueImageTask(true, aSourceNode); + } } bool HTMLImageElement::UpdateResponsiveSource( @@ -1209,7 +1133,8 @@ bool HTMLImageElement::SelectSourceForTagWithAttrs( return false; } - // Using srcset or picture , build a responsive selector for this tag. + // Using srcset or picture , build a responsive selector for this + // tag. RefPtr sel = new ResponsiveImageSelector(aDocument); sel->SetCandidatesFromSourceSet(aSrcsetAttr); @@ -1272,24 +1197,7 @@ void HTMLImageElement::SetLazyLoading() { UpdateImageState(true); } -void HTMLImageElement::StartLoadingIfNeeded() { - if (!LoadingEnabled() || !ShouldLoadImage()) { - return; - } - - // Use script runner for the case the adopt is from appendChild. - // Bug 1076583 - We still behave synchronously in the non-responsive case - nsContentUtils::AddScriptRunner( - InResponsiveMode() - ? NewRunnableMethod("dom::HTMLImageElement::QueueImageLoadTask", - this, &HTMLImageElement::QueueImageLoadTask, - true) - : NewRunnableMethod("dom::HTMLImageElement::MaybeLoadImage", - this, &HTMLImageElement::MaybeLoadImage, - true)); -} - -void HTMLImageElement::StopLazyLoading(StartLoading aStartLoading) { +void HTMLImageElement::StopLazyLoading(StartLoad aStartLoad) { if (!mLazyLoading) { return; } @@ -1299,8 +1207,8 @@ void HTMLImageElement::StopLazyLoading(StartLoading aStartLoading) { obs->Unobserve(*this); } - if (aStartLoading == StartLoading::Yes) { - StartLoadingIfNeeded(); + if (aStartLoad == StartLoad::Yes) { + UpdateSourceSyncAndQueueImageTask(true); } } @@ -1372,15 +1280,6 @@ void HTMLImageElement::SetDensity(double aDensity) { } } -void HTMLImageElement::QueueImageLoadTask(bool aAlwaysLoad) { - RefPtr task = - new ImageLoadTask(this, aAlwaysLoad, mUseUrgentStartForChannel); - // The task checks this to determine if it was the last - // queued event, and so earlier tasks are implicitly canceled. - mPendingImageLoadTask = task; - CycleCollectedJSContext::Get()->DispatchToMicroTask(task.forget()); -} - FetchPriority HTMLImageElement::GetFetchPriorityForImage() const { return nsGenericHTMLElement::GetFetchPriority(); } diff --git a/dom/html/HTMLImageElement.h b/dom/html/HTMLImageElement.h index 1097d1fb048cf..9bfe434e9b6b7 100644 --- a/dom/html/HTMLImageElement.h +++ b/dom/html/HTMLImageElement.h @@ -79,11 +79,8 @@ class HTMLImageElement final : public nsGenericHTMLElement, nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override; void NodeInfoChanged(Document* aOldDoc) override; - nsresult CopyInnerTo(HTMLImageElement* aDest); - void MaybeLoadImage(bool aAlwaysForceLoad); - bool IsMap() { return GetBoolAttr(nsGkAtoms::ismap); } void SetIsMap(bool aIsMap, ErrorResult& aError) { SetHTMLBoolAttr(nsGkAtoms::ismap, aIsMap, aError); @@ -255,9 +252,8 @@ class HTMLImageElement final : public nsGenericHTMLElement, const nsAString& aTypeAttr, const nsAString& aMediaAttr, nsAString& aResult); - enum class FromIntersectionObserver : bool { No, Yes }; - enum class StartLoading : bool { No, Yes }; - void StopLazyLoading(StartLoading); + enum class StartLoad : bool { No, Yes }; + void StopLazyLoading(StartLoad = StartLoad::Yes); // This is used when restyling, for retrieving the extra style from the source // element. @@ -270,28 +266,19 @@ class HTMLImageElement final : public nsGenericHTMLElement, // Update the responsive source synchronously and queues a task to run // LoadSelectedImage pending stable state. - // - // Pending Bug 1076583 this is only used by the responsive image - // algorithm (InResponsiveMode()) -- synchronous actions when just - // using img.src will bypass this, and update source and kick off - // image load synchronously. void UpdateSourceSyncAndQueueImageTask( bool aAlwaysLoad, const HTMLSourceElement* aSkippedSource = nullptr); // True if we have a srcset attribute or a parent, regardless of if // any valid responsive sources were parsed from either. - bool HaveSrcsetOrInPicture(); - - // True if we are using the newer image loading algorithm. This will be the - // only mode after Bug 1076583 - bool InResponsiveMode(); + bool HaveSrcsetOrInPicture() const; // True if the given URL equals the last URL that was loaded by this element. bool SelectedSourceMatchesLast(nsIURI* aSelectedSource); // Load the current mResponsiveSelector (responsive mode) or src attr image. // Note: This doesn't run the full selection for the responsive selector. - nsresult LoadSelectedImage(bool aForce, bool aNotify, bool aAlwaysLoad); + void LoadSelectedImage(bool aAlwaysLoad); // True if this string represents a type we would support on static bool SupportedPictureSourceType(const nsAString& aType); @@ -310,9 +297,11 @@ class HTMLImageElement final : public nsGenericHTMLElement, void PictureSourceDimensionChanged(HTMLSourceElement* aSourceNode, bool aNotify); - void PictureSourceAdded(HTMLSourceElement* aSourceNode = nullptr); + void PictureSourceAdded(bool aNotify, + HTMLSourceElement* aSourceNode = nullptr); // This should be called prior to the unbind, such that nextsibling works - void PictureSourceRemoved(HTMLSourceElement* aSourceNode = nullptr); + void PictureSourceRemoved(bool aNotify, + HTMLSourceElement* aSourceNode = nullptr); // Re-evaluates all source nodes (picture ,) and finds // the best source set for mResponsiveSelector. If a better source @@ -397,8 +386,6 @@ class HTMLImageElement final : public nsGenericHTMLElement, // Set this image as a lazy load image due to loading="lazy". void SetLazyLoading(); - void StartLoadingIfNeeded(); - bool IsInPicture() const { return GetParentElement() && GetParentElement()->IsHTMLElement(nsGkAtoms::picture); diff --git a/dom/html/HTMLPictureElement.cpp b/dom/html/HTMLPictureElement.cpp index 45b1e4e3e3f25..d14726a3c1d04 100644 --- a/dom/html/HTMLPictureElement.cpp +++ b/dom/html/HTMLPictureElement.cpp @@ -32,14 +32,14 @@ void HTMLPictureElement::RemoveChildNode(nsIContent* aKid, bool aNotify) { MOZ_ASSERT(aKid); if (auto* img = HTMLImageElement::FromNode(aKid)) { - img->PictureSourceRemoved(); + img->PictureSourceRemoved(aNotify); } else if (auto* source = HTMLSourceElement::FromNode(aKid)) { // Find all img siblings after this to notify them of its demise nsCOMPtr nextSibling = source->GetNextSibling(); if (nextSibling && nextSibling->GetParentNode() == this) { do { if (auto* img = HTMLImageElement::FromNode(nextSibling)) { - img->PictureSourceRemoved(source); + img->PictureSourceRemoved(aNotify, source); } } while ((nextSibling = nextSibling->GetNextSibling())); } @@ -57,14 +57,14 @@ void HTMLPictureElement::InsertChildBefore(nsIContent* aKid, } if (auto* img = HTMLImageElement::FromNode(aKid)) { - img->PictureSourceAdded(); + img->PictureSourceAdded(aNotify); } else if (auto* source = HTMLSourceElement::FromNode(aKid)) { // Find all img siblings after this to notify them of its insertion nsCOMPtr nextSibling = source->GetNextSibling(); if (nextSibling && nextSibling->GetParentNode() == this) { do { if (auto* img = HTMLImageElement::FromNode(nextSibling)) { - img->PictureSourceAdded(source); + img->PictureSourceAdded(aNotify, source); } } while ((nextSibling = nextSibling->GetNextSibling())); } diff --git a/dom/tests/mochitest/general/test_img_mutations.html b/dom/tests/mochitest/general/test_img_mutations.html index 88cb40e1814f2..6e953e8c0050e 100644 --- a/dom/tests/mochitest/general/test_img_mutations.html +++ b/dom/tests/mochitest/general/test_img_mutations.html @@ -49,39 +49,50 @@ } } function expectEvents(loads, errors, callback) { - if (!loads && !errors) { - setTimeout(callback, 0); - } else { - expectingLoads += loads; - expectingErrors += errors; - info("Waiting for " + expectingLoads + " load and " + expectingErrors + " error events"); - afterExpectCallback = callback; - } + let p = new Promise(resolve => { + if (!loads && !errors) { + setTimeout(resolve, 0); + } else { + expectingLoads += loads; + expectingErrors += errors; + info("Waiting for " + expectingLoads + " load and " + expectingErrors + " error events"); + afterExpectCallback = resolve; + } + }); + return p.then(() => callback && callback()); } // // Test that img.src still does some work synchronously per the older spec (bug 1076583) // - tests.push(function test1() { + tests.push(async function test1() { info("test 1"); img.src = testPNG50; - is(img.currentSrc, testPNG50, "Should have synchronously selected source"); + is(img.currentSrc, "", "Should not have synchronously selected source"); + + await expectEvents(1, 0); + is(img.currentSrc, testPNG50, "Should now have testPNG50 as current request"); // Assigning a wrong URL should not trigger error event (bug 1321300). img.src = '//:0'; // Wrong URL + is(img.currentSrc, "", "Should have dropped current request sync"); img.src = "non_existent_image.404"; - ok(img.currentSrc.endsWith("non_existent_image.404"), "Should have synchronously selected source"); + is(img.currentSrc, "", "Should still have empty current request"); + + await expectEvents(0, 1); + ok(img.currentSrc.endsWith("non_existent_image.404"), "Should have asynchronously selected source"); img.removeAttribute("src"); - is(img.currentSrc, '', "Should have dropped currentSrc"); + is(img.currentSrc, "", "Should have dropped currentSrc sync"); // Load another image while previous load is still pending img.src = testPNG200; - is(img.currentSrc, testPNG200, "Should have synchronously selected source"); + is(img.currentSrc, "", "Should asynchronously load selected source"); - // No events should have fired synchronously, now we should get just one load (and no 404 error) - expectEvents(1, 0, nextTest); + await expectEvents(1, 0); + is(img.currentSrc, testPNG200, "Should have asynchronously loaded selected source"); + nextTest(); }); @@ -193,26 +204,25 @@ }); // Removing srcset attr should async switch back to src - tests.push(function () { + tests.push(async function () { info("test 10"); is(img.currentSrc, testPNG200, "Should have testPNG200 as current request"); img.removeAttribute("srcset"); - is(img.currentSrc, testPNG200, "Should still have testPNG200 as current request"); + is(img.currentSrc, testPNG100, "Should testPNG100 as current request (hits sync load case for src)"); - expectEvents(1, 0, function() { - is(img.currentSrc, testPNG100, "Should now have testPNG100 as current request"); + await expectEvents(1, 0); + is(img.currentSrc, testPNG100, "Should now have testPNG100 as current request"); - expectEvents(0, 0, nextTest); - }); + expectEvents(0, 0, nextTest); }); function nextTest() { if (tests.length) { // Spin event loop to make sure no unexpected image events are // pending (unexpected events will assert in the handlers) - setTimeout(function() { - (tests.shift())(); + setTimeout(async function() { + await (tests.shift())(); }, 0); } else { // Remove the event listeners to prevent the prefenv being popped from diff --git a/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html.ini b/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html.ini index 53511670cefd9..f89c598a39ba5 100644 --- a/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html.ini +++ b/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image-from-script.sub.html.ini @@ -1,3 +1,3 @@ [securitypolicyviolation-block-cross-origin-image-from-script.sub.html] - expected: - if (os == "android") and fission: [OK, TIMEOUT] + [Non-redirected cross-origin URLs are not stripped.] + expected: FAIL diff --git a/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html.ini b/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html.ini new file mode 100644 index 0000000000000..3d3531dc0b55a --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html.ini @@ -0,0 +1,3 @@ +[securitypolicyviolation-block-cross-origin-image.sub.html] + [Non-redirected cross-origin URLs are not stripped.] + expected: FAIL diff --git a/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html.ini b/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html.ini index 1383fa78064a1..e3ca9694e1cf3 100644 --- a/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html.ini +++ b/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html.ini @@ -1,3 +1,3 @@ [securitypolicyviolation-block-image-from-script.sub.html] - expected: - if (os == "android") and fission: [OK, TIMEOUT] + [Non-redirected cross-origin URLs are not stripped.] + expected: FAIL diff --git a/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html.ini b/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html.ini new file mode 100644 index 0000000000000..900d04f76cb28 --- /dev/null +++ b/testing/web-platform/meta/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image.sub.html.ini @@ -0,0 +1,3 @@ +[securitypolicyviolation-block-image.sub.html] + [Non-redirected same-origin URLs are not stripped.] + expected: FAIL diff --git a/testing/web-platform/meta/html/semantics/embedded-content/the-img-element/list-of-available-images-matching.https.html.ini b/testing/web-platform/meta/html/semantics/embedded-content/the-img-element/list-of-available-images-matching.https.html.ini index 9dc217e598c1e..6a938fb26c771 100644 --- a/testing/web-platform/meta/html/semantics/embedded-content/the-img-element/list-of-available-images-matching.https.html.ini +++ b/testing/web-platform/meta/html/semantics/embedded-content/the-img-element/list-of-available-images-matching.https.html.ini @@ -2,12 +2,6 @@ expected: if not tsan and (processor == "x86") and not debug: [OK, TIMEOUT] if tsan: CRASH - [list of available images tuple-matching logic] - expected: - if fission and (processor == "x86") and not debug: [FAIL, NOTRUN] - if not fission and (os == "android") and debug: [FAIL, PASS] - if not fission and (os == "linux"): [FAIL, PASS] - FAIL [registering service worker] expected: diff --git a/testing/web-platform/meta/html/semantics/embedded-content/the-img-element/update-the-image-data/current-request-microtask.html.ini b/testing/web-platform/meta/html/semantics/embedded-content/the-img-element/update-the-image-data/current-request-microtask.html.ini deleted file mode 100644 index 9fd84a88066d6..0000000000000 --- a/testing/web-platform/meta/html/semantics/embedded-content/the-img-element/update-the-image-data/current-request-microtask.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[current-request-microtask.html] - expected: - if (os == "android") and fission: [OK, TIMEOUT] - [currentSrc is updated only after the microtask that updates the current request is run] - expected: FAIL diff --git a/toolkit/components/extensions/test/mochitest/test_ext_web_accessible_incognito.html b/toolkit/components/extensions/test/mochitest/test_ext_web_accessible_incognito.html index 1009eb049644b..2b414d0c61f4b 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_web_accessible_incognito.html +++ b/toolkit/components/extensions/test/mochitest/test_ext_web_accessible_incognito.html @@ -146,10 +146,10 @@ await pb_extension.startup(); consoleMonitor.start([ - {message: /may not load or link to.*image.png/}, {message: /may not load or link to.*test_script.js/}, {message: /\ source URI is not allowed in this document/}, {message: /may not load or link to.*accessible.html/}, + {message: /may not load or link to.*image.png/}, ]); pb_extension.sendMessage("start", baseUrl);