[iOS] Replace "node assistance" terminology in WebKit with "focused element"
[WebKit-https.git] / Source / WebKit / UIProcess / SuspendedPageProxy.cpp
index 5d1fc5c..f198a81 100644 (file)
@@ -33,8 +33,8 @@
 #include "WebProcessMessages.h"
 #include "WebProcessPool.h"
 #include "WebProcessProxy.h"
-#include <WebCore/URL.h>
 #include <wtf/DebugUtilities.h>
+#include <wtf/URL.h>
 
 namespace WebKit {
 using namespace WebCore;
@@ -54,6 +54,7 @@ static const HashSet<IPC::StringReference>& messageNamesToIgnoreWhileSuspended()
         messageNames.get().add("DidDestroyNavigation");
         messageNames.get().add("DidFinishDocumentLoadForFrame");
         messageNames.get().add("DidFinishProgress");
+        messageNames.get().add("DidCompletePageTransition");
         messageNames.get().add("DidFirstLayoutForFrame");
         messageNames.get().add("DidFirstVisuallyNonEmptyLayoutForFrame");
         messageNames.get().add("DidNavigateWithNavigationData");
@@ -73,72 +74,115 @@ static const HashSet<IPC::StringReference>& messageNamesToIgnoreWhileSuspended()
 }
 #endif
 
-SuspendedPageProxy::SuspendedPageProxy(WebPageProxy& page, WebProcessProxy& process, WebBackForwardListItem& item)
+SuspendedPageProxy::SuspendedPageProxy(WebPageProxy& page, Ref<WebProcessProxy>&& process, WebBackForwardListItem& item, uint64_t mainFrameID)
     : m_page(page)
-    , m_process(&process)
-    , m_origin(SecurityOriginData::fromURL({ ParsedURLString, item.url() }))
+    , m_process(WTFMove(process))
+    , m_mainFrameID(mainFrameID)
+    , m_registrableDomain(toRegistrableDomain(URL(URL(), item.url())))
+#if PLATFORM(IOS_FAMILY)
+    , m_suspensionToken(m_process->throttler().backgroundActivityToken())
+#endif
 {
-    item.setSuspendedPage(*this);
-    m_process->processPool().registerSuspendedPageProxy(*this);
+    item.setSuspendedPage(this);
+    m_process->addMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_page.pageID(), *this);
+
     m_process->send(Messages::WebPage::SetIsSuspended(true), m_page.pageID());
 }
 
 SuspendedPageProxy::~SuspendedPageProxy()
 {
-    if (auto process = makeRefPtr(m_process)) {
-        process->send(Messages::WebPage::SetIsSuspended(false), m_page.pageID());
-        process->suspendedPageWasDestroyed(*this);
-        process->processPool().unregisterSuspendedPageProxy(*this);
-    }
-}
+    if (m_readyToUnsuspendHandler)
+        m_readyToUnsuspendHandler(nullptr);
 
-void SuspendedPageProxy::webProcessDidClose(WebProcessProxy& process)
-{
-    ASSERT_UNUSED(process, &process == m_process);
+    if (m_suspensionState == SuspensionState::Resumed)
+        return;
 
-    m_process->processPool().unregisterSuspendedPageProxy(*this);
-    m_process = nullptr;
+    // If the suspended page was not consumed before getting destroyed, then close the corresponding page
+    // on the WebProcess side.
+    m_process->send(Messages::WebPage::Close(), m_page.pageID());
+    m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_page.pageID());
 
-    // This will destroy |this|.
-    m_page.suspendedPageClosed(*this);
+    // We call maybeShutDown() asynchronously since the SuspendedPage is currently being removed from the WebProcessPool
+    // and we want to avoid re-entering WebProcessPool methods.
+    RunLoop::main().dispatch([process = m_process.copyRef()] {
+        process->maybeShutDown();
+    });
 }
 
-void SuspendedPageProxy::destroyWebPageInWebProcess()
+void SuspendedPageProxy::waitUntilReadyToUnsuspend(CompletionHandler<void(SuspendedPageProxy*)>&& completionHandler)
 {
-    m_process->send(Messages::WebPage::Close(), m_page.pageID());
-    m_page.suspendedPageClosed(*this);
+    if (m_readyToUnsuspendHandler)
+        m_readyToUnsuspendHandler(nullptr);
+
+    switch (m_suspensionState) {
+    case SuspensionState::Suspending:
+        m_readyToUnsuspendHandler = WTFMove(completionHandler);
+        break;
+    case SuspensionState::FailedToSuspend:
+    case SuspensionState::Suspended:
+        completionHandler(this);
+        break;
+    case SuspensionState::Resumed:
+        ASSERT_NOT_REACHED();
+        completionHandler(nullptr);
+        break;
+    }
+}
+
+void SuspendedPageProxy::unsuspend()
+{
+    ASSERT(m_suspensionState == SuspensionState::Suspended);
+
+    m_suspensionState = SuspensionState::Resumed;
+    m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_page.pageID());
+    m_process->send(Messages::WebPage::SetIsSuspended(false), m_page.pageID());
 }
 
-void SuspendedPageProxy::didFinishLoad()
+void SuspendedPageProxy::didProcessRequestToSuspend(SuspensionState newSuspensionState)
 {
-    ASSERT(m_process);
     LOG(ProcessSwapping, "SuspendedPageProxy %s from process %i finished transition to suspended", loggingString(), m_process->processIdentifier());
 
-#if !LOG_DISABLED
-    m_finishedSuspending = true;
+    ASSERT(m_suspensionState == SuspensionState::Suspending);
+    ASSERT(newSuspensionState == SuspensionState::Suspended || newSuspensionState == SuspensionState::FailedToSuspend);
+
+    m_suspensionState = newSuspensionState;
+
+#if PLATFORM(IOS_FAMILY)
+    m_suspensionToken = nullptr;
 #endif
 
-    m_process->send(Messages::WebProcess::UpdateActivePages(), 0);
+    if (m_readyToUnsuspendHandler)
+        m_readyToUnsuspendHandler(this);
 }
 
 void SuspendedPageProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder& decoder)
 {
     ASSERT(decoder.messageReceiverName() == Messages::WebPageProxy::messageReceiverName());
 
-    if (decoder.messageName() == Messages::WebPageProxy::DidFinishLoadForFrame::name()) {
-        didFinishLoad();
+    if (decoder.messageName() == Messages::WebPageProxy::DidSuspendAfterProcessSwap::name()) {
+        didProcessRequestToSuspend(SuspensionState::Suspended);
+        return;
+    }
+
+    if (decoder.messageName() == Messages::WebPageProxy::DidFailToSuspendAfterProcessSwap::name()) {
+        didProcessRequestToSuspend(SuspensionState::FailedToSuspend);
         return;
     }
+
 #if !LOG_DISABLED
     if (!messageNamesToIgnoreWhileSuspended().contains(decoder.messageName()))
         LOG(ProcessSwapping, "SuspendedPageProxy received unexpected WebPageProxy message '%s'", decoder.messageName().toString().data());
 #endif
 }
 
+void SuspendedPageProxy::didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&)
+{
+}
+
 #if !LOG_DISABLED
 const char* SuspendedPageProxy::loggingString() const
 {
-    return debugString("(", String::format("%p", this), " page ID ", String::number(m_page.pageID()), ", m_finishedSuspending ", String::number(m_finishedSuspending), ")");
+    return debugString("(", String::format("%p", this), " page ID ", String::number(m_page.pageID()), ", m_suspensionState ", String::number(static_cast<unsigned>(m_suspensionState)), ")");
 }
 #endif