Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1356)

Unified Diff: Source/core/loader/HistoryController.h

Issue 28983004: Split the frame tree logic out of HistoryItem (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/loader/FrameLoaderTypes.h ('k') | Source/core/loader/HistoryController.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/loader/HistoryController.h
diff --git a/Source/core/loader/HistoryController.h b/Source/core/loader/HistoryController.h
index f70840843cbf81dc51aede0abe16dd27c1c0c1d7..0392363d6d4ae7a2393954398a32dfc650e98007 100644
--- a/Source/core/loader/HistoryController.h
+++ b/Source/core/loader/HistoryController.h
@@ -32,6 +32,7 @@
#include "core/history/HistoryItem.h"
#include "core/loader/FrameLoaderTypes.h"
+#include "wtf/HashMap.h"
#include "wtf/Noncopyable.h"
#include "wtf/RefPtr.h"
#include "wtf/text/WTFString.h"
@@ -39,68 +40,158 @@
namespace WebCore {
class Frame;
+class HistoryEntry;
+class Page;
class SerializedScriptValue;
+
+// A guide to history state in Blink:
+//
+// HistoryController: Owned by Page, is the entry point for interacting with history.
+// Handles most of the operations to modify history state, navigate to an existing
+// back/forward entry, etc.
+// HistoryEntry: Represents a single entry in the back/forward list, encapsulating
+// all frames in the page it represents. It provides access to each frame's
+// state via lookups by frame id or frame name.
+// HistoryNode: Represents a single frame in a HistoryEntry. Owned by a HistoryEntry. HistoryNodes
+// form a tree that mirrors the FrameTree in the corresponding page. HistoryNodes represent
+// the structure of the page, but don't hold any per-frame state except a list of child frames.
+// HistoryItem (lives in a separate file): The state for a given frame. Can persist across
+// navigations. HistoryItem is reference counted, and each HistoryNode holds a reference
+// to its single corresponding HistoryItem. Can be referenced by multiple HistoryNodes and
+// can therefore exist in multiple HistoryEntry instances.
+//
+// Suppose we have the following page, foo.com, which embeds foo.com/a in an iframe:
+//
+// HistoryEntry 0:
+// HistoryNode 0_0 (HistoryItem A (url: foo.com))
+// HistoryNode 0_1: (HistoryItem B (url: foo.com/a))
+//
+// Now we navigation the top frame to bar.com, which embeds bar.com/b and bar.com/c in iframes,
+// and bar.com/b in turn embeds bar.com/d. We will create a new HistoryEntry with a tree
+// containing 4 new HistoryNodes. The state will be:
+//
+// HistoryEntry 1:
+// HistoryNode 1_0 (HistoryItem C (url: bar.com))
+// HistoryNode 1_1: (HistoryItem D (url: bar.com/b))
+// HistoryNode 1_3: (HistoryItem F (url: bar.com/d))
+// HistoryNode 1_2: (HistoryItem E (url: bar.com/c))
+//
+//
+// Finally, we navigate the first subframe from bar.com/b to bar.com/e, which embeds bar.com/f.
+// We will create a new HistoryEntry and new HistoryNode for each frame. Any frame that
+// navigates (bar.com/e and its child, bar.com/f) will receive a new HistoryItem. However,
+// 2 frames were not navigated (bar.com and bar.com/c), so those two frames will reuse the
+// existing HistoryItem:
+//
+// HistoryEntry 2:
+// HistoryNode 2_0 (HistoryItem C (url: bar.com)) *REUSED*
+// HistoryNode 2_1: (HistoryItem G (url: bar.com/e))
+// HistoryNode 2_3: (HistoryItem H (url: bar.com/f))
+// HistoryNode 2_2: (HistoryItem E (url: bar.com/c)) *REUSED*
+//
+
+class HistoryNode {
+public:
+ static PassOwnPtr<HistoryNode> create(HistoryEntry*, HistoryItem*);
+ ~HistoryNode() { }
+
+ HistoryNode* addChild(PassRefPtr<HistoryItem>);
+ PassOwnPtr<HistoryNode> cloneAndReplace(HistoryEntry*, HistoryItem* newItem, HistoryItem* oldItem, bool clipAtTarget, Frame*);
+ HistoryItem* value() { return m_value.get(); }
+ void updateValue(PassRefPtr<HistoryItem> item) { m_value = item; }
+ const Vector<OwnPtr<HistoryNode> >& children() const { return m_children; }
+
+private:
+ HistoryNode(HistoryEntry*, HistoryItem*);
+
+ HistoryEntry* m_entry;
+ Vector<OwnPtr<HistoryNode> > m_children;
+ RefPtr<HistoryItem> m_value;
+};
+
+class HistoryEntry {
+public:
+ static PassOwnPtr<HistoryEntry> create(HistoryItem* root);
+ PassOwnPtr<HistoryEntry> cloneAndReplace(HistoryItem* newItem, HistoryItem* oldItem, bool clipAtTarget, Page*);
+
+ HistoryNode* historyNodeForFrame(Frame*);
+ HistoryItem* itemForFrame(Frame*);
+ HistoryItem* root() const { return m_root->value(); }
+ HistoryNode* rootHistoryNode() const { return m_root.get(); }
+
+private:
+ friend class HistoryNode;
+
+ HistoryEntry() { }
+ explicit HistoryEntry(HistoryItem* root);
+
+ OwnPtr<HistoryNode> m_root;
+ HashMap<uint64_t, HistoryNode*> m_framesToItems;
+ HashMap<String, HistoryNode*> m_uniqueNamesToItems;
+};
+
class HistoryController {
WTF_MAKE_NONCOPYABLE(HistoryController);
public:
- explicit HistoryController(Frame*);
+ explicit HistoryController(Page*);
~HistoryController();
+ // Should only be called by embedder. To request a back/forward
+ // navigation, call FrameLoaderClient::navigateBackForward().
+ void goToItem(HistoryItem*);
+
void clearScrollPositionAndViewState();
- void restoreScrollPositionAndViewState();
+ void restoreScrollPositionAndViewState(Frame*);
+
+ void updateBackForwardListForFragmentScroll(Frame*);
- void updateBackForwardListForFragmentScroll();
+ void saveDocumentAndScrollState(Frame*);
+ void restoreDocumentState(Frame*);
- void saveDocumentAndScrollState();
- void restoreDocumentState();
+ void updateForCommit(Frame*);
+ void updateForSameDocumentNavigation(Frame*);
- void updateForCommit();
- void updateForSameDocumentNavigation();
+ PassRefPtr<HistoryItem> currentItemForExport(Frame*);
+ PassRefPtr<HistoryItem> previousItemForExport(Frame*);
+ PassRefPtr<HistoryItem> provisionalItemForExport(Frame*);
- HistoryItem* currentItem() const { return m_currentItem.get(); }
- void setCurrentItem(HistoryItem*);
- bool currentItemShouldBeReplaced() const;
+ HistoryItem* currentItem(Frame*) const;
+ bool currentItemShouldBeReplaced(Frame*) const;
- HistoryItem* previousItem() const { return m_previousItem.get(); }
+ HistoryItem* previousItem(Frame*) const;
+ void clearProvisionalEntry();
- HistoryItem* provisionalItem() const { return m_provisionalItem.get(); }
- void setProvisionalItem(HistoryItem*);
+ bool inSameDocumentLoad() const { return !m_sameDocumentLoadsInProgress.isEmpty() && m_differentDocumentLoadsInProgress.isEmpty(); }
- void pushState(PassRefPtr<SerializedScriptValue>, const String& url);
- void replaceState(PassRefPtr<SerializedScriptValue>, const String& url);
+ void pushState(Frame*, PassRefPtr<SerializedScriptValue>, const String& url);
+ void replaceState(Frame*, PassRefPtr<SerializedScriptValue>, const String& url);
void setDefersLoading(bool);
private:
- friend class Page;
- bool shouldStopLoadingForHistoryItem(HistoryItem*) const;
- void goToItem(HistoryItem*);
-
- void initializeItem(HistoryItem*);
- PassRefPtr<HistoryItem> createItem();
- PassRefPtr<HistoryItem> createItemTree(Frame* targetFrame, bool clipAtTarget);
+ void goToEntry(PassOwnPtr<HistoryEntry>);
+ void recursiveGoToEntry(Frame*);
- void updateForStandardLoad();
- void updateForInitialLoadInChildFrame();
+ void initializeItem(HistoryItem*, Frame*);
+ PassRefPtr<HistoryItem> createItem(Frame*);
+ void createItemTree(Frame* targetFrame, bool clipAtTarget);
- void recursiveSetProvisionalItem(HistoryItem*, HistoryItem*);
- void recursiveGoToItem(HistoryItem*, HistoryItem*);
- void recursiveUpdateForCommit();
- void recursiveUpdateForSameDocumentNavigation();
- bool itemsAreClones(HistoryItem*, HistoryItem*) const;
- bool currentFramesMatchItem(HistoryItem*) const;
+ void updateForStandardLoad(Frame*);
+ void updateForInitialLoadInChildFrame(Frame*);
- void createNewBackForwardItem(bool doClip);
- void updateWithoutCreatingNewBackForwardItem();
+ void createNewBackForwardItem(Frame*, bool doClip);
+ void updateWithoutCreatingNewBackForwardItem(Frame*);
- void clearProvisionalItemsInAllFrames();
+ Page* m_page;
- Frame* m_frame;
+ OwnPtr<HistoryEntry> m_currentEntry;
+ OwnPtr<HistoryEntry> m_previousEntry;
+ OwnPtr<HistoryEntry> m_provisionalEntry;
- RefPtr<HistoryItem> m_currentItem;
- RefPtr<HistoryItem> m_previousItem;
- RefPtr<HistoryItem> m_provisionalItem;
+ typedef HashMap<Frame*, HistoryItem*> HistoryFrameLoadSet;
+ HistoryFrameLoadSet m_sameDocumentLoadsInProgress;
+ HistoryFrameLoadSet m_differentDocumentLoadsInProgress;
bool m_defersLoading;
RefPtr<HistoryItem> m_deferredItem;
« no previous file with comments | « Source/core/loader/FrameLoaderTypes.h ('k') | Source/core/loader/HistoryController.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698