From 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Tue, 27 Jun 2017 06:07:23 +0000 Subject: webkitgtk-2.16.5 --- Source/WebCore/loader/HistoryController.cpp | 400 +++++++++++++++------------- 1 file changed, 210 insertions(+), 190 deletions(-) (limited to 'Source/WebCore/loader/HistoryController.cpp') diff --git a/Source/WebCore/loader/HistoryController.cpp b/Source/WebCore/loader/HistoryController.cpp index ffd9d32c1..417446ef7 100644 --- a/Source/WebCore/loader/HistoryController.cpp +++ b/Source/WebCore/loader/HistoryController.cpp @@ -12,7 +12,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -41,22 +41,21 @@ #include "FrameTree.h" #include "FrameView.h" #include "HistoryItem.h" +#include "LinkHash.h" #include "Logging.h" #include "MainFrame.h" #include "Page.h" #include "PageCache.h" -#include "PageGroup.h" -#include "PlatformStrategies.h" #include "ScrollingCoordinator.h" -#include "Settings.h" -#include "VisitedLinkStrategy.h" +#include "SerializedScriptValue.h" +#include "VisitedLinkStore.h" #include namespace WebCore { -static inline void addVisitedLink(Page* page, const URL& url) +static inline void addVisitedLink(Page& page, const URL& url) { - platformStrategies()->visitedLinkStrategy()->addVisitedLink(page, visitedLinkHash(url.string())); + page.visitedLinkStore().addVisitedLink(page, visitedLinkHash(url.string())); } HistoryController::HistoryController(Frame& frame) @@ -72,20 +71,33 @@ HistoryController::~HistoryController() void HistoryController::saveScrollPositionAndViewStateToItem(HistoryItem* item) { - if (!item || !m_frame.view()) + FrameView* frameView = m_frame.view(); + if (!item || !frameView) return; - if (m_frame.document()->inPageCache()) - item->setScrollPoint(m_frame.view()->cachedScrollPosition()); + if (m_frame.document()->pageCacheState() != Document::NotInPageCache) + item->setScrollPosition(frameView->cachedScrollPosition()); else - item->setScrollPoint(m_frame.view()->scrollPosition()); + item->setScrollPosition(frameView->scrollPosition()); + +#if PLATFORM(IOS) + item->setExposedContentRect(frameView->exposedContentRect()); + item->setUnobscuredContentRect(frameView->unobscuredContentRect()); +#endif Page* page = m_frame.page(); - if (page && m_frame.isMainFrame()) - item->setPageScaleFactor(page->pageScaleFactor()); + if (page && m_frame.isMainFrame()) { + item->setPageScaleFactor(page->pageScaleFactor() / page->viewScaleFactor()); +#if PLATFORM(IOS) + item->setObscuredInset(page->obscuredInset()); +#endif + } // 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); + m_frame.loader().client().saveViewStateToItem(*item); + + // Notify clients that the HistoryItem has changed. + item->notifyChanged(); } void HistoryController::clearScrollPositionAndViewState() @@ -93,7 +105,7 @@ void HistoryController::clearScrollPositionAndViewState() if (!m_currentItem) return; - m_currentItem->clearScrollPoint(); + m_currentItem->clearScrollPosition(); m_currentItem->setPageScaleFactor(0); } @@ -110,7 +122,7 @@ void HistoryController::clearScrollPositionAndViewState() */ void HistoryController::restoreScrollPositionAndViewState() { - if (!m_frame.loader().stateMachine()->committedFirstRealDocumentLoad()) + if (!m_frame.loader().stateMachine().committedFirstRealDocumentLoad()) return; ASSERT(m_currentItem); @@ -122,31 +134,44 @@ void HistoryController::restoreScrollPositionAndViewState() // so there *is* no scroll or view state to restore! if (!m_currentItem) return; - - // FIXME: It would be great to work out a way to put this code in WebCore instead of calling - // through to the client. It's currently used only for the PDF view on Mac. - m_frame.loader().client().restoreViewState(); - // Don't restore scroll point on iOS as FrameLoaderClient::restoreViewState() does that. -#if !PLATFORM(IOS) + FrameView* view = m_frame.view(); + // FIXME: There is some scrolling related work that needs to happen whenever a page goes into the // page cache and similar work that needs to occur when it comes out. This is where we do the work // that needs to happen when we exit, and the work that needs to happen when we enter is in // Document::setIsInPageCache(bool). It would be nice if there was more symmetry in these spots. // https://bugs.webkit.org/show_bug.cgi?id=98698 - if (FrameView* view = m_frame.view()) { + if (view) { Page* page = m_frame.page(); if (page && m_frame.isMainFrame()) { if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) - scrollingCoordinator->frameViewRootLayerDidChange(view); + scrollingCoordinator->frameViewRootLayerDidChange(*view); } + } + + // 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().restoreViewState(); - if (!view->wasScrolledByUser()) { - if (page && m_frame.isMainFrame() && m_currentItem->pageScaleFactor()) - page->setPageScaleFactor(m_currentItem->pageScaleFactor(), m_currentItem->scrollPoint()); - else - view->setScrollPosition(m_currentItem->scrollPoint()); +#if !PLATFORM(IOS) + // Don't restore scroll point on iOS as FrameLoaderClient::restoreViewState() does that. + if (view && !view->wasScrolledByUser()) { + Page* page = m_frame.page(); + auto desiredScrollPosition = m_currentItem->scrollPosition(); + LOG(Scrolling, "HistoryController::restoreScrollPositionAndViewState scrolling to %d,%d", desiredScrollPosition.x(), desiredScrollPosition.y()); + if (page && m_frame.isMainFrame() && m_currentItem->pageScaleFactor()) + page->setPageScaleFactor(m_currentItem->pageScaleFactor() * page->viewScaleFactor(), desiredScrollPosition); + else + view->setScrollPosition(desiredScrollPosition); + + // If the scroll position doesn't have to be clamped, consider it successfully restored. + if (m_frame.isMainFrame()) { + auto adjustedDesiredScrollPosition = view->adjustScrollPositionWithinRange(desiredScrollPosition); + if (desiredScrollPosition == adjustedDesiredScrollPosition) + m_frame.loader().client().didRestoreScrollPosition(); } + } #endif } @@ -160,7 +185,7 @@ void HistoryController::saveDocumentState() { // FIXME: Reading this bit of FrameLoader state here is unfortunate. I need to study // this more to see if we can remove this dependency. - if (m_frame.loader().stateMachine()->creatingInitialEmptyDocument()) + if (m_frame.loader().stateMachine().creatingInitialEmptyDocument()) return; // For a standard page load, we will have a previous item set, which will be used to @@ -178,12 +203,14 @@ void HistoryController::saveDocumentState() if (!item) return; - Document* document = m_frame.document(); - ASSERT(document); - - if (item->isCurrentDocument(document) && document->hasLivingRenderTree()) { + ASSERT(m_frame.document()); + Document& document = *m_frame.document(); + if (item->isCurrentDocument(document) && document.hasLivingRenderTree()) { + if (DocumentLoader* documentLoader = document.loader()) + item->setShouldOpenExternalURLsPolicy(documentLoader->shouldOpenExternalURLsPolicyToPropagate()); + LOG(Loading, "WebCoreLoading %s: saving form state to %p", m_frame.tree().uniqueName().string().utf8().data(), item); - item->setDocumentState(document->formElementsState()); + item->setDocumentState(document.formElementsState()); } } @@ -200,18 +227,18 @@ void HistoryController::saveDocumentAndScrollState() void HistoryController::restoreDocumentState() { switch (m_frame.loader().loadType()) { - case FrameLoadTypeReload: - case FrameLoadTypeReloadFromOrigin: - case FrameLoadTypeSame: - case FrameLoadTypeReplace: - // Not restoring the document state. - return; - case FrameLoadTypeBack: - case FrameLoadTypeForward: - case FrameLoadTypeIndexedBackForward: - case FrameLoadTypeRedirectWithLockedBackForwardList: - case FrameLoadTypeStandard: - break; + case FrameLoadType::Reload: + case FrameLoadType::ReloadFromOrigin: + case FrameLoadType::Same: + case FrameLoadType::Replace: + // Not restoring the document state. + return; + case FrameLoadType::Back: + case FrameLoadType::Forward: + case FrameLoadType::IndexedBackForward: + case FrameLoadType::RedirectWithLockedBackForwardList: + case FrameLoadType::Standard: + break; } if (!m_currentItem) @@ -221,17 +248,21 @@ void HistoryController::restoreDocumentState() if (m_frame.loader().documentLoader()->isClientRedirect()) return; + m_frame.loader().documentLoader()->setShouldOpenExternalURLsPolicy(m_currentItem->shouldOpenExternalURLsPolicy()); + LOG(Loading, "WebCoreLoading %s: restoring form state from %p", m_frame.tree().uniqueName().string().utf8().data(), m_currentItem.get()); m_frame.document()->setStateForNewFormElements(m_currentItem->documentState()); } void HistoryController::invalidateCurrentItemCachedPage() { - // When we are pre-commit, the currentItem is where any page cache data resides. - if (!pageCache()->get(currentItem())) + if (!currentItem()) return; - std::unique_ptr cachedPage = pageCache()->take(currentItem()); + // When we are pre-commit, the currentItem is where any page cache data resides. + std::unique_ptr cachedPage = PageCache::singleton().take(*currentItem(), m_frame.page()); + if (!cachedPage) + return; // FIXME: This is a grotesque hack to fix Crash in RenderFlow::detach // Somehow the PageState object is not properly updated, and is holding onto a stale document. @@ -239,12 +270,12 @@ void HistoryController::invalidateCurrentItemCachedPage() ASSERT(cachedPage->document() == m_frame.document()); if (cachedPage->document() == m_frame.document()) { - cachedPage->document()->setInPageCache(false); + cachedPage->document()->setPageCacheState(Document::NotInPageCache); cachedPage->clear(); } } -bool HistoryController::shouldStopLoadingForHistoryItem(HistoryItem* targetItem) const +bool HistoryController::shouldStopLoadingForHistoryItem(HistoryItem& targetItem) const { if (!m_currentItem) return false; @@ -258,7 +289,7 @@ bool HistoryController::shouldStopLoadingForHistoryItem(HistoryItem* targetItem) // Main funnel for navigating to a previous location (back/forward, non-search snap-back) // This includes recursion to handle loading into framesets properly -void HistoryController::goToItem(HistoryItem* targetItem, FrameLoadType type) +void HistoryController::goToItem(HistoryItem& targetItem, FrameLoadType type) { ASSERT(!m_frame.tree().parent()); @@ -269,26 +300,27 @@ void HistoryController::goToItem(HistoryItem* targetItem, FrameLoadType type) Page* page = m_frame.page(); if (!page) return; - if (!m_frame.loader().client().shouldGoToHistoryItem(targetItem)) + if (!m_frame.loader().client().shouldGoToHistoryItem(&targetItem)) return; if (m_defersLoading) { - m_deferredItem = targetItem; + m_deferredItem = &targetItem; m_deferredFrameLoadType = type; return; } // Set the BF cursor before commit, which lets the user quickly click back/forward again. - // - plus, it only makes sense for the top level of the operation through the frametree, + // - plus, it only makes sense for the top level of the operation through the frame tree, // as opposed to happening for some/one of the page commits that might happen soon RefPtr currentItem = page->backForward().currentItem(); - page->backForward().setCurrentItem(targetItem); + page->backForward().setCurrentItem(&targetItem); m_frame.loader().client().updateGlobalHistoryItemForPage(); // 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.get(), type); + recursiveSetProvisionalItem(targetItem, currentItem.get()); + // Now that all other frames have provisional items, do the actual navigation. recursiveGoToItem(targetItem, currentItem.get(), type); } @@ -297,17 +329,14 @@ void HistoryController::setDefersLoading(bool defer) { m_defersLoading = defer; if (!defer && m_deferredItem) { - goToItem(m_deferredItem.get(), m_deferredFrameLoadType); - m_deferredItem = 0; + goToItem(*m_deferredItem, m_deferredFrameLoadType); + m_deferredItem = nullptr; } } void HistoryController::updateForBackForwardNavigation() { -#if !LOG_DISABLED - if (m_frame.loader().documentLoader()) - LOG(History, "WebCoreHistory: Updating History for back/forward navigation in frame %s", m_frame.loader().documentLoader()->title().string().utf8().data()); -#endif + LOG(History, "HistoryController %p updateForBackForwardNavigation: Updating History for back/forward navigation in frame %p (main frame %d) %s", this, &m_frame, m_frame.isMainFrame(), m_frame.loader().documentLoader() ? m_frame.loader().documentLoader()->url().string().utf8().data() : ""); // Must grab the current scroll position before disturbing it if (!m_frameLoadComplete) @@ -320,16 +349,16 @@ void HistoryController::updateForBackForwardNavigation() void HistoryController::updateForReload() { -#if !LOG_DISABLED - if (m_frame.loader().documentLoader()) - LOG(History, "WebCoreHistory: Updating History for reload in frame %s", m_frame.loader().documentLoader()->title().string().utf8().data()); -#endif + LOG(History, "HistoryController %p updateForReload: Updating History for reload in frame %p (main frame %d) %s", this, &m_frame, m_frame.isMainFrame(), m_frame.loader().documentLoader() ? m_frame.loader().documentLoader()->url().string().utf8().data() : ""); if (m_currentItem) { - pageCache()->remove(m_currentItem.get()); + PageCache::singleton().remove(*m_currentItem); - if (m_frame.loader().loadType() == FrameLoadTypeReload || m_frame.loader().loadType() == FrameLoadTypeReloadFromOrigin) + if (m_frame.loader().loadType() == FrameLoadType::Reload || m_frame.loader().loadType() == FrameLoadType::ReloadFromOrigin) saveScrollPositionAndViewStateToItem(m_currentItem.get()); + + // Rebuild the history item tree when reloading as trying to re-associate everything is too error-prone. + m_currentItem->clearChildren(); } // When reloading the page, we may end up redirecting to a different URL @@ -345,11 +374,11 @@ void HistoryController::updateForReload() void HistoryController::updateForStandardLoad(HistoryUpdateType updateType) { - LOG(History, "WebCoreHistory: Updating History for Standard Load in frame %s", m_frame.loader().documentLoader()->url().string().ascii().data()); + LOG(History, "HistoryController %p updateForStandardLoad: Updating History for standard load in frame %p (main frame %d) %s", this, &m_frame, m_frame.isMainFrame(), m_frame.loader().documentLoader()->url().string().ascii().data()); FrameLoader& frameLoader = m_frame.loader(); - bool needPrivacy = m_frame.settings().privateBrowsingEnabled(); + bool needPrivacy = m_frame.page()->usesEphemeralSession(); const URL& historyURL = frameLoader.documentLoader()->urlForHistory(); if (!frameLoader.documentLoader()->isClientRedirect()) { @@ -372,7 +401,7 @@ void HistoryController::updateForStandardLoad(HistoryUpdateType updateType) if (!historyURL.isEmpty() && !needPrivacy) { if (Page* page = m_frame.page()) - addVisitedLink(page, historyURL); + addVisitedLink(*page, historyURL); if (!frameLoader.documentLoader()->didCreateGlobalHistoryEntry() && frameLoader.documentLoader()->unreachableURL().isEmpty() && !m_frame.document()->url().isEmpty()) frameLoader.client().updateGlobalHistoryRedirectLinks(); @@ -381,12 +410,9 @@ void HistoryController::updateForStandardLoad(HistoryUpdateType updateType) void HistoryController::updateForRedirectWithLockedBackForwardList() { -#if !LOG_DISABLED - if (m_frame.loader().documentLoader()) - LOG(History, "WebCoreHistory: Updating History for redirect load in frame %s", m_frame.loader().documentLoader()->title().string().utf8().data()); -#endif + LOG(History, "HistoryController %p updateForRedirectWithLockedBackForwardList: Updating History for redirect load in frame %p (main frame %d) %s", this, &m_frame, m_frame.isMainFrame(), m_frame.loader().documentLoader() ? m_frame.loader().documentLoader()->url().string().utf8().data() : ""); - bool needPrivacy = m_frame.settings().privateBrowsingEnabled(); + bool needPrivacy = m_frame.page()->usesEphemeralSession(); const URL& historyURL = m_frame.loader().documentLoader()->urlForHistory(); if (m_frame.loader().documentLoader()->isClientRedirect()) { @@ -413,7 +439,7 @@ void HistoryController::updateForRedirectWithLockedBackForwardList() if (!historyURL.isEmpty() && !needPrivacy) { if (Page* page = m_frame.page()) - addVisitedLink(page, historyURL); + addVisitedLink(*page, historyURL); if (!m_frame.loader().documentLoader()->didCreateGlobalHistoryEntry() && m_frame.loader().documentLoader()->unreachableURL().isEmpty() && !m_frame.document()->url().isEmpty()) m_frame.loader().client().updateGlobalHistoryRedirectLinks(); @@ -422,34 +448,29 @@ void HistoryController::updateForRedirectWithLockedBackForwardList() void HistoryController::updateForClientRedirect() { -#if !LOG_DISABLED - if (m_frame.loader().documentLoader()) - LOG(History, "WebCoreHistory: Updating History for client redirect in frame %s", m_frame.loader().documentLoader()->title().string().utf8().data()); -#endif + LOG(History, "HistoryController %p updateForClientRedirect: Updating History for client redirect in frame %p (main frame %d) %s", this, &m_frame, m_frame.isMainFrame(), m_frame.loader().documentLoader() ? m_frame.loader().documentLoader()->url().string().utf8().data() : ""); // Clear out form data so we don't try to restore it into the incoming page. Must happen after // webcore has closed the URL and saved away the form state. if (m_currentItem) { m_currentItem->clearDocumentState(); - m_currentItem->clearScrollPoint(); + m_currentItem->clearScrollPosition(); } - bool needPrivacy = m_frame.settings().privateBrowsingEnabled(); + bool needPrivacy = m_frame.page()->usesEphemeralSession(); const URL& historyURL = m_frame.loader().documentLoader()->urlForHistory(); if (!historyURL.isEmpty() && !needPrivacy) { if (Page* page = m_frame.page()) - addVisitedLink(page, historyURL); + addVisitedLink(*page, historyURL); } } void HistoryController::updateForCommit() { FrameLoader& frameLoader = m_frame.loader(); -#if !LOG_DISABLED - if (frameLoader.documentLoader()) - LOG(History, "WebCoreHistory: Updating History for commit in frame %s", frameLoader.documentLoader()->title().string().utf8().data()); -#endif + LOG(History, "HistoryController %p updateForCommit: Updating History for commit in frame %p (main frame %d) %s", this, &m_frame, m_frame.isMainFrame(), m_frame.loader().documentLoader() ? m_frame.loader().documentLoader()->url().string().utf8().data() : ""); + FrameLoadType type = frameLoader.loadType(); if (isBackForwardLoadType(type) || isReplaceLoadTypeWithProvisionalItem(type) @@ -458,11 +479,14 @@ void HistoryController::updateForCommit() // the provisional item for restoring state. // Note previousItem must be set before we close the URL, which will // happen when the data source is made non-provisional below - m_frameLoadComplete = false; - m_previousItem = m_currentItem; + + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=146842 + // We should always have a provisional item when committing, but we sometimes don't. + // Not having one leads to us not having a m_currentItem later, which is also a terrible known issue. + // We should get to the bottom of this. ASSERT(m_provisionalItem); - m_currentItem = m_provisionalItem; - m_provisionalItem = 0; + setCurrentItem(m_provisionalItem.get()); + m_provisionalItem = nullptr; // 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 @@ -473,14 +497,14 @@ void HistoryController::updateForCommit() bool HistoryController::isReplaceLoadTypeWithProvisionalItem(FrameLoadType type) { - // Going back to an error page in a subframe can trigger a FrameLoadTypeReplace + // Going back to an error page in a subframe can trigger a FrameLoadType::Replace // while m_provisionalItem is set, so we need to commit it. - return type == FrameLoadTypeReplace && m_provisionalItem; + return type == FrameLoadType::Replace && m_provisionalItem; } bool HistoryController::isReloadTypeWithProvisionalItem(FrameLoadType type) { - return (type == FrameLoadTypeReload || type == FrameLoadTypeReloadFromOrigin) && m_provisionalItem; + return (type == FrameLoadType::Reload || type == FrameLoadType::ReloadFromOrigin) && m_provisionalItem; } void HistoryController::recursiveUpdateForCommit() @@ -493,7 +517,7 @@ void HistoryController::recursiveUpdateForCommit() // 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())) { + if (m_currentItem && itemsAreClones(*m_currentItem, m_provisionalItem.get())) { ASSERT(m_frameLoadComplete); saveDocumentState(); saveScrollPositionAndViewStateToItem(m_currentItem.get()); @@ -502,10 +526,8 @@ void HistoryController::recursiveUpdateForCommit() view->setWasScrolledByUser(false); // Now commit the provisional item - m_frameLoadComplete = false; - m_previousItem = m_currentItem; - m_currentItem = m_provisionalItem; - m_provisionalItem = 0; + setCurrentItem(m_provisionalItem.get()); + m_provisionalItem = nullptr; // Restore form state (works from currentItem) restoreDocumentState(); @@ -524,14 +546,14 @@ void HistoryController::updateForSameDocumentNavigation() if (m_frame.document()->url().isEmpty()) return; - if (m_frame.settings().privateBrowsingEnabled()) + if (m_frame.page()->usesEphemeralSession()) return; Page* page = m_frame.page(); if (!page) return; - addVisitedLink(page, m_frame.document()->url()); + addVisitedLink(*page, m_frame.document()->url()); m_frame.mainFrame().loader().history().recursiveUpdateForSameDocumentNavigation(); if (m_currentItem) { @@ -549,14 +571,12 @@ void HistoryController::recursiveUpdateForSameDocumentNavigation() // The provisional item may represent a different pending navigation. // Don't commit it if it isn't a same document navigation. - if (m_currentItem && !m_currentItem->shouldDoSameDocumentNavigationTo(m_provisionalItem.get())) + if (m_currentItem && !m_currentItem->shouldDoSameDocumentNavigationTo(*m_provisionalItem)) return; // Commit the provisional item. - m_frameLoadComplete = false; - m_previousItem = m_currentItem; - m_currentItem = m_provisionalItem; - m_provisionalItem = 0; + setCurrentItem(m_provisionalItem.get()); + m_provisionalItem = nullptr; // Iterate over the rest of the tree. for (Frame* child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling()) @@ -580,9 +600,9 @@ void HistoryController::setCurrentItem(HistoryItem* item) void HistoryController::setCurrentItemTitle(const StringWithDirection& title) { + // FIXME: This ignores the title's direction. if (m_currentItem) - // FIXME: make use of title.direction() as well. - m_currentItem->setTitle(title.string()); + m_currentItem->setTitle(title.string); } bool HistoryController::currentItemShouldBeReplaced() const @@ -591,7 +611,14 @@ bool HistoryController::currentItemShouldBeReplaced() const // "If the browsing context's session history contains only one Document, // and that was the about:blank Document created when the browsing context // was created, then the navigation must be done with replacement enabled." - return m_currentItem && !m_previousItem && equalIgnoringCase(m_currentItem->urlString(), blankURL()); + return m_currentItem && !m_previousItem && equalIgnoringASCIICase(m_currentItem->urlString(), blankURL()); +} + +void HistoryController::clearPreviousItem() +{ + m_previousItem = nullptr; + for (Frame* child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling()) + child->loader().history().clearPreviousItem(); } void HistoryController::setProvisionalItem(HistoryItem* item) @@ -599,7 +626,7 @@ void HistoryController::setProvisionalItem(HistoryItem* item) m_provisionalItem = item; } -void HistoryController::initializeItem(HistoryItem* item) +void HistoryController::initializeItem(HistoryItem& item) { DocumentLoader* documentLoader = m_frame.loader().documentLoader(); ASSERT(documentLoader); @@ -627,40 +654,37 @@ void HistoryController::initializeItem(HistoryItem* item) if (originalURL.isEmpty()) originalURL = blankURL(); - Frame* parentFrame = m_frame.tree().parent(); - String parent = parentFrame ? parentFrame->tree().uniqueName() : ""; StringWithDirection title = documentLoader->title(); - item->setURL(url); - item->setTarget(m_frame.tree().uniqueName()); - item->setParent(parent); - // FIXME: should store title directionality in history as well. - item->setTitle(title.string()); - item->setOriginalURLString(originalURL.string()); + item.setURL(url); + item.setTarget(m_frame.tree().uniqueName()); + // FIXME: Should store the title direction as well. + item.setTitle(title.string); + item.setOriginalURLString(originalURL.string()); if (!unreachableURL.isEmpty() || documentLoader->response().httpStatusCode() >= 400) - item->setLastVisitWasFailure(true); + item.setLastVisitWasFailure(true); + + item.setShouldOpenExternalURLsPolicy(documentLoader->shouldOpenExternalURLsPolicyToPropagate()); // Save form state if this is a POST - item->setFormInfoFromRequest(documentLoader->request()); + item.setFormInfoFromRequest(documentLoader->request()); } -PassRefPtr HistoryController::createItem() +Ref HistoryController::createItem() { - RefPtr item = HistoryItem::create(); - initializeItem(item.get()); + Ref item = HistoryItem::create(); + initializeItem(item); // Set the item for which we will save document state - m_frameLoadComplete = false; - m_previousItem = m_currentItem; - m_currentItem = item; + setCurrentItem(item.ptr()); - return item.release(); + return item; } -PassRefPtr HistoryController::createItemTree(Frame& targetFrame, bool clipAtTarget) +Ref HistoryController::createItemTree(Frame& targetFrame, bool clipAtTarget) { - RefPtr bfItem = createItem(); + Ref bfItem = createItem(); if (!m_frameLoadComplete) saveScrollPositionAndViewStateToItem(m_previousItem.get()); @@ -700,54 +724,47 @@ PassRefPtr HistoryController::createItemTree(Frame& targetFrame, bo // 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) +void HistoryController::recursiveSetProvisionalItem(HistoryItem& item, HistoryItem* fromItem) { - ASSERT(item); + if (!itemsAreClones(item, fromItem)) + return; - if (itemsAreClones(item, fromItem)) { - // Set provisional item, which will be committed in recursiveUpdateForCommit. - m_provisionalItem = item; + // Set provisional item, which will be committed in recursiveUpdateForCommit. + m_provisionalItem = &item; - const HistoryItemVector& childItems = item->children(); + for (auto& childItem : item.children()) { + const String& childFrameName = childItem->target(); - int size = childItems.size(); + HistoryItem* fromChildItem = fromItem->childItemWithTarget(childFrameName); + ASSERT(fromChildItem); + Frame* childFrame = m_frame.tree().child(childFrameName); + ASSERT(childFrame); - 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); - } + childFrame->loader().history().recursiveSetProvisionalItem(childItem, fromChildItem); } } // 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); - - 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 { +void HistoryController::recursiveGoToItem(HistoryItem& item, HistoryItem* fromItem, FrameLoadType type) +{ + if (!itemsAreClones(item, fromItem)) { m_frame.loader().loadItem(item, type); + return; + } + + // Just iterate over the rest, looking for frames to navigate. + for (auto& childItem : item.children()) { + const String& childFrameName = childItem->target(); + + HistoryItem* fromChildItem = fromItem->childItemWithTarget(childFrameName); + ASSERT(fromChildItem); + if (Frame* childFrame = m_frame.tree().child(childFrameName)) + childFrame->loader().history().recursiveGoToItem(childItem, fromChildItem, type); } } -bool HistoryController::itemsAreClones(HistoryItem* item1, HistoryItem* item2) const +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 @@ -756,11 +773,10 @@ bool HistoryController::itemsAreClones(HistoryItem* item1, HistoryItem* item2) c // 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 != item2 - && item1->itemSequenceNumber() == item2->itemSequenceNumber() - && currentFramesMatchItem(item1) + return item2 + && &item1 != item2 + && item1.itemSequenceNumber() == item2->itemSequenceNumber() + && currentFramesMatchItem(&item1) && item2->hasSameFrames(item1); } @@ -770,13 +786,12 @@ bool HistoryController::currentFramesMatchItem(HistoryItem* item) const if ((!m_frame.tree().uniqueName().isEmpty() || !item->target().isEmpty()) && m_frame.tree().uniqueName() != item->target()) return false; - const HistoryItemVector& childItems = item->children(); + const auto& childItems = item->children(); if (childItems.size() != m_frame.tree().childCount()) return false; - unsigned size = childItems.size(); - for (unsigned i = 0; i < size; ++i) { - if (!m_frame.tree().child(childItems[i]->target())) + for (auto& item : childItems) { + if (!m_frame.tree().child(item->target())) return false; } @@ -799,9 +814,10 @@ void HistoryController::updateBackForwardListClippedAtTarget(bool doClip) FrameLoader& frameLoader = m_frame.mainFrame().loader(); - RefPtr topItem = frameLoader.history().createItemTree(m_frame, doClip); - LOG(BackForward, "WebCoreBackForward - Adding backforward item %p for frame %s", topItem.get(), m_frame.loader().documentLoader()->url().string().ascii().data()); - page->backForward().addItem(topItem.release()); + Ref topItem = frameLoader.history().createItemTree(m_frame, doClip); + LOG(History, "HistoryController %p updateBackForwardListClippedAtTarget: Adding backforward item %p in frame %p (main frame %d) %s", this, topItem.ptr(), &m_frame, m_frame.isMainFrame(), m_frame.loader().documentLoader()->url().string().utf8().data()); + + page->backForward().addItem(WTFMove(topItem)); } void HistoryController::updateCurrentItem() @@ -821,7 +837,7 @@ void HistoryController::updateCurrentItem() // dependent on the document. bool isTargetItem = m_currentItem->isTargetItem(); m_currentItem->reset(); - initializeItem(m_currentItem.get()); + initializeItem(*m_currentItem); m_currentItem->setIsTargetItem(isTargetItem); } else { // Even if the final URL didn't change, the form data may have changed. @@ -829,7 +845,7 @@ void HistoryController::updateCurrentItem() } } -void HistoryController::pushState(PassRefPtr stateObject, const String& title, const String& urlString) +void HistoryController::pushState(RefPtr&& stateObject, const String& title, const String& urlString) { if (!m_currentItem) return; @@ -838,40 +854,44 @@ void HistoryController::pushState(PassRefPtr stateObject, ASSERT(page); // Get a HistoryItem tree for the current frame tree. - RefPtr topItem = m_frame.mainFrame().loader().history().createItemTree(m_frame, false); + Ref topItem = m_frame.mainFrame().loader().history().createItemTree(m_frame, false); // Override data in the current item (created by createItemTree) to reflect // the pushState() arguments. m_currentItem->setTitle(title); - m_currentItem->setStateObject(stateObject); + m_currentItem->setStateObject(WTFMove(stateObject)); m_currentItem->setURLString(urlString); - page->backForward().addItem(topItem.release()); + LOG(History, "HistoryController %p pushState: Adding top item %p, setting url of current item %p to %s", this, topItem.ptr(), m_currentItem.get(), urlString.ascii().data()); + + page->backForward().addItem(WTFMove(topItem)); - if (m_frame.settings().privateBrowsingEnabled()) + if (m_frame.page()->usesEphemeralSession()) return; - addVisitedLink(page, URL(ParsedURLString, urlString)); + addVisitedLink(*page, URL(ParsedURLString, urlString)); m_frame.loader().client().updateGlobalHistory(); } -void HistoryController::replaceState(PassRefPtr stateObject, const String& title, const String& urlString) +void HistoryController::replaceState(RefPtr&& stateObject, const String& title, const String& urlString) { if (!m_currentItem) return; + LOG(History, "HistoryController %p replaceState: Setting url of current item %p to %s", this, m_currentItem.get(), urlString.ascii().data()); + if (!urlString.isEmpty()) m_currentItem->setURLString(urlString); m_currentItem->setTitle(title); - m_currentItem->setStateObject(stateObject); - m_currentItem->setFormData(0); + m_currentItem->setStateObject(WTFMove(stateObject)); + m_currentItem->setFormData(nullptr); m_currentItem->setFormContentType(String()); - if (m_frame.settings().privateBrowsingEnabled()) + if (m_frame.page()->usesEphemeralSession()) return; ASSERT(m_frame.page()); - addVisitedLink(m_frame.page(), URL(ParsedURLString, urlString)); + addVisitedLink(*m_frame.page(), URL(ParsedURLString, urlString)); m_frame.loader().client().updateGlobalHistory(); } -- cgit v1.2.1