summaryrefslogtreecommitdiff
path: root/Source/WebCore/history
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/history
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/history')
-rw-r--r--Source/WebCore/history/BackForwardClient.h28
-rw-r--r--Source/WebCore/history/BackForwardController.cpp19
-rw-r--r--Source/WebCore/history/BackForwardController.h21
-rw-r--r--Source/WebCore/history/BackForwardList.cpp300
-rw-r--r--Source/WebCore/history/BackForwardList.h97
-rw-r--r--Source/WebCore/history/CachedFrame.cpp144
-rw-r--r--Source/WebCore/history/CachedFrame.h30
-rw-r--r--Source/WebCore/history/CachedFramePlatformData.h8
-rw-r--r--Source/WebCore/history/CachedPage.cpp103
-rw-r--r--Source/WebCore/history/CachedPage.h36
-rw-r--r--Source/WebCore/history/HistoryItem.cpp474
-rw-r--r--Source/WebCore/history/HistoryItem.h220
-rw-r--r--Source/WebCore/history/PageCache.cpp703
-rw-r--r--Source/WebCore/history/PageCache.h110
14 files changed, 724 insertions, 1569 deletions
diff --git a/Source/WebCore/history/BackForwardClient.h b/Source/WebCore/history/BackForwardClient.h
index 8ba55e578..f1bafdecc 100644
--- a/Source/WebCore/history/BackForwardClient.h
+++ b/Source/WebCore/history/BackForwardClient.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2010, 2016 Apple Inc. All rights reserved.
* Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (C) 2009 Google, Inc. All rights reserved.
*
@@ -12,10 +12,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -25,8 +25,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef BackForwardClient_h
-#define BackForwardClient_h
+#pragma once
#include <wtf/Forward.h>
#include <wtf/RefCounted.h>
@@ -41,7 +40,7 @@ public:
{
}
- virtual void addItem(PassRefPtr<HistoryItem>) = 0;
+ virtual void addItem(Ref<HistoryItem>&&) = 0;
virtual void goToItem(HistoryItem*) = 0;
@@ -50,23 +49,6 @@ public:
virtual int forwardListCount() = 0;
virtual void close() = 0;
-
-#if PLATFORM(IOS)
- // FIXME: These methods seem to violate the encapsulation of this class.
- virtual unsigned current() = 0;
- virtual void setCurrent(unsigned newCurrent) = 0;
-
- // FIXME: Consider renaming this method once we upstream the iOS changes to WebView.mm.
- virtual bool clearAllPageCaches() = 0;
-#endif
-
- // FIXME: Delete these once all callers are using BackForwardController
- // instead of calling this directly.
- HistoryItem* backItem() { return itemAtIndex(-1); }
- HistoryItem* currentItem() { return itemAtIndex(0); }
- HistoryItem* forwardItem() { return itemAtIndex(1); }
};
} // namespace WebCore
-
-#endif // BackForwardClient_h
diff --git a/Source/WebCore/history/BackForwardController.cpp b/Source/WebCore/history/BackForwardController.cpp
index 2d1d02009..1bc8b5a5f 100644
--- a/Source/WebCore/history/BackForwardController.cpp
+++ b/Source/WebCore/history/BackForwardController.cpp
@@ -26,18 +26,15 @@
#include "config.h"
#include "BackForwardController.h"
-#include "BackForwardList.h"
-#include "HistoryItem.h"
+#include "BackForwardClient.h"
#include "Page.h"
namespace WebCore {
-BackForwardController::BackForwardController(Page& page, PassRefPtr<BackForwardClient> client)
+BackForwardController::BackForwardController(Page& page, Ref<BackForwardClient>&& client)
: m_page(page)
- , m_client(client)
+ , m_client(WTFMove(client))
{
- if (!m_client)
- m_client = BackForwardList::create(&page);
}
BackForwardController::~BackForwardController()
@@ -74,7 +71,7 @@ void BackForwardController::goBackOrForward(int distance)
if (!item)
return;
- m_page.goToItem(item, FrameLoadTypeIndexedBackForward);
+ m_page.goToItem(*item, FrameLoadType::IndexedBackForward);
}
bool BackForwardController::goBack()
@@ -83,7 +80,7 @@ bool BackForwardController::goBack()
if (!item)
return false;
- m_page.goToItem(item, FrameLoadTypeBack);
+ m_page.goToItem(*item, FrameLoadType::Back);
return true;
}
@@ -93,13 +90,13 @@ bool BackForwardController::goForward()
if (!item)
return false;
- m_page.goToItem(item, FrameLoadTypeForward);
+ m_page.goToItem(*item, FrameLoadType::Forward);
return true;
}
-void BackForwardController::addItem(PassRefPtr<HistoryItem> item)
+void BackForwardController::addItem(Ref<HistoryItem>&& item)
{
- m_client->addItem(item);
+ m_client->addItem(WTFMove(item));
}
void BackForwardController::setCurrentItem(HistoryItem* item)
diff --git a/Source/WebCore/history/BackForwardController.h b/Source/WebCore/history/BackForwardController.h
index 638774643..60693d788 100644
--- a/Source/WebCore/history/BackForwardController.h
+++ b/Source/WebCore/history/BackForwardController.h
@@ -23,8 +23,7 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef BackForwardController_h
-#define BackForwardController_h
+#pragma once
#include <wtf/Noncopyable.h>
#include <wtf/Forward.h>
@@ -39,25 +38,25 @@ class Page;
class BackForwardController {
WTF_MAKE_NONCOPYABLE(BackForwardController); WTF_MAKE_FAST_ALLOCATED;
public:
- BackForwardController(Page&, PassRefPtr<BackForwardClient>);
+ BackForwardController(Page&, Ref<BackForwardClient>&&);
~BackForwardController();
BackForwardClient* client() const { return m_client.get(); }
- bool canGoBackOrForward(int distance) const;
+ WEBCORE_EXPORT bool canGoBackOrForward(int distance) const;
void goBackOrForward(int distance);
- bool goBack();
- bool goForward();
+ WEBCORE_EXPORT bool goBack();
+ WEBCORE_EXPORT bool goForward();
- void addItem(PassRefPtr<HistoryItem>);
+ void addItem(Ref<HistoryItem>&&);
void setCurrentItem(HistoryItem*);
int count() const;
- int backCount() const;
- int forwardCount() const;
+ WEBCORE_EXPORT int backCount() const;
+ WEBCORE_EXPORT int forwardCount() const;
- HistoryItem* itemAtIndex(int);
+ WEBCORE_EXPORT HistoryItem* itemAtIndex(int);
void close();
@@ -71,5 +70,3 @@ private:
};
} // namespace WebCore
-
-#endif // BackForwardController_h
diff --git a/Source/WebCore/history/BackForwardList.cpp b/Source/WebCore/history/BackForwardList.cpp
deleted file mode 100644
index b031ef16d..000000000
--- a/Source/WebCore/history/BackForwardList.cpp
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
- * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "BackForwardList.h"
-
-#include "Frame.h"
-#include "FrameLoader.h"
-#include "FrameLoaderClient.h"
-#include "HistoryItem.h"
-#include "Logging.h"
-#include "Page.h"
-#include "PageCache.h"
-#include "SerializedScriptValue.h"
-
-namespace WebCore {
-
-static const unsigned DefaultCapacity = 100;
-static const unsigned NoCurrentItemIndex = UINT_MAX;
-
-BackForwardList::BackForwardList(Page* page)
- : m_page(page)
- , m_current(NoCurrentItemIndex)
- , m_capacity(DefaultCapacity)
- , m_closed(true)
- , m_enabled(true)
-{
-}
-
-BackForwardList::~BackForwardList()
-{
- ASSERT(m_closed);
-}
-
-void BackForwardList::addItem(PassRefPtr<HistoryItem> prpItem)
-{
- ASSERT(prpItem);
- if (m_capacity == 0 || !m_enabled)
- return;
-
- // Toss anything in the forward list
- if (m_current != NoCurrentItemIndex) {
- unsigned targetSize = m_current + 1;
- while (m_entries.size() > targetSize) {
- RefPtr<HistoryItem> item = m_entries.last();
- m_entries.removeLast();
- m_entryHash.remove(item);
- pageCache()->remove(item.get());
- }
- }
-
- // 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_current != 0 || m_capacity == 1)) {
- RefPtr<HistoryItem> item = m_entries[0];
- m_entries.remove(0);
- m_entryHash.remove(item);
- pageCache()->remove(item.get());
- m_current--;
- }
-
- m_entryHash.add(prpItem.get());
- m_entries.insert(m_current + 1, prpItem);
- m_current++;
-}
-
-void BackForwardList::goBack()
-{
- ASSERT(m_current > 0);
- if (m_current > 0) {
- m_current--;
- }
-}
-
-void BackForwardList::goForward()
-{
- ASSERT(m_current < m_entries.size() - 1);
- if (m_current < m_entries.size() - 1) {
- m_current++;
- }
-}
-
-void BackForwardList::goToItem(HistoryItem* item)
-{
- if (!m_entries.size() || !item)
- return;
-
- unsigned int index = 0;
- for (; index < m_entries.size(); ++index)
- if (m_entries[index] == item)
- break;
- if (index < m_entries.size()) {
- m_current = index;
- }
-}
-
-HistoryItem* BackForwardList::backItem()
-{
- if (m_current && m_current != NoCurrentItemIndex)
- return m_entries[m_current - 1].get();
- return 0;
-}
-
-HistoryItem* BackForwardList::currentItem()
-{
- if (m_current != NoCurrentItemIndex)
- return m_entries[m_current].get();
- return 0;
-}
-
-HistoryItem* BackForwardList::forwardItem()
-{
- if (m_entries.size() && m_current < m_entries.size() - 1)
- return m_entries[m_current + 1].get();
- return 0;
-}
-
-void BackForwardList::backListWithLimit(int limit, HistoryItemVector& list)
-{
- list.clear();
- if (m_current != NoCurrentItemIndex) {
- unsigned first = std::max((int)m_current - limit, 0);
- for (; first < m_current; ++first)
- list.append(m_entries[first]);
- }
-}
-
-void BackForwardList::forwardListWithLimit(int limit, HistoryItemVector& list)
-{
- ASSERT(limit > -1);
- list.clear();
- if (!m_entries.size())
- return;
-
- unsigned lastEntry = m_entries.size() - 1;
- if (m_current < lastEntry) {
- int last = std::min(m_current + limit, lastEntry);
- limit = m_current + 1;
- for (; limit <= last; ++limit)
- list.append(m_entries[limit]);
- }
-}
-
-int BackForwardList::capacity()
-{
- return m_capacity;
-}
-
-void BackForwardList::setCapacity(int size)
-{
- while (size < (int)m_entries.size()) {
- RefPtr<HistoryItem> item = m_entries.last();
- m_entries.removeLast();
- m_entryHash.remove(item);
- pageCache()->remove(item.get());
- }
-
- if (!size)
- m_current = NoCurrentItemIndex;
- else if (m_current > m_entries.size() - 1) {
- m_current = m_entries.size() - 1;
- }
- m_capacity = size;
-}
-
-bool BackForwardList::enabled()
-{
- return m_enabled;
-}
-
-void BackForwardList::setEnabled(bool enabled)
-{
- m_enabled = enabled;
- if (!enabled) {
- int capacity = m_capacity;
- setCapacity(0);
- setCapacity(capacity);
- }
-}
-
-int BackForwardList::backListCount()
-{
- return m_current == NoCurrentItemIndex ? 0 : m_current;
-}
-
-int BackForwardList::forwardListCount()
-{
- return m_current == NoCurrentItemIndex ? 0 : (int)m_entries.size() - (m_current + 1);
-}
-
-HistoryItem* BackForwardList::itemAtIndex(int index)
-{
- // Do range checks without doing math on index to avoid overflow.
- if (index < -(int)m_current)
- return 0;
-
- if (index > forwardListCount())
- return 0;
-
- return m_entries[index + m_current].get();
-}
-
-HistoryItemVector& BackForwardList::entries()
-{
- return m_entries;
-}
-
-#if PLATFORM(IOS)
-unsigned BackForwardList::current()
-{
- return m_current;
-}
-
-void BackForwardList::setCurrent(unsigned newCurrent)
-{
- m_current = newCurrent;
-}
-
-bool BackForwardList::clearAllPageCaches()
-{
- bool didRemoveAtLeastOneItem = false;
- unsigned length = m_entries.size();
- for (unsigned i = 0; i < length; ++i) {
- HistoryItem* item = m_entries[i].get();
- if (item->isInPageCache()) {
- didRemoveAtLeastOneItem = true;
- pageCache()->remove(item);
- }
- }
- return didRemoveAtLeastOneItem;
-}
-#endif
-
-void BackForwardList::close()
-{
- int size = m_entries.size();
- for (int i = 0; i < size; ++i)
- pageCache()->remove(m_entries[i].get());
- m_entries.clear();
- m_entryHash.clear();
- m_page = 0;
- m_closed = true;
-}
-
-bool BackForwardList::closed()
-{
- return m_closed;
-}
-
-void BackForwardList::removeItem(HistoryItem* item)
-{
- if (!item)
- return;
-
- for (unsigned i = 0; i < m_entries.size(); ++i)
- if (m_entries[i] == item) {
- m_entries.remove(i);
- m_entryHash.remove(item);
- if (m_current == NoCurrentItemIndex || m_current < i)
- break;
- if (m_current > i)
- m_current--;
- else {
- size_t count = m_entries.size();
- if (m_current >= count)
- m_current = count ? count - 1 : NoCurrentItemIndex;
- }
- break;
- }
-}
-
-bool BackForwardList::containsItem(HistoryItem* entry)
-{
- return m_entryHash.contains(entry);
-}
-
-}; // namespace WebCore
diff --git a/Source/WebCore/history/BackForwardList.h b/Source/WebCore/history/BackForwardList.h
deleted file mode 100644
index ae7adfa16..000000000
--- a/Source/WebCore/history/BackForwardList.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2006, 2010 Apple Inc. All rights reserved.
- * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
- * Copyright (C) 2009 Google, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BackForwardList_h
-#define BackForwardList_h
-
-#include "BackForwardClient.h"
-#include <wtf/HashSet.h>
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
-class Page;
-
-typedef Vector<RefPtr<HistoryItem>> HistoryItemVector;
-typedef HashSet<RefPtr<HistoryItem>> HistoryItemHashSet;
-
-class BackForwardList : public BackForwardClient {
-public:
- static PassRefPtr<BackForwardList> create(Page* page) { return adoptRef(new BackForwardList(page)); }
- virtual ~BackForwardList();
-
- Page* page() { return m_page; }
-
- virtual void addItem(PassRefPtr<HistoryItem>) override;
- void goBack();
- void goForward();
- virtual void goToItem(HistoryItem*) override;
-
- HistoryItem* backItem();
- HistoryItem* currentItem();
- HistoryItem* forwardItem();
- virtual HistoryItem* itemAtIndex(int) override;
-
- void backListWithLimit(int, HistoryItemVector&);
- void forwardListWithLimit(int, HistoryItemVector&);
-
- int capacity();
- void setCapacity(int);
- bool enabled();
- void setEnabled(bool);
- virtual int backListCount() override;
- virtual int forwardListCount() override;
- bool containsItem(HistoryItem*);
-
- virtual void close() override;
- bool closed();
-
- void removeItem(HistoryItem*);
- HistoryItemVector& entries();
-
-#if PLATFORM(IOS)
- virtual unsigned current() override;
- virtual void setCurrent(unsigned newCurrent) override;
-
- virtual bool clearAllPageCaches() override;
-#endif
-
-private:
- explicit BackForwardList(Page*);
-
- Page* m_page;
- HistoryItemVector m_entries;
- HistoryItemHashSet m_entryHash;
- unsigned m_current;
- unsigned m_capacity;
- bool m_closed;
- bool m_enabled;
-};
-
-} // namespace WebCore
-
-#endif // BackForwardList_h
diff --git a/Source/WebCore/history/CachedFrame.cpp b/Source/WebCore/history/CachedFrame.cpp
index 1f61671d7..210285243 100644
--- a/Source/WebCore/history/CachedFrame.cpp
+++ b/Source/WebCore/history/CachedFrame.cpp
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,44 +24,32 @@
*/
#include "config.h"
-#include "CachedPage.h"
+#include "CachedFrame.h"
-#include "AnimationController.h"
+#include "CSSAnimationController.h"
#include "CachedFramePlatformData.h"
+#include "CachedPage.h"
#include "DOMWindow.h"
#include "Document.h"
#include "DocumentLoader.h"
-#include "EventHandler.h"
-#include "EventNames.h"
-#include "ExceptionCode.h"
-#include "FocusController.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
#include "FrameView.h"
-#include "HistoryController.h"
-#include "HistoryItem.h"
#include "Logging.h"
#include "MainFrame.h"
#include "Page.h"
-#include "PageTransitionEvent.h"
+#include "PageCache.h"
+#include "SVGDocumentExtensions.h"
#include "ScriptController.h"
#include "SerializedScriptValue.h"
#include <wtf/RefCountedLeakCounter.h>
#include <wtf/text/CString.h>
-#if ENABLE(SVG)
-#include "SVGDocumentExtensions.h"
-#endif
-
-#if ENABLE(TOUCH_EVENTS)
+#if PLATFORM(IOS) || ENABLE(TOUCH_EVENTS)
#include "Chrome.h"
#include "ChromeClient.h"
#endif
-#if USE(ACCELERATED_COMPOSITING)
-#include "PageCache.h"
-#endif
-
namespace WebCore {
DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, cachedFrameCounter, ("CachedFrame"));
@@ -70,12 +58,8 @@ CachedFrameBase::CachedFrameBase(Frame& frame)
: m_document(frame.document())
, m_documentLoader(frame.loader().documentLoader())
, m_view(frame.view())
- , m_mousePressNode(frame.eventHandler().mousePressNode())
, m_url(frame.document()->url())
, m_isMainFrame(!frame.tree().parent())
-#if USE(ACCELERATED_COMPOSITING)
- , m_isComposited(frame.view()->hasCompositedContent())
-#endif
{
}
@@ -88,6 +72,17 @@ CachedFrameBase::~CachedFrameBase()
ASSERT(!m_document);
}
+void CachedFrameBase::pruneDetachedChildFrames()
+{
+ for (size_t i = m_childFrames.size(); i;) {
+ --i;
+ if (m_childFrames[i]->view()->frame().page())
+ continue;
+ m_childFrames[i]->destroy();
+ m_childFrames.remove(i);
+ }
+}
+
void CachedFrameBase::restore()
{
ASSERT(m_document->view() == m_view);
@@ -98,31 +93,27 @@ void CachedFrameBase::restore()
Frame& frame = m_view->frame();
m_cachedFrameScriptData->restore(frame);
-#if ENABLE(SVG)
if (m_document->svgExtensions())
- m_document->accessSVGExtensions()->unpauseAnimations();
-#endif
+ m_document->accessSVGExtensions().unpauseAnimations();
frame.animation().resumeAnimationsForDocument(m_document.get());
- frame.eventHandler().setMousePressNode(m_mousePressNode.get());
- m_document->resumeActiveDOMObjects(ActiveDOMObject::DocumentWillBecomeInactive);
- m_document->resumeScriptedAnimationControllerCallbacks();
+
+ m_document->resume(ActiveDOMObject::PageCache);
// It is necessary to update any platform script objects after restoring the
// cached page.
frame.script().updatePlatformScriptObjects();
-#if USE(ACCELERATED_COMPOSITING)
- if (m_isComposited)
- frame.view()->restoreBackingStores();
-#endif
-
frame.loader().client().didRestoreFromPageCache();
+ pruneDetachedChildFrames();
+
// Reconstruct the FrameTree. And open the child CachedFrames in their respective FrameLoaders.
- for (unsigned i = 0; i < m_childFrames.size(); ++i) {
- frame.tree().appendChild(&m_childFrames[i]->view()->frame());
- m_childFrames[i]->open();
+ for (auto& childFrame : m_childFrames) {
+ ASSERT(childFrame->view()->frame().page());
+ frame.tree().appendChild(childFrame->view()->frame());
+ childFrame->open();
+ ASSERT_WITH_SECURITY_IMPLICATION(m_document == frame.document());
}
#if PLATFORM(IOS)
@@ -131,25 +122,14 @@ void CachedFrameBase::restore()
if (DOMWindow* domWindow = m_document->domWindow()) {
// FIXME: Add SCROLL_LISTENER to the list of event types on Document, and use m_document->hasListenerType(). See <rdar://problem/9615482>.
+ // FIXME: Can use Document::hasListenerType() now.
if (domWindow->scrollEventListenerCount() && frame.page())
- frame.page()->chrome().client().setNeedsScrollNotifications(&frame, true);
+ frame.page()->chrome().client().setNeedsScrollNotifications(frame, true);
}
}
#endif
- // FIXME: update Page Visibility state here.
- // https://bugs.webkit.org/show_bug.cgi?id=116770
- m_document->enqueuePageshowEvent(PageshowEventPersisted);
-
- HistoryItem* historyItem = frame.loader().history().currentItem();
- m_document->enqueuePopstateEvent(historyItem && historyItem->stateObject() ? historyItem->stateObject() : SerializedScriptValue::nullValue());
-
-#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS)
- if (m_document->hasTouchEventHandlers())
- m_document->page()->chrome().client().needTouchEvents(true);
-#endif
-
- m_document->documentDidResumeFromPageCache();
+ frame.view()->didRestoreFromPageCache();
}
CachedFrame::CachedFrame(Frame& frame)
@@ -161,38 +141,21 @@ CachedFrame::CachedFrame(Frame& frame)
ASSERT(m_document);
ASSERT(m_documentLoader);
ASSERT(m_view);
-
- if (frame.page()->focusController().focusedFrame() == &frame)
- frame.page()->focusController().setFocusedFrame(&frame.mainFrame());
-
- // Custom scrollbar renderers will get reattached when the document comes out of the page cache
- m_view->detachCustomScrollbars();
-
- m_document->setInPageCache(true);
- frame.loader().stopLoading(UnloadEventPolicyUnloadAndPageHide);
+ ASSERT(m_document->pageCacheState() == Document::InPageCache);
// Create the CachedFrames for all Frames in the FrameTree.
for (Frame* child = frame.tree().firstChild(); child; child = child->tree().nextSibling())
m_childFrames.append(std::make_unique<CachedFrame>(*child));
- // Active DOM objects must be suspended before we cache the frame script data,
- // but after we've fired the pagehide event, in case that creates more objects.
- // Suspending must also happen after we've recursed over child frames, in case
- // those create more objects.
- m_document->documentWillSuspendForPageCache();
- m_document->suspendScriptedAnimationControllerCallbacks();
- m_document->suspendActiveDOMObjects(ActiveDOMObject::DocumentWillBecomeInactive);
+ // Active DOM objects must be suspended before we cache the frame script data.
+ m_document->suspend(ActiveDOMObject::PageCache);
+
m_cachedFrameScriptData = std::make_unique<ScriptCachedFrameData>(frame);
- m_document->domWindow()->suspendForPageCache();
+ m_document->domWindow()->suspendForDocumentSuspension();
frame.loader().client().savePlatformDataToCachedFrame(this);
-#if USE(ACCELERATED_COMPOSITING)
- if (m_isComposited && pageCache()->shouldClearBackingStores())
- frame.view()->clearBackingStores();
-#endif
-
// documentWillSuspendForPageCache() can set up a layout timer on the FrameView, so clear timers after that.
frame.clearTimers();
@@ -201,7 +164,7 @@ CachedFrame::CachedFrame(Frame& frame)
// 1 - We reuse the main frame, so when it navigates to a new page load it needs to start with a blank FrameTree.
// 2 - It's much easier to destroy a CachedFrame while it resides in the PageCache if it is disconnected from its parent.
for (unsigned i = 0; i < m_childFrames.size(); ++i)
- frame.tree().removeChild(&m_childFrames[i]->view()->frame());
+ frame.tree().removeChild(m_childFrames[i]->view()->frame());
if (!m_isMainFrame)
frame.page()->decrementSubframeCount();
@@ -219,18 +182,25 @@ CachedFrame::CachedFrame(Frame& frame)
if (m_isMainFrame) {
if (DOMWindow* domWindow = m_document->domWindow()) {
if (domWindow->scrollEventListenerCount() && frame.page())
- frame.page()->chrome().client().setNeedsScrollNotifications(&frame, false);
+ frame.page()->chrome().client().setNeedsScrollNotifications(frame, false);
}
}
#endif
+
+ m_document->detachFromCachedFrame(*this);
+
+ ASSERT_WITH_SECURITY_IMPLICATION(!m_documentLoader->isLoading());
}
void CachedFrame::open()
{
ASSERT(m_view);
+ ASSERT(m_document);
if (!m_isMainFrame)
m_view->frame().page()->incrementSubframeCount();
+ m_document->attachToCachedFrame(*this);
+
m_view->frame().loader().open(*this);
}
@@ -243,7 +213,7 @@ void CachedFrame::clear()
// This means the CachedFrame has been:
// 1 - Successfully restore()'d by going back/forward.
// 2 - destroy()'ed because the PageCache is pruning or the WebView was closed.
- ASSERT(!m_document->inPageCache());
+ ASSERT(m_document->pageCacheState() == Document::NotInPageCache);
ASSERT(m_view);
ASSERT(!m_document->frame() || m_document->frame() == &m_view->frame());
@@ -252,7 +222,6 @@ void CachedFrame::clear()
m_document = nullptr;
m_view = nullptr;
- m_mousePressNode = nullptr;
m_url = URL();
m_cachedFramePlatformData = nullptr;
@@ -265,15 +234,15 @@ void CachedFrame::destroy()
return;
// Only CachedFrames that are still in the PageCache should be destroyed in this manner
- ASSERT(m_document->inPageCache());
+ ASSERT(m_document->pageCacheState() == Document::InPageCache);
ASSERT(m_view);
- ASSERT(m_document->frame() == &m_view->frame());
+ ASSERT(!m_document->frame());
m_document->domWindow()->willDestroyCachedFrame();
- if (!m_isMainFrame) {
- m_view->frame().detachFromPage();
+ if (!m_isMainFrame && m_view->frame().page()) {
m_view->frame().loader().detachViewsAndDocumentLoader();
+ m_view->frame().detachFromPage();
}
for (int i = m_childFrames.size() - 1; i >= 0; --i)
@@ -284,11 +253,13 @@ void CachedFrame::destroy()
Frame::clearTimers(m_view.get(), m_document.get());
+ m_view->frame().animation().detachFromDocument(m_document.get());
+
// FIXME: Why do we need to call removeAllEventListeners here? When the document is in page cache, this method won't work
// fully anyway, because the document won't be able to access its DOMWindow object (due to being frameless).
m_document->removeAllEventListeners();
- m_document->setInPageCache(false);
+ m_document->setPageCacheState(Document::NotInPageCache);
m_document->prepareForDestruction();
clear();
@@ -296,7 +267,7 @@ void CachedFrame::destroy()
void CachedFrame::setCachedFramePlatformData(std::unique_ptr<CachedFramePlatformData> data)
{
- m_cachedFramePlatformData = std::move(data);
+ m_cachedFramePlatformData = WTFMove(data);
}
CachedFramePlatformData* CachedFrame::cachedFramePlatformData()
@@ -304,6 +275,11 @@ CachedFramePlatformData* CachedFrame::cachedFramePlatformData()
return m_cachedFramePlatformData.get();
}
+void CachedFrame::setHasInsecureContent(HasInsecureContent hasInsecureContent)
+{
+ m_hasInsecureContent = hasInsecureContent;
+}
+
int CachedFrame::descendantFrameCount() const
{
int count = m_childFrames.size();
diff --git a/Source/WebCore/history/CachedFrame.h b/Source/WebCore/history/CachedFrame.h
index e9f367bbd..e0be571a2 100644
--- a/Source/WebCore/history/CachedFrame.h
+++ b/Source/WebCore/history/CachedFrame.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,8 +23,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CachedFrame_h
-#define CachedFrame_h
+#pragma once
#include "DOMWindow.h"
#include "URL.h"
@@ -39,6 +38,7 @@ class Document;
class DocumentLoader;
class FrameView;
class Node;
+enum class HasInsecureContent;
class CachedFrameBase {
public:
@@ -52,23 +52,23 @@ public:
protected:
CachedFrameBase(Frame&);
~CachedFrameBase();
-
+
+ void pruneDetachedChildFrames();
+
RefPtr<Document> m_document;
RefPtr<DocumentLoader> m_documentLoader;
RefPtr<FrameView> m_view;
- RefPtr<Node> m_mousePressNode;
URL m_url;
std::unique_ptr<ScriptCachedFrameData> m_cachedFrameScriptData;
std::unique_ptr<CachedFramePlatformData> m_cachedFramePlatformData;
bool m_isMainFrame;
-#if USE(ACCELERATED_COMPOSITING)
- bool m_isComposited;
-#endif
-
+ std::optional<HasInsecureContent> m_hasInsecureContent;
+
Vector<std::unique_ptr<CachedFrame>> m_childFrames;
};
class CachedFrame : private CachedFrameBase {
+ WTF_MAKE_FAST_ALLOCATED;
public:
explicit CachedFrame(Frame&);
@@ -76,18 +76,18 @@ public:
void clear();
void destroy();
- void setCachedFramePlatformData(std::unique_ptr<CachedFramePlatformData>);
- CachedFramePlatformData* cachedFramePlatformData();
+ WEBCORE_EXPORT void setCachedFramePlatformData(std::unique_ptr<CachedFramePlatformData>);
+ WEBCORE_EXPORT CachedFramePlatformData* cachedFramePlatformData();
+
+ WEBCORE_EXPORT void setHasInsecureContent(HasInsecureContent);
+ std::optional<HasInsecureContent> hasInsecureContent() const { return m_hasInsecureContent; }
using CachedFrameBase::document;
using CachedFrameBase::view;
using CachedFrameBase::url;
DocumentLoader* documentLoader() const { return m_documentLoader.get(); }
- Node* mousePressNode() const { return m_mousePressNode.get(); }
int descendantFrameCount() const;
};
} // namespace WebCore
-
-#endif // CachedFrame_h
diff --git a/Source/WebCore/history/CachedFramePlatformData.h b/Source/WebCore/history/CachedFramePlatformData.h
index 01da8e5a6..56f4431b9 100644
--- a/Source/WebCore/history/CachedFramePlatformData.h
+++ b/Source/WebCore/history/CachedFramePlatformData.h
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -25,8 +25,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CachedFramePlatformData_h
-#define CachedFramePlatformData_h
+
+#pragma once
namespace WebCore {
@@ -41,5 +41,3 @@ public:
};
} // namespace WebCore
-
-#endif // CachedFramePlatformData_h
diff --git a/Source/WebCore/history/CachedPage.cpp b/Source/WebCore/history/CachedPage.cpp
index cad18497e..3ddd9c18d 100644
--- a/Source/WebCore/history/CachedPage.cpp
+++ b/Source/WebCore/history/CachedPage.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -30,9 +30,13 @@
#include "Element.h"
#include "FocusController.h"
#include "FrameView.h"
+#include "HistoryController.h"
+#include "HistoryItem.h"
#include "MainFrame.h"
+#include "NoEventDispatchAssertion.h"
#include "Node.h"
#include "Page.h"
+#include "PageTransitionEvent.h"
#include "Settings.h"
#include "VisitedLinkState.h"
#include <wtf/CurrentTime.h>
@@ -50,13 +54,9 @@ namespace WebCore {
DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, cachedPageCounter, ("CachedPage"));
CachedPage::CachedPage(Page& page)
- : m_timeStamp(monotonicallyIncreasingTime())
- , m_expirationTime(m_timeStamp + page.settings().backForwardCacheExpirationInterval())
+ : m_page(page)
+ , m_expirationTime(monotonicallyIncreasingTime() + page.settings().backForwardCacheExpirationInterval())
, m_cachedMainFrame(std::make_unique<CachedFrame>(page.mainFrame()))
- , m_needStyleRecalcForVisitedLinks(false)
- , m_needsFullStyleRecalc(false)
- , m_needsCaptionPreferencesChanged(false)
- , m_needsDeviceScaleChanged(false)
{
#ifndef NDEBUG
cachedPageCounter.increment();
@@ -69,8 +69,33 @@ CachedPage::~CachedPage()
cachedPageCounter.decrement();
#endif
- destroy();
- ASSERT(!m_cachedMainFrame);
+ if (m_cachedMainFrame)
+ m_cachedMainFrame->destroy();
+}
+
+static void firePageShowAndPopStateEvents(Page& page)
+{
+ // Dispatching JavaScript events can cause frame destruction.
+ auto& mainFrame = page.mainFrame();
+ Vector<Ref<Frame>> childFrames;
+ for (auto* child = mainFrame.tree().traverseNextInPostOrderWithWrap(true); child; child = child->tree().traverseNextInPostOrderWithWrap(false))
+ childFrames.append(*child);
+
+ for (auto& child : childFrames) {
+ if (!child->tree().isDescendantOf(&mainFrame))
+ continue;
+ auto* document = child->document();
+ if (!document)
+ continue;
+
+ // FIXME: Update Page Visibility state here.
+ // https://bugs.webkit.org/show_bug.cgi?id=116770
+ document->dispatchPageshowEvent(PageshowEventPersisted);
+
+ auto* historyItem = child->loader().history().currentItem();
+ if (historyItem && historyItem->stateObject())
+ document->dispatchPopstateEvent(historyItem->stateObject());
+ }
}
void CachedPage::restore(Page& page)
@@ -79,7 +104,13 @@ void CachedPage::restore(Page& page)
ASSERT(m_cachedMainFrame->view()->frame().isMainFrame());
ASSERT(!page.subframeCount());
- m_cachedMainFrame->open();
+ {
+ // Do not dispatch DOM events as their JavaScript listeners could cause the page to be put
+ // into the page cache before we have finished restoring it from the page cache.
+ NoEventDispatchAssertion noEventDispatchAssertion;
+
+ m_cachedMainFrame->open();
+ }
// Restore the focus appearance for the focused element.
// FIXME: Right now we don't support pages w/ frames in the b/f cache. This may need to be tweaked when we add support for that.
@@ -89,32 +120,39 @@ void CachedPage::restore(Page& page)
// We don't want focused nodes changing scroll position when restoring from the cache
// as it can cause ugly jumps before we manage to restore the cached position.
page.mainFrame().selection().suppressScrolling();
+
+ bool hadProhibitsScrolling = false;
+ FrameView* frameView = page.mainFrame().view();
+ if (frameView) {
+ hadProhibitsScrolling = frameView->prohibitsScrolling();
+ frameView->setProhibitsScrolling(true);
+ }
#endif
- element->updateFocusAppearance(true);
+ element->updateFocusAppearance(SelectionRestorationMode::Restore);
#if PLATFORM(IOS)
+ if (frameView)
+ frameView->setProhibitsScrolling(hadProhibitsScrolling);
page.mainFrame().selection().restoreScrolling();
#endif
}
- if (m_needStyleRecalcForVisitedLinks) {
- for (Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext())
- frame->document()->visitedLinkState().invalidateStyleForAllLinks();
- }
-
-#if USE(ACCELERATED_COMPOSITING)
- if (m_needsDeviceScaleChanged) {
+ if (m_needsDeviceOrPageScaleChanged)
page.mainFrame().deviceOrPageScaleFactorChanged();
- }
-#endif
- if (m_needsFullStyleRecalc)
- page.setNeedsRecalcStyleInAllFrames();
+ page.setNeedsRecalcStyleInAllFrames();
#if ENABLE(VIDEO_TRACK)
if (m_needsCaptionPreferencesChanged)
page.captionPreferencesChanged();
#endif
+ if (m_needsUpdateContentsSize) {
+ if (FrameView* frameView = page.mainFrame().view())
+ frameView->updateContentsSize();
+ }
+
+ firePageShowAndPopStateEvents(page);
+
clear();
}
@@ -122,17 +160,12 @@ void CachedPage::clear()
{
ASSERT(m_cachedMainFrame);
m_cachedMainFrame->clear();
- m_cachedMainFrame = 0;
- m_needStyleRecalcForVisitedLinks = false;
- m_needsFullStyleRecalc = false;
-}
-
-void CachedPage::destroy()
-{
- if (m_cachedMainFrame)
- m_cachedMainFrame->destroy();
-
- m_cachedMainFrame = 0;
+ m_cachedMainFrame = nullptr;
+#if ENABLE(VIDEO_TRACK)
+ m_needsCaptionPreferencesChanged = false;
+#endif
+ m_needsDeviceOrPageScaleChanged = false;
+ m_needsUpdateContentsSize = false;
}
bool CachedPage::hasExpired() const
diff --git a/Source/WebCore/history/CachedPage.h b/Source/WebCore/history/CachedPage.h
index bb83e0fff..73bdd5a9c 100644
--- a/Source/WebCore/history/CachedPage.h
+++ b/Source/WebCore/history/CachedPage.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,18 +23,18 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CachedPage_h
-#define CachedPage_h
+#pragma once
#include "CachedFrame.h"
namespace WebCore {
-
+
class Document;
class DocumentLoader;
class Page;
class CachedPage {
+ WTF_MAKE_FAST_ALLOCATED;
public:
explicit CachedPage(Page&);
~CachedPage();
@@ -42,37 +42,31 @@ public:
void restore(Page&);
void clear();
+ Page& page() const { return m_page; }
Document* document() const { return m_cachedMainFrame->document(); }
DocumentLoader* documentLoader() const { return m_cachedMainFrame->documentLoader(); }
- double timeStamp() const { return m_timeStamp; }
bool hasExpired() const;
CachedFrame* cachedMainFrame() { return m_cachedMainFrame.get(); }
- void markForVistedLinkStyleRecalc() { m_needStyleRecalcForVisitedLinks = true; }
- void markForFullStyleRecalc() { m_needsFullStyleRecalc = true; }
#if ENABLE(VIDEO_TRACK)
void markForCaptionPreferencesChanged() { m_needsCaptionPreferencesChanged = true; }
#endif
-#if USE(ACCELERATED_COMPOSITING)
- void markForDeviceScaleChanged() { m_needsDeviceScaleChanged = true; }
-#endif
+ void markForDeviceOrPageScaleChanged() { m_needsDeviceOrPageScaleChanged = true; }
-private:
- void destroy();
+ void markForContentsSizeChanged() { m_needsUpdateContentsSize = true; }
- double m_timeStamp;
+private:
+ Page& m_page;
double m_expirationTime;
std::unique_ptr<CachedFrame> m_cachedMainFrame;
- bool m_needStyleRecalcForVisitedLinks;
- bool m_needsFullStyleRecalc;
- bool m_needsCaptionPreferencesChanged;
- bool m_needsDeviceScaleChanged;
+#if ENABLE(VIDEO_TRACK)
+ bool m_needsCaptionPreferencesChanged { false };
+#endif
+ bool m_needsDeviceOrPageScaleChanged { false };
+ bool m_needsUpdateContentsSize { false };
};
} // namespace WebCore
-
-#endif // CachedPage_h
-
diff --git a/Source/WebCore/history/HistoryItem.cpp b/Source/WebCore/history/HistoryItem.cpp
index 8ce0841b9..7a5fbbb45 100644
--- a/Source/WebCore/history/HistoryItem.cpp
+++ b/Source/WebCore/history/HistoryItem.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005, 2006, 2008, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2005, 2006, 2008, 2011, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -37,14 +37,10 @@
#include <stdio.h>
#include <wtf/CurrentTime.h>
#include <wtf/DateMath.h>
-#include <wtf/Decoder.h>
-#include <wtf/Encoder.h>
#include <wtf/text/CString.h>
namespace WebCore {
-const uint32_t backForwardTreeEncodingVersion = 2;
-
static long long generateSequenceNumber()
{
// Initialize to the current time to reduce the likelihood of generating
@@ -57,7 +53,7 @@ static void defaultNotifyHistoryItemChanged(HistoryItem*)
{
}
-void (*notifyHistoryItemChanged)(HistoryItem*) = defaultNotifyHistoryItemChanged;
+WEBCORE_EXPORT void (*notifyHistoryItemChanged)(HistoryItem*) = defaultNotifyHistoryItemChanged;
HistoryItem::HistoryItem()
: m_pageScaleFactor(0)
@@ -65,13 +61,7 @@ HistoryItem::HistoryItem()
, m_isTargetItem(false)
, m_itemSequenceNumber(generateSequenceNumber())
, m_documentSequenceNumber(generateSequenceNumber())
- , m_next(0)
- , m_prev(0)
-#if PLATFORM(IOS)
- , m_scale(0)
- , m_scaleIsInitial(false)
- , m_bookmarkID(0)
-#endif
+ , m_pruningReason(PruningReason::None)
{
}
@@ -84,14 +74,8 @@ HistoryItem::HistoryItem(const String& urlString, const String& title)
, m_isTargetItem(false)
, m_itemSequenceNumber(generateSequenceNumber())
, m_documentSequenceNumber(generateSequenceNumber())
- , m_next(0)
- , m_prev(0)
-#if PLATFORM(IOS)
- , m_scale(0)
- , m_scaleIsInitial(false)
- , m_bookmarkID(0)
-#endif
-{
+ , m_pruningReason(PruningReason::None)
+{
iconDatabase().retainIconForPageURL(m_urlString);
}
@@ -105,39 +89,11 @@ HistoryItem::HistoryItem(const String& urlString, const String& title, const Str
, m_isTargetItem(false)
, m_itemSequenceNumber(generateSequenceNumber())
, m_documentSequenceNumber(generateSequenceNumber())
- , m_next(0)
- , m_prev(0)
-#if PLATFORM(IOS)
- , m_scale(0)
- , m_scaleIsInitial(false)
- , m_bookmarkID(0)
-#endif
+ , m_pruningReason(PruningReason::None)
{
iconDatabase().retainIconForPageURL(m_urlString);
}
-HistoryItem::HistoryItem(const URL& url, const String& target, const String& parent, const String& title)
- : m_urlString(url.string())
- , m_originalURLString(url.string())
- , m_target(target)
- , m_parent(parent)
- , m_title(title)
- , m_pageScaleFactor(0)
- , m_lastVisitWasFailure(false)
- , m_isTargetItem(false)
- , m_itemSequenceNumber(generateSequenceNumber())
- , m_documentSequenceNumber(generateSequenceNumber())
- , m_next(0)
- , m_prev(0)
-#if PLATFORM(IOS)
- , m_scale(0)
- , m_scaleIsInitial(false)
- , m_bookmarkID(0)
-#endif
-{
- iconDatabase().retainIconForPageURL(m_urlString);
-}
-
HistoryItem::~HistoryItem()
{
ASSERT(!m_cachedPage);
@@ -150,21 +106,20 @@ inline HistoryItem::HistoryItem(const HistoryItem& item)
, m_originalURLString(item.m_originalURLString)
, m_referrer(item.m_referrer)
, m_target(item.m_target)
- , m_parent(item.m_parent)
, m_title(item.m_title)
, m_displayTitle(item.m_displayTitle)
- , m_scrollPoint(item.m_scrollPoint)
+ , m_scrollPosition(item.m_scrollPosition)
, m_pageScaleFactor(item.m_pageScaleFactor)
, m_lastVisitWasFailure(item.m_lastVisitWasFailure)
, m_isTargetItem(item.m_isTargetItem)
, m_itemSequenceNumber(item.m_itemSequenceNumber)
, m_documentSequenceNumber(item.m_documentSequenceNumber)
, m_formContentType(item.m_formContentType)
+ , m_pruningReason(PruningReason::None)
#if PLATFORM(IOS)
+ , m_obscuredInset(item.m_obscuredInset)
, m_scale(item.m_scale)
, m_scaleIsInitial(item.m_scaleIsInitial)
- , m_bookmarkID(item.m_bookmarkID)
- , m_sharedLinkUniqueIdentifier(item.m_sharedLinkUniqueIdentifier)
#endif
{
if (item.m_formData)
@@ -174,14 +129,11 @@ inline HistoryItem::HistoryItem(const HistoryItem& item)
m_children.reserveInitialCapacity(size);
for (unsigned i = 0; i < size; ++i)
m_children.uncheckedAppend(item.m_children[i]->copy());
-
- if (item.m_redirectURLs)
- m_redirectURLs = std::make_unique<Vector<String>>(*item.m_redirectURLs);
}
-PassRefPtr<HistoryItem> HistoryItem::copy() const
+Ref<HistoryItem> HistoryItem::copy() const
{
- return adoptRef(new HistoryItem(*this));
+ return adoptRef(*new HistoryItem(*this));
}
void HistoryItem::reset()
@@ -192,21 +144,18 @@ void HistoryItem::reset()
m_originalURLString = String();
m_referrer = String();
m_target = String();
- m_parent = String();
m_title = String();
m_displayTitle = String();
m_lastVisitWasFailure = false;
m_isTargetItem = false;
- m_redirectURLs = nullptr;
-
m_itemSequenceNumber = generateSequenceNumber();
- m_stateObject = 0;
+ m_stateObject = nullptr;
m_documentSequenceNumber = generateSequenceNumber();
- m_formData = 0;
+ m_formData = nullptr;
m_formContentType = String();
clearChildren();
@@ -259,11 +208,6 @@ const String& HistoryItem::target() const
return m_target;
}
-const String& HistoryItem::parent() const
-{
- return m_parent;
-}
-
void HistoryItem::setAlternateTitle(const String& alternateTitle)
{
m_displayTitle = alternateTitle;
@@ -283,7 +227,7 @@ void HistoryItem::setURLString(const String& urlString)
void HistoryItem::setURL(const URL& url)
{
- pageCache()->remove(this);
+ PageCache::singleton().remove(*this);
setURLString(url.string());
clearDocumentState();
}
@@ -312,25 +256,19 @@ void HistoryItem::setTarget(const String& target)
notifyHistoryItemChanged(this);
}
-void HistoryItem::setParent(const String& parent)
-{
- m_parent = parent;
-}
-
-const IntPoint& HistoryItem::scrollPoint() const
+const IntPoint& HistoryItem::scrollPosition() const
{
- return m_scrollPoint;
+ return m_scrollPosition;
}
-void HistoryItem::setScrollPoint(const IntPoint& point)
+void HistoryItem::setScrollPosition(const IntPoint& position)
{
- m_scrollPoint = point;
+ m_scrollPosition = position;
}
-void HistoryItem::clearScrollPoint()
+void HistoryItem::clearScrollPosition()
{
- m_scrollPoint.setX(0);
- m_scrollPoint.setY(0);
+ m_scrollPosition = IntPoint();
}
float HistoryItem::pageScaleFactor() const
@@ -358,6 +296,16 @@ void HistoryItem::clearDocumentState()
m_documentState.clear();
}
+void HistoryItem::setShouldOpenExternalURLsPolicy(ShouldOpenExternalURLsPolicy policy)
+{
+ m_shouldOpenExternalURLsPolicy = policy;
+}
+
+ShouldOpenExternalURLsPolicy HistoryItem::shouldOpenExternalURLsPolicy() const
+{
+ return m_shouldOpenExternalURLsPolicy;
+}
+
bool HistoryItem::isTargetItem() const
{
return m_isTargetItem;
@@ -368,71 +316,52 @@ void HistoryItem::setIsTargetItem(bool flag)
m_isTargetItem = flag;
}
-void HistoryItem::setStateObject(PassRefPtr<SerializedScriptValue> object)
+void HistoryItem::setStateObject(RefPtr<SerializedScriptValue>&& object)
{
- m_stateObject = object;
+ m_stateObject = WTFMove(object);
}
-void HistoryItem::addChildItem(PassRefPtr<HistoryItem> child)
+void HistoryItem::addChildItem(Ref<HistoryItem>&& child)
{
ASSERT(!childItemWithTarget(child->target()));
- m_children.append(child);
+ m_children.append(WTFMove(child));
}
-void HistoryItem::setChildItem(PassRefPtr<HistoryItem> child)
+void HistoryItem::setChildItem(Ref<HistoryItem>&& child)
{
ASSERT(!child->isTargetItem());
unsigned size = m_children.size();
for (unsigned i = 0; i < size; ++i) {
if (m_children[i]->target() == child->target()) {
child->setIsTargetItem(m_children[i]->isTargetItem());
- m_children[i] = child;
+ m_children[i] = WTFMove(child);
return;
}
}
- m_children.append(child);
+ m_children.append(WTFMove(child));
}
-HistoryItem* HistoryItem::childItemWithTarget(const String& target) const
+HistoryItem* HistoryItem::childItemWithTarget(const String& target)
{
unsigned size = m_children.size();
for (unsigned i = 0; i < size; ++i) {
if (m_children[i]->target() == target)
- return m_children[i].get();
+ return m_children[i].ptr();
}
- return 0;
+ return nullptr;
}
-HistoryItem* HistoryItem::childItemWithDocumentSequenceNumber(long long number) const
+HistoryItem* HistoryItem::childItemWithDocumentSequenceNumber(long long number)
{
unsigned size = m_children.size();
for (unsigned i = 0; i < size; ++i) {
if (m_children[i]->documentSequenceNumber() == number)
- return m_children[i].get();
+ return m_children[i].ptr();
}
- return 0;
-}
-
-// <rdar://problem/4895849> HistoryItem::findTargetItem() should be replaced with a non-recursive method.
-HistoryItem* HistoryItem::findTargetItem()
-{
- if (m_isTargetItem)
- return this;
- unsigned size = m_children.size();
- for (unsigned i = 0; i < size; ++i) {
- if (HistoryItem* match = m_children[i]->targetItem())
- return match;
- }
- return 0;
-}
-
-HistoryItem* HistoryItem::targetItem()
-{
- HistoryItem* foundItem = findTargetItem();
- return foundItem ? foundItem : this;
+ return nullptr;
}
-const HistoryItemVector& HistoryItem::children() const
+const Vector<Ref<HistoryItem>>& HistoryItem::children() const
{
return m_children;
}
@@ -447,49 +376,37 @@ void HistoryItem::clearChildren()
m_children.clear();
}
-bool HistoryItem::isAncestorOf(const HistoryItem* item) const
-{
- for (size_t i = 0; i < m_children.size(); ++i) {
- HistoryItem* child = m_children[i].get();
- if (child == item)
- return true;
- if (child->isAncestorOf(item))
- return true;
- }
- return false;
-}
-
// We do same-document navigation if going to a different item and if either of the following is true:
// - The other item corresponds to the same document (for history entries created via pushState or fragment changes).
// - The other item corresponds to the same set of documents, including frames (for history entries created via regular navigation)
-bool HistoryItem::shouldDoSameDocumentNavigationTo(HistoryItem* otherItem) const
+bool HistoryItem::shouldDoSameDocumentNavigationTo(HistoryItem& otherItem) const
{
- if (this == otherItem)
+ if (this == &otherItem)
return false;
- if (stateObject() || otherItem->stateObject())
- return documentSequenceNumber() == otherItem->documentSequenceNumber();
+ if (stateObject() || otherItem.stateObject())
+ return documentSequenceNumber() == otherItem.documentSequenceNumber();
- if ((url().hasFragmentIdentifier() || otherItem->url().hasFragmentIdentifier()) && equalIgnoringFragmentIdentifier(url(), otherItem->url()))
- return documentSequenceNumber() == otherItem->documentSequenceNumber();
+ if ((url().hasFragmentIdentifier() || otherItem.url().hasFragmentIdentifier()) && equalIgnoringFragmentIdentifier(url(), otherItem.url()))
+ return documentSequenceNumber() == otherItem.documentSequenceNumber();
return hasSameDocumentTree(otherItem);
}
// Does a recursive check that this item and its descendants have the same
// document sequence numbers as the other item.
-bool HistoryItem::hasSameDocumentTree(HistoryItem* otherItem) const
+bool HistoryItem::hasSameDocumentTree(HistoryItem& otherItem) const
{
- if (documentSequenceNumber() != otherItem->documentSequenceNumber())
+ if (documentSequenceNumber() != otherItem.documentSequenceNumber())
return false;
- if (children().size() != otherItem->children().size())
+ if (children().size() != otherItem.children().size())
return false;
for (size_t i = 0; i < children().size(); i++) {
- HistoryItem* child = children()[i].get();
- HistoryItem* otherChild = otherItem->childItemWithDocumentSequenceNumber(child->documentSequenceNumber());
- if (!otherChild || !child->hasSameDocumentTree(otherChild))
+ auto& child = children()[i].get();
+ auto* otherChild = otherItem.childItemWithDocumentSequenceNumber(child.documentSequenceNumber());
+ if (!otherChild || !child.hasSameDocumentTree(*otherChild))
return false;
}
@@ -498,16 +415,16 @@ bool HistoryItem::hasSameDocumentTree(HistoryItem* otherItem) const
// Does a non-recursive check that this item and its immediate children have the
// same frames as the other item.
-bool HistoryItem::hasSameFrames(HistoryItem* otherItem) const
+bool HistoryItem::hasSameFrames(HistoryItem& otherItem) const
{
- if (target() != otherItem->target())
+ if (target() != otherItem.target())
return false;
- if (children().size() != otherItem->children().size())
+ if (children().size() != otherItem.children().size())
return false;
for (size_t i = 0; i < children().size(); i++) {
- if (!otherItem->childItemWithTarget(children()[i]->target()))
+ if (!otherItem.childItemWithTarget(children()[i]->target()))
return false;
}
@@ -523,20 +440,20 @@ void HistoryItem::setFormInfoFromRequest(const ResourceRequest& request)
{
m_referrer = request.httpReferrer();
- if (equalIgnoringCase(request.httpMethod(), "POST")) {
+ if (equalLettersIgnoringASCIICase(request.httpMethod(), "post")) {
// FIXME: Eventually we have to make this smart enough to handle the case where
// we have a stream for the body to handle the "data interspersed with files" feature.
m_formData = request.httpBody();
m_formContentType = request.httpContentType();
} else {
- m_formData = 0;
+ m_formData = nullptr;
m_formContentType = String();
}
}
-void HistoryItem::setFormData(PassRefPtr<FormData> formData)
+void HistoryItem::setFormData(RefPtr<FormData>&& formData)
{
- m_formData = formData;
+ m_formData = WTFMove(formData);
}
void HistoryItem::setFormContentType(const String& formContentType)
@@ -549,266 +466,15 @@ FormData* HistoryItem::formData()
return m_formData.get();
}
-bool HistoryItem::isCurrentDocument(Document* doc) const
+bool HistoryItem::isCurrentDocument(Document& document) const
{
// FIXME: We should find a better way to check if this is the current document.
- return equalIgnoringFragmentIdentifier(url(), doc->url());
-}
-
-void HistoryItem::addRedirectURL(const String& url)
-{
- if (!m_redirectURLs)
- m_redirectURLs = std::make_unique<Vector<String>>();
-
- // Our API allows us to store all the URLs in the redirect chain, but for
- // now we only have a use for the final URL.
- (*m_redirectURLs).resize(1);
- (*m_redirectURLs)[0] = url;
-}
-
-Vector<String>* HistoryItem::redirectURLs() const
-{
- return m_redirectURLs.get();
-}
-
-void HistoryItem::setRedirectURLs(std::unique_ptr<Vector<String>> redirectURLs)
-{
- m_redirectURLs = std::move(redirectURLs);
-}
-
-void HistoryItem::encodeBackForwardTree(Encoder& encoder) const
-{
- encoder.encodeUInt32(backForwardTreeEncodingVersion);
-
- encodeBackForwardTreeNode(encoder);
-}
-
-void HistoryItem::encodeBackForwardTree(KeyedEncoder& encoder) const
-{
- encoder.encodeUInt32("version", backForwardTreeEncodingVersion);
-
- encoder.encodeObject("root", *this, [](KeyedEncoder& encoder, const HistoryItem& item) {
- item.encodeBackForwardTreeNode(encoder);
- });
+ return equalIgnoringFragmentIdentifier(url(), document.url());
}
-void HistoryItem::encodeBackForwardTreeNode(Encoder& encoder) const
+void HistoryItem::notifyChanged()
{
- size_t size = m_children.size();
- encoder.encodeUInt64(size);
- for (size_t i = 0; i < size; ++i) {
- const HistoryItem& child = *m_children[i];
-
- encoder.encodeString(child.m_originalURLString);
-
- encoder.encodeString(child.m_urlString);
-
- child.encodeBackForwardTreeNode(encoder);
- }
-
- encoder.encodeInt64(m_documentSequenceNumber);
-
- size = m_documentState.size();
- encoder.encodeUInt64(size);
- for (size_t i = 0; i < size; ++i)
- encoder.encodeString(m_documentState[i]);
-
- encoder.encodeString(m_formContentType);
-
- encoder.encodeBool(m_formData);
- if (m_formData)
- m_formData->encode(encoder);
-
- encoder.encodeInt64(m_itemSequenceNumber);
-
- encoder.encodeString(m_referrer);
-
- encoder.encodeInt32(m_scrollPoint.x());
- encoder.encodeInt32(m_scrollPoint.y());
-
- encoder.encodeFloat(m_pageScaleFactor);
-
- encoder.encodeBool(m_stateObject);
- if (m_stateObject)
- encoder.encodeBytes(m_stateObject->data().data(), m_stateObject->data().size());
-
- encoder.encodeString(m_target);
-}
-
-void HistoryItem::encodeBackForwardTreeNode(KeyedEncoder& encoder) const
-{
- encoder.encodeObjects("children", m_children.begin(), m_children.end(), [](KeyedEncoder& encoder, const RefPtr<HistoryItem>& child) {
- encoder.encodeString("originalURLString", child->m_originalURLString);
- encoder.encodeString("urlString", child->m_urlString);
-
- child->encodeBackForwardTreeNode(encoder);
- });
-
- encoder.encodeInt64("documentSequenceNumber", m_documentSequenceNumber);
-
- encoder.encodeObjects("documentState", m_documentState.begin(), m_documentState.end(), [](KeyedEncoder& encoder, const String& string) {
- encoder.encodeString("string", string);
- });
-
- encoder.encodeString("formContentType", m_formContentType);
-
- encoder.encodeConditionalObject("formData", m_formData.get(), [](KeyedEncoder&, const FormData&) {
- // FIXME: Implement.
- });
-
- encoder.encodeInt64("itemSequenceNumber", m_itemSequenceNumber);
-
- encoder.encodeString("referrer", m_referrer);
-
- encoder.encodeObject("scrollPoint", m_scrollPoint, [](KeyedEncoder& encoder, const IntPoint& scrollPoint) {
- encoder.encodeInt32("x", scrollPoint.x());
- encoder.encodeInt32("y", scrollPoint.y());
- });
-
- encoder.encodeFloat("pageScaleFactor", m_pageScaleFactor);
-
- encoder.encodeConditionalObject("stateObject", m_stateObject.get(), [](KeyedEncoder& encoder, const SerializedScriptValue& stateObject) {
- encoder.encodeBytes("data", stateObject.data().data(), stateObject.data().size());
- });
-
- encoder.encodeString("target", m_target);
-}
-
-struct DecodeRecursionStackElement {
- RefPtr<HistoryItem> node;
- size_t i;
- uint64_t size;
-
- DecodeRecursionStackElement(PassRefPtr<HistoryItem> node, size_t i, uint64_t size)
- : node(node)
- , i(i)
- , size(size)
- {
- }
-};
-
-PassRefPtr<HistoryItem> HistoryItem::decodeBackForwardTree(const String& topURLString, const String& topTitle, const String& topOriginalURLString, Decoder& decoder)
-{
- // Since the data stream is not trusted, the decode has to be non-recursive.
- // We don't want bad data to cause a stack overflow.
-
- uint32_t version;
- if (!decoder.decodeUInt32(version))
- return 0;
- if (version != backForwardTreeEncodingVersion)
- return 0;
-
- String urlString = topURLString;
- String title = topTitle;
- String originalURLString = topOriginalURLString;
-
- Vector<DecodeRecursionStackElement, 16> recursionStack;
-
-recurse:
- RefPtr<HistoryItem> node = create(urlString, title);
-
- node->setOriginalURLString(originalURLString);
-
- title = String();
-
- uint64_t size;
- if (!decoder.decodeUInt64(size))
- return 0;
- size_t i;
- RefPtr<HistoryItem> child;
- for (i = 0; i < size; ++i) {
- if (!decoder.decodeString(originalURLString))
- return 0;
-
- if (!decoder.decodeString(urlString))
- return 0;
-
- recursionStack.append(DecodeRecursionStackElement(node.release(), i, size));
- goto recurse;
-
-resume:
- node->m_children.append(child.release());
- }
-
- if (!decoder.decodeInt64(node->m_documentSequenceNumber))
- return 0;
-
- if (!decoder.decodeUInt64(size))
- return 0;
- for (i = 0; i < size; ++i) {
- String state;
- if (!decoder.decodeString(state))
- return 0;
- node->m_documentState.append(state);
- }
-
- if (!decoder.decodeString(node->m_formContentType))
- return 0;
-
- bool hasFormData;
- if (!decoder.decodeBool(hasFormData))
- return 0;
- if (hasFormData) {
- node->m_formData = FormData::decode(decoder);
- if (!node->m_formData)
- return 0;
- }
-
- if (!decoder.decodeInt64(node->m_itemSequenceNumber))
- return 0;
-
- if (!decoder.decodeString(node->m_referrer))
- return 0;
-
- int32_t x;
- if (!decoder.decodeInt32(x))
- return 0;
- int32_t y;
- if (!decoder.decodeInt32(y))
- return 0;
- node->m_scrollPoint = IntPoint(x, y);
-
- if (!decoder.decodeFloat(node->m_pageScaleFactor))
- return 0;
-
- bool hasStateObject;
- if (!decoder.decodeBool(hasStateObject))
- return 0;
- if (hasStateObject) {
- Vector<uint8_t> bytes;
- if (!decoder.decodeBytes(bytes))
- return 0;
- node->m_stateObject = SerializedScriptValue::adopt(bytes);
- }
-
- if (!decoder.decodeString(node->m_target))
- return 0;
-
- // Simulate recursion with our own stack.
- if (!recursionStack.isEmpty()) {
- DecodeRecursionStackElement& element = recursionStack.last();
- child = node.release();
- node = element.node.release();
- i = element.i;
- size = element.size;
- recursionStack.removeLast();
- goto resume;
- }
-
- return node.release();
-}
-
-PassRefPtr<HistoryItem> HistoryItem::decodeBackForwardTree(const String&, const String&, const String&, KeyedDecoder& decoder)
-{
- uint32_t version;
- if (!decoder.decodeUInt32("version", version))
- return nullptr;
-
- if (version != backForwardTreeEncodingVersion)
- return nullptr;
-
- // FIXME: Implement.
- return nullptr;
+ notifyHistoryItemChanged(this);
}
#ifndef NDEBUG
diff --git a/Source/WebCore/history/HistoryItem.h b/Source/WebCore/history/HistoryItem.h
index 9ae72afa0..60b0b8c5a 100644
--- a/Source/WebCore/history/HistoryItem.h
+++ b/Source/WebCore/history/HistoryItem.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2008, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2008, 2011, 2014 Apple Inc. All rights reserved.
* Copyright (C) 2012 Research In Motion Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -11,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -24,10 +24,12 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HistoryItem_h
-#define HistoryItem_h
+#pragma once
+#include "FloatRect.h"
+#include "FrameLoaderTypes.h"
#include "IntPoint.h"
+#include "IntRect.h"
#include "SerializedScriptValue.h"
#include <memory>
#include <wtf/RefCounted.h>
@@ -37,7 +39,7 @@
#include "ViewportArguments.h"
#endif
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
#import <wtf/RetainPtr.h>
typedef struct objc_object* id;
#endif
@@ -49,89 +51,78 @@ class Document;
class FormData;
class HistoryItem;
class Image;
-class KeyedDecoder;
-class KeyedEncoder;
class ResourceRequest;
class URL;
+enum class PruningReason;
-typedef Vector<RefPtr<HistoryItem>> HistoryItemVector;
-
-extern void (*notifyHistoryItemChanged)(HistoryItem*);
+WEBCORE_EXPORT extern void (*notifyHistoryItemChanged)(HistoryItem*);
class HistoryItem : public RefCounted<HistoryItem> {
friend class PageCache;
public:
- static PassRefPtr<HistoryItem> create() { return adoptRef(new HistoryItem); }
- static PassRefPtr<HistoryItem> create(const String& urlString, const String& title)
- {
- return adoptRef(new HistoryItem(urlString, title));
- }
- static PassRefPtr<HistoryItem> create(const String& urlString, const String& title, const String& alternateTitle)
+ static Ref<HistoryItem> create() { return adoptRef(*new HistoryItem); }
+ static Ref<HistoryItem> create(const String& urlString, const String& title)
{
- return adoptRef(new HistoryItem(urlString, title, alternateTitle));
+ return adoptRef(*new HistoryItem(urlString, title));
}
- static PassRefPtr<HistoryItem> create(const URL& url, const String& target, const String& parent, const String& title)
+ static Ref<HistoryItem> create(const String& urlString, const String& title, const String& alternateTitle)
{
- return adoptRef(new HistoryItem(url, target, parent, title));
+ return adoptRef(*new HistoryItem(urlString, title, alternateTitle));
}
- ~HistoryItem();
+ WEBCORE_EXPORT ~HistoryItem();
- PassRefPtr<HistoryItem> copy() const;
+ WEBCORE_EXPORT Ref<HistoryItem> copy() const;
// Resets the HistoryItem to its initial state, as returned by create().
void reset();
- void encodeBackForwardTree(Encoder&) const;
- void encodeBackForwardTree(KeyedEncoder&) const;
- static PassRefPtr<HistoryItem> decodeBackForwardTree(const String& urlString, const String& title, const String& originalURLString, Decoder&);
- static PassRefPtr<HistoryItem> decodeBackForwardTree(const String& urlString, const String& title, const String& originalURLString, KeyedDecoder&);
-
- const String& originalURLString() const;
- const String& urlString() const;
- const String& title() const;
+ WEBCORE_EXPORT const String& originalURLString() const;
+ WEBCORE_EXPORT const String& urlString() const;
+ WEBCORE_EXPORT const String& title() const;
bool isInPageCache() const { return m_cachedPage.get(); }
- bool hasCachedPageExpired() const;
+ WEBCORE_EXPORT bool hasCachedPageExpired() const;
- void setAlternateTitle(const String& alternateTitle);
- const String& alternateTitle() const;
+ WEBCORE_EXPORT void setAlternateTitle(const String&);
+ WEBCORE_EXPORT const String& alternateTitle() const;
- const String& parent() const;
- URL url() const;
- URL originalURL() const;
- const String& referrer() const;
- const String& target() const;
- bool isTargetItem() const;
+ WEBCORE_EXPORT URL url() const;
+ WEBCORE_EXPORT URL originalURL() const;
+ WEBCORE_EXPORT const String& referrer() const;
+ WEBCORE_EXPORT const String& target() const;
+ WEBCORE_EXPORT bool isTargetItem() const;
- FormData* formData();
- String formContentType() const;
+ WEBCORE_EXPORT FormData* formData();
+ WEBCORE_EXPORT String formContentType() const;
bool lastVisitWasFailure() const { return m_lastVisitWasFailure; }
- const IntPoint& scrollPoint() const;
- void setScrollPoint(const IntPoint&);
- void clearScrollPoint();
+ WEBCORE_EXPORT const IntPoint& scrollPosition() const;
+ WEBCORE_EXPORT void setScrollPosition(const IntPoint&);
+ void clearScrollPosition();
- float pageScaleFactor() const;
- void setPageScaleFactor(float);
+ WEBCORE_EXPORT float pageScaleFactor() const;
+ WEBCORE_EXPORT void setPageScaleFactor(float);
- const Vector<String>& documentState() const;
- void setDocumentState(const Vector<String>&);
+ WEBCORE_EXPORT const Vector<String>& documentState() const;
+ WEBCORE_EXPORT void setDocumentState(const Vector<String>&);
void clearDocumentState();
+ WEBCORE_EXPORT void setShouldOpenExternalURLsPolicy(ShouldOpenExternalURLsPolicy);
+ WEBCORE_EXPORT ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy() const;
+
void setURL(const URL&);
- void setURLString(const String&);
- void setOriginalURLString(const String&);
- void setReferrer(const String&);
- void setTarget(const String&);
- void setParent(const String&);
- void setTitle(const String&);
- void setIsTargetItem(bool);
+ WEBCORE_EXPORT void setURLString(const String&);
+ WEBCORE_EXPORT void setOriginalURLString(const String&);
+ WEBCORE_EXPORT void setReferrer(const String&);
+ WEBCORE_EXPORT void setTarget(const String&);
+ WEBCORE_EXPORT void setTitle(const String&);
+ WEBCORE_EXPORT void setIsTargetItem(bool);
- void setStateObject(PassRefPtr<SerializedScriptValue> object);
- PassRefPtr<SerializedScriptValue> stateObject() const { return m_stateObject; }
+ WEBCORE_EXPORT void setStateObject(RefPtr<SerializedScriptValue>&&);
+ SerializedScriptValue* stateObject() const { return m_stateObject.get(); }
void setItemSequenceNumber(long long number) { m_itemSequenceNumber = number; }
long long itemSequenceNumber() const { return m_itemSequenceNumber; }
@@ -140,38 +131,32 @@ public:
long long documentSequenceNumber() const { return m_documentSequenceNumber; }
void setFormInfoFromRequest(const ResourceRequest&);
- void setFormData(PassRefPtr<FormData>);
- void setFormContentType(const String&);
+ WEBCORE_EXPORT void setFormData(RefPtr<FormData>&&);
+ WEBCORE_EXPORT void setFormContentType(const String&);
void setLastVisitWasFailure(bool wasFailure) { m_lastVisitWasFailure = wasFailure; }
- void addChildItem(PassRefPtr<HistoryItem>);
- void setChildItem(PassRefPtr<HistoryItem>);
- HistoryItem* childItemWithTarget(const String&) const;
- HistoryItem* childItemWithDocumentSequenceNumber(long long number) const;
- HistoryItem* targetItem();
- const HistoryItemVector& children() const;
- bool hasChildren() const;
+ WEBCORE_EXPORT void addChildItem(Ref<HistoryItem>&&);
+ void setChildItem(Ref<HistoryItem>&&);
+ WEBCORE_EXPORT HistoryItem* childItemWithTarget(const String&);
+ HistoryItem* childItemWithDocumentSequenceNumber(long long number);
+ WEBCORE_EXPORT const Vector<Ref<HistoryItem>>& children() const;
+ WEBCORE_EXPORT bool hasChildren() const;
void clearChildren();
- bool isAncestorOf(const HistoryItem*) const;
- bool shouldDoSameDocumentNavigationTo(HistoryItem* otherItem) const;
- bool hasSameFrames(HistoryItem* otherItem) const;
-
- void addRedirectURL(const String&);
- Vector<String>* redirectURLs() const;
- void setRedirectURLs(std::unique_ptr<Vector<String>>);
+ bool shouldDoSameDocumentNavigationTo(HistoryItem& otherItem) const;
+ bool hasSameFrames(HistoryItem& otherItem) const;
- bool isCurrentDocument(Document*) const;
+ bool isCurrentDocument(Document&) const;
-#if PLATFORM(MAC)
- id viewState() const;
- void setViewState(id);
+#if PLATFORM(COCOA)
+ WEBCORE_EXPORT id viewState() const;
+ WEBCORE_EXPORT void setViewState(id);
// Transient properties may be of any ObjC type. They are intended to be used to store state per back/forward list entry.
// The properties will not be persisted; when the history item is removed, the properties will be lost.
- id getTransientProperty(const String&) const;
- void setTransientProperty(const String&, id);
+ WEBCORE_EXPORT id getTransientProperty(const String&) const;
+ WEBCORE_EXPORT void setTransientProperty(const String&, id);
#endif
#ifndef NDEBUG
@@ -180,8 +165,24 @@ public:
#endif
#if PLATFORM(IOS)
+ FloatRect exposedContentRect() const { return m_exposedContentRect; }
+ void setExposedContentRect(FloatRect exposedContentRect) { m_exposedContentRect = exposedContentRect; }
+
+ IntRect unobscuredContentRect() const { return m_unobscuredContentRect; }
+ void setUnobscuredContentRect(IntRect unobscuredContentRect) { m_unobscuredContentRect = unobscuredContentRect; }
+
+ FloatSize obscuredInset() const { return m_obscuredInset; }
+ void setObscuredInset(const FloatSize& inset) { m_obscuredInset = inset; }
+
+ FloatSize minimumLayoutSizeInScrollViewCoordinates() const { return m_minimumLayoutSizeInScrollViewCoordinates; }
+ void setMinimumLayoutSizeInScrollViewCoordinates(FloatSize minimumLayoutSizeInScrollViewCoordinates) { m_minimumLayoutSizeInScrollViewCoordinates = minimumLayoutSizeInScrollViewCoordinates; }
+
+ IntSize contentSize() const { return m_contentSize; }
+ void setContentSize(IntSize contentSize) { m_contentSize = contentSize; }
+
float scale() const { return m_scale; }
bool scaleIsInitial() const { return m_scaleIsInitial; }
+ void setScaleIsInitial(bool scaleIsInitial) { m_scaleIsInitial = scaleIsInitial; }
void setScale(float newScale, bool isInitial)
{
m_scale = newScale;
@@ -190,46 +191,40 @@ public:
const ViewportArguments& viewportArguments() const { return m_viewportArguments; }
void setViewportArguments(const ViewportArguments& viewportArguments) { m_viewportArguments = viewportArguments; }
-
- uint32_t bookmarkID() const { return m_bookmarkID; }
- void setBookmarkID(uint32_t bookmarkID) { m_bookmarkID = bookmarkID; }
- String sharedLinkUniqueIdentifier() const { return m_sharedLinkUniqueIdentifier; }
- void setSharedLinkUniqueIdentifier(const String& sharedLinkUniqueidentifier) { m_sharedLinkUniqueIdentifier = sharedLinkUniqueidentifier; }
#endif
-private:
- HistoryItem();
- HistoryItem(const String& urlString, const String& title);
- HistoryItem(const String& urlString, const String& title, const String& alternateTitle);
- HistoryItem(const URL& url, const String& frameName, const String& parent, const String& title);
+ void notifyChanged();
- explicit HistoryItem(const HistoryItem&);
+ void setWasRestoredFromSession(bool wasRestoredFromSession) { m_wasRestoredFromSession = wasRestoredFromSession; }
+ bool wasRestoredFromSession() const { return m_wasRestoredFromSession; }
- bool hasSameDocumentTree(HistoryItem* otherItem) const;
+private:
+ WEBCORE_EXPORT HistoryItem();
+ WEBCORE_EXPORT HistoryItem(const String& urlString, const String& title);
+ WEBCORE_EXPORT HistoryItem(const String& urlString, const String& title, const String& alternateTitle);
- HistoryItem* findTargetItem();
+ HistoryItem(const HistoryItem&);
- void encodeBackForwardTreeNode(Encoder&) const;
- void encodeBackForwardTreeNode(KeyedEncoder&) const;
+ bool hasSameDocumentTree(HistoryItem& otherItem) const;
String m_urlString;
String m_originalURLString;
String m_referrer;
String m_target;
- String m_parent;
String m_title;
String m_displayTitle;
- IntPoint m_scrollPoint;
+ IntPoint m_scrollPosition;
float m_pageScaleFactor;
Vector<String> m_documentState;
+
+ ShouldOpenExternalURLsPolicy m_shouldOpenExternalURLsPolicy { ShouldOpenExternalURLsPolicy::ShouldNotAllow };
- HistoryItemVector m_children;
+ Vector<Ref<HistoryItem>> m_children;
bool m_lastVisitWasFailure;
bool m_isTargetItem;
-
- std::unique_ptr<Vector<String>> m_redirectURLs;
+ bool m_wasRestoredFromSession { false };
// If two HistoryItems have the same item sequence number, then they are
// clones of one another. Traversing history from one such HistoryItem to
@@ -250,30 +245,29 @@ private:
String m_formContentType;
// PageCache controls these fields.
- HistoryItem* m_next;
- HistoryItem* m_prev;
std::unique_ptr<CachedPage> m_cachedPage;
+ PruningReason m_pruningReason;
#if PLATFORM(IOS)
- float m_scale;
- bool m_scaleIsInitial;
+ FloatRect m_exposedContentRect;
+ IntRect m_unobscuredContentRect;
+ FloatSize m_minimumLayoutSizeInScrollViewCoordinates;
+ IntSize m_contentSize;
+ FloatSize m_obscuredInset;
+ float m_scale { 0 }; // Note that UIWebView looks for a non-zero value, so this has to start as 0.
+ bool m_scaleIsInitial { false };
ViewportArguments m_viewportArguments;
-
- uint32_t m_bookmarkID;
- String m_sharedLinkUniqueIdentifier;
#endif
-#if PLATFORM(MAC)
+#if PLATFORM(COCOA)
RetainPtr<id> m_viewState;
std::unique_ptr<HashMap<String, RetainPtr<id>>> m_transientProperties;
#endif
-}; //class HistoryItem
+};
-} //namespace WebCore
+} // namespace WebCore
-#ifndef NDEBUG
-// Outside the WebCore namespace for ease of invocation from gdb.
+#if ENABLE(TREE_DEBUGGING)
+// Outside the WebCore namespace for ease of invocation from the debugger.
extern "C" int showTree(const WebCore::HistoryItem*);
#endif
-
-#endif // HISTORYITEM_H
diff --git a/Source/WebCore/history/PageCache.cpp b/Source/WebCore/history/PageCache.cpp
index 57ec24efb..02f8ff418 100644
--- a/Source/WebCore/history/PageCache.cpp
+++ b/Source/WebCore/history/PageCache.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2014, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -28,28 +28,29 @@
#include "ApplicationCacheHost.h"
#include "BackForwardController.h"
-#include "MemoryCache.h"
#include "CachedPage.h"
#include "DOMWindow.h"
-#include "DatabaseManager.h"
#include "DeviceMotionController.h"
#include "DeviceOrientationController.h"
+#include "DiagnosticLoggingClient.h"
+#include "DiagnosticLoggingKeys.h"
#include "Document.h"
#include "DocumentLoader.h"
+#include "FocusController.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
-#include "FrameLoaderStateMachine.h"
#include "FrameView.h"
-#include "HistogramSupport.h"
#include "HistoryController.h"
-#include "HistoryItem.h"
+#include "IgnoreOpensDuringUnloadCountIncrementer.h"
#include "Logging.h"
#include "MainFrame.h"
+#include "MemoryPressureHandler.h"
+#include "NoEventDispatchAssertion.h"
#include "Page.h"
#include "Settings.h"
-#include "SharedWorkerRepository.h"
#include "SubframeLoader.h"
-#include <wtf/CurrentTime.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/SetForScope.h>
#include <wtf/text/CString.h>
#include <wtf/text/StringConcatenate.h>
@@ -57,514 +58,448 @@
#include "DeviceProximityController.h"
#endif
-#if PLATFORM(IOS)
-#include "MemoryPressureHandler.h"
-#endif
-
namespace WebCore {
-#if !defined(NDEBUG)
-
#define PCLOG(...) LOG(PageCache, "%*s%s", indentLevel*4, "", makeString(__VA_ARGS__).utf8().data())
-
-// Used in histograms, please only add at the end, and do not remove elements (renaming e.g. to "FooEnumUnused1" is fine).
-// This is because statistics may be gathered from histograms between versions over time, and re-using values causes collisions.
-enum ReasonFrameCannotBeInPageCache {
- NoDocumentLoader = 0,
- MainDocumentError,
- IsErrorPage,
- HasPlugins,
- IsHttpsAndCacheControlled,
- HasUnloadListener,
- HasDatabaseHandles,
- HasSharedWorkers,
- NoHistoryItem,
- QuickRedirectComing,
- IsLoadingInAPISense,
- IsStopping,
- CannotSuspendActiveDOMObjects,
- DocumentLoaderUsesApplicationCache,
- ClientDeniesCaching,
- NumberOfReasonsFramesCannotBeInPageCache,
-};
-COMPILE_ASSERT(NumberOfReasonsFramesCannotBeInPageCache <= sizeof(unsigned)*8, ReasonFrameCannotBeInPageCacheDoesNotFitInBitmap);
-
-static unsigned logCanCacheFrameDecision(Frame* frame, int indentLevel)
+
+static inline void logPageCacheFailureDiagnosticMessage(DiagnosticLoggingClient& client, const String& reason)
+{
+ client.logDiagnosticMessage(DiagnosticLoggingKeys::pageCacheFailureKey(), reason, ShouldSample::Yes);
+}
+
+static inline void logPageCacheFailureDiagnosticMessage(Page* page, const String& reason)
+{
+ if (!page)
+ return;
+
+ logPageCacheFailureDiagnosticMessage(page->diagnosticLoggingClient(), reason);
+}
+
+static bool canCacheFrame(Frame& frame, DiagnosticLoggingClient& diagnosticLoggingClient, unsigned indentLevel)
{
PCLOG("+---");
- if (!frame->loader().documentLoader()) {
+ FrameLoader& frameLoader = frame.loader();
+
+ // Prevent page caching if a subframe is still in provisional load stage.
+ // We only do this check for subframes because the main frame is reused when navigating to a new page.
+ if (!frame.isMainFrame() && frameLoader.state() == FrameStateProvisional) {
+ PCLOG(" -Frame is in provisional load stage");
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::provisionalLoadKey());
+ return false;
+ }
+
+ DocumentLoader* documentLoader = frameLoader.documentLoader();
+ if (!documentLoader) {
PCLOG(" -There is no DocumentLoader object");
- return 1 << NoDocumentLoader;
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::noDocumentLoaderKey());
+ return false;
}
- URL currentURL = frame->loader().documentLoader()->url();
- URL newURL = frame->loader().provisionalDocumentLoader() ? frame->loader().provisionalDocumentLoader()->url() : URL();
+ URL currentURL = documentLoader->url();
+ URL newURL = frameLoader.provisionalDocumentLoader() ? frameLoader.provisionalDocumentLoader()->url() : URL();
if (!newURL.isEmpty())
PCLOG(" Determining if frame can be cached navigating from (", currentURL.string(), ") to (", newURL.string(), "):");
else
PCLOG(" Determining if subframe with URL (", currentURL.string(), ") can be cached:");
- unsigned rejectReasons = 0;
- if (!frame->loader().documentLoader()->mainDocumentError().isNull()) {
+ bool isCacheable = true;
+ if (!documentLoader->mainDocumentError().isNull()) {
PCLOG(" -Main document has an error");
-#if !PLATFORM(IOS)
- rejectReasons |= 1 << MainDocumentError;
-#else
- if (frame->loader().documentLoader()->mainDocumentError().isCancellation() && frame->loader().documentLoader()->subresourceLoadersArePageCacheAcceptable())
- PCLOG(" -But, it was a cancellation and all loaders during the cancel were loading images.");
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::mainDocumentErrorKey());
+
+ if (documentLoader->mainDocumentError().isCancellation() && documentLoader->subresourceLoadersArePageCacheAcceptable())
+ PCLOG(" -But, it was a cancellation and all loaders during the cancelation were loading images or XHR.");
else
- rejectReasons |= 1 << MainDocumentError;
-#endif
+ isCacheable = false;
}
- if (frame->loader().documentLoader()->substituteData().isValid() && frame->loader().documentLoader()->substituteData().failingURL().isEmpty()) {
+ // Do not cache error pages (these can be recognized as pages with substitute data or unreachable URLs).
+ if (documentLoader->substituteData().isValid() && !documentLoader->substituteData().failingURL().isEmpty()) {
PCLOG(" -Frame is an error page");
- rejectReasons |= 1 << IsErrorPage;
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::isErrorPageKey());
+ isCacheable = false;
}
- if (frame->loader().subframeLoader().containsPlugins() && !frame->page()->settings().pageCacheSupportsPlugins()) {
+ if (frameLoader.subframeLoader().containsPlugins() && !frame.page()->settings().pageCacheSupportsPlugins()) {
PCLOG(" -Frame contains plugins");
- rejectReasons |= 1 << HasPlugins;
- }
- if (frame->document()->url().protocolIs("https")
- && (frame->loader().documentLoader()->response().cacheControlContainsNoCache()
- || frame->loader().documentLoader()->response().cacheControlContainsNoStore())) {
- PCLOG(" -Frame is HTTPS, and cache control prohibits caching or storing");
- rejectReasons |= 1 << IsHttpsAndCacheControlled;
- }
- if (frame->document()->domWindow() && frame->document()->domWindow()->hasEventListeners(eventNames().unloadEvent)) {
- PCLOG(" -Frame has an unload event listener");
-#if !PLATFORM(IOS)
- rejectReasons |= 1 << HasUnloadListener;
-#else
- // iOS allows pages with unload event listeners to enter the page cache.
- PCLOG(" -BUT iOS allows these pages to be cached.");
-#endif
- }
-#if ENABLE(SQL_DATABASE)
- if (DatabaseManager::manager().hasOpenDatabases(frame->document())) {
- PCLOG(" -Frame has open database handles");
- rejectReasons |= 1 << HasDatabaseHandles;
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::hasPluginsKey());
+ isCacheable = false;
}
-#endif
-#if ENABLE(SHARED_WORKERS)
- if (SharedWorkerRepository::hasSharedWorkers(frame->document())) {
- PCLOG(" -Frame has associated SharedWorkers");
- rejectReasons |= 1 << HasSharedWorkers;
+ if (frame.isMainFrame() && frame.document() && frame.document()->url().protocolIs("https") && documentLoader->response().cacheControlContainsNoStore()) {
+ PCLOG(" -Frame is HTTPS, and cache control prohibits storing");
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::httpsNoStoreKey());
+ isCacheable = false;
}
-#endif
- if (!frame->loader().history().currentItem()) {
- PCLOG(" -No current history item");
- rejectReasons |= 1 << NoHistoryItem;
+ if (frame.isMainFrame() && !frameLoader.history().currentItem()) {
+ PCLOG(" -Main frame has no current history item");
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::noCurrentHistoryItemKey());
+ isCacheable = false;
}
- if (frame->loader().quickRedirectComing()) {
+ if (frameLoader.quickRedirectComing()) {
PCLOG(" -Quick redirect is coming");
- rejectReasons |= 1 << QuickRedirectComing;
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::quirkRedirectComingKey());
+ isCacheable = false;
}
- if (frame->loader().documentLoader()->isLoadingInAPISense()) {
- PCLOG(" -DocumentLoader is still loading in API sense");
- rejectReasons |= 1 << IsLoadingInAPISense;
+ if (documentLoader->isLoading()) {
+ PCLOG(" -DocumentLoader is still loading");
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::isLoadingKey());
+ isCacheable = false;
}
- if (frame->loader().documentLoader()->isStopping()) {
+ if (documentLoader->isStopping()) {
PCLOG(" -DocumentLoader is in the middle of stopping");
- rejectReasons |= 1 << IsStopping;
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::documentLoaderStoppingKey());
+ isCacheable = false;
}
- if (!frame->document()->canSuspendActiveDOMObjects()) {
- PCLOG(" -The document cannot suspect its active DOM Objects");
- rejectReasons |= 1 << CannotSuspendActiveDOMObjects;
+
+ Vector<ActiveDOMObject*> unsuspendableObjects;
+ if (frame.document() && !frame.document()->canSuspendActiveDOMObjectsForDocumentSuspension(&unsuspendableObjects)) {
+ PCLOG(" -The document cannot suspend its active DOM Objects");
+ for (auto* activeDOMObject : unsuspendableObjects) {
+ PCLOG(" - Unsuspendable: ", activeDOMObject->activeDOMObjectName());
+ diagnosticLoggingClient.logDiagnosticMessage(DiagnosticLoggingKeys::unsuspendableDOMObjectKey(), activeDOMObject->activeDOMObjectName(), ShouldSample::Yes);
+ UNUSED_PARAM(activeDOMObject);
+ }
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::cannotSuspendActiveDOMObjectsKey());
+ isCacheable = false;
}
- if (!frame->loader().documentLoader()->applicationCacheHost()->canCacheInPageCache()) {
+ // FIXME: We should investigating caching frames that have an associated
+ // application cache. <rdar://problem/5917899> tracks that work.
+ if (!documentLoader->applicationCacheHost().canCacheInPageCache()) {
PCLOG(" -The DocumentLoader uses an application cache");
- rejectReasons |= 1 << DocumentLoaderUsesApplicationCache;
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::applicationCacheKey());
+ isCacheable = false;
}
- if (!frame->loader().client().canCachePage()) {
+ if (!frameLoader.client().canCachePage()) {
PCLOG(" -The client says this frame cannot be cached");
- rejectReasons |= 1 << ClientDeniesCaching;
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::deniedByClientKey());
+ isCacheable = false;
}
- HistogramSupport::histogramEnumeration("PageCache.FrameCacheable", !rejectReasons, 2);
- int reasonCount = 0;
- for (int i = 0; i < NumberOfReasonsFramesCannotBeInPageCache; ++i) {
- if (rejectReasons & (1 << i)) {
- ++reasonCount;
- HistogramSupport::histogramEnumeration("PageCache.FrameRejectReason", i, NumberOfReasonsFramesCannotBeInPageCache);
- }
+ for (Frame* child = frame.tree().firstChild(); child; child = child->tree().nextSibling()) {
+ if (!canCacheFrame(*child, diagnosticLoggingClient, indentLevel + 1))
+ isCacheable = false;
}
- HistogramSupport::histogramEnumeration("PageCache.FrameRejectReasonCount", reasonCount, 1 + NumberOfReasonsFramesCannotBeInPageCache);
-
- for (Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling())
- rejectReasons |= logCanCacheFrameDecision(child, indentLevel + 1);
- PCLOG(rejectReasons ? " Frame CANNOT be cached" : " Frame CAN be cached");
+ PCLOG(isCacheable ? " Frame CAN be cached" : " Frame CANNOT be cached");
PCLOG("+---");
- return rejectReasons;
+ return isCacheable;
}
-// Used in histograms, please only add at the end, and do not remove elements (renaming e.g. to "FooEnumUnused1" is fine).
-// This is because statistics may be gathered from histograms between versions over time, and re-using values causes collisions.
-enum ReasonPageCannotBeInPageCache {
- FrameCannotBeInPageCache = 0,
- DisabledBackForwardList,
- DisabledPageCache,
- UsesDeviceMotion,
- UsesDeviceOrientation,
- IsReload,
- IsReloadFromOrigin,
- IsSameLoad,
- NumberOfReasonsPagesCannotBeInPageCache,
-};
-COMPILE_ASSERT(NumberOfReasonsPagesCannotBeInPageCache <= sizeof(unsigned)*8, ReasonPageCannotBeInPageCacheDoesNotFitInBitmap);
-
-static void logCanCachePageDecision(Page* page)
+static bool canCachePage(Page& page)
{
- // Only bother logging for main frames that have actually loaded and have content.
- if (page->mainFrame().loader().stateMachine()->creatingInitialEmptyDocument())
- return;
- URL currentURL = page->mainFrame().loader().documentLoader() ? page->mainFrame().loader().documentLoader()->url() : URL();
- if (currentURL.isEmpty())
- return;
-
- int indentLevel = 0;
+ unsigned indentLevel = 0;
PCLOG("--------\n Determining if page can be cached:");
+
+ DiagnosticLoggingClient& diagnosticLoggingClient = page.diagnosticLoggingClient();
+ bool isCacheable = canCacheFrame(page.mainFrame(), diagnosticLoggingClient, indentLevel + 1);
- unsigned rejectReasons = 0;
- unsigned frameRejectReasons = logCanCacheFrameDecision(&page->mainFrame(), indentLevel+1);
- if (frameRejectReasons)
- rejectReasons |= 1 << FrameCannotBeInPageCache;
-
- if (!page->settings().usesPageCache()) {
+ if (!page.settings().usesPageCache() || page.isResourceCachingDisabled()) {
PCLOG(" -Page settings says b/f cache disabled");
- rejectReasons |= 1 << DisabledPageCache;
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::isDisabledKey());
+ isCacheable = false;
}
#if ENABLE(DEVICE_ORIENTATION) && !PLATFORM(IOS)
- if (DeviceMotionController::isActiveAt(page)) {
+ if (DeviceMotionController::isActiveAt(&page)) {
PCLOG(" -Page is using DeviceMotion");
- rejectReasons |= 1 << UsesDeviceMotion;
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::deviceMotionKey());
+ isCacheable = false;
}
- if (DeviceOrientationController::isActiveAt(page)) {
+ if (DeviceOrientationController::isActiveAt(&page)) {
PCLOG(" -Page is using DeviceOrientation");
- rejectReasons |= 1 << UsesDeviceOrientation;
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::deviceOrientationKey());
+ isCacheable = false;
}
#endif
#if ENABLE(PROXIMITY_EVENTS)
if (DeviceProximityController::isActiveAt(page)) {
PCLOG(" -Page is using DeviceProximity");
- rejectReasons |= 1 << UsesDeviceMotion;
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, deviceProximityKey);
+ isCacheable = false;
}
#endif
- FrameLoadType loadType = page->mainFrame().loader().loadType();
- if (loadType == FrameLoadTypeReload) {
+ FrameLoadType loadType = page.mainFrame().loader().loadType();
+ switch (loadType) {
+ case FrameLoadType::Reload:
+ // No point writing to the cache on a reload, since we will just write over it again when we leave that page.
PCLOG(" -Load type is: Reload");
- rejectReasons |= 1 << IsReload;
- }
- if (loadType == FrameLoadTypeReloadFromOrigin) {
- PCLOG(" -Load type is: Reload from origin");
- rejectReasons |= 1 << IsReloadFromOrigin;
- }
- if (loadType == FrameLoadTypeSame) {
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::reloadKey());
+ isCacheable = false;
+ break;
+ case FrameLoadType::Same: // user loads same URL again (but not reload button)
+ // No point writing to the cache on a same load, since we will just write over it again when we leave that page.
PCLOG(" -Load type is: Same");
- rejectReasons |= 1 << IsSameLoad;
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::sameLoadKey());
+ isCacheable = false;
+ break;
+ case FrameLoadType::RedirectWithLockedBackForwardList:
+ // Don't write to the cache if in the middle of a redirect, since we will want to store the final page we end up on.
+ PCLOG(" -Load type is: RedirectWithLockedBackForwardList");
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::redirectKey());
+ isCacheable = false;
+ break;
+ case FrameLoadType::Replace:
+ // No point writing to the cache on a replace, since we will just write over it again when we leave that page.
+ PCLOG(" -Load type is: Replace");
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::replaceKey());
+ isCacheable = false;
+ break;
+ case FrameLoadType::ReloadFromOrigin: {
+ // No point writing to the cache on a reload, since we will just write over it again when we leave that page.
+ PCLOG(" -Load type is: ReloadFromOrigin");
+ logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::reloadFromOriginKey());
+ isCacheable = false;
+ break;
+ }
+ case FrameLoadType::Standard:
+ case FrameLoadType::Back:
+ case FrameLoadType::Forward:
+ case FrameLoadType::IndexedBackForward: // a multi-item hop in the backforward list
+ // Cacheable.
+ break;
}
- PCLOG(rejectReasons ? " Page CANNOT be cached\n--------" : " Page CAN be cached\n--------");
-
- HistogramSupport::histogramEnumeration("PageCache.PageCacheable", !rejectReasons, 2);
- int reasonCount = 0;
- for (int i = 0; i < NumberOfReasonsPagesCannotBeInPageCache; ++i) {
- if (rejectReasons & (1 << i)) {
- ++reasonCount;
- HistogramSupport::histogramEnumeration("PageCache.PageRejectReason", i, NumberOfReasonsPagesCannotBeInPageCache);
- }
- }
- HistogramSupport::histogramEnumeration("PageCache.PageRejectReasonCount", reasonCount, 1 + NumberOfReasonsPagesCannotBeInPageCache);
- const bool settingsDisabledPageCache = rejectReasons & (1 << DisabledPageCache);
- HistogramSupport::histogramEnumeration("PageCache.PageRejectReasonCountExcludingSettings", reasonCount - settingsDisabledPageCache, NumberOfReasonsPagesCannotBeInPageCache);
-
- // Report also on the frame reasons by page; this is distinct from the per frame statistics since it coalesces the
- // causes from all subframes together.
- HistogramSupport::histogramEnumeration("PageCache.FrameCacheableByPage", !frameRejectReasons, 2);
- int frameReasonCount = 0;
- for (int i = 0; i <= NumberOfReasonsFramesCannotBeInPageCache; ++i) {
- if (frameRejectReasons & (1 << i)) {
- ++frameReasonCount;
- HistogramSupport::histogramEnumeration("PageCache.FrameRejectReasonByPage", i, NumberOfReasonsFramesCannotBeInPageCache);
- }
- }
-
- HistogramSupport::histogramEnumeration("PageCache.FrameRejectReasonCountByPage", frameReasonCount, 1 + NumberOfReasonsFramesCannotBeInPageCache);
-}
-
-#endif // !defined(NDEBUG)
+ if (isCacheable)
+ PCLOG(" Page CAN be cached\n--------");
+ else
+ PCLOG(" Page CANNOT be cached\n--------");
-PageCache* pageCache()
-{
- static PageCache* staticPageCache = new PageCache;
- return staticPageCache;
+ diagnosticLoggingClient.logDiagnosticMessageWithResult(DiagnosticLoggingKeys::pageCacheKey(), DiagnosticLoggingKeys::canCacheKey(), isCacheable ? DiagnosticLoggingResultPass : DiagnosticLoggingResultFail, ShouldSample::Yes);
+ return isCacheable;
}
-PageCache::PageCache()
- : m_capacity(0)
- , m_size(0)
- , m_head(0)
- , m_tail(0)
-#if USE(ACCELERATED_COMPOSITING)
- , m_shouldClearBackingStores(false)
-#endif
+PageCache& PageCache::singleton()
{
+ static NeverDestroyed<PageCache> globalPageCache;
+ return globalPageCache;
}
-bool PageCache::canCachePageContainingThisFrame(Frame* frame)
+bool PageCache::canCache(Page& page) const
{
- for (Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
- if (!canCachePageContainingThisFrame(child))
- return false;
- }
-
- FrameLoader& frameLoader = frame->loader();
- DocumentLoader* documentLoader = frameLoader.documentLoader();
- Document* document = frame->document();
-
- return documentLoader
-#if !PLATFORM(IOS)
- && documentLoader->mainDocumentError().isNull()
-#else
- && (documentLoader->mainDocumentError().isNull() || (documentLoader->mainDocumentError().isCancellation() && documentLoader->subresourceLoadersArePageCacheAcceptable()))
-#endif
- // Do not cache error pages (these can be recognized as pages with substitute data or unreachable URLs).
- && !(documentLoader->substituteData().isValid() && !documentLoader->substituteData().failingURL().isEmpty())
- && (!frameLoader.subframeLoader().containsPlugins() || frame->page()->settings().pageCacheSupportsPlugins())
- && (!document->url().protocolIs("https") || (!documentLoader->response().cacheControlContainsNoCache() && !documentLoader->response().cacheControlContainsNoStore()))
-#if !PLATFORM(IOS)
- && (!document->domWindow() || !document->domWindow()->hasEventListeners(eventNames().unloadEvent))
-#endif
-#if ENABLE(SQL_DATABASE)
- && !DatabaseManager::manager().hasOpenDatabases(document)
-#endif
-#if ENABLE(SHARED_WORKERS)
- && !SharedWorkerRepository::hasSharedWorkers(document)
-#endif
- && frameLoader.history().currentItem()
- && !frameLoader.quickRedirectComing()
- && !documentLoader->isLoadingInAPISense()
- && !documentLoader->isStopping()
- && document->canSuspendActiveDOMObjects()
- // FIXME: We should investigating caching frames that have an associated
- // application cache. <rdar://problem/5917899> tracks that work.
- && documentLoader->applicationCacheHost()->canCacheInPageCache()
- && frameLoader.client().canCachePage();
-}
-
-bool PageCache::canCache(Page* page) const
-{
- if (!page)
+ if (!m_maxSize) {
+ logPageCacheFailureDiagnosticMessage(&page, DiagnosticLoggingKeys::isDisabledKey());
return false;
-
-#if !defined(NDEBUG)
- logCanCachePageDecision(page);
-#endif
+ }
-#if PLATFORM(IOS)
- if (memoryPressureHandler().hasReceivedMemoryPressure())
+ if (MemoryPressureHandler::singleton().isUnderMemoryPressure()) {
+ logPageCacheFailureDiagnosticMessage(&page, DiagnosticLoggingKeys::underMemoryPressureKey());
return false;
-#endif
-
- // Cache the page, if possible.
- // Don't write to the cache if in the middle of a redirect, since we will want to
- // store the final page we end up on.
- // No point writing to the cache on a reload or loadSame, since we will just write
- // over it again when we leave that page.
- FrameLoadType loadType = page->mainFrame().loader().loadType();
+ }
- return m_capacity > 0
- && canCachePageContainingThisFrame(&page->mainFrame())
- && page->settings().usesPageCache()
-#if ENABLE(DEVICE_ORIENTATION) && !PLATFORM(IOS)
- && !DeviceMotionController::isActiveAt(page)
- && !DeviceOrientationController::isActiveAt(page)
-#endif
-#if ENABLE(PROXIMITY_EVENTS)
- && !DeviceProximityController::isActiveAt(page)
-#endif
- && (loadType == FrameLoadTypeStandard
- || loadType == FrameLoadTypeBack
- || loadType == FrameLoadTypeForward
- || loadType == FrameLoadTypeIndexedBackForward);
+ return canCachePage(page);
}
-void PageCache::pruneToCapacityNow(int capacity)
+void PageCache::pruneToSizeNow(unsigned size, PruningReason pruningReason)
{
- int savedCapacity = m_capacity;
- setCapacity(capacity);
- setCapacity(savedCapacity);
+ SetForScope<unsigned> change(m_maxSize, size);
+ prune(pruningReason);
}
-void PageCache::setCapacity(int capacity)
+void PageCache::setMaxSize(unsigned maxSize)
{
- ASSERT(capacity >= 0);
- m_capacity = std::max(capacity, 0);
-
- prune();
+ m_maxSize = maxSize;
+ prune(PruningReason::None);
}
-int PageCache::frameCount() const
+unsigned PageCache::frameCount() const
{
- int frameCount = 0;
- for (HistoryItem* current = m_head; current; current = current->m_next) {
- ++frameCount;
- ASSERT(current->m_cachedPage);
- frameCount += current->m_cachedPage ? current->m_cachedPage->cachedMainFrame()->descendantFrameCount() : 0;
+ unsigned frameCount = m_items.size();
+ for (auto& item : m_items) {
+ ASSERT(item->m_cachedPage);
+ frameCount += item->m_cachedPage->cachedMainFrame()->descendantFrameCount();
}
return frameCount;
}
-void PageCache::markPagesForVistedLinkStyleRecalc()
+void PageCache::markPagesForDeviceOrPageScaleChanged(Page& page)
{
- for (HistoryItem* current = m_head; current; current = current->m_next) {
- if (current->m_cachedPage)
- current->m_cachedPage->markForVistedLinkStyleRecalc();
+ for (auto& item : m_items) {
+ CachedPage& cachedPage = *item->m_cachedPage;
+ if (&page.mainFrame() == &cachedPage.cachedMainFrame()->view()->frame())
+ cachedPage.markForDeviceOrPageScaleChanged();
}
}
-void PageCache::markPagesForFullStyleRecalc(Page* page)
+void PageCache::markPagesForContentsSizeChanged(Page& page)
{
- for (HistoryItem* current = m_head; current; current = current->m_next) {
- CachedPage* cachedPage = current->m_cachedPage.get();
- if (cachedPage && &page->mainFrame() == &cachedPage->cachedMainFrame()->view()->frame())
- cachedPage->markForFullStyleRecalc();
+ for (auto& item : m_items) {
+ CachedPage& cachedPage = *item->m_cachedPage;
+ if (&page.mainFrame() == &cachedPage.cachedMainFrame()->view()->frame())
+ cachedPage.markForContentsSizeChanged();
}
}
-
-#if USE(ACCELERATED_COMPOSITING)
-void PageCache::markPagesForDeviceScaleChanged(Page* page)
+#if ENABLE(VIDEO_TRACK)
+void PageCache::markPagesForCaptionPreferencesChanged()
{
- for (HistoryItem* current = m_head; current; current = current->m_next) {
- CachedPage* cachedPage = current->m_cachedPage.get();
- if (cachedPage && &page->mainFrame() == &cachedPage->cachedMainFrame()->view()->frame())
- cachedPage->markForDeviceScaleChanged();
+ for (auto& item : m_items) {
+ ASSERT(item->m_cachedPage);
+ item->m_cachedPage->markForCaptionPreferencesChanged();
}
}
#endif
-#if ENABLE(VIDEO_TRACK)
-void PageCache::markPagesForCaptionPreferencesChanged()
+static String pruningReasonToDiagnosticLoggingKey(PruningReason pruningReason)
+{
+ switch (pruningReason) {
+ case PruningReason::MemoryPressure:
+ return DiagnosticLoggingKeys::prunedDueToMemoryPressureKey();
+ case PruningReason::ProcessSuspended:
+ return DiagnosticLoggingKeys::prunedDueToProcessSuspended();
+ case PruningReason::ReachedMaxSize:
+ return DiagnosticLoggingKeys::prunedDueToMaxSizeReached();
+ case PruningReason::None:
+ break;
+ }
+ ASSERT_NOT_REACHED();
+ return emptyString();
+}
+
+static void setPageCacheState(Page& page, Document::PageCacheState pageCacheState)
{
- for (HistoryItem* current = m_head; current; current = current->m_next) {
- if (current->m_cachedPage)
- current->m_cachedPage->markForCaptionPreferencesChanged();
+ for (Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
+ if (auto* document = frame->document())
+ document->setPageCacheState(pageCacheState);
}
}
-#endif
-void PageCache::add(PassRefPtr<HistoryItem> prpItem, Page& page)
+// When entering page cache, tear down the render tree before setting the in-cache flag.
+// This maintains the invariant that render trees are never present in the page cache.
+// Note that destruction happens bottom-up so that the main frame's tree dies last.
+static void destroyRenderTree(MainFrame& mainFrame)
{
- ASSERT(prpItem);
- ASSERT(canCache(&page));
-
- HistoryItem* item = prpItem.leakRef(); // Balanced in remove().
+ for (Frame* frame = mainFrame.tree().traversePreviousWithWrap(true); frame; frame = frame->tree().traversePreviousWithWrap(false)) {
+ if (!frame->document())
+ continue;
+ auto& document = *frame->document();
+ if (document.hasLivingRenderTree())
+ document.destroyRenderTree();
+ }
+}
- // Remove stale cache entry if necessary.
- if (item->m_cachedPage)
- remove(item);
+static void firePageHideEventRecursively(Frame& frame)
+{
+ auto* document = frame.document();
+ if (!document)
+ return;
- item->m_cachedPage = std::make_unique<CachedPage>(page);
- addToLRUList(item);
- ++m_size;
-
- prune();
+ // stopLoading() will fire the pagehide event in each subframe and the HTML specification states
+ // that the parent document's ignore-opens-during-unload counter should be incremented while the
+ // pagehide event is being fired in its subframes:
+ // https://html.spec.whatwg.org/multipage/browsers.html#unload-a-document
+ IgnoreOpensDuringUnloadCountIncrementer ignoreOpensDuringUnloadCountIncrementer(document);
+
+ frame.loader().stopLoading(UnloadEventPolicyUnloadAndPageHide);
+
+ for (RefPtr<Frame> child = frame.tree().firstChild(); child; child = child->tree().nextSibling())
+ firePageHideEventRecursively(*child);
}
-std::unique_ptr<CachedPage> PageCache::take(HistoryItem* item)
+void PageCache::addIfCacheable(HistoryItem& item, Page* page)
{
- if (!item)
- return nullptr;
+ if (item.isInPageCache())
+ return;
- std::unique_ptr<CachedPage> cachedPage = std::move(item->m_cachedPage);
+ if (!page || !canCache(*page))
+ return;
- removeFromLRUList(item);
- --m_size;
+ setPageCacheState(*page, Document::AboutToEnterPageCache);
- item->deref(); // Balanced in add().
+ // Focus the main frame, defocusing a focused subframe (if we have one). We do this here,
+ // before the page enters the page cache, while we still can dispatch DOM blur/focus events.
+ if (page->focusController().focusedFrame())
+ page->focusController().setFocusedFrame(&page->mainFrame());
- if (!cachedPage)
- return nullptr;
+ // Fire the pagehide event in all frames.
+ firePageHideEventRecursively(page->mainFrame());
- if (cachedPage->hasExpired()) {
- LOG(PageCache, "Not restoring page for %s from back/forward cache because cache entry has expired", item->url().string().ascii().data());
- return nullptr;
+ // Check that the page is still page-cacheable after firing the pagehide event. The JS event handlers
+ // could have altered the page in a way that could prevent caching.
+ if (!canCache(*page)) {
+ setPageCacheState(*page, Document::NotInPageCache);
+ return;
}
- return cachedPage;
-}
+ destroyRenderTree(page->mainFrame());
-CachedPage* PageCache::get(HistoryItem* item)
-{
- if (!item)
- return 0;
+ setPageCacheState(*page, Document::InPageCache);
- if (CachedPage* cachedPage = item->m_cachedPage.get()) {
- if (!cachedPage->hasExpired())
- return cachedPage;
-
- LOG(PageCache, "Not restoring page for %s from back/forward cache because cache entry has expired", item->url().string().ascii().data());
- pageCache()->remove(item);
- }
- return 0;
+ // Make sure we no longer fire any JS events past this point.
+ NoEventDispatchAssertion assertNoEventDispatch;
+
+ item.m_cachedPage = std::make_unique<CachedPage>(*page);
+ item.m_pruningReason = PruningReason::None;
+ m_items.add(&item);
+
+ prune(PruningReason::ReachedMaxSize);
}
-void PageCache::remove(HistoryItem* item)
+std::unique_ptr<CachedPage> PageCache::take(HistoryItem& item, Page* page)
{
- // Safely ignore attempts to remove items not in the cache.
- if (!item || !item->m_cachedPage)
- return;
+ if (!item.m_cachedPage) {
+ if (item.m_pruningReason != PruningReason::None)
+ logPageCacheFailureDiagnosticMessage(page, pruningReasonToDiagnosticLoggingKey(item.m_pruningReason));
+ return nullptr;
+ }
- item->m_cachedPage = nullptr;
- removeFromLRUList(item);
- --m_size;
+ m_items.remove(&item);
+ std::unique_ptr<CachedPage> cachedPage = WTFMove(item.m_cachedPage);
- item->deref(); // Balanced in add().
+ if (cachedPage->hasExpired() || (page && page->isResourceCachingDisabled())) {
+ LOG(PageCache, "Not restoring page for %s from back/forward cache because cache entry has expired", item.url().string().ascii().data());
+ logPageCacheFailureDiagnosticMessage(page, DiagnosticLoggingKeys::expiredKey());
+ return nullptr;
+ }
+
+ return cachedPage;
}
-void PageCache::prune()
+void PageCache::removeAllItemsForPage(Page& page)
{
- while (m_size > m_capacity) {
- ASSERT(m_tail && m_tail->m_cachedPage);
- remove(m_tail);
+ for (auto it = m_items.begin(); it != m_items.end();) {
+ // Increment iterator first so it stays valid after the removal.
+ auto current = it;
+ ++it;
+ if (&(*current)->m_cachedPage->page() == &page) {
+ (*current)->m_cachedPage = nullptr;
+ m_items.remove(current);
+ }
}
}
-void PageCache::addToLRUList(HistoryItem* item)
+CachedPage* PageCache::get(HistoryItem& item, Page* page)
{
- item->m_next = m_head;
- item->m_prev = 0;
+ CachedPage* cachedPage = item.m_cachedPage.get();
+ if (!cachedPage) {
+ if (item.m_pruningReason != PruningReason::None)
+ logPageCacheFailureDiagnosticMessage(page, pruningReasonToDiagnosticLoggingKey(item.m_pruningReason));
+ return nullptr;
+ }
- if (m_head) {
- ASSERT(m_tail);
- m_head->m_prev = item;
- } else {
- ASSERT(!m_tail);
- m_tail = item;
+ if (cachedPage->hasExpired() || (page && page->isResourceCachingDisabled())) {
+ LOG(PageCache, "Not restoring page for %s from back/forward cache because cache entry has expired", item.url().string().ascii().data());
+ logPageCacheFailureDiagnosticMessage(page, DiagnosticLoggingKeys::expiredKey());
+ remove(item);
+ return nullptr;
}
+ return cachedPage;
+}
+
+void PageCache::remove(HistoryItem& item)
+{
+ // Safely ignore attempts to remove items not in the cache.
+ if (!item.m_cachedPage)
+ return;
- m_head = item;
+ m_items.remove(&item);
+ item.m_cachedPage = nullptr;
}
-void PageCache::removeFromLRUList(HistoryItem* item)
+void PageCache::prune(PruningReason pruningReason)
{
- if (!item->m_next) {
- ASSERT(item == m_tail);
- m_tail = item->m_prev;
- } else {
- ASSERT(item != m_tail);
- item->m_next->m_prev = item->m_prev;
- }
-
- if (!item->m_prev) {
- ASSERT(item == m_head);
- m_head = item->m_next;
- } else {
- ASSERT(item != m_head);
- item->m_prev->m_next = item->m_next;
+ while (pageCount() > maxSize()) {
+ auto oldestItem = m_items.takeFirst();
+ oldestItem->m_cachedPage = nullptr;
+ oldestItem->m_pruningReason = pruningReason;
}
}
diff --git a/Source/WebCore/history/PageCache.h b/Source/WebCore/history/PageCache.h
index ebab10c1e..edda9e755 100644
--- a/Source/WebCore/history/PageCache.h
+++ b/Source/WebCore/history/PageCache.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,83 +23,63 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef PageCache_h
-#define PageCache_h
+#pragma once
+#include "HistoryItem.h"
#include "Timer.h"
#include <wtf/Forward.h>
-#include <wtf/HashSet.h>
+#include <wtf/ListHashSet.h>
#include <wtf/Noncopyable.h>
namespace WebCore {
- class CachedPage;
- class Frame;
- class HistoryItem;
- class Page;
-
- class PageCache {
- WTF_MAKE_NONCOPYABLE(PageCache); WTF_MAKE_FAST_ALLOCATED;
- public:
- friend PageCache* pageCache();
-
- bool canCache(Page*) const;
-
- void setCapacity(int); // number of pages to cache
- int capacity() { return m_capacity; }
-
- void add(PassRefPtr<HistoryItem>, Page&); // Prunes if capacity() is exceeded.
- void remove(HistoryItem*);
- CachedPage* get(HistoryItem* item);
- std::unique_ptr<CachedPage> take(HistoryItem*);
-
- int pageCount() const { return m_size; }
- int frameCount() const;
-
- void markPagesForVistedLinkStyleRecalc();
-
- // Will mark all cached pages associated with the given page as needing style recalc.
- void markPagesForFullStyleRecalc(Page*);
-
- // Used when memory is low to prune some cached pages.
- void pruneToCapacityNow(int capacity);
+class CachedPage;
+class Frame;
+class Page;
-#if ENABLE(VIDEO_TRACK)
- void markPagesForCaptionPreferencesChanged();
-#endif
+enum class PruningReason { None, ProcessSuspended, MemoryPressure, ReachedMaxSize };
-#if USE(ACCELERATED_COMPOSITING)
- bool shouldClearBackingStores() const { return m_shouldClearBackingStores; }
- void setShouldClearBackingStores(bool flag) { m_shouldClearBackingStores = flag; }
- void markPagesForDeviceScaleChanged(Page*);
-#endif
+class PageCache {
+ WTF_MAKE_NONCOPYABLE(PageCache); WTF_MAKE_FAST_ALLOCATED;
+public:
+ // Function to obtain the global page cache.
+ WEBCORE_EXPORT static PageCache& singleton();
+
+ bool canCache(Page&) const;
- private:
- PageCache(); // Use pageCache() instead.
- ~PageCache(); // Not implemented to make sure nobody accidentally calls delete -- WebCore does not delete singletons.
-
- static bool canCachePageContainingThisFrame(Frame*);
+ // Used when memory is low to prune some cached pages.
+ WEBCORE_EXPORT void pruneToSizeNow(unsigned maxSize, PruningReason);
+ WEBCORE_EXPORT void setMaxSize(unsigned); // number of pages to cache.
+ unsigned maxSize() const { return m_maxSize; }
- void addToLRUList(HistoryItem*); // Adds to the head of the list.
- void removeFromLRUList(HistoryItem*);
+ void addIfCacheable(HistoryItem&, Page*); // Prunes if maxSize() is exceeded.
+ WEBCORE_EXPORT void remove(HistoryItem&);
+ CachedPage* get(HistoryItem&, Page*);
+ std::unique_ptr<CachedPage> take(HistoryItem&, Page*);
- void prune();
+ void removeAllItemsForPage(Page&);
- int m_capacity;
- int m_size;
+ unsigned pageCount() const { return m_items.size(); }
+ WEBCORE_EXPORT unsigned frameCount() const;
- // LRU List
- HistoryItem* m_head;
- HistoryItem* m_tail;
-
-#if USE(ACCELERATED_COMPOSITING)
- bool m_shouldClearBackingStores;
+ void markPagesForDeviceOrPageScaleChanged(Page&);
+ void markPagesForContentsSizeChanged(Page&);
+#if ENABLE(VIDEO_TRACK)
+ void markPagesForCaptionPreferencesChanged();
#endif
- };
- // Function to obtain the global page cache.
- PageCache* pageCache();
+private:
+ PageCache() = default; // Use singleton() instead.
+ ~PageCache() = delete; // Make sure nobody accidentally calls delete -- WebCore does not delete singletons.
-} // namespace WebCore
+ static bool canCachePageContainingThisFrame(Frame&);
+
+ void prune(PruningReason);
-#endif // PageCache_h
+ ListHashSet<RefPtr<HistoryItem>> m_items;
+ unsigned m_maxSize {0};
+
+ friend class WTF::NeverDestroyed<PageCache>;
+};
+
+} // namespace WebCore