summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/loader/HistoryController.cpp
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-05-13 16:23:25 +0100
committerBen Murdoch <benm@google.com>2011-05-16 11:35:02 +0100
commit65f03d4f644ce73618e5f4f50dd694b26f55ae12 (patch)
treef478babb801e720de7bfaee23443ffe029f58731 /Source/WebCore/loader/HistoryController.cpp
parent47de4a2fb7262c7ebdb9cd133ad2c54c187454d0 (diff)
downloadexternal_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.cpp132
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
{