| 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;
|
|
|