[WK2] Fire a layout milestone on session restore based on render tree size
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Nov 2014 23:27:26 +0000 (23:27 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Nov 2014 23:27:26 +0000 (23:27 +0000)
https://bugs.webkit.org/show_bug.cgi?id=138711
rdar://problem/16033854

Reviewed by Anders Carlsson.
Source/WebCore:

New layout milestone for session restore based on render tree size. Only used
in WK2 at present.

* page/LayoutMilestones.h:

Source/WebKit2:

Add a session-restore layout milestone which fires after restoring a session,
when the render tree size reaches 50% of the size saved in the session state.

* Shared/SessionState.h: Add renderTreeSize.
* UIProcess/API/Cocoa/WKWebView.mm:
(layoutMilestones): Translate from SPI to WebCore milestones.
* UIProcess/API/Cocoa/WKWebViewPrivate.h: New iOS-only milestone, er, event.
* UIProcess/Cocoa/NavigationState.mm:
(WebKit::renderingProgressEvents): Translate from WebCore milestone to rendering event.
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::WebPageProxy): Init stuff.
(WebKit::WebPageProxy::sessionState):
(WebKit::WebPageProxy::restoreFromSessionState): Zero out the target render tree size,
then get it out of session state and set the flag to say that we haven't reached it yet.
(WebKit::WebPageProxy::listenForLayoutMilestones): Set a flag to know that we should fire
the milestone. The other milestones get sent directly to WebCore.
* UIProcess/WebPageProxy.h:
* UIProcess/ios/WebPageProxyIOS.mm:
(WebKit::exceedsRenderTreeSizeSizeThreshold): Return true when we've reached 50%.
(WebKit::WebPageProxy::didCommitLayerTree): Fire the milestone when appropriate.
* UIProcess/mac/LegacySessionStateCoding.cpp: Rev the session state data for iOS
(where doing so is less disruptive). Standardize some CFString constants.
(WebKit::encodeSessionHistory): Wrap for legibility.
(WebKit::encodeLegacySessionState): Make a CFNumber for render tree size, and store
it in the root dictionary.
(WebKit::decodeBackForwardTreeNode): Move a comment to match another similar block.
(WebKit::decodeLegacySessionState): Decode render tree size and store it.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@176097 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/page/LayoutMilestones.h
Source/WebKit2/ChangeLog
Source/WebKit2/Shared/SessionState.h
Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h
Source/WebKit2/UIProcess/Cocoa/NavigationState.mm
Source/WebKit2/UIProcess/WebPageProxy.cpp
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm
Source/WebKit2/UIProcess/mac/LegacySessionStateCoding.cpp

index 3922392..34c1e5a 100644 (file)
@@ -1,3 +1,16 @@
+2014-11-13  Simon Fraser  <simon.fraser@apple.com>
+
+        [WK2] Fire a layout milestone on session restore based on render tree size
+        https://bugs.webkit.org/show_bug.cgi?id=138711
+        rdar://problem/16033854
+
+        Reviewed by Anders Carlsson.
+
+        New layout milestone for session restore based on render tree size. Only used
+        in WK2 at present.
+
+        * page/LayoutMilestones.h:
+
 2014-11-13  Dan Bernstein  <mitz@apple.com>
 
         Policy client not called for navigations through the page cache
index 7007434..b125bc4 100644 (file)
@@ -37,7 +37,8 @@ enum LayoutMilestoneFlag {
     DidHitRelevantRepaintedObjectsAreaThreshold = 1 << 2,
     DidFirstFlushForHeaderLayer = 1 << 3,
     DidFirstLayoutAfterSuppressedIncrementalRendering = 1 << 4,
-    DidFirstPaintAfterSuppressedIncrementalRendering = 1 << 5
+    DidFirstPaintAfterSuppressedIncrementalRendering = 1 << 5,
+    ReachedSessionRestorationRenderTreeSizeThreshold = 1 << 6 // FIXME: only implemented by WK2 currently.
 };
 
 typedef unsigned LayoutMilestones;
index 1a4c016..4685ebc 100644 (file)
@@ -1,3 +1,39 @@
+2014-11-13  Simon Fraser  <simon.fraser@apple.com>
+
+        [WK2] Fire a layout milestone on session restore based on render tree size
+        https://bugs.webkit.org/show_bug.cgi?id=138711
+        rdar://problem/16033854
+
+        Reviewed by Anders Carlsson.
+        
+        Add a session-restore layout milestone which fires after restoring a session,
+        when the render tree size reaches 50% of the size saved in the session state.
+
+        * Shared/SessionState.h: Add renderTreeSize.
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (layoutMilestones): Translate from SPI to WebCore milestones.
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h: New iOS-only milestone, er, event.
+        * UIProcess/Cocoa/NavigationState.mm:
+        (WebKit::renderingProgressEvents): Translate from WebCore milestone to rendering event.
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::WebPageProxy): Init stuff.
+        (WebKit::WebPageProxy::sessionState):
+        (WebKit::WebPageProxy::restoreFromSessionState): Zero out the target render tree size,
+        then get it out of session state and set the flag to say that we haven't reached it yet.
+        (WebKit::WebPageProxy::listenForLayoutMilestones): Set a flag to know that we should fire
+        the milestone. The other milestones get sent directly to WebCore.
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/ios/WebPageProxyIOS.mm:
+        (WebKit::exceedsRenderTreeSizeSizeThreshold): Return true when we've reached 50%.
+        (WebKit::WebPageProxy::didCommitLayerTree): Fire the milestone when appropriate.
+        * UIProcess/mac/LegacySessionStateCoding.cpp: Rev the session state data for iOS
+        (where doing so is less disruptive). Standardize some CFString constants.
+        (WebKit::encodeSessionHistory): Wrap for legibility.
+        (WebKit::encodeLegacySessionState): Make a CFNumber for render tree size, and store
+        it in the root dictionary.
+        (WebKit::decodeBackForwardTreeNode): Move a comment to match another similar block.
+        (WebKit::decodeLegacySessionState): Decode render tree size and store it.
+
 2014-11-13  Tim Horton  <timothy_horton@apple.com>
 
         Adjust the WKBundlePageOverlay Data Detectors SPI
index 614d419..d4d6a2b 100644 (file)
@@ -140,6 +140,7 @@ struct BackForwardListState {
 
 struct SessionState {
     BackForwardListState backForwardListState;
+    uint64_t renderTreeSize;
     WebCore::URL provisionalURL;
 };
 
index 20b2554..ab58f51 100644 (file)
@@ -1808,6 +1808,9 @@ static inline WebCore::LayoutMilestones layoutMilestones(_WKRenderingProgressEve
     if (events & _WKRenderingProgressEventFirstPaintWithSignificantArea)
         milestones |= WebCore::DidHitRelevantRepaintedObjectsAreaThreshold;
 
+    if (events & _WKRenderingProgressEventReachedSessionRestorationRenderTreeSizeThreshold)
+        milestones |= WebCore::ReachedSessionRestorationRenderTreeSizeThreshold;
+
     return milestones;
 }
 
index a54d143..b4ce7ae 100644 (file)
@@ -30,6 +30,7 @@
 typedef NS_OPTIONS(NSUInteger, _WKRenderingProgressEvents) {
     _WKRenderingProgressEventFirstLayout = 1 << 0,
     _WKRenderingProgressEventFirstPaintWithSignificantArea = 1 << 2,
+    _WKRenderingProgressEventReachedSessionRestorationRenderTreeSizeThreshold WK_ENUM_AVAILABLE(WK_MAC_TBA, WK_IOS_TBA) = 1 << 3
 } WK_ENUM_AVAILABLE(10_10, 8_0);
 
 typedef NS_ENUM(NSInteger, _WKPaginationMode) {
index 7941dbf..5a6b714 100644 (file)
@@ -673,6 +673,9 @@ static _WKRenderingProgressEvents renderingProgressEvents(WebCore::LayoutMilesto
     if (milestones & WebCore::DidHitRelevantRepaintedObjectsAreaThreshold)
         events |= _WKRenderingProgressEventFirstPaintWithSignificantArea;
 
+    if (milestones & WebCore::ReachedSessionRestorationRenderTreeSizeThreshold)
+        events |= _WKRenderingProgressEventReachedSessionRestorationRenderTreeSizeThreshold;
+
     return events;
 }
 
index 43f0d6c..b40cb96 100644 (file)
@@ -361,6 +361,9 @@ WebPageProxy::WebPageProxy(PageClient& pageClient, WebProcessProxy& process, uin
     , m_isShowingNavigationGestureSnapshot(false)
     , m_pageCount(0)
     , m_renderTreeSize(0)
+    , m_sessionRestorationRenderTreeSize(0)
+    , m_wantsSessionRestorationRenderTreeSizeThresholdEvent(false)
+    , m_hitRenderTreeSizeThreshold(false)
     , m_shouldSendEventsSynchronously(false)
     , m_suppressVisibilityUpdates(false)
     , m_autoSizingShouldExpandToViewHeight(false)
@@ -1931,11 +1934,15 @@ SessionState WebPageProxy::sessionState(const std::function<bool (WebBackForward
     if (!provisionalURLString.isEmpty())
         sessionState.provisionalURL = URL(URL(), provisionalURLString);
 
+    sessionState.renderTreeSize = renderTreeSize();
     return sessionState;
 }
 
 uint64_t WebPageProxy::restoreFromSessionState(SessionState sessionState, bool navigate)
 {
+    m_sessionRestorationRenderTreeSize = 0;
+    m_hitRenderTreeSizeThreshold = false;
+
     bool hasBackForwardList = !!sessionState.backForwardListState.currentIndex;
 
     if (hasBackForwardList) {
@@ -1947,8 +1954,11 @@ uint64_t WebPageProxy::restoreFromSessionState(SessionState sessionState, bool n
         process().send(Messages::WebPage::RestoreSession(m_backForwardList->itemStates()), m_pageID);
     }
 
+    // FIXME: Navigating should be separate from state restoration.
     if (navigate) {
-        // FIXME: Navigating should be separate from state restoration.
+        m_sessionRestorationRenderTreeSize = sessionState.renderTreeSize;
+        if (!m_sessionRestorationRenderTreeSize)
+            m_hitRenderTreeSizeThreshold = true; // If we didn't get data on renderTreeSize, just don't fire the milestone.
 
         if (!sessionState.provisionalURL.isNull())
             return loadRequest(sessionState.provisionalURL);
@@ -2107,6 +2117,8 @@ void WebPageProxy::listenForLayoutMilestones(WebCore::LayoutMilestones milestone
 {
     if (!isValid())
         return;
+    
+    m_wantsSessionRestorationRenderTreeSizeThresholdEvent = milestones & WebCore::ReachedSessionRestorationRenderTreeSizeThreshold;
 
     m_process->send(Messages::WebPage::ListenForLayoutMilestones(milestones), m_pageID);
 }
index 307d8cb..5fe798f 100644 (file)
@@ -1557,6 +1557,9 @@ private:
     WebCore::IntRect m_visibleScrollerThumbRect;
 
     uint64_t m_renderTreeSize;
+    uint64_t m_sessionRestorationRenderTreeSize;
+    bool m_wantsSessionRestorationRenderTreeSizeThresholdEvent;
+    bool m_hitRenderTreeSizeThreshold;
 
     bool m_shouldSendEventsSynchronously;
 
index e01f8ac..5936daf 100644 (file)
@@ -332,6 +332,12 @@ void WebPageProxy::setDeviceOrientation(int32_t deviceOrientation)
     }
 }
 
+static bool exceedsRenderTreeSizeSizeThreshold(uint64_t thresholdSize, uint64_t committedSize)
+{
+    const double thesholdSizeFraction = 0.5; // Empirically-derived.
+    return committedSize > thresholdSize * thesholdSizeFraction;
+}
+
 void WebPageProxy::didCommitLayerTree(const WebKit::RemoteLayerTreeTransaction& layerTreeTransaction)
 {
     m_pageExtendedBackgroundColor = layerTreeTransaction.pageExtendedBackgroundColor();
@@ -349,6 +355,12 @@ void WebPageProxy::didCommitLayerTree(const WebKit::RemoteLayerTreeTransaction&
     }
 
     m_pageClient.didCommitLayerTree(layerTreeTransaction);
+
+    if (m_wantsSessionRestorationRenderTreeSizeThresholdEvent && !m_hitRenderTreeSizeThreshold
+        && exceedsRenderTreeSizeSizeThreshold(m_sessionRestorationRenderTreeSize, layerTreeTransaction.renderTreeSize())) {
+        m_hitRenderTreeSizeThreshold = true;
+        m_loaderClient->didLayout(this, WebCore::ReachedSessionRestorationRenderTreeSizeThreshold, nullptr);
+    }
 }
 
 void WebPageProxy::selectWithGesture(const WebCore::IntPoint point, WebCore::TextGranularity granularity, uint32_t gestureType, uint32_t gestureState, std::function<void (const WebCore::IntPoint&, uint32_t, uint32_t, uint32_t, CallbackBase::Error)> callbackFunction)
index 7dc6898..164acbd 100644 (file)
@@ -40,6 +40,7 @@ static const uint32_t sessionStateDataVersion = 2;
 
 static const CFStringRef sessionHistoryKey = CFSTR("SessionHistory");
 static const CFStringRef provisionalURLKey = CFSTR("ProvisionalURL");
+static const CFStringRef renderTreeSizeKey = CFSTR("RenderTreeSize");
 
 // Session history keys.
 static const uint32_t sessionHistoryVersion = 1;
@@ -50,9 +51,9 @@ static const CFStringRef sessionHistoryEntriesKey = CFSTR("SessionHistoryEntries
 
 // Session history entry keys.
 static const CFStringRef sessionHistoryEntryURLKey = CFSTR("SessionHistoryEntryURL");
-static CFStringRef sessionHistoryEntryTitleKey = CFSTR("SessionHistoryEntryTitle");
-static CFStringRef sessionHistoryEntryOriginalURLKey = CFSTR("SessionHistoryEntryOriginalURL");
-static CFStringRef sessionHistoryEntryDataKey = CFSTR("SessionHistoryEntryData");
+static const CFStringRef sessionHistoryEntryTitleKey = CFSTR("SessionHistoryEntryTitle");
+static const CFStringRef sessionHistoryEntryOriginalURLKey = CFSTR("SessionHistoryEntryOriginalURL");
+static const CFStringRef sessionHistoryEntryDataKey = CFSTR("SessionHistoryEntryData");
 
 // Session history entry data.
 const uint32_t sessionHistoryEntryDataVersion = 2;
@@ -426,7 +427,12 @@ static RetainPtr<CFDictionaryRef> encodeSessionHistory(const BackForwardListStat
         auto originalURL = item.pageState.mainFrameState.originalURLString.createCFString();
         auto data = encodeSessionHistoryEntryData(item.pageState.mainFrameState);
 
-        auto entryDictionary = createDictionary({ { sessionHistoryEntryURLKey, url.get() }, { sessionHistoryEntryTitleKey, title.get() }, { sessionHistoryEntryOriginalURLKey, originalURL.get() }, { sessionHistoryEntryDataKey, data.get() } });
+        auto entryDictionary = createDictionary({
+            { sessionHistoryEntryURLKey, url.get() },
+            { sessionHistoryEntryTitleKey, title.get() },
+            { sessionHistoryEntryOriginalURLKey, originalURL.get() },
+            { sessionHistoryEntryDataKey, data.get() },
+        });
 
         CFArrayAppendValue(entries.get(), entryDictionary.get());
     }
@@ -441,12 +447,21 @@ RefPtr<API::Data> encodeLegacySessionState(const SessionState& sessionState)
 {
     auto sessionHistoryDictionary = encodeSessionHistory(sessionState.backForwardListState);
     auto provisionalURLString = sessionState.provisionalURL.isNull() ? nullptr : sessionState.provisionalURL.string().createCFString();
+    RetainPtr<CFNumberRef> renderTreeSizeNumber(adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &sessionState.renderTreeSize)));
 
     RetainPtr<CFDictionaryRef> stateDictionary;
-    if (provisionalURLString)
-        stateDictionary = createDictionary({ { sessionHistoryKey, sessionHistoryDictionary.get() }, { provisionalURLKey, provisionalURLString.get() } });
-    else
-        stateDictionary = createDictionary({ { sessionHistoryKey, sessionHistoryDictionary.get() } });
+    if (provisionalURLString) {
+        stateDictionary = createDictionary({
+            { sessionHistoryKey, sessionHistoryDictionary.get() },
+            { provisionalURLKey, provisionalURLString.get() },
+            { renderTreeSizeKey, renderTreeSizeNumber.get() }
+        });
+    } else {
+        stateDictionary = createDictionary({
+            { sessionHistoryKey, sessionHistoryDictionary.get() },
+            { renderTreeSizeKey, renderTreeSizeNumber.get() }
+        });
+    }
 
     auto writeStream = adoptCF(CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault, nullptr));
     if (!writeStream)
@@ -902,8 +917,8 @@ static void decodeBackForwardTreeNode(HistoryEntryDataDecoder& decoder, FrameSta
 
     decoder >> frameState.target;
 
-    // FIXME: iOS should not use the legacy session state decoder.
 #if PLATFORM(IOS)
+    // FIXME: iOS should not use the legacy session state decoder.
     decoder >> frameState.exposedContentRect;
     decoder >> frameState.unobscuredContentRect;
     decoder >> frameState.minimumLayoutSizeInScrollViewCoordinates;
@@ -1087,6 +1102,11 @@ bool decodeLegacySessionState(const uint8_t* bytes, size_t size, SessionState& s
             return false;
     }
 
+    if (auto renderTreeSize = dynamic_cf_cast<CFNumberRef>(CFDictionaryGetValue(sessionStateDictionary.get(), renderTreeSizeKey)))
+        CFNumberGetValue(renderTreeSize, kCFNumberSInt64Type, &sessionState.renderTreeSize);
+    else
+        sessionState.renderTreeSize = 0;
+
     return true;
 }