Skip to content

Commit 89117a2

Browse files
committed
[view-transitions] Skip view transition on hidden pages
https://bugs.webkit.org/show_bug.cgi?id=271248 rdar://125017653 Reviewed by NOBODY (OOPS!). Follow: - https://drafts.csswg.org/css-view-transitions-1/#page-visibility-change-steps - w3c/csswg-drafts#9543 * LayoutTests/TestExpectations: * LayoutTests/imported/w3c/web-platform-tests/css/css-view-transitions/transition-in-hidden-page-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/css/css-view-transitions/transition-in-hidden-page.html: * LayoutTests/imported/w3c/web-platform-tests/css/css-view-transitions/window-resize-aborts-transition-before-ready.html: * LayoutTests/imported/w3c/web-platform-tests/css/css-view-transitions/window-resize-aborts-transition.html: * LayoutTests/platform/ios/TestExpectations: * LayoutTests/platform/mac-wk2/TestExpectations: Remove duplicate test expectations to reduce confusion. * LayoutTests/platform/wpe/TestExpectations: * Source/WebCore/dom/Document.cpp: (WebCore::Document::visibilityStateChanged): Make this more robust to allow unregistering clients while iterating. (WebCore::Document::resolveViewTransitionRule): (WebCore::Document::reveal): (WebCore::Document::startViewTransition): * Source/WebCore/dom/ViewTransition.cpp: (WebCore::ViewTransition::ViewTransition): (WebCore::ViewTransition::stop): (WebCore::ViewTransition::visibilityStateChanged): * Source/WebCore/dom/ViewTransition.h:
1 parent 3c3c719 commit 89117a2

11 files changed

+50
-13
lines changed

LayoutTests/TestExpectations

+1-2
Original file line numberDiff line numberDiff line change
@@ -7468,12 +7468,10 @@ imported/w3c/web-platform-tests/css/css-view-transitions/paint-holding-in-iframe
74687468
imported/w3c/web-platform-tests/css/css-view-transitions/iframe-transition.sub.html [ Skip ]
74697469
imported/w3c/web-platform-tests/css/css-view-transitions/fragmented-during-transition-skips.html [ Skip ]
74707470
imported/w3c/web-platform-tests/css/css-view-transitions/root-element-display-none-during-transition-crash.html [ Skip ]
7471-
imported/w3c/web-platform-tests/css/css-view-transitions/transition-in-hidden-page.html [ Skip ]
74727471

74737472
# Flakes
74747473
imported/w3c/web-platform-tests/css/css-view-transitions/synchronous-callback-skipped-before-run.html [ Failure Pass ]
74757474
imported/w3c/web-platform-tests/css/css-view-transitions/old-content-intrinsic-aspect-ratio.html [ ImageOnlyFailure Pass ]
7476-
imported/w3c/web-platform-tests/css/css-view-transitions/navigation/hide-before-reveal.html [ Failure Pass ]
74777475
imported/w3c/web-platform-tests/css/css-view-transitions/navigation/pageswap-ctor.html [ Failure Pass ]
74787476

74797477
# Reftests with variants are not supported
@@ -7494,6 +7492,7 @@ imported/w3c/web-platform-tests/css/css-view-transitions/navigation/chromium-pai
74947492
imported/w3c/web-platform-tests/css/css-view-transitions/navigation/root-element-transition-iframe-with-startVT-on-main.html [ ImageOnlyFailure ]
74957493
# https://github.com/w3c/csswg-drafts/issues/10800
74967494
imported/w3c/web-platform-tests/css/css-view-transitions/navigation/pageswap-long-delay.html [ Failure ]
7495+
webkit.org/b/278028 imported/w3c/web-platform-tests/css/css-view-transitions/navigation/hide-before-reveal.html [ Failure ]
74977496

74987497
# prerender not supported.
74997498
imported/w3c/web-platform-tests/css/css-view-transitions/navigation/prerender-removed-during-navigation.html [ Skip ]
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
FAIL A view transition should be immediately skipped if started when document is hidden assert_unreached: Should have rejected: undefined Reached unreachable code
3-
FAIL A view transition should be skipped when a document becomes hidden while processing update callback assert_equals: expected "rejected" but got "fulfilled"
4-
FAIL A view transition should be skipped when a document becomes hidden while animating assert_equals: expected "finished" but got "timeout"
2+
PASS A view transition should be immediately skipped if started when document is hidden
3+
PASS A view transition should be skipped when a document becomes hidden while processing update callback
4+
PASS A view transition should be skipped when a document becomes hidden while animating
55

LayoutTests/imported/w3c/web-platform-tests/css/css-view-transitions/transition-in-hidden-page.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
await wsc.minimize();
2222
assert_true(document.hidden);
2323
const transition = document.startViewTransition();
24-
await wsc.restore();
2524
await promise_rejects_dom(t, "InvalidStateError", transition.ready);
25+
await wsc.restore();
2626
}, "A view transition should be immediately skipped if started when document is hidden");
2727

2828
promise_test(async t => {

LayoutTests/imported/w3c/web-platform-tests/css/css-view-transitions/window-resize-aborts-transition-before-ready.html

+6
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@
3434
popup_win = window.open('about:blank', 'popup', 'width=300,height=300');
3535
});
3636

37+
if (popup_win.document.visibilityState == "hidden") {
38+
await new Promise((resolve) => {
39+
popup_win.document.addEventListener("visibilitychange", resolve, { once: true });
40+
});
41+
}
42+
3743
// Resize the window while the update callback is running (i.e. before
3844
// capturing the new state).
3945
let transition = popup_win.document.startViewTransition(async () => {

LayoutTests/imported/w3c/web-platform-tests/css/css-view-transitions/window-resize-aborts-transition.html

+6
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@
4545
html::view-transition-old(*) {animation-duration: 10s;opacity: 1;}
4646
</style>`;
4747

48+
if (popupDoc.visibilityState == "hidden") {
49+
await new Promise((resolve) => {
50+
popupDoc.addEventListener("visibilitychange", resolve, { once: true });
51+
});
52+
}
53+
4854
// Start a transition inside the popup.
4955
let transition = popupDoc.startViewTransition(() => {
5056
popupDoc.documentElement.classList.add('new');

LayoutTests/platform/ios/TestExpectations

+2
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,8 @@ fast/css/variables/env/ios [ Pass ]
13371337

13381338
# Tests use resizable popups which are not a thing on iOS.
13391339
imported/w3c/web-platform-tests/css/css-view-transitions/window-resize-aborts-transition-before-ready.html [ Failure ]
1340+
imported/w3c/web-platform-tests/css/css-view-transitions/window-resize-aborts-transition.html [ Failure ]
1341+
imported/w3c/web-platform-tests/css/css-view-transitions/transition-in-hidden-page.html [ Failure ]
13401342

13411343
imported/w3c/web-platform-tests/css/css-view-transitions/navigation/hide-before-reveal.html [ Failure ]
13421344
imported/w3c/web-platform-tests/css/css-view-transitions/navigation/pageswap-push-from-click.html [ Failure ]

LayoutTests/platform/mac-wk2/TestExpectations

-3
Original file line numberDiff line numberDiff line change
@@ -1789,9 +1789,6 @@ imported/w3c/web-platform-tests/css/css-view-transitions/new-content-intrinsic-a
17891789
tiled-drawing/scrolling/overflow/overflow-scrolled-down-tile-coverage.html [ Pass Failure ]
17901790
tiled-drawing/scrolling/overflow/overflow-scrolled-up-tile-coverage.html [ Pass Failure ]
17911791

1792-
# rdar://133772823 ([Sonoma wk2] imported/w3c/web-platform-tests/css/css-view-transitions/navigation/hide-before-reveal.html is a flaky failure
1793-
[ Sonoma+ ] imported/w3c/web-platform-tests/css/css-view-transitions/navigation/hide-before-reveal.html [ Pass Failure ]
1794-
17951792
# webkit.org/b/278178 [macOS Debug] imported/w3c/web-platform-tests/css/cssom-view/scroll-behavior-smooth-positions.html is a flaky failure
17961793
imported/w3c/web-platform-tests/css/cssom-view/scroll-behavior-smooth-positions.html [ Pass Failure ]
17971794

LayoutTests/platform/wpe/TestExpectations

+1
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,7 @@ compositing/visible-rect/scrolled.html [ Failure ]
15881588
compositing/video/video-border-radius-clipping.html [ Pass ImageOnlyFailure ]
15891589

15901590
imported/w3c/web-platform-tests/css/css-view-transitions/capture-with-visibility-mixed-descendants.html [ ImageOnlyFailure ]
1591+
imported/w3c/web-platform-tests/css/css-view-transitions/transition-in-hidden-page.html [ Skip ]
15911592

15921593
webkit.org/b/272224 imported/w3c/web-platform-tests/selection/textcontrols/selectionchange.html [ Failure ]
15931594

Source/WebCore/dom/Document.cpp

+10-3
Original file line numberDiff line numberDiff line change
@@ -2343,8 +2343,9 @@ void Document::visibilityStateChanged()
23432343
{
23442344
// https://w3c.github.io/page-visibility/#reacting-to-visibilitychange-changes
23452345
queueTaskToDispatchEvent(TaskSource::UserInteraction, Event::create(eventNames().visibilitychangeEvent, Event::CanBubble::Yes, Event::IsCancelable::No));
2346-
for (auto& client : m_visibilityStateCallbackClients)
2346+
m_visibilityStateCallbackClients.forEach([](auto& client) {
23472347
client.visibilityStateChanged();
2348+
});
23482349

23492350
#if ENABLE(MEDIA_STREAM) && PLATFORM(IOS_FAMILY)
23502351
if (auto mediaSessionManager = PlatformMediaSessionManager::sharedManagerIfExists()) {
@@ -8068,7 +8069,7 @@ void Document::dispatchPagehideEvent(PageshowEventPersistence persisted)
80688069
// https://www.w3.org/TR/css-view-transitions-2/#vt-rule-algo
80698070
std::variant<Document::SkipTransition, Vector<AtomString>> Document::resolveViewTransitionRule()
80708071
{
8071-
if (visibilityState() == VisibilityState::Hidden)
8072+
if (hidden())
80728073
return SkipTransition { };
80738074

80748075
auto rule = styleScope().resolver().viewTransitionRule();
@@ -8089,7 +8090,7 @@ void Document::reveal()
80898090

80908091
PageRevealEvent::Init init;
80918092

8092-
RefPtr<ViewTransition> inboundTransition = ViewTransition::resolveInboundCrossDocumentViewTransition(*this, std::exchange(m_inboundViewTransitionParams, nullptr));
8093+
RefPtr inboundTransition = ViewTransition::resolveInboundCrossDocumentViewTransition(*this, std::exchange(m_inboundViewTransitionParams, nullptr));
80938094
if (inboundTransition)
80948095
init.viewTransition = inboundTransition;
80958096

@@ -10828,6 +10829,7 @@ void Document::flushDeferredRenderingIsSuppressedForViewTransitionChanges()
1082810829
}
1082910830
}
1083010831

10832+
// https://drafts.csswg.org/css-view-transitions/#ViewTransition-prepare
1083110833
RefPtr<ViewTransition> Document::startViewTransition(StartViewTransitionCallbackOptions&& callbackOptions)
1083210834
{
1083310835
if (!globalObject())
@@ -10851,6 +10853,11 @@ RefPtr<ViewTransition> Document::startViewTransition(StartViewTransitionCallback
1085110853

1085210854
Ref viewTransition = ViewTransition::createSamePage(*this, WTFMove(updateCallback), WTFMove(activeTypes));
1085310855

10856+
if (hidden()) {
10857+
viewTransition->skipViewTransition(Exception { ExceptionCode::InvalidStateError, "View transition was skipped because document visibility state is hidden."_s });
10858+
return viewTransition;
10859+
}
10860+
1085410861
if (RefPtr activeViewTransition = m_activeViewTransition)
1085510862
activeViewTransition->skipViewTransition(Exception { ExceptionCode::AbortError, "Old view transition aborted by new view transition."_s });
1085610863

Source/WebCore/dom/ViewTransition.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ ViewTransition::ViewTransition(Document& document, RefPtr<ViewTransitionUpdateCa
6868
, m_finished(createPromiseAndWrapper(document))
6969
, m_types(ViewTransitionTypeSet::create(document, WTFMove(initialActiveTypes)))
7070
{
71+
document.registerForVisibilityStateChangedCallbacks(*this);
7172
}
7273

7374
ViewTransition::ViewTransition(Document& document, Vector<AtomString>&& initialActiveTypes)
@@ -859,12 +860,26 @@ RenderViewTransitionCapture* ViewTransition::viewTransitionNewPseudoForCapturedE
859860
return nullptr;
860861
}
861862

863+
// https://drafts.csswg.org/css-view-transitions/#page-visibility-change-steps
864+
void ViewTransition::visibilityStateChanged()
865+
{
866+
if (!document())
867+
return;
868+
869+
if (protectedDocument()->hidden()) {
870+
if (protectedDocument()->activeViewTransition() == this)
871+
skipViewTransition(Exception { ExceptionCode::InvalidStateError, "Skipping view transition because document visibility state has become hidden."_s });
872+
} else
873+
ASSERT(!protectedDocument()->activeViewTransition());
874+
}
875+
862876
void ViewTransition::stop()
863877
{
864878
if (!document())
865879
return;
866880

867881
m_phase = ViewTransitionPhase::Done;
882+
document()->unregisterForVisibilityStateChangedCallbacks(*this);
868883

869884
if (document()->activeViewTransition() == this)
870885
clearViewTransition();

Source/WebCore/dom/ViewTransition.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "Styleable.h"
3636
#include "ViewTransitionTypeSet.h"
3737
#include "ViewTransitionUpdateCallback.h"
38+
#include "VisibilityChangeClient.h"
3839
#include <wtf/CheckedRef.h>
3940
#include <wtf/Ref.h>
4041
#include <wtf/TZoneMalloc.h>
@@ -150,7 +151,7 @@ struct ViewTransitionParams {
150151
float initialPageZoom;
151152
};
152153

153-
class ViewTransition : public RefCounted<ViewTransition>, public CanMakeWeakPtr<ViewTransition>, public ActiveDOMObject {
154+
class ViewTransition : public RefCounted<ViewTransition>, public VisibilityChangeClient, public ActiveDOMObject {
154155
WTF_MAKE_TZONE_ALLOCATED(ViewTransition);
155156
public:
156157
static Ref<ViewTransition> createSamePage(Document&, RefPtr<ViewTransitionUpdateCallback>&&, Vector<AtomString>&&);
@@ -208,6 +209,9 @@ class ViewTransition : public RefCounted<ViewTransition>, public CanMakeWeakPtr<
208209

209210
void clearViewTransition();
210211

212+
// VisibilityChangeClient.
213+
void visibilityStateChanged() final;
214+
211215
// ActiveDOMObject.
212216
void stop() final;
213217

0 commit comments

Comments
 (0)