summaryrefslogtreecommitdiff
path: root/Source/WebKit2/UIProcess/WebBackForwardList.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit2/UIProcess/WebBackForwardList.cpp')
-rw-r--r--Source/WebKit2/UIProcess/WebBackForwardList.cpp228
1 files changed, 191 insertions, 37 deletions
diff --git a/Source/WebKit2/UIProcess/WebBackForwardList.cpp b/Source/WebKit2/UIProcess/WebBackForwardList.cpp
index 411ea56c4..c88e68c95 100644
--- a/Source/WebKit2/UIProcess/WebBackForwardList.cpp
+++ b/Source/WebKit2/UIProcess/WebBackForwardList.cpp
@@ -27,10 +27,28 @@
#include "WebBackForwardList.h"
#include "APIArray.h"
+#include "SessionState.h"
#include "WebPageProxy.h"
+#include <WebCore/DiagnosticLoggingClient.h>
+#include <WebCore/DiagnosticLoggingKeys.h>
namespace WebKit {
+using namespace WebCore;
+
+// FIXME: Make this static once WebBackForwardListCF.cpp is no longer using it.
+uint64_t generateWebBackForwardItemID();
+
+uint64_t generateWebBackForwardItemID()
+{
+ // These IDs exist in the UIProcess for items created by the UIProcess.
+ // The IDs generated here need to never collide with the IDs created in WebBackForwardListProxy in the WebProcess.
+ // We accomplish this by starting from 2, and only ever using even ids.
+ static uint64_t uniqueHistoryItemID = 0;
+ uniqueHistoryItemID += 2;
+ return uniqueHistoryItemID;
+}
+
static const unsigned DefaultCapacity = 100;
WebBackForwardList::WebBackForwardList(WebPageProxy& page)
@@ -58,7 +76,8 @@ void WebBackForwardList::pageClosed()
ASSERT(m_entries[i]);
if (!m_entries[i])
continue;
- m_page->backForwardRemovedItem(m_entries[i]->itemID());
+
+ didRemoveItem(*m_entries[i]);
}
}
@@ -74,23 +93,25 @@ void WebBackForwardList::addItem(WebBackForwardListItem* newItem)
if (!m_capacity || !newItem || !m_page)
return;
- Vector<RefPtr<API::Object>> removedItems;
+ Vector<RefPtr<WebBackForwardListItem>> removedItems;
if (m_hasCurrentIndex) {
+ m_page->recordAutomaticNavigationSnapshot();
+
// Toss everything in the forward list.
unsigned targetSize = m_currentIndex + 1;
removedItems.reserveCapacity(m_entries.size() - targetSize);
while (m_entries.size() > targetSize) {
- m_page->backForwardRemovedItem(m_entries.last()->itemID());
- removedItems.append(m_entries.last().release());
+ didRemoveItem(*m_entries.last());
+ removedItems.append(WTFMove(m_entries.last()));
m_entries.removeLast();
}
// Toss the first item if the list is getting too big, as long as we're not using it
// (or even if we are, if we only want 1 entry).
if (m_entries.size() == m_capacity && (m_currentIndex || m_capacity == 1)) {
- m_page->backForwardRemovedItem(m_entries[0]->itemID());
- removedItems.append(m_entries[0].release());
+ didRemoveItem(*m_entries[0]);
+ removedItems.append(WTFMove(m_entries[0]));
m_entries.remove(0);
if (m_entries.isEmpty())
@@ -108,26 +129,41 @@ void WebBackForwardList::addItem(WebBackForwardListItem* newItem)
ASSERT(m_entries[i]);
if (!m_entries[i])
continue;
- m_page->backForwardRemovedItem(m_entries[i]->itemID());
- removedItems.append(m_entries[i].release());
+ didRemoveItem(*m_entries[i]);
+ removedItems.append(WTFMove(m_entries[i]));
}
m_entries.clear();
}
-
+
+ bool shouldKeepCurrentItem = true;
+
if (!m_hasCurrentIndex) {
ASSERT(m_entries.isEmpty());
m_currentIndex = 0;
m_hasCurrentIndex = true;
- } else
- m_currentIndex++;
+ } else {
+ shouldKeepCurrentItem = m_page->shouldKeepCurrentBackForwardListItemInList(m_entries[m_currentIndex].get());
+ if (shouldKeepCurrentItem)
+ m_currentIndex++;
+ }
- // m_current never be pointing more than 1 past the end of the entries Vector.
- // If it is, something has gone wrong and we should not try to insert the new item.
- ASSERT(m_currentIndex <= m_entries.size());
- if (m_currentIndex <= m_entries.size())
- m_entries.insert(m_currentIndex, newItem);
+ if (!shouldKeepCurrentItem) {
+ // m_current should never be pointing past the end of the entries Vector.
+ // If it is, something has gone wrong and we should not try to swap in the new item.
+ ASSERT(m_currentIndex < m_entries.size());
+
+ removedItems.append(m_entries[m_currentIndex]);
+ m_entries[m_currentIndex] = newItem;
+ } else {
+ // m_current should never be pointing more than 1 past the end of the entries Vector.
+ // If it is, something has gone wrong and we should not try to insert the new item.
+ ASSERT(m_currentIndex <= m_entries.size());
- m_page->didChangeBackForwardList(newItem, &removedItems);
+ if (m_currentIndex <= m_entries.size())
+ m_entries.insert(m_currentIndex, newItem);
+ }
+
+ m_page->didChangeBackForwardList(newItem, WTFMove(removedItems));
}
void WebBackForwardList::goToItem(WebBackForwardListItem* item)
@@ -136,16 +172,40 @@ void WebBackForwardList::goToItem(WebBackForwardListItem* item)
if (!m_entries.size() || !item || !m_page || !m_hasCurrentIndex)
return;
-
- unsigned index = 0;
- for (; index < m_entries.size(); ++index) {
- if (m_entries[index] == item)
- break;
+
+ size_t targetIndex = m_entries.find(item);
+
+ // If the target item wasn't even in the list, there's nothing else to do.
+ if (targetIndex == notFound)
+ return;
+
+ if (targetIndex < m_currentIndex) {
+ unsigned delta = m_entries.size() - targetIndex - 1;
+ String deltaValue = delta > 10 ? ASCIILiteral("over10") : String::number(delta);
+ m_page->logDiagnosticMessage(WebCore::DiagnosticLoggingKeys::backNavigationDeltaKey(), deltaValue, ShouldSample::No);
}
- if (index < m_entries.size()) {
- m_currentIndex = index;
- m_page->didChangeBackForwardList(0, 0);
+
+ // If we're going to an item different from the current item, ask the client if the current
+ // item should remain in the list.
+ WebBackForwardListItem* currentItem = m_entries[m_currentIndex].get();
+ bool shouldKeepCurrentItem = true;
+ if (currentItem != item) {
+ m_page->recordAutomaticNavigationSnapshot();
+ shouldKeepCurrentItem = m_page->shouldKeepCurrentBackForwardListItemInList(m_entries[m_currentIndex].get());
}
+
+ // If the client said to remove the current item, remove it and then update the target index.
+ Vector<RefPtr<WebBackForwardListItem>> removedItems;
+ if (!shouldKeepCurrentItem) {
+ removedItems.append(currentItem);
+ m_entries.remove(m_currentIndex);
+ targetIndex = m_entries.find(item);
+
+ ASSERT(targetIndex != notFound);
+ }
+
+ m_currentIndex = targetIndex;
+ m_page->didChangeBackForwardList(nullptr, removedItems);
}
WebBackForwardListItem* WebBackForwardList::currentItem() const
@@ -200,7 +260,17 @@ int WebBackForwardList::forwardListCount() const
return m_page && m_hasCurrentIndex ? m_entries.size() - (m_currentIndex + 1) : 0;
}
-PassRefPtr<API::Array> WebBackForwardList::backListAsAPIArrayWithLimit(unsigned limit) const
+Ref<API::Array> WebBackForwardList::backList() const
+{
+ return backListAsAPIArrayWithLimit(backListCount());
+}
+
+Ref<API::Array> WebBackForwardList::forwardList() const
+{
+ return forwardListAsAPIArrayWithLimit(forwardListCount());
+}
+
+Ref<API::Array> WebBackForwardList::backListAsAPIArrayWithLimit(unsigned limit) const
{
ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
@@ -221,10 +291,10 @@ PassRefPtr<API::Array> WebBackForwardList::backListAsAPIArrayWithLimit(unsigned
vector.uncheckedAppend(m_entries[i].get());
}
- return API::Array::create(std::move(vector));
+ return API::Array::create(WTFMove(vector));
}
-PassRefPtr<API::Array> WebBackForwardList::forwardListAsAPIArrayWithLimit(unsigned limit) const
+Ref<API::Array> WebBackForwardList::forwardListAsAPIArrayWithLimit(unsigned limit) const
{
ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
@@ -245,7 +315,27 @@ PassRefPtr<API::Array> WebBackForwardList::forwardListAsAPIArrayWithLimit(unsign
vector.uncheckedAppend(m_entries[i].get());
}
- return API::Array::create(std::move(vector));
+ return API::Array::create(WTFMove(vector));
+}
+
+void WebBackForwardList::removeAllItems()
+{
+ ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
+
+ Vector<RefPtr<WebBackForwardListItem>> removedItems;
+
+ for (auto& entry : m_entries) {
+ ASSERT(entry);
+ if (!entry)
+ continue;
+
+ didRemoveItem(*entry);
+ removedItems.append(WTFMove(entry));
+ }
+
+ m_entries.clear();
+ m_hasCurrentIndex = false;
+ m_page->didChangeBackForwardList(nullptr, WTFMove(removedItems));
}
void WebBackForwardList::clear()
@@ -257,7 +347,7 @@ void WebBackForwardList::clear()
return;
RefPtr<WebBackForwardListItem> currentItem = this->currentItem();
- Vector<RefPtr<API::Object>> removedItems;
+ Vector<RefPtr<WebBackForwardListItem>> removedItems;
if (!currentItem) {
// We should only ever have no current item if we also have no current item index.
@@ -269,13 +359,13 @@ void WebBackForwardList::clear()
if (!m_entries[i])
continue;
- m_page->backForwardRemovedItem(m_entries[i]->itemID());
- removedItems.append(m_entries[i].release());
+ didRemoveItem(*m_entries[i]);
+ removedItems.append(WTFMove(m_entries[i]));
}
m_entries.clear();
m_hasCurrentIndex = false;
- m_page->didChangeBackForwardList(0, &removedItems);
+ m_page->didChangeBackForwardList(nullptr, WTFMove(removedItems));
return;
}
@@ -283,26 +373,90 @@ void WebBackForwardList::clear()
for (size_t i = 0; i < size; ++i) {
ASSERT(m_entries[i]);
if (m_entries[i] && m_entries[i] != currentItem)
- m_page->backForwardRemovedItem(m_entries[i]->itemID());
+ didRemoveItem(*m_entries[i]);
}
removedItems.reserveCapacity(size - 1);
for (size_t i = 0; i < size; ++i) {
if (i != m_currentIndex && m_hasCurrentIndex && m_entries[i])
- removedItems.append(m_entries[i].release());
+ removedItems.append(WTFMove(m_entries[i]));
}
m_currentIndex = 0;
if (currentItem) {
m_entries.shrink(1);
- m_entries[0] = currentItem.release();
+ m_entries[0] = WTFMove(currentItem);
} else {
m_entries.clear();
m_hasCurrentIndex = false;
}
- m_page->didChangeBackForwardList(0, &removedItems);
+ m_page->didChangeBackForwardList(nullptr, WTFMove(removedItems));
+}
+
+BackForwardListState WebBackForwardList::backForwardListState(const std::function<bool (WebBackForwardListItem&)>& filter) const
+{
+ ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
+
+ BackForwardListState backForwardListState;
+ if (m_hasCurrentIndex)
+ backForwardListState.currentIndex = m_currentIndex;
+
+ for (size_t i = 0; i < m_entries.size(); ++i) {
+ auto& entry = *m_entries[i];
+
+ if (filter && !filter(entry)) {
+ auto& currentIndex = backForwardListState.currentIndex;
+ if (currentIndex && i <= currentIndex.value() && currentIndex.value())
+ --currentIndex.value();
+
+ continue;
+ }
+
+ backForwardListState.items.append(entry.itemState());
+ }
+
+ if (backForwardListState.items.isEmpty())
+ backForwardListState.currentIndex = std::nullopt;
+ else if (backForwardListState.items.size() <= backForwardListState.currentIndex.value())
+ backForwardListState.currentIndex = backForwardListState.items.size() - 1;
+
+ return backForwardListState;
+}
+
+void WebBackForwardList::restoreFromState(BackForwardListState backForwardListState)
+{
+ Vector<RefPtr<WebBackForwardListItem>> items;
+ items.reserveInitialCapacity(backForwardListState.items.size());
+
+ for (auto& backForwardListItemState : backForwardListState.items) {
+ backForwardListItemState.identifier = generateWebBackForwardItemID();
+ items.uncheckedAppend(WebBackForwardListItem::create(WTFMove(backForwardListItemState), m_page->pageID()));
+ }
+ m_hasCurrentIndex = !!backForwardListState.currentIndex;
+ m_currentIndex = backForwardListState.currentIndex.value_or(0);
+ m_entries = WTFMove(items);
+}
+
+Vector<BackForwardListItemState> WebBackForwardList::itemStates() const
+{
+ Vector<BackForwardListItemState> itemStates;
+ itemStates.reserveInitialCapacity(m_entries.size());
+
+ for (const auto& entry : m_entries)
+ itemStates.uncheckedAppend(entry->itemState());
+
+ return itemStates;
+}
+
+void WebBackForwardList::didRemoveItem(WebBackForwardListItem& backForwardListItem)
+{
+ m_page->backForwardRemovedItem(backForwardListItem.itemID());
+
+#if PLATFORM(COCOA)
+ backForwardListItem.setSnapshot(nullptr);
+#endif
}
} // namespace WebKit