Skip to content

Commit 2cda3fd

Browse files
committed
[PageLifecycle] Ensure that the show_plc/hide_plc callbacks are invoked after the visibilityChange events are dispatched.
1 parent c599351 commit 2cda3fd

6 files changed

Lines changed: 56 additions & 7 deletions

File tree

Source/WebCore/dom/Document.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,10 +1854,15 @@ void Document::unregisterForVisibilityStateChangedCallbacks(VisibilityChangeClie
18541854
m_visibilityStateCallbackClients.remove(client);
18551855
}
18561856

1857-
void Document::visibilityStateChanged()
1857+
void Document::visibilityStateChanged(CompletionHandler<void(Document&)>&& completionHandler)
18581858
{
18591859
// https://w3c.github.io/page-visibility/#reacting-to-visibilitychange-changes
1860-
queueTaskToDispatchEvent(TaskSource::UserInteraction, Event::create(eventNames().visibilitychangeEvent, Event::CanBubble::Yes, Event::IsCancelable::No));
1860+
eventLoop().queueTask(TaskSource::UserInteraction, [document = Ref { *this }, completionHandler = WTFMove(completionHandler)] () mutable {
1861+
document->dispatchEvent(Event::create(eventNames().visibilitychangeEvent, Event::CanBubble::Yes, Event::IsCancelable::No));
1862+
if (completionHandler)
1863+
completionHandler(document);
1864+
});
1865+
18611866
for (auto& client : m_visibilityStateCallbackClients)
18621867
client.visibilityStateChanged();
18631868

Source/WebCore/dom/Document.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ class Document
493493
WEBCORE_EXPORT void setDocumentURI(const String&);
494494

495495
WEBCORE_EXPORT VisibilityState visibilityState() const;
496-
void visibilityStateChanged();
496+
void visibilityStateChanged(CompletionHandler<void(Document&)>&&);
497497
WEBCORE_EXPORT bool hidden() const;
498498

499499
void setTimerThrottlingEnabled(bool);

Source/WebCore/page/Page.cpp

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2544,6 +2544,24 @@ void Page::setIsVisible(bool isVisible)
25442544
setActivityState(state);
25452545
}
25462546

2547+
class VisibilityChangeEventNotifier : public RefCounted<VisibilityChangeEventNotifier> {
2548+
public:
2549+
VisibilityChangeEventNotifier() = default;
2550+
virtual ~VisibilityChangeEventNotifier() = default;
2551+
2552+
void setCompletionHandler(CompletionHandler<void()>&& completionHandler) { m_completionHandler = WTFMove(completionHandler); };
2553+
void addDocument(Ref<Document> document) { m_documents.add(document); };
2554+
void removeDocument(Ref<Document> document) {
2555+
m_documents.remove(document);
2556+
if (m_documents.isEmpty())
2557+
m_completionHandler();
2558+
}
2559+
2560+
private:
2561+
CompletionHandler<void()> m_completionHandler;
2562+
HashSet<Ref<Document>> m_documents;
2563+
};
2564+
25472565
void Page::setIsVisibleInternal(bool isVisible)
25482566
{
25492567
// FIXME: The visibility state should be stored on the top-level document.
@@ -2608,9 +2626,21 @@ void Page::setIsVisibleInternal(bool isVisible)
26082626
view->hide();
26092627
}
26102628

2611-
forEachDocument([] (Document& document) {
2612-
document.visibilityStateChanged();
2613-
});
2629+
if (m_visibilityChangeCompletionHandler) {
2630+
Ref<VisibilityChangeEventNotifier> notifier = adoptRef(*new VisibilityChangeEventNotifier());
2631+
notifier->setCompletionHandler(std::exchange(m_visibilityChangeCompletionHandler, { }));
2632+
2633+
forEachDocument([notifier] (Document& document) {
2634+
notifier->addDocument(document);
2635+
document.visibilityStateChanged([protectedNotifier = Ref { notifier }] (Document& document) {
2636+
protectedNotifier->removeDocument(document);
2637+
});
2638+
});
2639+
} else {
2640+
forEachDocument([] (Document& document) {
2641+
document.visibilityStateChanged({ });
2642+
});
2643+
}
26142644
}
26152645

26162646
void Page::setIsPrerender()

Source/WebCore/page/Page.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
#include <memory>
5454
#include <pal/SessionID.h>
5555
#include <wtf/Assertions.h>
56+
#include <wtf/CompletionHandler.h>
5657
#include <wtf/Forward.h>
5758
#include <wtf/Function.h>
5859
#include <wtf/HashSet.h>
@@ -980,6 +981,7 @@ class Page : public Supplementable<Page>, public CanMakeWeakPtr<Page> {
980981
#if ENABLE(IMAGE_ANALYSIS)
981982
WEBCORE_EXPORT void analyzeImagesForFindInPage();
982983
#endif
984+
void setVisibilityChangeCompletionHandler(CompletionHandler<void()>&& completionHandler) { m_visibilityChangeCompletionHandler = WTFMove(completionHandler); }
983985
private:
984986
struct Navigation {
985987
RegistrableDomain domain;
@@ -1342,6 +1344,8 @@ class Page : public Supplementable<Page>, public CanMakeWeakPtr<Page> {
13421344
#endif
13431345

13441346
ContentSecurityPolicyModeForExtension m_contentSecurityPolicyModeForExtension { ContentSecurityPolicyModeForExtension::None };
1347+
1348+
CompletionHandler<void()> m_visibilityChangeCompletionHandler;
13451349
};
13461350

13471351
inline PageGroup& Page::group()

Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,8 @@ void DrawingAreaCoordinatedGraphics::activityStateDidChange(OptionSet<ActivitySt
429429
}
430430
}
431431

432-
completionHandler();
432+
if (completionHandler)
433+
completionHandler();
433434
}
434435

435436
void DrawingAreaCoordinatedGraphics::attachViewOverlayGraphicsLayer(GraphicsLayer* viewOverlayRootLayer)

Source/WebKit/WebProcess/WebPage/WebPage.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3634,6 +3634,15 @@ void WebPage::setActivityState(OptionSet<ActivityState::Flag> activityState, Act
36343634

36353635
ASSERT_WITH_MESSAGE(m_page, "setActivityState called on %" PRIu64 " but WebCore page was null", identifier().toUInt64());
36363636
if (m_page) {
3637+
if (changed & ActivityState::IsVisible) {
3638+
// VisibilityChange events are queued, not emitted directly. Due to that, in order to ensure that the
3639+
// UIProcess will be notified after the event was dispatched and not before, we need to execute the callback
3640+
// after the event is dispatched to the page and the different documents, and not just after the drawingArea is
3641+
// done, which is the usual case.
3642+
// So, in this case, pass an empty callback to the drawingArea and pass the real callback to the page.
3643+
m_page->setVisibilityChangeCompletionHandler(std::exchange(callback, { }));
3644+
}
3645+
36373646
SetForScope currentlyChangingActivityState { m_lastActivityStateChanges, changed };
36383647
m_page->setActivityState(activityState);
36393648
}

0 commit comments

Comments
 (0)