標籤:webkit
曆史項管理根據標準定義,由Page管理一個Joint Session History, 包含了各個子Frame的曆史項。邏輯上對應如下的關係:
從上面看三個層次:Page,Frame,以及JS Binding的介面。頁面載入的核心是由Frame通過FrameLoader來完成的,HistoryController及BackForwardController可以視為頁面載入進行曆史項操作的介面。 Frame層次中通過HistoryController, Page層次中通過BackForwardController進行曆史項操作。
BackForwardClient及HistoryItem則儲存著曆史項的具體內容。曆史項的變化訊息則由FrameLoaderClient負責發送(適配到WebKit層)。
Page層次中的主要類別關係如下:
一個HistoryItem可以理解為標準中定義的state。HistoryItem儲存和Joint Session History的關係表現在其儲存的成員變數上:
m_target, m_parent儲存的都是Frame名稱,可以從FrameTree擷取到Frame, 分別代表著此HistoryItem對應的Frame, 以及其父Frame。
m_scrollPoint則是當前顯示的位置。如果是通過Anchor跳轉,這個值就會有所區分。
m_stateObject則是通過HTML5 History API的pushState及replaceState所操作的內容。
JSBinding層則是由History通過Frame向JS提供服務。在Frame的層次上,Frame主要通過FrameLoader進行曆史項操作。頁面跳轉操作則由Frame的NavigatorScheduler來完成。在HTML5 Spec中關於Session History的操作集中在HistoryController裡,一部分邏輯分散在NavigationScheduler裡,比如NavigationScheduler::mustLockBackForwardList()函數,以及1秒內跳轉的處理邏輯。
當頁面前進後退時,具體的載入操作還是以FrameLoader為核心的,HistoryController和BackForwardController充其量還主要是儲存操作。曆史項的變化也還需要由FrameLoaderClient及其在各個平台的實現來派發到WebKit及UI層(中WebHistoryDelegate即為Mac OS下WebView接收曆史項相關資訊的Delegate)。
當頁面通過JS執行pushState,在WebCore就會在HistoryController中產生一個含有此State的HistoryItem,然後添加到BackForwardList(BackForwardClient)中。以下是其時序圖:
以下是頁面跳轉時,向JS發送popState訊息的時序圖:
具體的行為邏輯,通讀標準定義是合適的。附連結如下:
https://html.spec.whatwg.org/multipage/browsers.html
從WebKit對外的適配,具體的實現差異比較大,但都會以曆史項變化的訊息通知來對應UI上的前進後退操作及狀態顯示,這樣可以保持一致性。
比如在Mac OS下,一個曆史項變化時,WebFrameLoaderClient::updateGlobalHistory()會使用如下的方式通知到WebView上:
if ([view historyDelegate]) { WebHistoryDelegateImplementationCache* implementations = WebViewGetHistoryDelegateImplementations(view); if (implementations->navigatedFunc) { WebNavigationData *data = [[WebNavigationData alloc] initWithURLString:loader->url() title:nilOrNSString(loader->title().string()) originalRequest:loader->originalRequestCopy().nsURLRequest(UpdateHTTPBody) response:loader->response().nsURLResponse() hasSubstituteData:loader->substituteData().isValid() clientRedirectSource:loader->clientRedirectSourceForHistory()]; CallHistoryDelegate(implementations->navigatedFunc, view, @selector(webView:didNavigateWithNavigationData:inFrame:), data, m_webFrame.get()); [data release]; } return; }
曆史項的建立及通知流程如下:
轉載請註明出處: http://blog.csdn.net/horkychen
WebKit曆史項管理的實現