// 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(); HistoryItem* fromChildItem = fromItem->childItemWithTarget(childFrameName); ASSERT(fromChildItem); Frame* childFrame = m_frame->tree()->child(childFrameName); ASSERT(childFrame); childFrame->loader()->history()->recursiveGoToItem(childItems[i].get(), fromChildItem, type); } } else { m_frame->loader()->loadItem(item, type); } }
// 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, 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); if (itemsAreClones(item, fromItem)) { // Set provisional item, which will be committed in recursiveUpdateForCommit. m_provisionalItem = item; const HistoryItemVector& childItems = item->children(); 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); } } }
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) if (m_currentItem && itemsAreClones(m_currentItem.get(), m_provisionalItem.get())) { ASSERT(m_frameLoadComplete); saveDocumentState(); saveScrollPositionAndViewStateToItem(m_currentItem.get()); saveTextWrapWidth(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(); restoreTextWrapWidth(); } // Iterate over the rest of the tree for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) child->loader()->history()->recursiveUpdateForCommit(); }