Add globally-unique HistoryItem identifiers (and have WebKit2 adopt them).
[WebKit-https.git] / Source / WebKit / Shared / WebBackForwardListItem.cpp
1 /*
2  * Copyright (C) 2010-2011, 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "WebBackForwardListItem.h"
28
29 #include <WebCore/URL.h>
30
31 using namespace WebCore;
32
33 namespace WebKit {
34
35 Ref<WebBackForwardListItem> WebBackForwardListItem::create(BackForwardListItemState&& backForwardListItemState, uint64_t pageID)
36 {
37     return adoptRef(*new WebBackForwardListItem(WTFMove(backForwardListItemState), pageID));
38 }
39
40 WebBackForwardListItem::WebBackForwardListItem(BackForwardListItemState&& backForwardListItemState, uint64_t pageID)
41     : m_itemState(WTFMove(backForwardListItemState))
42     , m_pageID(pageID)
43 {
44     auto result = allItems().add(m_itemState.identifier, this);
45     ASSERT_UNUSED(result, result.isNewEntry);
46 }
47
48 WebBackForwardListItem::~WebBackForwardListItem()
49 {
50     ASSERT(allItems().get(m_itemState.identifier) == this);
51     allItems().remove(m_itemState.identifier);
52 }
53
54 HashMap<BackForwardItemIdentifier, WebBackForwardListItem*>& WebBackForwardListItem::allItems()
55 {
56     static NeverDestroyed<HashMap<BackForwardItemIdentifier, WebBackForwardListItem*>> items;
57     return items;
58 }
59
60 WebBackForwardListItem* WebBackForwardListItem::itemForID(const BackForwardItemIdentifier& identifier)
61 {
62     return allItems().get(identifier);
63 }
64
65 static const FrameState* childItemWithDocumentSequenceNumber(const FrameState& frameState, int64_t number)
66 {
67     for (const auto& child : frameState.children) {
68         if (child.documentSequenceNumber == number)
69             return &child;
70     }
71
72     return nullptr;
73 }
74
75 static bool documentTreesAreEqual(const FrameState& a, const FrameState& b)
76 {
77     if (a.documentSequenceNumber != b.documentSequenceNumber)
78         return false;
79
80     if (a.children.size() != b.children.size())
81         return false;
82
83     for (const auto& child : a.children) {
84         const FrameState* otherChild = childItemWithDocumentSequenceNumber(b, child.documentSequenceNumber);
85         if (!otherChild || !documentTreesAreEqual(child, *otherChild))
86             return false;
87     }
88
89     return true;
90 }
91
92 bool WebBackForwardListItem::itemIsInSameDocument(const WebBackForwardListItem& other) const
93 {
94     if (m_pageID != other.m_pageID)
95         return false;
96
97     // The following logic must be kept in sync with WebCore::HistoryItem::shouldDoSameDocumentNavigationTo.
98
99     const FrameState& mainFrameState = m_itemState.pageState.mainFrameState;
100     const FrameState& otherMainFrameState = other.m_itemState.pageState.mainFrameState;
101
102     if (mainFrameState.stateObjectData || otherMainFrameState.stateObjectData)
103         return mainFrameState.documentSequenceNumber == otherMainFrameState.documentSequenceNumber;
104
105     WebCore::URL url = WebCore::URL(WebCore::ParsedURLString, mainFrameState.urlString);
106     WebCore::URL otherURL = WebCore::URL(WebCore::ParsedURLString, otherMainFrameState.urlString);
107
108     if ((url.hasFragmentIdentifier() || otherURL.hasFragmentIdentifier()) && equalIgnoringFragmentIdentifier(url, otherURL))
109         return mainFrameState.documentSequenceNumber == otherMainFrameState.documentSequenceNumber;
110
111     return documentTreesAreEqual(mainFrameState, otherMainFrameState);
112 }
113
114 void WebBackForwardListItem::setSuspendedPage(SuspendedPageProxy& page)
115 {
116     m_suspendedPage = &page;
117 }
118
119 } // namespace WebKit