[PSON] Introduce a WebContent Process cache
[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 "SuspendedPageProxy.h"
30 #include "WebProcessPool.h"
31 #include "WebProcessProxy.h"
32 #include <wtf/DebugUtilities.h>
33 #include <wtf/URL.h>
34
35 namespace WebKit {
36 using namespace WebCore;
37
38 Ref<WebBackForwardListItem> WebBackForwardListItem::create(BackForwardListItemState&& backForwardListItemState, uint64_t pageID)
39 {
40     return adoptRef(*new WebBackForwardListItem(WTFMove(backForwardListItemState), pageID));
41 }
42
43 WebBackForwardListItem::WebBackForwardListItem(BackForwardListItemState&& backForwardListItemState, uint64_t pageID)
44     : m_itemState(WTFMove(backForwardListItemState))
45     , m_pageID(pageID)
46     , m_lastProcessIdentifier(m_itemState.identifier.processIdentifier)
47 {
48     auto result = allItems().add(m_itemState.identifier, this);
49     ASSERT_UNUSED(result, result.isNewEntry);
50 }
51
52 WebBackForwardListItem::~WebBackForwardListItem()
53 {
54     ASSERT(allItems().get(m_itemState.identifier) == this);
55     allItems().remove(m_itemState.identifier);
56
57     removeSuspendedPageFromProcessPool();
58 }
59
60 HashMap<BackForwardItemIdentifier, WebBackForwardListItem*>& WebBackForwardListItem::allItems()
61 {
62     static NeverDestroyed<HashMap<BackForwardItemIdentifier, WebBackForwardListItem*>> items;
63     return items;
64 }
65
66 WebBackForwardListItem* WebBackForwardListItem::itemForID(const BackForwardItemIdentifier& identifier)
67 {
68     return allItems().get(identifier);
69 }
70
71 static const FrameState* childItemWithDocumentSequenceNumber(const FrameState& frameState, int64_t number)
72 {
73     for (const auto& child : frameState.children) {
74         if (child.documentSequenceNumber == number)
75             return &child;
76     }
77
78     return nullptr;
79 }
80
81 static const FrameState* childItemWithTarget(const FrameState& frameState, const String& target)
82 {
83     for (const auto& child : frameState.children) {
84         if (child.target == target)
85             return &child;
86     }
87
88     return nullptr;
89 }
90
91 static bool documentTreesAreEqual(const FrameState& a, const FrameState& b)
92 {
93     if (a.documentSequenceNumber != b.documentSequenceNumber)
94         return false;
95
96     if (a.children.size() != b.children.size())
97         return false;
98
99     for (const auto& child : a.children) {
100         const FrameState* otherChild = childItemWithDocumentSequenceNumber(b, child.documentSequenceNumber);
101         if (!otherChild || !documentTreesAreEqual(child, *otherChild))
102             return false;
103     }
104
105     return true;
106 }
107
108 bool WebBackForwardListItem::itemIsInSameDocument(const WebBackForwardListItem& other) const
109 {
110     if (m_pageID != other.m_pageID)
111         return false;
112
113     // The following logic must be kept in sync with WebCore::HistoryItem::shouldDoSameDocumentNavigationTo().
114
115     const FrameState& mainFrameState = m_itemState.pageState.mainFrameState;
116     const FrameState& otherMainFrameState = other.m_itemState.pageState.mainFrameState;
117
118     if (mainFrameState.stateObjectData || otherMainFrameState.stateObjectData)
119         return mainFrameState.documentSequenceNumber == otherMainFrameState.documentSequenceNumber;
120
121     URL url = URL({ }, mainFrameState.urlString);
122     URL otherURL = URL({ }, otherMainFrameState.urlString);
123
124     if ((url.hasFragmentIdentifier() || otherURL.hasFragmentIdentifier()) && equalIgnoringFragmentIdentifier(url, otherURL))
125         return mainFrameState.documentSequenceNumber == otherMainFrameState.documentSequenceNumber;
126
127     return documentTreesAreEqual(mainFrameState, otherMainFrameState);
128 }
129
130 static bool hasSameFrames(const FrameState& a, const FrameState& b)
131 {
132     if (a.target != b.target)
133         return false;
134
135     if (a.children.size() != b.children.size())
136         return false;
137
138     for (const auto& child : a.children) {
139         if (!childItemWithTarget(b, child.target))
140             return false;
141     }
142
143     return true;
144 }
145
146 bool WebBackForwardListItem::itemIsClone(const WebBackForwardListItem& other)
147 {
148     // The following logic must be kept in sync with WebCore::HistoryItem::itemsAreClones().
149
150     if (this == &other)
151         return false;
152
153     const FrameState& mainFrameState = m_itemState.pageState.mainFrameState;
154     const FrameState& otherMainFrameState = other.m_itemState.pageState.mainFrameState;
155
156     if (mainFrameState.itemSequenceNumber != otherMainFrameState.itemSequenceNumber)
157         return false;
158
159     return hasSameFrames(mainFrameState, otherMainFrameState);
160 }
161
162 void WebBackForwardListItem::setSuspendedPage(SuspendedPageProxy* page)
163 {
164     if (m_suspendedPage == page)
165         return;
166
167     removeSuspendedPageFromProcessPool();
168     m_suspendedPage = makeWeakPtr(page);
169 }
170
171 void WebBackForwardListItem::removeSuspendedPageFromProcessPool()
172 {
173     if (!m_suspendedPage)
174         return;
175
176     m_suspendedPage->process().processPool().removeSuspendedPage(*m_suspendedPage);
177     ASSERT(!m_suspendedPage);
178 }
179
180 #if !LOG_DISABLED
181 const char* WebBackForwardListItem::loggingString()
182 {
183     return debugString("Back/forward item ID ", itemID().logString(), ", original URL ", originalURL(), ", current URL ", url(), m_suspendedPage ? "(has a suspended page)" : "");
184 }
185 #endif // !LOG_DISABLED
186
187 } // namespace WebKit