Skip to content

Commit 38f0080

Browse files
committed
[PageLifecycle] Emit proper events when freezing and resuming.
1 parent 2cda3fd commit 38f0080

8 files changed

Lines changed: 85 additions & 5 deletions

File tree

Source/WebCore/dom/Document.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9250,6 +9250,29 @@ bool Document::lazyImageLoadingEnabled() const
92509250
return m_settings->lazyImageLoadingEnabled() && !m_quirks->shouldDisableLazyImageLoadingQuirk();
92519251
}
92529252

9253+
// https://wicg.github.io/page-lifecycle/spec.html#freeze-steps
9254+
void Document::freeze()
9255+
{
9256+
if (m_frozen)
9257+
return;
9258+
9259+
m_frozen = true;
9260+
dispatchEvent(Event::create(eventNames().freezeEvent, Event::CanBubble::No, Event::IsCancelable::No));
9261+
}
9262+
9263+
// https://wicg.github.io/page-lifecycle/spec.html#resume-steps
9264+
void Document::resume(CompletionHandler<void(Document&)>&& completionHandler)
9265+
{
9266+
if (!m_frozen)
9267+
return;
9268+
9269+
eventLoop().queueTask(TaskSource::UserInteraction, [document = Ref { *this }, this, completionHandler = WTFMove(completionHandler)] () mutable {
9270+
dispatchEvent(Event::create(eventNames().resumeEvent, Event::CanBubble::No, Event::IsCancelable::No));
9271+
m_frozen = false;
9272+
completionHandler(document);
9273+
});
9274+
}
9275+
92539276
} // namespace WebCore
92549277

92559278
#undef DOCUMENT_RELEASE_LOG

Source/WebCore/dom/Document.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1696,6 +1696,9 @@ class Document
16961696
// This should be used over the settings lazy loading image flag due to a quirk, which may occur causing website images to fail to load properly.
16971697
bool lazyImageLoadingEnabled() const;
16981698

1699+
void freeze();
1700+
void resume(CompletionHandler<void(Document&)>&&);
1701+
16991702
protected:
17001703
enum ConstructionFlags { Synthesized = 1, NonRenderedPlaceholder = 1 << 1 };
17011704
WEBCORE_EXPORT Document(Frame*, const Settings&, const URL&, DocumentClasses = { }, unsigned constructionFlags = 0, ScriptExecutionContextIdentifier = { });
@@ -2292,6 +2295,8 @@ class Document
22922295
Vector<Function<void()>> m_whenIsVisibleHandlers;
22932296

22942297
WeakHashSet<Element> m_elementsWithPendingUserAgentShadowTreeUpdates;
2298+
2299+
bool m_frozen { false };
22952300
};
22962301

22972302
Element* eventTargetElementForDocument(Document*);

Source/WebCore/dom/Document.idl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ typedef (HTMLScriptElement or SVGScriptElement) HTMLOrSVGScriptElement;
9494

9595
// Non standard: It has been dropped from Blink already.
9696
RenderingContext? getCSSCanvasContext(DOMString contextId, DOMString name, long width, long height);
97+
98+
[EnabledBySetting=PageLifecycleAPIEnabled] attribute EventHandler onfreeze;
99+
[EnabledBySetting=PageLifecycleAPIEnabled] attribute EventHandler onresume;
97100
};
98101

99102
enum DocumentReadyState { "loading", "interactive", "complete" };

Source/WebCore/dom/EventNames.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ namespace WebCore {
130130
macro(focusin) \
131131
macro(focusout) \
132132
macro(formdata) \
133+
macro(freeze) \
133134
macro(gamepadconnected) \
134135
macro(gamepaddisconnected) \
135136
macro(gatheringstatechange) \

Source/WebCore/history/BackForwardCache.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ static void destroyRenderTree(Frame& mainFrame)
403403
}
404404
}
405405

406-
static void firePageHideEventRecursively(Frame& frame)
406+
static void firePageHideEventRecursively(Frame& frame, bool usePageLifecycleEvents)
407407
{
408408
auto* document = frame.document();
409409
if (!document)
@@ -415,10 +415,11 @@ static void firePageHideEventRecursively(Frame& frame)
415415
// https://html.spec.whatwg.org/multipage/browsers.html#unload-a-document
416416
IgnoreOpensDuringUnloadCountIncrementer ignoreOpensDuringUnloadCountIncrementer(document);
417417

418-
frame.loader().stopLoading(UnloadEventPolicy::UnloadAndPageHide);
418+
UnloadEventPolicy eventPolicy = usePageLifecycleEvents ? UnloadEventPolicy::None : UnloadEventPolicy::UnloadAndPageHide;
419+
frame.loader().stopLoading(eventPolicy);
419420

420421
for (RefPtr<Frame> child = frame.tree().firstChild(); child; child = child->tree().nextSibling())
421-
firePageHideEventRecursively(*child);
422+
firePageHideEventRecursively(*child, usePageLifecycleEvents);
422423
}
423424

424425
std::unique_ptr<CachedPage> BackForwardCache::trySuspendPage(Page& page, ForceSuspension forceSuspension)
@@ -438,7 +439,7 @@ std::unique_ptr<CachedPage> BackForwardCache::trySuspendPage(Page& page, ForceSu
438439
focusController->setFocusedFrame(&page.mainFrame());
439440

440441
// Fire the pagehide event in all frames.
441-
firePageHideEventRecursively(page.mainFrame());
442+
firePageHideEventRecursively(page.mainFrame(), m_usePageLifecycleEvents);
442443

443444
destroyRenderTree(page.mainFrame());
444445

Source/WebCore/history/BackForwardCache.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ class BackForwardCache {
6969
void markPagesForCaptionPreferencesChanged();
7070
#endif
7171

72+
void setUsePageLifecycleEvents(bool use) { m_usePageLifecycleEvents = use; }
73+
7274
private:
7375
BackForwardCache();
7476
~BackForwardCache() = delete; // Make sure nobody accidentally calls delete -- WebCore does not delete singletons.
@@ -87,6 +89,8 @@ class BackForwardCache {
8789
bool m_isInRemoveAllItemsForPage { false };
8890
#endif
8991

92+
bool m_usePageLifecycleEvents { false };
93+
9094
friend class WTF::NeverDestroyed<BackForwardCache>;
9195
};
9296

Source/WebKit/WebProcess/WebPage/WebPage.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3789,15 +3789,42 @@ void WebPage::suspend(CompletionHandler<void(bool)>&& completionHandler)
37893789
if (!m_page)
37903790
return completionHandler(false);
37913791

3792+
m_isLifecycleSuspended = true;
3793+
3794+
// Suspend all the documents, so they can send the freeze event to the apps.
3795+
m_page->forEachDocument([] (Document& document) {
3796+
document.freeze();
3797+
});
3798+
37923799
freezeLayerTree(LayerTreeFreezeReason::PageSuspended);
37933800

3801+
BackForwardCache::singleton().setUsePageLifecycleEvents(true);
37943802
m_cachedPage = BackForwardCache::singleton().suspendPage(*m_page);
3803+
BackForwardCache::singleton().setUsePageLifecycleEvents(false);
37953804
ASSERT(m_cachedPage);
37963805
if (auto mainFrame = m_mainFrame->coreFrame())
37973806
mainFrame->loader().detachFromAllOpenedFrames();
37983807
completionHandler(true);
37993808
}
38003809

3810+
class ResumeEventNotifier : public RefCounted<ResumeEventNotifier> {
3811+
public:
3812+
ResumeEventNotifier() = default;
3813+
virtual ~ResumeEventNotifier() = default;
3814+
3815+
void setCompletionHandler(CompletionHandler<void()>&& completionHandler) { m_completionHandler = WTFMove(completionHandler); };
3816+
void addDocument(Ref<Document> document) { m_documents.add(document); };
3817+
void removeDocument(Ref<Document> document) {
3818+
m_documents.remove(document);
3819+
if (m_documents.isEmpty())
3820+
m_completionHandler();
3821+
}
3822+
3823+
private:
3824+
CompletionHandler<void()> m_completionHandler;
3825+
HashSet<Ref<Document>> m_documents;
3826+
};
3827+
38013828
void WebPage::resume(CompletionHandler<void(bool)>&& completionHandler)
38023829
{
38033830
WEBPAGE_RELEASE_LOG(Loading, "resume: m_page=%p", m_page.get());
@@ -3811,7 +3838,22 @@ void WebPage::resume(CompletionHandler<void(bool)>&& completionHandler)
38113838

38123839
cachedPage->restore(*m_page);
38133840
unfreezeLayerTree(LayerTreeFreezeReason::PageSuspended);
3814-
completionHandler(true);
3841+
3842+
// Create a notifier that will call the completionHandler once all the documents
3843+
// have dispatched their resume event.
3844+
Ref<ResumeEventNotifier> notifier = adoptRef(*new ResumeEventNotifier());
3845+
notifier->setCompletionHandler([this, completionHandler = std::exchange(completionHandler, { })] () mutable {
3846+
m_isLifecycleSuspended = false;
3847+
completionHandler(true);
3848+
});
3849+
3850+
// Resume all the documents.
3851+
m_page->forEachDocument([notifier] (Document& document) {
3852+
notifier->addDocument(document);
3853+
document.resume([protectedNotifier = Ref { notifier }] (Document& document) {
3854+
protectedNotifier->removeDocument(document);
3855+
});
3856+
});
38153857
}
38163858

38173859
IntPoint WebPage::screenToRootView(const IntPoint& point)

Source/WebKit/WebProcess/WebPage/WebPage.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2429,6 +2429,7 @@ class WebPage : public API::ObjectImpl<API::Object::Type::BundlePage>, public IP
24292429

24302430
OptionSet<LayerTreeFreezeReason> m_layerTreeFreezeReasons;
24312431
bool m_isSuspended { false };
2432+
bool m_isLifecycleSuspended { false };
24322433
bool m_needsFontAttributes { false };
24332434
bool m_firstFlushAfterCommit { false };
24342435
#if PLATFORM(COCOA)

0 commit comments

Comments
 (0)