diff options
author | Ben Murdoch <benm@google.com> | 2011-05-13 16:23:25 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-05-16 11:35:02 +0100 |
commit | 65f03d4f644ce73618e5f4f50dd694b26f55ae12 (patch) | |
tree | f478babb801e720de7bfaee23443ffe029f58731 /Source/WebCore/loader/HistoryController.cpp | |
parent | 47de4a2fb7262c7ebdb9cd133ad2c54c187454d0 (diff) | |
download | external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.zip external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.tar.gz external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.tar.bz2 |
Merge WebKit at r75993: Initial merge by git.
Change-Id: I602bbdc3974787a3b0450456a30a7868286921c3
Diffstat (limited to 'Source/WebCore/loader/HistoryController.cpp')
-rw-r--r-- | Source/WebCore/loader/HistoryController.cpp | 132 |
1 files changed, 99 insertions, 33 deletions
diff --git a/Source/WebCore/loader/HistoryController.cpp b/Source/WebCore/loader/HistoryController.cpp index ff733a9..dda4e56 100644 --- a/Source/WebCore/loader/HistoryController.cpp +++ b/Source/WebCore/loader/HistoryController.cpp @@ -80,6 +80,8 @@ void HistoryController::saveScrollPositionAndViewStateToItem(HistoryItem* item) return; item->setScrollPoint(m_frame->view()->scrollPosition()); + item->setPageScaleFactor(m_frame->pageScaleFactor()); + // FIXME: It would be great to work out a way to put this code in WebCore instead of calling through to the client. m_frame->loader()->client()->saveViewStateToItem(item); } @@ -114,9 +116,12 @@ void HistoryController::restoreScrollPositionAndViewState() // through to the client. It's currently used only for the PDF view on Mac. m_frame->loader()->client()->restoreViewState(); - if (FrameView* view = m_frame->view()) - if (!view->wasScrolledByUser()) + if (FrameView* view = m_frame->view()) { + if (!view->wasScrolledByUser()) { view->setScrollPosition(m_currentItem->scrollPoint()); + m_frame->scalePage(m_currentItem->pageScaleFactor(), m_currentItem->scrollPoint()); + } + } } void HistoryController::updateBackForwardListForFragmentScroll() @@ -235,6 +240,13 @@ void HistoryController::goToItem(HistoryItem* targetItem, FrameLoadType type) page->backForward()->setCurrentItem(targetItem); Settings* settings = m_frame->settings(); page->setGlobalHistoryItem((!settings || settings->privateBrowsingEnabled()) ? 0 : targetItem); + + // First set the provisional item of any frames that are not actually navigating. + // This must be done before trying to navigate the desired frame, because some + // navigations can commit immediately (such as about:blank). We must be sure that + // all frames have provisional items set before the commit. + recursiveSetProvisionalItem(targetItem, currentItem, type); + // Now that all other frames have provisional items, do the actual navigation. recursiveGoToItem(targetItem, currentItem, type); } @@ -399,9 +411,50 @@ void HistoryController::updateForCommit() ASSERT(m_provisionalItem); m_currentItem = m_provisionalItem; m_provisionalItem = 0; + + // Tell all other frames in the tree to commit their provisional items and + // restore their scroll position. We'll avoid this frame (which has already + // committed) and its children (which will be replaced). + Page* page = m_frame->page(); + ASSERT(page); + page->mainFrame()->loader()->history()->recursiveUpdateForCommit(); } } +void HistoryController::recursiveUpdateForCommit() +{ + // The frame that navigated will now have a null provisional item. + // Ignore it and its children. + if (!m_provisionalItem) + return; + + // For each frame that already had the content the item requested (based on + // (a matching URL and frame tree snapshot), just restore the scroll position. + // Save form state (works from currentItem, since m_frameLoadComplete is true) + ASSERT(m_frameLoadComplete); + saveDocumentState(); + saveScrollPositionAndViewStateToItem(m_currentItem.get()); + + if (FrameView* view = m_frame->view()) + view->setWasScrolledByUser(false); + + // Now commit the provisional item + m_frameLoadComplete = false; + m_previousItem = m_currentItem; + m_currentItem = m_provisionalItem; + m_provisionalItem = 0; + + // Restore form state (works from currentItem) + restoreDocumentState(); + + // Restore the scroll position (we choose to do this rather than going back to the anchor point) + restoreScrollPositionAndViewState(); + + // Iterate over the rest of the tree + for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) + child->loader()->history()->recursiveUpdateForCommit(); +} + void HistoryController::updateForSameDocumentNavigation() { if (m_frame->loader()->url().isEmpty()) @@ -551,44 +604,42 @@ PassRefPtr<HistoryItem> HistoryController::createItemTree(Frame* targetFrame, bo // The general idea here is to traverse the frame tree and the item tree in parallel, // tracking whether each frame already has the content the item requests. If there is -// a match (by URL), we just restore scroll position and recurse. Otherwise we must -// reload that frame, and all its kids. -void HistoryController::recursiveGoToItem(HistoryItem* item, HistoryItem* fromItem, FrameLoadType type) +// a match, we set the provisional item and recurse. Otherwise we will reload that +// frame and all its kids in recursiveGoToItem. +void HistoryController::recursiveSetProvisionalItem(HistoryItem* item, HistoryItem* fromItem, FrameLoadType type) { ASSERT(item); ASSERT(fromItem); - // If the item we're going to is a clone of the item we're at, then do - // not load it again, and continue history traversal to its children. - // The current frame tree and the frame tree snapshot in the item have - // to match. - // Note: If item and fromItem are the same, then we need to create a new - // document. - if (item != fromItem - && item->itemSequenceNumber() == fromItem->itemSequenceNumber() - && currentFramesMatchItem(item) - && fromItem->hasSameFrames(item)) - { - // This content is good, so leave it alone and look for children that need reloading - // Save form state (works from currentItem, since m_frameLoadComplete is true) - ASSERT(m_frameLoadComplete); - saveDocumentState(); - saveScrollPositionAndViewStateToItem(m_currentItem.get()); + if (itemsAreClones(item, fromItem)) { + // Set provisional item, which will be committed in recursiveUpdateForCommit. + m_provisionalItem = item; - if (FrameView* view = m_frame->view()) - view->setWasScrolledByUser(false); + const HistoryItemVector& childItems = item->children(); - m_previousItem = m_currentItem; - m_currentItem = item; - - // Restore form state (works from currentItem) - restoreDocumentState(); - - // Restore the scroll position (we choose to do this rather than going back to the anchor point) - restoreScrollPositionAndViewState(); - + int size = childItems.size(); + for (int i = 0; i < size; ++i) { + String childFrameName = childItems[i]->target(); + HistoryItem* fromChildItem = fromItem->childItemWithTarget(childFrameName); + ASSERT(fromChildItem); + Frame* childFrame = m_frame->tree()->child(childFrameName); + ASSERT(childFrame); + childFrame->loader()->history()->recursiveSetProvisionalItem(childItems[i].get(), fromChildItem, type); + } + } +} + +// We now traverse the frame tree and item tree a second time, loading frames that +// do have the content the item requests. +void HistoryController::recursiveGoToItem(HistoryItem* item, HistoryItem* fromItem, FrameLoadType type) +{ + ASSERT(item); + ASSERT(fromItem); + + if (itemsAreClones(item, fromItem)) { + // Just iterate over the rest, looking for frames to navigate. const HistoryItemVector& childItems = item->children(); - + int size = childItems.size(); for (int i = 0; i < size; ++i) { String childFrameName = childItems[i]->target(); @@ -603,6 +654,21 @@ void HistoryController::recursiveGoToItem(HistoryItem* item, HistoryItem* fromIt } } +bool HistoryController::itemsAreClones(HistoryItem* item1, HistoryItem* item2) const +{ + // If the item we're going to is a clone of the item we're at, then we do + // not need to load it again. The current frame tree and the frame tree + // snapshot in the item have to match. + // Note: Some clients treat a navigation to the current history item as + // a reload. Thus, if item1 and item2 are the same, we need to create a + // new document and should not consider them clones. + // (See http://webkit.org/b/35532 for details.) + return item1 != item2 + && item1->itemSequenceNumber() == item2->itemSequenceNumber() + && currentFramesMatchItem(item1) + && item2->hasSameFrames(item1); +} + // Helper method that determines whether the current frame tree matches given history item's. bool HistoryController::currentFramesMatchItem(HistoryItem* item) const { |