diff options
Diffstat (limited to 'Source/WebCore/history')
17 files changed, 1004 insertions, 1738 deletions
diff --git a/Source/WebCore/history/mac/HistoryItemMac.mm b/Source/WebCore/history/BackForwardClient.h index 9b077a1ef..778ac8ff0 100644 --- a/Source/WebCore/history/mac/HistoryItemMac.mm +++ b/Source/WebCore/history/BackForwardClient.h @@ -1,5 +1,7 @@ /* - * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * 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 @@ -10,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 @@ -23,45 +25,42 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" -#include "HistoryItem.h" +#ifndef BackForwardClient_h +#define BackForwardClient_h -#include <wtf/text/StringHash.h> +#include <wtf/Forward.h> +#include <wtf/RefCounted.h> namespace WebCore { -id HistoryItem::viewState() const -{ - return m_viewState.get(); -} +class HistoryItem; -void HistoryItem::setViewState(id statePList) -{ - id newState = [statePList copy]; - m_viewState = newState; - [newState release]; -} +class BackForwardClient : public RefCounted<BackForwardClient> { +public: + virtual ~BackForwardClient() + { + } -id HistoryItem::getTransientProperty(const String& key) const -{ - if (!m_transientProperties) - return nil; - return m_transientProperties->get(key).get(); -} + virtual void addItem(Ref<HistoryItem>&&) = 0; -void HistoryItem::setTransientProperty(const String& key, id value) -{ - if (!value) { - if (m_transientProperties) { - m_transientProperties->remove(key); - if (m_transientProperties->isEmpty()) - m_transientProperties.clear(); - } - } else { - if (!m_transientProperties) - m_transientProperties = adoptPtr(new HashMap<String, RetainPtr<id> >); - m_transientProperties->set(key, value); - } -} + virtual void goToItem(HistoryItem*) = 0; + + virtual HistoryItem* itemAtIndex(int) = 0; + virtual int backListCount() = 0; + 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 +}; } // namespace WebCore + +#endif // BackForwardClient_h diff --git a/Source/WebCore/history/BackForwardController.cpp b/Source/WebCore/history/BackForwardController.cpp index ca363b80a..2317ad726 100644 --- a/Source/WebCore/history/BackForwardController.cpp +++ b/Source/WebCore/history/BackForwardController.cpp @@ -26,52 +26,80 @@ #include "config.h" #include "BackForwardController.h" -#include "BackForwardListImpl.h" +#include "BackForwardList.h" #include "HistoryItem.h" #include "Page.h" namespace WebCore { -BackForwardController::BackForwardController(Page* page, PassRefPtr<BackForwardList> client) +BackForwardController::BackForwardController(Page& page, RefPtr<BackForwardClient>&& client) : m_page(page) - , m_client(client) + , m_client(WTFMove(client)) { if (!m_client) - m_client = BackForwardListImpl::create(page); + m_client = BackForwardList::create(&page); } BackForwardController::~BackForwardController() { } -PassOwnPtr<BackForwardController> BackForwardController::create(Page* page, PassRefPtr<BackForwardList> client) -{ - return adoptPtr(new BackForwardController(page, client)); -} - bool BackForwardController::canGoBackOrForward(int distance) const { - return m_page->canGoBackOrForward(distance); + if (!distance) + return true; + if (distance > 0 && distance <= forwardCount()) + return true; + if (distance < 0 && -distance <= backCount()) + return true; + return false; } void BackForwardController::goBackOrForward(int distance) { - m_page->goBackOrForward(distance); + if (!distance) + return; + + HistoryItem* item = itemAtIndex(distance); + if (!item) { + if (distance > 0) { + if (int forwardCount = this->forwardCount()) + item = itemAtIndex(forwardCount); + } else { + if (int backCount = this->backCount()) + item = itemAtIndex(-backCount); + } + } + + if (!item) + return; + + m_page.goToItem(*item, FrameLoadType::IndexedBackForward); } bool BackForwardController::goBack() { - return m_page->goBack(); + HistoryItem* item = backItem(); + if (!item) + return false; + + m_page.goToItem(*item, FrameLoadType::Back); + return true; } bool BackForwardController::goForward() { - return m_page->goForward(); + HistoryItem* item = forwardItem(); + if (!item) + return false; + + 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) @@ -81,7 +109,7 @@ void BackForwardController::setCurrentItem(HistoryItem* item) int BackForwardController::count() const { - return m_page->getHistoryLength(); + return m_client->backListCount() + 1 + m_client->forwardListCount(); } int BackForwardController::backCount() const @@ -99,11 +127,6 @@ HistoryItem* BackForwardController::itemAtIndex(int i) return m_client->itemAtIndex(i); } -bool BackForwardController::isActive() -{ - return m_client->isActive(); -} - void BackForwardController::close() { m_client->close(); diff --git a/Source/WebCore/history/BackForwardController.h b/Source/WebCore/history/BackForwardController.h index aa2b2f8df..5a24f8ede 100644 --- a/Source/WebCore/history/BackForwardController.h +++ b/Source/WebCore/history/BackForwardController.h @@ -32,35 +32,32 @@ namespace WebCore { -class BackForwardList; +class BackForwardClient; class HistoryItem; class Page; class BackForwardController { WTF_MAKE_NONCOPYABLE(BackForwardController); WTF_MAKE_FAST_ALLOCATED; public: + BackForwardController(Page&, RefPtr<BackForwardClient>&&); ~BackForwardController(); - static PassOwnPtr<BackForwardController> create(Page*, PassRefPtr<BackForwardList>); + BackForwardClient* client() const { return m_client.get(); } - BackForwardList* 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; - - HistoryItem* itemAtIndex(int); + WEBCORE_EXPORT int backCount() const; + WEBCORE_EXPORT int forwardCount() const; - bool isActive(); + WEBCORE_EXPORT HistoryItem* itemAtIndex(int); void close(); @@ -69,10 +66,8 @@ public: HistoryItem* forwardItem() { return itemAtIndex(1); } private: - BackForwardController(Page*, PassRefPtr<BackForwardList>); - - Page* m_page; - RefPtr<BackForwardList> m_client; + Page& m_page; + RefPtr<BackForwardClient> m_client; }; } // namespace WebCore diff --git a/Source/WebCore/history/BackForwardListImpl.cpp b/Source/WebCore/history/BackForwardList.cpp index 05b2a0edf..5a378d75d 100644 --- a/Source/WebCore/history/BackForwardListImpl.cpp +++ b/Source/WebCore/history/BackForwardList.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2005, 2006 Apple 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 @@ -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 @@ -25,7 +25,7 @@ */ #include "config.h" -#include "BackForwardListImpl.h" +#include "BackForwardList.h" #include "Frame.h" #include "FrameLoader.h" @@ -36,14 +36,12 @@ #include "PageCache.h" #include "SerializedScriptValue.h" -using namespace std; - namespace WebCore { static const unsigned DefaultCapacity = 100; static const unsigned NoCurrentItemIndex = UINT_MAX; -BackForwardListImpl::BackForwardListImpl(Page* page) +BackForwardList::BackForwardList(Page* page) : m_page(page) , m_current(NoCurrentItemIndex) , m_capacity(DefaultCapacity) @@ -52,44 +50,42 @@ BackForwardListImpl::BackForwardListImpl(Page* page) { } -BackForwardListImpl::~BackForwardListImpl() +BackForwardList::~BackForwardList() { ASSERT(m_closed); } -void BackForwardListImpl::addItem(PassRefPtr<HistoryItem> prpItem) +void BackForwardList::addItem(Ref<HistoryItem>&& newItem) { - ASSERT(prpItem); - if (m_capacity == 0 || !m_enabled) + if (!m_capacity || !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()); + Ref<HistoryItem> item = m_entries.takeLast(); + m_entryHash.remove(item.ptr()); + PageCache::singleton().remove(item); } } // 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]; + if (m_entries.size() == m_capacity && (m_current || m_capacity == 1)) { + Ref<HistoryItem> item = WTFMove(m_entries[0]); m_entries.remove(0); - m_entryHash.remove(item); - pageCache()->remove(item.get()); - m_current--; + m_entryHash.remove(item.ptr()); + PageCache::singleton().remove(item); + --m_current; } - m_entryHash.add(prpItem.get()); - m_entries.insert(m_current + 1, prpItem); - m_current++; + m_entryHash.add(newItem.ptr()); + m_entries.insert(m_current + 1, WTFMove(newItem)); + ++m_current; } -void BackForwardListImpl::goBack() +void BackForwardList::goBack() { ASSERT(m_current > 0); if (m_current > 0) { @@ -97,7 +93,7 @@ void BackForwardListImpl::goBack() } } -void BackForwardListImpl::goForward() +void BackForwardList::goForward() { ASSERT(m_current < m_entries.size() - 1); if (m_current < m_entries.size() - 1) { @@ -105,52 +101,52 @@ void BackForwardListImpl::goForward() } } -void BackForwardListImpl::goToItem(HistoryItem* item) +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) + if (m_entries[index].ptr() == item) break; if (index < m_entries.size()) { m_current = index; } } -HistoryItem* BackForwardListImpl::backItem() +HistoryItem* BackForwardList::backItem() { if (m_current && m_current != NoCurrentItemIndex) - return m_entries[m_current - 1].get(); - return 0; + return m_entries[m_current - 1].ptr(); + return nullptr; } -HistoryItem* BackForwardListImpl::currentItem() +HistoryItem* BackForwardList::currentItem() { if (m_current != NoCurrentItemIndex) - return m_entries[m_current].get(); - return 0; + return m_entries[m_current].ptr(); + return nullptr; } -HistoryItem* BackForwardListImpl::forwardItem() +HistoryItem* BackForwardList::forwardItem() { if (m_entries.size() && m_current < m_entries.size() - 1) - return m_entries[m_current + 1].get(); - return 0; + return m_entries[m_current + 1].ptr(); + return nullptr; } -void BackForwardListImpl::backListWithLimit(int limit, HistoryItemVector& list) +void BackForwardList::backListWithLimit(int limit, HistoryItemVector& list) { list.clear(); if (m_current != NoCurrentItemIndex) { - unsigned first = max((int)m_current - limit, 0); + unsigned first = std::max(static_cast<int>(m_current) - limit, 0); for (; first < m_current; ++first) - list.append(m_entries[first]); + list.append(m_entries[first].get()); } } -void BackForwardListImpl::forwardListWithLimit(int limit, HistoryItemVector& list) +void BackForwardList::forwardListWithLimit(int limit, HistoryItemVector& list) { ASSERT(limit > -1); list.clear(); @@ -159,25 +155,24 @@ void BackForwardListImpl::forwardListWithLimit(int limit, HistoryItemVector& lis unsigned lastEntry = m_entries.size() - 1; if (m_current < lastEntry) { - int last = min(m_current + limit, lastEntry); + int last = std::min(m_current + limit, lastEntry); limit = m_current + 1; for (; limit <= last; ++limit) - list.append(m_entries[limit]); + list.append(m_entries[limit].get()); } } -int BackForwardListImpl::capacity() +int BackForwardList::capacity() { return m_capacity; } -void BackForwardListImpl::setCapacity(int size) +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()); + while (size < static_cast<int>(m_entries.size())) { + Ref<HistoryItem> item = m_entries.takeLast(); + m_entryHash.remove(item.ptr()); + PageCache::singleton().remove(item); } if (!size) @@ -188,12 +183,12 @@ void BackForwardListImpl::setCapacity(int size) m_capacity = size; } -bool BackForwardListImpl::enabled() +bool BackForwardList::enabled() { return m_enabled; } -void BackForwardListImpl::setEnabled(bool enabled) +void BackForwardList::setEnabled(bool enabled) { m_enabled = enabled; if (!enabled) { @@ -203,56 +198,79 @@ void BackForwardListImpl::setEnabled(bool enabled) } } -int BackForwardListImpl::backListCount() +int BackForwardList::backListCount() { return m_current == NoCurrentItemIndex ? 0 : m_current; } -int BackForwardListImpl::forwardListCount() +int BackForwardList::forwardListCount() { return m_current == NoCurrentItemIndex ? 0 : (int)m_entries.size() - (m_current + 1); } -HistoryItem* BackForwardListImpl::itemAtIndex(int index) +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 < -static_cast<int>(m_current)) + return nullptr; if (index > forwardListCount()) - return 0; + return nullptr; - return m_entries[index + m_current].get(); + return m_entries[index + m_current].ptr(); } -HistoryItemVector& BackForwardListImpl::entries() +HistoryItemVector& BackForwardList::entries() { return m_entries; } -void BackForwardListImpl::close() +#if PLATFORM(IOS) +unsigned BackForwardList::current() +{ + return m_current; +} + +void BackForwardList::setCurrent(unsigned newCurrent) { - int size = m_entries.size(); - for (int i = 0; i < size; ++i) - pageCache()->remove(m_entries[i].get()); + m_current = newCurrent; +} + +bool BackForwardList::clearAllPageCaches() +{ + bool didRemoveAtLeastOneItem = false; + for (auto& item : m_entries) { + if (item->isInPageCache()) { + didRemoveAtLeastOneItem = true; + PageCache::singleton().remove(item); + } + } + return didRemoveAtLeastOneItem; +} +#endif + +void BackForwardList::close() +{ + for (auto& item : m_entries) + PageCache::singleton().remove(item); m_entries.clear(); m_entryHash.clear(); - m_page = 0; + m_page = nullptr; m_closed = true; } -bool BackForwardListImpl::closed() +bool BackForwardList::closed() { return m_closed; } -void BackForwardListImpl::removeItem(HistoryItem* item) +void BackForwardList::removeItem(HistoryItem* item) { if (!item) return; - for (unsigned i = 0; i < m_entries.size(); ++i) - if (m_entries[i] == item) { + for (unsigned i = 0; i < m_entries.size(); ++i) { + if (m_entries[i].ptr() == item) { m_entries.remove(i); m_entryHash.remove(item); if (m_current == NoCurrentItemIndex || m_current < i) @@ -266,9 +284,10 @@ void BackForwardListImpl::removeItem(HistoryItem* item) } break; } + } } -bool BackForwardListImpl::containsItem(HistoryItem* entry) +bool BackForwardList::containsItem(HistoryItem* entry) { return m_entryHash.contains(entry); } diff --git a/Source/WebCore/history/BackForwardList.h b/Source/WebCore/history/BackForwardList.h index 3f2881963..59292760c 100644 --- a/Source/WebCore/history/BackForwardList.h +++ b/Source/WebCore/history/BackForwardList.h @@ -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 @@ -28,40 +28,70 @@ #ifndef BackForwardList_h #define BackForwardList_h -#include <wtf/Forward.h> -#include <wtf/RefCounted.h> +#include "BackForwardClient.h" +#include <wtf/HashSet.h> +#include <wtf/Vector.h> namespace WebCore { -class HistoryItem; +class Page; -// FIXME: Rename this class to BackForwardClient, and rename the -// getter in Page accordingly. -class BackForwardList : public RefCounted<BackForwardList> { +typedef Vector<Ref<HistoryItem>> HistoryItemVector; +typedef HashSet<RefPtr<HistoryItem>> HistoryItemHashSet; + +class BackForwardList : public BackForwardClient { public: - virtual ~BackForwardList() - { - } + static Ref<BackForwardList> create(Page* page) { return adoptRef(*new BackForwardList(page)); } + virtual ~BackForwardList(); - virtual void addItem(PassRefPtr<HistoryItem>) = 0; + Page* page() { return m_page; } - virtual void goToItem(HistoryItem*) = 0; + virtual void addItem(Ref<HistoryItem>&&) override; + WEBCORE_EXPORT void goBack(); + WEBCORE_EXPORT void goForward(); + virtual void goToItem(HistoryItem*) override; - virtual HistoryItem* itemAtIndex(int) = 0; - virtual int backListCount() = 0; - virtual int forwardListCount() = 0; + WEBCORE_EXPORT HistoryItem* backItem(); + WEBCORE_EXPORT HistoryItem* currentItem(); + WEBCORE_EXPORT HistoryItem* forwardItem(); + virtual HistoryItem* itemAtIndex(int) override; - virtual bool isActive() = 0; + WEBCORE_EXPORT void backListWithLimit(int, HistoryItemVector&); + WEBCORE_EXPORT void forwardListWithLimit(int, HistoryItemVector&); - virtual void close() = 0; + WEBCORE_EXPORT int capacity(); + WEBCORE_EXPORT void setCapacity(int); + WEBCORE_EXPORT bool enabled(); + WEBCORE_EXPORT void setEnabled(bool); + virtual int backListCount() override; + virtual int forwardListCount() override; + WEBCORE_EXPORT bool containsItem(HistoryItem*); - // 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); } -}; + virtual void close() override; + WEBCORE_EXPORT bool closed(); + + WEBCORE_EXPORT void removeItem(HistoryItem*); + WEBCORE_EXPORT HistoryItemVector& entries(); + +#if PLATFORM(IOS) + virtual unsigned current() override; + virtual void setCurrent(unsigned newCurrent) override; + virtual bool clearAllPageCaches() override; +#endif + +private: + WEBCORE_EXPORT 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/BackForwardListImpl.h b/Source/WebCore/history/BackForwardListImpl.h deleted file mode 100644 index 167912af5..000000000 --- a/Source/WebCore/history/BackForwardListImpl.h +++ /dev/null @@ -1,94 +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 BackForwardListImpl_h -#define BackForwardListImpl_h - -#include "BackForwardList.h" -#include <wtf/HashSet.h> -#include <wtf/Vector.h> - -namespace WebCore { - -class Page; - -typedef Vector<RefPtr<HistoryItem> > HistoryItemVector; -typedef HashSet<RefPtr<HistoryItem> > HistoryItemHashSet; - -// FIXME: After renaming BackForwardList to BackForwardClient, -// rename this to BackForwardList. -class BackForwardListImpl : public BackForwardList { -public: - static PassRefPtr<BackForwardListImpl> create(Page* page) { return adoptRef(new BackForwardListImpl(page)); } - virtual ~BackForwardListImpl(); - - Page* page() { return m_page; } - - virtual void addItem(PassRefPtr<HistoryItem>); - void goBack(); - void goForward(); - virtual void goToItem(HistoryItem*); - - HistoryItem* backItem(); - HistoryItem* currentItem(); - HistoryItem* forwardItem(); - virtual HistoryItem* itemAtIndex(int); - - void backListWithLimit(int, HistoryItemVector&); - void forwardListWithLimit(int, HistoryItemVector&); - - int capacity(); - void setCapacity(int); - bool enabled(); - void setEnabled(bool); - virtual int backListCount(); - virtual int forwardListCount(); - bool containsItem(HistoryItem*); - - virtual void close(); - bool closed(); - - void removeItem(HistoryItem*); - HistoryItemVector& entries(); - -private: - explicit BackForwardListImpl(Page*); - - virtual bool isActive() { return enabled() && capacity(); } - - Page* m_page; - HistoryItemVector m_entries; - HistoryItemHashSet m_entryHash; - unsigned m_current; - unsigned m_capacity; - bool m_closed; - bool m_enabled; -}; - -} // namespace WebCore - -#endif // BackForwardListImpl_h diff --git a/Source/WebCore/history/CachedFrame.cpp b/Source/WebCore/history/CachedFrame.cpp index d3d7cb0d0..29dbe9a59 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 @@ -31,64 +31,47 @@ #include "DOMWindow.h" #include "Document.h" #include "DocumentLoader.h" -#include "EventHandler.h" #include "EventNames.h" #include "ExceptionCode.h" -#include "FocusController.h" -#include "Frame.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 "PageCache.h" #include "PageTransitionEvent.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 { -#ifndef NDEBUG -static WTF::RefCountedLeakCounter& cachedFrameCounter() -{ - DEFINE_STATIC_LOCAL(WTF::RefCountedLeakCounter, counter, ("CachedFrame")); - return counter; -} -#endif +DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, cachedFrameCounter, ("CachedFrame")); -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 +CachedFrameBase::CachedFrameBase(Frame& frame) + : m_document(frame.document()) + , m_documentLoader(frame.loader().documentLoader()) + , m_view(frame.view()) + , m_url(frame.document()->url()) + , m_isMainFrame(!frame.tree().parent()) + , m_isComposited(frame.view()->hasCompositedContent()) { } CachedFrameBase::~CachedFrameBase() { #ifndef NDEBUG - cachedFrameCounter().decrement(); + cachedFrameCounter.decrement(); #endif // CachedFrames should always have had destroy() called by their parent CachedPage ASSERT(!m_document); @@ -101,109 +84,103 @@ void CachedFrameBase::restore() if (m_isMainFrame) m_view->setParentVisible(true); - Frame* frame = m_view->frame(); + 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->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(); + frame.script().updatePlatformScriptObjects(); -#if USE(ACCELERATED_COMPOSITING) if (m_isComposited) - frame->view()->restoreBackingStores(); -#endif - - frame->loader()->client()->didRestoreFromPageCache(); + frame.view()->restoreBackingStores(); - // Reconstruct the FrameTree - for (unsigned i = 0; i < m_childFrames.size(); ++i) - frame->tree()->appendChild(m_childFrames[i]->view()->frame()); + frame.loader().client().didRestoreFromPageCache(); - // Open the child CachedFrames in their respective FrameLoaders. - for (unsigned i = 0; i < m_childFrames.size(); ++i) + // 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(); + } + +#if PLATFORM(IOS) + if (m_isMainFrame) { + frame.loader().client().didRestoreFrameHierarchyForCachedFrame(); + + 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); + } + } +#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(); + + HistoryItem* historyItem = frame.loader().history().currentItem(); m_document->enqueuePopstateEvent(historyItem && historyItem->stateObject() ? historyItem->stateObject() : SerializedScriptValue::nullValue()); - -#if ENABLE(TOUCH_EVENTS) + +#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS) if (m_document->hasTouchEventHandlers()) - m_document->page()->chrome().client()->needTouchEvents(true); + m_document->page()->chrome().client().needTouchEvents(true); #endif - m_document->documentDidResumeFromPageCache(); } -CachedFrame::CachedFrame(Frame* frame) +CachedFrame::CachedFrame(Frame& frame) : CachedFrameBase(frame) { #ifndef NDEBUG - cachedFrameCounter().increment(); + cachedFrameCounter.increment(); #endif ASSERT(m_document); ASSERT(m_documentLoader); ASSERT(m_view); - if (frame->page()->focusController()->focusedFrame() == frame) - frame->page()->focusController()->setFocusedFrame(frame->page()->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->inPageCache()); // Create the CachedFrames for all Frames in the FrameTree. - for (Frame* child = frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) - m_childFrames.append(CachedFrame::create(child)); + 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); - m_cachedFrameScriptData = adoptPtr(new ScriptCachedFrameData(frame)); + // Active DOM objects must be suspended before we cache the frame script data. + m_document->suspend(ActiveDOMObject::PageCache); - m_document->domWindow()->suspendForPageCache(); + m_cachedFrameScriptData = std::make_unique<ScriptCachedFrameData>(frame); - frame->loader()->client()->savePlatformDataToCachedFrame(this); + m_document->domWindow()->suspendForDocumentSuspension(); -#if USE(ACCELERATED_COMPOSITING) - if (m_isComposited && pageCache()->shouldClearBackingStores()) - frame->view()->clearBackingStores(); -#endif + frame.loader().client().savePlatformDataToCachedFrame(this); + + if (m_isComposited && PageCache::singleton().shouldClearBackingStores()) + frame.view()->clearBackingStores(); // documentWillSuspendForPageCache() can set up a layout timer on the FrameView, so clear timers after that. - frame->clearTimers(); + frame.clearTimers(); // Deconstruct the FrameTree, to restore it later. // We do this for two reasons: // 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(); + frame.page()->decrementSubframeCount(); - frame->loader()->client()->didSaveToPageCache(); + frame.loader().client().didSaveToPageCache(); #ifndef NDEBUG if (m_isMainFrame) @@ -212,15 +189,25 @@ CachedFrame::CachedFrame(Frame* frame) LOG(PageCache, "Finished creating CachedFrame for child frame with url '%s' and DocumentLoader %p\n", m_url.string().utf8().data(), m_documentLoader.get()); #endif +#if PLATFORM(IOS) + if (m_isMainFrame) { + if (DOMWindow* domWindow = m_document->domWindow()) { + if (domWindow->scrollEventListenerCount() && frame.page()) + frame.page()->chrome().client().setNeedsScrollNotifications(&frame, false); + } + } +#endif + + ASSERT_WITH_SECURITY_IMPLICATION(!m_documentLoader->isLoading()); } void CachedFrame::open() { ASSERT(m_view); - m_view->frame()->loader()->open(*this); - if (!m_isMainFrame) - m_view->frame()->page()->incrementSubframeCount(); + m_view->frame().page()->incrementSubframeCount(); + + m_view->frame().loader().open(*this); } void CachedFrame::clear() @@ -234,18 +221,17 @@ void CachedFrame::clear() // 2 - destroy()'ed because the PageCache is pruning or the WebView was closed. ASSERT(!m_document->inPageCache()); ASSERT(m_view); - ASSERT(m_document->frame() == m_view->frame()); + ASSERT(!m_document->frame() || m_document->frame() == &m_view->frame()); for (int i = m_childFrames.size() - 1; i >= 0; --i) m_childFrames[i]->clear(); - m_document = 0; - m_view = 0; - m_mousePressNode = 0; - m_url = KURL(); + m_document = nullptr; + m_view = nullptr; + m_url = URL(); - m_cachedFramePlatformData.clear(); - m_cachedFrameScriptData.clear(); + m_cachedFramePlatformData = nullptr; + m_cachedFrameScriptData = nullptr; } void CachedFrame::destroy() @@ -256,13 +242,13 @@ void CachedFrame::destroy() // Only CachedFrames that are still in the PageCache should be destroyed in this manner ASSERT(m_document->inPageCache()); ASSERT(m_view); - ASSERT(m_document->frame() == m_view->frame()); + ASSERT(m_document->frame() == &m_view->frame()); m_document->domWindow()->willDestroyCachedFrame(); if (!m_isMainFrame) { - m_view->frame()->detachFromPage(); - m_view->frame()->loader()->detachViewsAndDocumentLoader(); + m_view->frame().detachFromPage(); + m_view->frame().loader().detachViewsAndDocumentLoader(); } for (int i = m_childFrames.size() - 1; i >= 0; --i) @@ -278,16 +264,14 @@ void CachedFrame::destroy() m_document->removeAllEventListeners(); m_document->setInPageCache(false); - // FIXME: We don't call willRemove here. Why is that OK? - m_document->detach(); - m_view->clearFrame(); + m_document->prepareForDestruction(); clear(); } -void CachedFrame::setCachedFramePlatformData(PassOwnPtr<CachedFramePlatformData> data) +void CachedFrame::setCachedFramePlatformData(std::unique_ptr<CachedFramePlatformData> data) { - m_cachedFramePlatformData = data; + m_cachedFramePlatformData = WTFMove(data); } CachedFramePlatformData* CachedFrame::cachedFramePlatformData() diff --git a/Source/WebCore/history/CachedFrame.h b/Source/WebCore/history/CachedFrame.h index 463fa7f8b..e65e60992 100644 --- a/Source/WebCore/history/CachedFrame.h +++ b/Source/WebCore/history/CachedFrame.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2010, 2013 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 @@ -27,10 +27,8 @@ #define CachedFrame_h #include "DOMWindow.h" -#include "KURL.h" +#include "URL.h" #include "ScriptCachedFrameData.h" -#include <wtf/PassOwnPtr.h> -#include <wtf/RefCounted.h> #include <wtf/RefPtr.h> namespace WebCore { @@ -42,57 +40,49 @@ class DocumentLoader; class FrameView; class Node; -typedef Vector<RefPtr<CachedFrame> > CachedFrameVector; - class CachedFrameBase { public: void restore(); Document* document() const { return m_document.get(); } FrameView* view() const { return m_view.get(); } - const KURL& url() const { return m_url; } + const URL& url() const { return m_url; } bool isMainFrame() { return m_isMainFrame; } protected: - CachedFrameBase(Frame*); + CachedFrameBase(Frame&); ~CachedFrameBase(); RefPtr<Document> m_document; RefPtr<DocumentLoader> m_documentLoader; RefPtr<FrameView> m_view; - RefPtr<Node> m_mousePressNode; - KURL m_url; - OwnPtr<ScriptCachedFrameData> m_cachedFrameScriptData; - OwnPtr<CachedFramePlatformData> m_cachedFramePlatformData; + 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 - CachedFrameVector m_childFrames; + Vector<std::unique_ptr<CachedFrame>> m_childFrames; }; -class CachedFrame : public RefCounted<CachedFrame>, private CachedFrameBase { +class CachedFrame : private CachedFrameBase { + WTF_MAKE_FAST_ALLOCATED; public: - static PassRefPtr<CachedFrame> create(Frame* frame) { return adoptRef(new CachedFrame(frame)); } + explicit CachedFrame(Frame&); void open(); void clear(); void destroy(); - void setCachedFramePlatformData(PassOwnPtr<CachedFramePlatformData>); - CachedFramePlatformData* cachedFramePlatformData(); + WEBCORE_EXPORT void setCachedFramePlatformData(std::unique_ptr<CachedFramePlatformData>); + WEBCORE_EXPORT CachedFramePlatformData* cachedFramePlatformData(); 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; - -private: - explicit CachedFrame(Frame*); }; } // namespace WebCore diff --git a/Source/WebCore/history/CachedFramePlatformData.h b/Source/WebCore/history/CachedFramePlatformData.h index 01da8e5a6..5ae7be57d 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. * diff --git a/Source/WebCore/history/CachedPage.cpp b/Source/WebCore/history/CachedPage.cpp index 61a06da78..d4ff648e2 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 @@ -29,8 +29,8 @@ #include "Document.h" #include "Element.h" #include "FocusController.h" -#include "Frame.h" #include "FrameView.h" +#include "MainFrame.h" #include "Node.h" #include "Page.h" #include "Settings.h" @@ -39,25 +39,19 @@ #include <wtf/RefCountedLeakCounter.h> #include <wtf/StdLibExtras.h> +#if PLATFORM(IOS) +#include "FrameSelection.h" +#endif + using namespace JSC; namespace WebCore { DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, cachedPageCounter, ("CachedPage")); -PassRefPtr<CachedPage> CachedPage::create(Page* page) -{ - return adoptRef(new CachedPage(page)); -} - -CachedPage::CachedPage(Page* page) - : m_timeStamp(currentTime()) - , m_expirationTime(m_timeStamp + page->settings()->backForwardCacheExpirationInterval()) - , m_cachedMainFrame(CachedFrame::create(page->mainFrame())) - , m_needStyleRecalcForVisitedLinks(false) - , m_needsFullStyleRecalc(false) - , m_needsCaptionPreferencesChanged(false) - , m_needsDeviceScaleChanged(false) +CachedPage::CachedPage(Page& page) + : m_expirationTime(monotonicallyIncreasingTime() + page.settings().backForwardCacheExpirationInterval()) + , m_cachedMainFrame(std::make_unique<CachedFrame>(page.mainFrame())) { #ifndef NDEBUG cachedPageCounter.increment(); @@ -70,44 +64,57 @@ CachedPage::~CachedPage() cachedPageCounter.decrement(); #endif - destroy(); - ASSERT(!m_cachedMainFrame); + if (m_cachedMainFrame) + m_cachedMainFrame->destroy(); } -void CachedPage::restore(Page* page) +void CachedPage::restore(Page& page) { ASSERT(m_cachedMainFrame); - ASSERT(page && page->mainFrame() && page->mainFrame() == m_cachedMainFrame->view()->frame()); - ASSERT(!page->subframeCount()); + ASSERT(m_cachedMainFrame->view()->frame().isMainFrame()); + ASSERT(!page.subframeCount()); + + page.setNeedsRecalcStyleInAllFrames(); 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. - Document* focusedDocument = page->focusController()->focusedOrMainFrame()->document(); - if (Element* element = focusedDocument->focusedElement()) - element->updateFocusAppearance(true); - - 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 (Frame* frame = page->mainFrame()) - frame->deviceOrPageScaleFactorChanged(); - } + Document* focusedDocument = page.focusController().focusedOrMainFrame().document(); + if (Element* element = focusedDocument->focusedElement()) { +#if PLATFORM(IOS) + // 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(SelectionRestorationMode::Restore); +#if PLATFORM(IOS) + if (frameView) + frameView->setProhibitsScrolling(hadProhibitsScrolling); + page.mainFrame().selection().restoreScrolling(); +#endif + } - if (m_needsFullStyleRecalc) - page->setNeedsRecalcStyleInAllFrames(); + if (m_needsDeviceOrPageScaleChanged) + page.mainFrame().deviceOrPageScaleFactorChanged(); #if ENABLE(VIDEO_TRACK) if (m_needsCaptionPreferencesChanged) - page->captionPreferencesChanged(); + page.captionPreferencesChanged(); #endif + if (m_needsUpdateContentsSize) { + if (FrameView* frameView = page.mainFrame().view()) + frameView->updateContentsSize(); + } + clear(); } @@ -115,22 +122,17 @@ 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 { - return currentTime() > m_expirationTime; + return monotonicallyIncreasingTime() > m_expirationTime; } } // namespace WebCore diff --git a/Source/WebCore/history/CachedPage.h b/Source/WebCore/history/CachedPage.h index c804efc8b..c082bc498 100644 --- a/Source/WebCore/history/CachedPage.h +++ b/Source/WebCore/history/CachedPage.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2013 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 @@ -27,51 +27,45 @@ #define CachedPage_h #include "CachedFrame.h" -#include <wtf/RefCounted.h> namespace WebCore { - + class Document; class DocumentLoader; class Page; -class CachedPage : public RefCounted<CachedPage> { +class CachedPage { + WTF_MAKE_FAST_ALLOCATED; public: - static PassRefPtr<CachedPage> create(Page*); + explicit CachedPage(Page&); ~CachedPage(); - void restore(Page*); + void restore(Page&); void clear(); - void destroy(); 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: - CachedPage(Page*); + void markForContentsSizeChanged() { m_needsUpdateContentsSize = true; } - double m_timeStamp; +private: double m_expirationTime; - RefPtr<CachedFrame> m_cachedMainFrame; - bool m_needStyleRecalcForVisitedLinks; - bool m_needsFullStyleRecalc; - bool m_needsCaptionPreferencesChanged; - bool m_needsDeviceScaleChanged; + std::unique_ptr<CachedFrame> m_cachedMainFrame; +#if ENABLE(VIDEO_TRACK) + bool m_needsCaptionPreferencesChanged { false }; +#endif + bool m_needsDeviceOrPageScaleChanged { false }; + bool m_needsUpdateContentsSize { false }; }; } // namespace WebCore diff --git a/Source/WebCore/history/HistoryItem.cpp b/Source/WebCore/history/HistoryItem.cpp index a389c0328..26bb7906f 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 @@ -29,20 +29,18 @@ #include "CachedPage.h" #include "Document.h" #include "IconDatabase.h" +#include "KeyedCoding.h" #include "PageCache.h" #include "ResourceRequest.h" #include "SerializedScriptValue.h" #include "SharedBuffer.h" #include <stdio.h> #include <wtf/CurrentTime.h> -#include <wtf/Decoder.h> -#include <wtf/Encoder.h> +#include <wtf/DateMath.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 @@ -55,79 +53,62 @@ static void defaultNotifyHistoryItemChanged(HistoryItem*) { } -void (*notifyHistoryItemChanged)(HistoryItem*) = defaultNotifyHistoryItemChanged; +WEBCORE_EXPORT void (*notifyHistoryItemChanged)(HistoryItem*) = defaultNotifyHistoryItemChanged; HistoryItem::HistoryItem() - : m_lastVisitedTime(0) - , m_lastVisitWasHTTPNonGet(false) - , m_pageScaleFactor(0) + : m_pageScaleFactor(0) , m_lastVisitWasFailure(false) , m_isTargetItem(false) - , m_visitCount(0) , m_itemSequenceNumber(generateSequenceNumber()) , m_documentSequenceNumber(generateSequenceNumber()) - , m_next(0) - , m_prev(0) + , m_pruningReason(PruningReason::None) +#if PLATFORM(IOS) + , m_scale(0) + , m_scaleIsInitial(false) + , m_bookmarkID(0) +#endif { } -HistoryItem::HistoryItem(const String& urlString, const String& title, double time) +HistoryItem::HistoryItem(const String& urlString, const String& title) : m_urlString(urlString) , m_originalURLString(urlString) , m_title(title) - , m_lastVisitedTime(time) - , m_lastVisitWasHTTPNonGet(false) , m_pageScaleFactor(0) , m_lastVisitWasFailure(false) , m_isTargetItem(false) - , m_visitCount(0) , m_itemSequenceNumber(generateSequenceNumber()) , m_documentSequenceNumber(generateSequenceNumber()) - , m_next(0) - , m_prev(0) + , m_pruningReason(PruningReason::None) +#if PLATFORM(IOS) + , m_scale(0) + , m_scaleIsInitial(false) + , m_bookmarkID(0) +#endif { iconDatabase().retainIconForPageURL(m_urlString); } -HistoryItem::HistoryItem(const String& urlString, const String& title, const String& alternateTitle, double time) +HistoryItem::HistoryItem(const String& urlString, const String& title, const String& alternateTitle) : m_urlString(urlString) , m_originalURLString(urlString) , m_title(title) , m_displayTitle(alternateTitle) - , m_lastVisitedTime(time) - , m_lastVisitWasHTTPNonGet(false) , m_pageScaleFactor(0) , m_lastVisitWasFailure(false) , m_isTargetItem(false) - , m_visitCount(0) , m_itemSequenceNumber(generateSequenceNumber()) , m_documentSequenceNumber(generateSequenceNumber()) - , m_next(0) - , m_prev(0) + , m_pruningReason(PruningReason::None) +#if PLATFORM(IOS) + , m_scale(0) + , m_scaleIsInitial(false) + , m_bookmarkID(0) +#endif { iconDatabase().retainIconForPageURL(m_urlString); } -HistoryItem::HistoryItem(const KURL& 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_lastVisitedTime(0) - , m_lastVisitWasHTTPNonGet(false) - , m_pageScaleFactor(0) - , m_lastVisitWasFailure(false) - , m_isTargetItem(false) - , m_visitCount(0) - , m_itemSequenceNumber(generateSequenceNumber()) - , m_documentSequenceNumber(generateSequenceNumber()) - , m_next(0) - , m_prev(0) -{ - iconDatabase().retainIconForPageURL(m_urlString); -} - HistoryItem::~HistoryItem() { ASSERT(!m_cachedPage); @@ -140,21 +121,22 @@ 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_lastVisitedTime(item.m_lastVisitedTime) - , m_lastVisitWasHTTPNonGet(item.m_lastVisitWasHTTPNonGet) - , 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_visitCount(item.m_visitCount) - , m_dailyVisitCounts(item.m_dailyVisitCounts) - , m_weeklyVisitCounts(item.m_weeklyVisitCounts) , m_itemSequenceNumber(item.m_itemSequenceNumber) , m_documentSequenceNumber(item.m_documentSequenceNumber) , m_formContentType(item.m_formContentType) + , m_pruningReason(PruningReason::None) +#if PLATFORM(IOS) + , 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) m_formData = item.m_formData->copy(); @@ -165,12 +147,12 @@ inline HistoryItem::HistoryItem(const HistoryItem& item) m_children.uncheckedAppend(item.m_children[i]->copy()); if (item.m_redirectURLs) - m_redirectURLs = adoptPtr(new Vector<String>(*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() @@ -181,27 +163,20 @@ void HistoryItem::reset() m_originalURLString = String(); m_referrer = String(); m_target = String(); - m_parent = String(); m_title = String(); m_displayTitle = String(); - m_lastVisitedTime = 0; - m_lastVisitWasHTTPNonGet = false; - m_lastVisitWasFailure = false; m_isTargetItem = false; - m_visitCount = 0; - m_dailyVisitCounts.clear(); - m_weeklyVisitCounts.clear(); - m_redirectURLs.clear(); + 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(); @@ -234,19 +209,14 @@ bool HistoryItem::hasCachedPageExpired() const return m_cachedPage ? m_cachedPage->hasExpired() : false; } -double HistoryItem::lastVisitedTime() const +URL HistoryItem::url() const { - return m_lastVisitedTime; + return URL(ParsedURLString, m_urlString); } -KURL HistoryItem::url() const +URL HistoryItem::originalURL() const { - return KURL(ParsedURLString, m_urlString); -} - -KURL HistoryItem::originalURL() const -{ - return KURL(ParsedURLString, m_originalURLString); + return URL(ParsedURLString, m_originalURLString); } const String& HistoryItem::referrer() const @@ -259,11 +229,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; @@ -281,9 +246,9 @@ void HistoryItem::setURLString(const String& urlString) notifyHistoryItemChanged(this); } -void HistoryItem::setURL(const KURL& url) +void HistoryItem::setURL(const URL& url) { - pageCache()->remove(this); + PageCache::singleton().remove(*this); setURLString(url.string()); clearDocumentState(); } @@ -312,114 +277,19 @@ void HistoryItem::setTarget(const String& target) notifyHistoryItemChanged(this); } -void HistoryItem::setParent(const String& parent) -{ - m_parent = parent; -} - -static inline int timeToDay(double time) -{ - static const double secondsPerDay = 60 * 60 * 24; - return static_cast<int>(ceil(time / secondsPerDay)); -} - -void HistoryItem::padDailyCountsForNewVisit(double time) -{ - if (m_dailyVisitCounts.isEmpty()) - m_dailyVisitCounts.insert(0, m_visitCount); - - int daysElapsed = timeToDay(time) - timeToDay(m_lastVisitedTime); - - if (daysElapsed < 0) - daysElapsed = 0; - - Vector<int> padding; - padding.fill(0, daysElapsed); - m_dailyVisitCounts.insert(0, padding); -} - -static const size_t daysPerWeek = 7; -static const size_t maxDailyCounts = 2 * daysPerWeek - 1; -static const size_t maxWeeklyCounts = 5; - -void HistoryItem::collapseDailyVisitsToWeekly() -{ - while (m_dailyVisitCounts.size() > maxDailyCounts) { - int oldestWeekTotal = 0; - for (size_t i = 0; i < daysPerWeek; i++) - oldestWeekTotal += m_dailyVisitCounts[m_dailyVisitCounts.size() - daysPerWeek + i]; - m_dailyVisitCounts.shrink(m_dailyVisitCounts.size() - daysPerWeek); - m_weeklyVisitCounts.insert(0, oldestWeekTotal); - } - - if (m_weeklyVisitCounts.size() > maxWeeklyCounts) - m_weeklyVisitCounts.shrink(maxWeeklyCounts); -} - -void HistoryItem::recordVisitAtTime(double time, VisitCountBehavior visitCountBehavior) -{ - padDailyCountsForNewVisit(time); - - m_lastVisitedTime = time; - - if (visitCountBehavior == IncreaseVisitCount) { - ++m_visitCount; - ++m_dailyVisitCounts[0]; - } - - collapseDailyVisitsToWeekly(); -} - -void HistoryItem::setLastVisitedTime(double time) -{ - if (m_lastVisitedTime != time) - recordVisitAtTime(time); -} - -void HistoryItem::visited(const String& title, double time, VisitCountBehavior visitCountBehavior) +const IntPoint& HistoryItem::scrollPosition() const { - m_title = title; - recordVisitAtTime(time, visitCountBehavior); + return m_scrollPosition; } -int HistoryItem::visitCount() const +void HistoryItem::setScrollPosition(const IntPoint& position) { - return m_visitCount; + m_scrollPosition = position; } -void HistoryItem::recordInitialVisit() +void HistoryItem::clearScrollPosition() { - ASSERT(!m_visitCount); - recordVisitAtTime(m_lastVisitedTime); -} - -void HistoryItem::setVisitCount(int count) -{ - m_visitCount = count; -} - -void HistoryItem::adoptVisitCounts(Vector<int>& dailyCounts, Vector<int>& weeklyCounts) -{ - m_dailyVisitCounts.clear(); - m_dailyVisitCounts.swap(dailyCounts); - m_weeklyVisitCounts.clear(); - m_weeklyVisitCounts.swap(weeklyCounts); -} - -const IntPoint& HistoryItem::scrollPoint() const -{ - return m_scrollPoint; -} - -void HistoryItem::setScrollPoint(const IntPoint& point) -{ - m_scrollPoint = point; -} - -void HistoryItem::clearScrollPoint() -{ - m_scrollPoint.setX(0); - m_scrollPoint.setY(0); + m_scrollPosition = IntPoint(); } float HistoryItem::pageScaleFactor() const @@ -447,6 +317,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; @@ -457,68 +337,49 @@ 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 @@ -536,13 +397,13 @@ void HistoryItem::clearChildren() m_children.clear(); } -bool HistoryItem::isAncestorOf(const HistoryItem* item) const +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) + auto& child = m_children[i].get(); + if (&child == &item) return true; - if (child->isAncestorOf(item)) + if (child.isAncestorOf(item)) return true; } return false; @@ -551,34 +412,34 @@ bool HistoryItem::isAncestorOf(const HistoryItem* item) const // 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; } @@ -587,16 +448,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; } @@ -612,20 +473,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) @@ -638,26 +499,16 @@ 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::mergeAutoCompleteHints(HistoryItem* otherItem) -{ - // FIXME: this is broken - we should be merging the daily counts - // somehow. but this is to support API that's not really used in - // practice so leave it broken for now. - ASSERT(otherItem); - if (otherItem != this) - m_visitCount += otherItem->m_visitCount; + return equalIgnoringFragmentIdentifier(url(), document.url()); } void HistoryItem::addRedirectURL(const String& url) { if (!m_redirectURLs) - m_redirectURLs = adoptPtr(new Vector<String>); + 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. @@ -670,183 +521,14 @@ Vector<String>* HistoryItem::redirectURLs() const return m_redirectURLs.get(); } -void HistoryItem::setRedirectURLs(PassOwnPtr<Vector<String> > redirectURLs) +void HistoryItem::setRedirectURLs(std::unique_ptr<Vector<String>> redirectURLs) { - m_redirectURLs = redirectURLs; + m_redirectURLs = WTFMove(redirectURLs); } -void HistoryItem::encodeBackForwardTree(Encoder& encoder) const +void HistoryItem::notifyChanged() { - encoder.encodeUInt32(backForwardTreeEncodingVersion); - - encodeBackForwardTreeNode(encoder); -} - -void HistoryItem::encodeBackForwardTreeNode(Encoder& encoder) const -{ - 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); -} - -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, 0); - - 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(); + notifyHistoryItemChanged(this); } #ifndef NDEBUG diff --git a/Source/WebCore/history/HistoryItem.h b/Source/WebCore/history/HistoryItem.h index 7fe4511e8..f94482239 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 @@ -27,14 +27,20 @@ #ifndef HistoryItem_h #define HistoryItem_h +#include "FloatRect.h" +#include "FrameLoaderTypes.h" #include "IntPoint.h" +#include "IntRect.h" #include "SerializedScriptValue.h" -#include <wtf/OwnPtr.h> -#include <wtf/PassOwnPtr.h> +#include <memory> #include <wtf/RefCounted.h> #include <wtf/text/WTFString.h> -#if PLATFORM(MAC) +#if PLATFORM(IOS) +#include "ViewportArguments.h" +#endif + +#if PLATFORM(COCOA) #import <wtf/RetainPtr.h> typedef struct objc_object* id; #endif @@ -45,10 +51,6 @@ typedef struct objc_object* id; #include <QDataStream> #endif -#if PLATFORM(BLACKBERRY) -#include "HistoryItemViewState.h" -#endif - namespace WebCore { class CachedPage; @@ -56,96 +58,80 @@ class Document; class FormData; class HistoryItem; class Image; -class KURL; class ResourceRequest; +class URL; +enum class PruningReason; -typedef Vector<RefPtr<HistoryItem> > HistoryItemVector; - -extern void (*notifyHistoryItemChanged)(HistoryItem*); +typedef Vector<Ref<HistoryItem>> HistoryItemVector; -enum VisitCountBehavior { - IncreaseVisitCount, - DoNotIncreaseVisitCount -}; +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, double lastVisited) + static Ref<HistoryItem> create() { return adoptRef(*new HistoryItem); } + static Ref<HistoryItem> create(const String& urlString, const String& title) { - return adoptRef(new HistoryItem(urlString, title, lastVisited)); + return adoptRef(*new HistoryItem(urlString, title)); } - static PassRefPtr<HistoryItem> create(const String& urlString, const String& title, const String& alternateTitle, double lastVisited) + static Ref<HistoryItem> create(const String& urlString, const String& title, const String& alternateTitle) { - return adoptRef(new HistoryItem(urlString, title, alternateTitle, lastVisited)); - } - static PassRefPtr<HistoryItem> create(const KURL& url, const String& target, const String& parent, const String& title) - { - 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; - static PassRefPtr<HistoryItem> decodeBackForwardTree(const String& urlString, const String& title, const String& originalURLString, Decoder&); - - const String& originalURLString() const; - const String& urlString() const; - const String& title() const; - - bool isInPageCache() const { return m_cachedPage; } - bool hasCachedPageExpired() const; - - double lastVisitedTime() const; + WEBCORE_EXPORT const String& originalURLString() const; + WEBCORE_EXPORT const String& urlString() const; + WEBCORE_EXPORT const String& title() const; - void setAlternateTitle(const String& alternateTitle); - const String& alternateTitle() const; + bool isInPageCache() const { return m_cachedPage.get(); } + WEBCORE_EXPORT bool hasCachedPageExpired() const; + + WEBCORE_EXPORT void setAlternateTitle(const String&); + WEBCORE_EXPORT const String& alternateTitle() const; - const String& parent() const; - KURL url() const; - KURL 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; - int visitCount() const; bool lastVisitWasFailure() const { return m_lastVisitWasFailure; } - bool lastVisitWasHTTPNonGet() const { return m_lastVisitWasHTTPNonGet; } - void mergeAutoCompleteHints(HistoryItem* otherItem); - - 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(); - void setURL(const KURL&); - 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 setShouldOpenExternalURLsPolicy(ShouldOpenExternalURLsPolicy); + WEBCORE_EXPORT ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy() const; + + void setURL(const URL&); + 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>&&); + RefPtr<SerializedScriptValue> stateObject() const { return m_stateObject; } void setItemSequenceNumber(long long number) { m_itemSequenceNumber = number; } long long itemSequenceNumber() const { return m_itemSequenceNumber; } @@ -154,59 +140,42 @@ 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 recordInitialVisit(); - - void setVisitCount(int); void setLastVisitWasFailure(bool wasFailure) { m_lastVisitWasFailure = wasFailure; } - void setLastVisitWasHTTPNonGet(bool wasNotGet) { m_lastVisitWasHTTPNonGet = wasNotGet; } - - 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 HistoryItemVector& children() const; + WEBCORE_EXPORT bool hasChildren() const; void clearChildren(); - bool isAncestorOf(const HistoryItem*) const; + bool isAncestorOf(const HistoryItem&) const; - bool shouldDoSameDocumentNavigationTo(HistoryItem* otherItem) const; - bool hasSameFrames(HistoryItem* otherItem) const; + bool shouldDoSameDocumentNavigationTo(HistoryItem& otherItem) const; + bool hasSameFrames(HistoryItem& otherItem) const; - // This should not be called directly for HistoryItems that are already included - // in GlobalHistory. The WebKit api for this is to use -[WebHistory setLastVisitedTimeInterval:forItem:] instead. - void setLastVisitedTime(double); - void visited(const String& title, double time, VisitCountBehavior); + WEBCORE_EXPORT void addRedirectURL(const String&); + WEBCORE_EXPORT Vector<String>* redirectURLs() const; + WEBCORE_EXPORT void setRedirectURLs(std::unique_ptr<Vector<String>>); - void addRedirectURL(const String&); - Vector<String>* redirectURLs() const; - void setRedirectURLs(PassOwnPtr<Vector<String> >); - - 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 #if PLATFORM(QT) QVariant userData() const { return m_userData; } void setUserData(const QVariant& userData) { m_userData = userData; } - - static PassRefPtr<HistoryItem> restoreState(QDataStream& buffer, int version); - QDataStream& saveState(QDataStream& out, int version) const; -#endif - -#if PLATFORM(BLACKBERRY) - HistoryItemViewState& viewState() { return m_viewState; } #endif #ifndef NDEBUG @@ -214,56 +183,71 @@ public: int showTreeWithIndent(unsigned indentLevel) const; #endif - void adoptVisitCounts(Vector<int>& dailyCounts, Vector<int>& weeklyCounts); - const Vector<int>& dailyVisitCounts() const { return m_dailyVisitCounts; } - const Vector<int>& weeklyVisitCounts() const { return m_weeklyVisitCounts; } +#if PLATFORM(IOS) + FloatRect exposedContentRect() const { return m_exposedContentRect; } + void setExposedContentRect(FloatRect exposedContentRect) { m_exposedContentRect = exposedContentRect; } -private: - HistoryItem(); - HistoryItem(const String& urlString, const String& title, double lastVisited); - HistoryItem(const String& urlString, const String& title, const String& alternateTitle, double lastVisited); - HistoryItem(const KURL& url, const String& frameName, const String& parent, const String& title); + IntRect unobscuredContentRect() const { return m_unobscuredContentRect; } + void setUnobscuredContentRect(IntRect unobscuredContentRect) { m_unobscuredContentRect = unobscuredContentRect; } - explicit HistoryItem(const HistoryItem&); + FloatSize minimumLayoutSizeInScrollViewCoordinates() const { return m_minimumLayoutSizeInScrollViewCoordinates; } + void setMinimumLayoutSizeInScrollViewCoordinates(FloatSize minimumLayoutSizeInScrollViewCoordinates) { m_minimumLayoutSizeInScrollViewCoordinates = minimumLayoutSizeInScrollViewCoordinates; } - void padDailyCountsForNewVisit(double time); - void collapseDailyVisitsToWeekly(); - void recordVisitAtTime(double, VisitCountBehavior = IncreaseVisitCount); - - bool hasSameDocumentTree(HistoryItem* otherItem) const; + 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; + m_scaleIsInitial = isInitial; + } + + 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 + + void notifyChanged(); - HistoryItem* findTargetItem(); + void setWasRestoredFromSession(bool wasRestoredFromSession) { m_wasRestoredFromSession = wasRestoredFromSession; } + bool wasRestoredFromSession() const { return m_wasRestoredFromSession; } - void encodeBackForwardTreeNode(Encoder&) 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(const HistoryItem&); - /* When adding new member variables to this class, please notify the Qt team. - * qt/HistoryItemQt.cpp contains code to serialize history items. - */ + 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; - double m_lastVisitedTime; - bool m_lastVisitWasHTTPNonGet; - - IntPoint m_scrollPoint; + IntPoint m_scrollPosition; float m_pageScaleFactor; Vector<String> m_documentState; + + ShouldOpenExternalURLsPolicy m_shouldOpenExternalURLsPolicy { ShouldOpenExternalURLsPolicy::ShouldNotAllow }; HistoryItemVector m_children; bool m_lastVisitWasFailure; bool m_isTargetItem; - int m_visitCount; - Vector<int> m_dailyVisitCounts; - Vector<int> m_weeklyVisitCounts; + bool m_wasRestoredFromSession { false }; - OwnPtr<Vector<String> > m_redirectURLs; + std::unique_ptr<Vector<String>> m_redirectURLs; // If two HistoryItems have the same item sequence number, then they are // clones of one another. Traversing history from one such HistoryItem to @@ -284,22 +268,30 @@ private: String m_formContentType; // PageCache controls these fields. - HistoryItem* m_next; - HistoryItem* m_prev; - RefPtr<CachedPage> m_cachedPage; - -#if PLATFORM(MAC) + std::unique_ptr<CachedPage> m_cachedPage; + PruningReason m_pruningReason; + +#if PLATFORM(IOS) + FloatRect m_exposedContentRect; + IntRect m_unobscuredContentRect; + FloatSize m_minimumLayoutSizeInScrollViewCoordinates; + IntSize m_contentSize; + float m_scale; + bool m_scaleIsInitial; + ViewportArguments m_viewportArguments; + + uint32_t m_bookmarkID; + String m_sharedLinkUniqueIdentifier; +#endif + +#if PLATFORM(COCOA) RetainPtr<id> m_viewState; - OwnPtr<HashMap<String, RetainPtr<id> > > m_transientProperties; + std::unique_ptr<HashMap<String, RetainPtr<id>>> m_transientProperties; #endif #if PLATFORM(QT) QVariant m_userData; #endif - -#if PLATFORM(BLACKBERRY) - HistoryItemViewState m_viewState; -#endif }; //class HistoryItem } //namespace WebCore diff --git a/Source/WebCore/history/PageCache.cpp b/Source/WebCore/history/PageCache.cpp index c45ca8015..84ded8cce 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 @@ -31,24 +31,27 @@ #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 "Frame.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 "Page.h" #include "Settings.h" -#include "SharedWorkerRepository.h" +#include "SubframeLoader.h" #include <wtf/CurrentTime.h> +#include <wtf/NeverDestroyed.h> +#include <wtf/TemporaryChange.h> #include <wtf/text/CString.h> #include <wtf/text/StringConcatenate.h> @@ -56,465 +59,419 @@ #include "DeviceProximityController.h" #endif -using namespace std; - 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.logDiagnosticMessageWithValue(DiagnosticLoggingKeys::pageCacheKey(), DiagnosticLoggingKeys::failureKey(), reason, ShouldSample::Yes); +} + +static inline void logPageCacheFailureDiagnosticMessage(Page* page, const String& reason) +{ + if (!page) + return; + + logPageCacheFailureDiagnosticMessage(page->mainFrame().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; } - KURL currentURL = frame->loader()->documentLoader()->url(); - KURL newURL = frame->loader()->provisionalDocumentLoader() ? frame->loader()->provisionalDocumentLoader()->url() : KURL(); + 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"); - rejectReasons |= 1 << MainDocumentError; + 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 + 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; + logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::hasPluginsKey()); + isCacheable = false; } - if (frame->document()->domWindow() && frame->document()->domWindow()->hasEventListeners(eventNames().unloadEvent)) { - PCLOG(" -Frame has an unload event listener"); - rejectReasons |= 1 << HasUnloadListener; + 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; } -#if ENABLE(SQL_DATABASE) - if (DatabaseManager::manager().hasOpenDatabases(frame->document())) { - PCLOG(" -Frame has open database handles"); - rejectReasons |= 1 << HasDatabaseHandles; + if (frame.isMainFrame() && !frameLoader.history().currentItem()) { + PCLOG(" -Main frame has no current history item"); + logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::noCurrentHistoryItemKey()); + isCacheable = false; } -#endif -#if ENABLE(SHARED_WORKERS) - if (SharedWorkerRepository::hasSharedWorkers(frame->document())) { - PCLOG(" -Frame has associated SharedWorkers"); - rejectReasons |= 1 << HasSharedWorkers; - } -#endif - if (!frame->loader()->history()->currentItem()) { - PCLOG(" -No current history item"); - rejectReasons |= 1 << NoHistoryItem; - } - 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.logDiagnosticMessageWithValue(DiagnosticLoggingKeys::pageCacheKey(), 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; - KURL currentURL = page->mainFrame()->loader()->documentLoader() ? page->mainFrame()->loader()->documentLoader()->url() : KURL(); - if (currentURL.isEmpty()) - return; - - int indentLevel = 0; + unsigned indentLevel = 0; PCLOG("--------\n Determining if page can be cached:"); - unsigned rejectReasons = 0; - unsigned frameRejectReasons = logCanCacheFrameDecision(page->mainFrame(), indentLevel+1); - if (frameRejectReasons) - rejectReasons |= 1 << FrameCannotBeInPageCache; + MainFrame& mainFrame = page.mainFrame(); + DiagnosticLoggingClient& diagnosticLoggingClient = mainFrame.diagnosticLoggingClient(); + bool isCacheable = canCacheFrame(mainFrame, diagnosticLoggingClient, indentLevel + 1); - if (!page->backForward()->isActive()) { - PCLOG(" -The back/forward list is disabled or has 0 capacity"); - rejectReasons |= 1 << DisabledBackForwardList; - } - if (!page->settings()->usesPageCache()) { + if (!page.settings().usesPageCache()) { PCLOG(" -Page settings says b/f cache disabled"); - rejectReasons |= 1 << DisabledPageCache; + logPageCacheFailureDiagnosticMessage(diagnosticLoggingClient, DiagnosticLoggingKeys::isDisabledKey()); + isCacheable = false; } -#if ENABLE(DEVICE_ORIENTATION) - if (DeviceMotionController::isActiveAt(page)) { +#if ENABLE(DEVICE_ORIENTATION) && !PLATFORM(IOS) + 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; + if (!m_maxSize) { + logPageCacheFailureDiagnosticMessage(&page, DiagnosticLoggingKeys::isDisabledKey()); + return false; } - - FrameLoader* frameLoader = frame->loader(); - DocumentLoader* documentLoader = frameLoader->documentLoader(); - Document* document = frame->document(); - - return documentLoader - && documentLoader->mainDocumentError().isNull() - // 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())) - && (!document->domWindow() || !document->domWindow()->hasEventListeners(eventNames().unloadEvent)) -#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 (MemoryPressureHandler::singleton().isUnderMemoryPressure()) { + logPageCacheFailureDiagnosticMessage(&page, DiagnosticLoggingKeys::underMemoryPressureKey()); return false; + } -#if !defined(NDEBUG) - logCanCachePageDecision(page); -#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->backForward()->isActive() - && page->settings()->usesPageCache() -#if ENABLE(DEVICE_ORIENTATION) - && !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::setCapacity(int capacity) +void PageCache::pruneToSizeNow(unsigned size, PruningReason pruningReason) { - ASSERT(capacity >= 0); - m_capacity = max(capacity, 0); + TemporaryChange<unsigned> change(m_maxSize, size); + prune(pruningReason); +} - prune(); +void PageCache::setMaxSize(unsigned maxSize) +{ + 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() -{ - for (HistoryItem* current = m_head; current; current = current->m_next) - current->m_cachedPage->markForVistedLinkStyleRecalc(); -} - -void PageCache::markPagesForFullStyleRecalc(Page* page) +void PageCache::markPagesForDeviceOrPageScaleChanged(Page& page) { - Frame* mainFrame = page->mainFrame(); - - for (HistoryItem* current = m_head; current; current = current->m_next) { - CachedPage* cachedPage = current->m_cachedPage.get(); - if (cachedPage->cachedMainFrame()->view()->frame() == mainFrame) - cachedPage->markForFullStyleRecalc(); + for (auto& item : m_items) { + CachedPage& cachedPage = *item->m_cachedPage; + if (&page.mainFrame() == &cachedPage.cachedMainFrame()->view()->frame()) + cachedPage.markForDeviceOrPageScaleChanged(); } } - -#if USE(ACCELERATED_COMPOSITING) -void PageCache::markPagesForDeviceScaleChanged(Page* page) +void PageCache::markPagesForContentsSizeChanged(Page& page) { - Frame* mainFrame = page->mainFrame(); - - for (HistoryItem* current = m_head; current; current = current->m_next) { - CachedPage* cachedPage = current->m_cachedPage.get(); - if (cachedPage->cachedMainFrame()->view()->frame() == mainFrame) - cachedPage->markForDeviceScaleChanged(); + for (auto& item : m_items) { + CachedPage& cachedPage = *item->m_cachedPage; + if (&page.mainFrame() == &cachedPage.cachedMainFrame()->view()->frame()) + cachedPage.markForContentsSizeChanged(); } } -#endif #if ENABLE(VIDEO_TRACK) void PageCache::markPagesForCaptionPreferencesChanged() { - for (HistoryItem* current = m_head; current; current = current->m_next) - current->m_cachedPage->markForCaptionPreferencesChanged(); + for (auto& item : m_items) { + ASSERT(item->m_cachedPage); + item->m_cachedPage->markForCaptionPreferencesChanged(); + } } #endif -void PageCache::add(PassRefPtr<HistoryItem> prpItem, Page* page) +static String pruningReasonToDiagnosticLoggingKey(PruningReason pruningReason) { - ASSERT(prpItem); - ASSERT(page); - ASSERT(canCache(page)); - - HistoryItem* item = prpItem.leakRef(); // Balanced in remove(). - - // Remove stale cache entry if necessary. - if (item->m_cachedPage) - remove(item); + 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(); +} - item->m_cachedPage = CachedPage::create(page); - addToLRUList(item); - ++m_size; - - prune(); +static void setInPageCache(Page& page, bool isInPageCache) +{ + for (Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext()) { + if (auto* document = frame->document()) + document->setInPageCache(isInPageCache); + } } -CachedPage* PageCache::get(HistoryItem* item) +static void firePageHideEventRecursively(Frame& frame) { - if (!item) - return 0; + auto* document = frame.document(); + if (!document) + return; - 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; + // 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); } -void PageCache::remove(HistoryItem* item) +void PageCache::addIfCacheable(HistoryItem& item, Page* page) { - // Safely ignore attempts to remove items not in the cache. - if (!item || !item->m_cachedPage) + if (item.isInPageCache()) + return; + + if (!page || !canCache(*page)) return; - item->m_cachedPage.clear(); - removeFromLRUList(item); - --m_size; + // Make sure all the documents know they are being added to the PageCache. + setInPageCache(*page, true); + + // 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()); + + // Fire the pagehide event in all frames. + firePageHideEventRecursively(page->mainFrame()); + + // 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)) { + setInPageCache(*page, false); + return; + } + + // Make sure we no longer fire any JS events past this point. + NoEventDispatchAssertion assertNoEventDispatch; - item->deref(); // Balanced in add(). + item.m_cachedPage = std::make_unique<CachedPage>(*page); + item.m_pruningReason = PruningReason::None; + m_items.add(&item); + + prune(PruningReason::ReachedMaxSize); } -void PageCache::prune() +std::unique_ptr<CachedPage> PageCache::take(HistoryItem& item, Page* page) { - while (m_size > m_capacity) { - ASSERT(m_tail && m_tail->m_cachedPage); - remove(m_tail); + if (!item.m_cachedPage) { + if (item.m_pruningReason != PruningReason::None) + logPageCacheFailureDiagnosticMessage(page, pruningReasonToDiagnosticLoggingKey(item.m_pruningReason)); + return nullptr; + } + + m_items.remove(&item); + std::unique_ptr<CachedPage> cachedPage = WTFMove(item.m_cachedPage); + + if (cachedPage->hasExpired()) { + 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::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()) { + 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 24d57da12..31b630bff 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 @@ -26,75 +26,64 @@ #ifndef PageCache_h #define PageCache_h +#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); - - 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*); +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(); - private: - PageCache(); // Use pageCache() instead. - ~PageCache(); // Not implemented to make sure nobody accidentally calls delete -- WebCore does not delete singletons. - - static bool canCachePageContainingThisFrame(Frame*); + bool canCache(Page&) const; - void addToLRUList(HistoryItem*); // Adds to the head of the list. - void removeFromLRUList(HistoryItem*); + // 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 prune(); + 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*); - 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(); + bool shouldClearBackingStores() const { return m_shouldClearBackingStores; } + void setShouldClearBackingStores(bool flag) { m_shouldClearBackingStores = flag; } + +private: + PageCache() = default; // Use singleton() instead. + ~PageCache() = delete; // Make sure nobody accidentally calls delete -- WebCore does not delete singletons. + + static bool canCachePageContainingThisFrame(Frame&); + + void prune(PruningReason); + + ListHashSet<RefPtr<HistoryItem>> m_items; + unsigned m_maxSize {0}; + bool m_shouldClearBackingStores {false}; + + friend class WTF::NeverDestroyed<PageCache>; +}; } // namespace WebCore diff --git a/Source/WebCore/history/blackberry/HistoryItemViewState.h b/Source/WebCore/history/blackberry/HistoryItemViewState.h deleted file mode 100644 index f2efb5d26..000000000 --- a/Source/WebCore/history/blackberry/HistoryItemViewState.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2011 Research In Motion Limited. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef HistoryItemViewState_h -#define HistoryItemViewState_h - -#include <BlackBerryPlatformString.h> -#include <wtf/text/WTFString.h> - -namespace WebCore { - -struct HistoryItemViewState { - - HistoryItemViewState() - : orientation(0) - , scale(1) - , minimumScale(-1.0) - , maximumScale(-1.0) - , isUserScalable(true) - , isZoomToFitScale(false) - , shouldReflowBlock(false) - , shouldSaveViewState(true) - { - } - - int orientation; - double scale; - double minimumScale; - double maximumScale; - bool isUserScalable; - bool isZoomToFitScale; - bool shouldReflowBlock; - bool shouldSaveViewState; - String networkToken; - BlackBerry::Platform::String webPageClientState; -}; - -} // namespace WebCore - -#endif // HistoryItemViewState_h diff --git a/Source/WebCore/history/qt/HistoryItemQt.cpp b/Source/WebCore/history/qt/HistoryItemQt.cpp deleted file mode 100644 index 5a54516f3..000000000 --- a/Source/WebCore/history/qt/HistoryItemQt.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/* - Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" -#include "HistoryItem.h" - -#include "FormData.h" -#include <wtf/Decoder.h> -#include <wtf/Encoder.h> -#include <wtf/text/CString.h> - -using namespace WTF; - -namespace WebCore { - -static QDataStream& operator<<(QDataStream& stream, const String& str) -{ - // could be faster - stream << QString(str); - return stream; -} - -static QDataStream& operator>>(QDataStream& stream, String& str) -{ - // mabe not the fastest way, but really easy - QString tmp; - stream >> tmp; - str = tmp; - return stream; -} - -class QDataStreamCoder : public WTF::Encoder, public WTF::Decoder { -public: - QDataStreamCoder(QDataStream&); - -private: - virtual void encodeBytes(const uint8_t*, size_t); - virtual void encodeBool(bool); - virtual void encodeUInt32(uint32_t); - virtual void encodeUInt64(uint64_t); - virtual void encodeInt32(int32_t); - virtual void encodeInt64(int64_t); - virtual void encodeFloat(float); - virtual void encodeDouble(double); - virtual void encodeString(const String&); - - virtual bool decodeBytes(Vector<uint8_t>&); - virtual bool decodeBool(bool&); - virtual bool decodeUInt32(uint32_t&); - virtual bool decodeUInt64(uint64_t&); - virtual bool decodeInt32(int32_t&); - virtual bool decodeInt64(int64_t&); - virtual bool decodeFloat(float&); - virtual bool decodeDouble(double&); - virtual bool decodeString(String&); - - QDataStream& m_stream; -}; - -QDataStreamCoder::QDataStreamCoder(QDataStream& stream) - : m_stream(stream) -{ -} - -void QDataStreamCoder::encodeBytes(const uint8_t* bytes, size_t size) -{ - m_stream << qint64(size); - for (; size > 0; --size) - m_stream << bytes++; -} - -void QDataStreamCoder::encodeBool(bool value) -{ - m_stream << value; -} - -void QDataStreamCoder::encodeUInt32(uint32_t value) -{ - m_stream << value; -} - -void QDataStreamCoder::encodeUInt64(uint64_t value) -{ - m_stream << static_cast<quint64>(value); -} - -void QDataStreamCoder::encodeInt32(int32_t value) -{ - m_stream << value; -} - -void QDataStreamCoder::encodeInt64(int64_t value) -{ - m_stream << static_cast<qint64>(value); -} - -void QDataStreamCoder::encodeFloat(float value) -{ - m_stream << value; -} - -void QDataStreamCoder::encodeDouble(double value) -{ - m_stream << value; -} - -void QDataStreamCoder::encodeString(const String& value) -{ - m_stream << value; -} - -bool QDataStreamCoder::decodeBytes(Vector<uint8_t>& out) -{ - out.clear(); - qint64 count; - uint8_t byte; - m_stream >> count; - out.reserveCapacity(count); - for (qint64 i = 0; i < count; ++i) { - m_stream >> byte; - out.append(byte); - } - return m_stream.status() == QDataStream::Ok; -} - -bool QDataStreamCoder::decodeBool(bool& out) -{ - m_stream >> out; - return m_stream.status() == QDataStream::Ok; -} - -bool QDataStreamCoder::decodeUInt32(uint32_t& out) -{ - m_stream >> out; - return m_stream.status() == QDataStream::Ok; -} - -bool QDataStreamCoder::decodeUInt64(uint64_t& out) -{ - quint64 tmp; - m_stream >> tmp; - // quint64 is defined to "long long unsigned", incompatible with uint64_t defined as "long unsigned" on 64bits archs. - out = tmp; - return m_stream.status() == QDataStream::Ok; -} - -bool QDataStreamCoder::decodeInt32(int32_t& out) -{ - m_stream >> out; - return m_stream.status() == QDataStream::Ok; -} - -bool QDataStreamCoder::decodeInt64(int64_t& out) -{ - qint64 tmp; - m_stream >> tmp; - // qint64 is defined to "long long", incompatible with int64_t defined as "long" on 64bits archs. - out = tmp; - return m_stream.status() == QDataStream::Ok; -} - -bool QDataStreamCoder::decodeFloat(float& out) -{ - m_stream >> out; - return m_stream.status() == QDataStream::Ok; -} - -bool QDataStreamCoder::decodeDouble(double& out) -{ - m_stream >> out; - return m_stream.status() == QDataStream::Ok; -} - -bool QDataStreamCoder::decodeString(String& out) -{ - m_stream >> out; - return m_stream.status() == QDataStream::Ok; -} - -PassRefPtr<HistoryItem> HistoryItem::restoreState(QDataStream& in, int version) -{ - ASSERT(version == 2); - - String url; - String title; - String originalURL; - in >> url >> title >> originalURL; - - QDataStreamCoder decoder(in); - RefPtr<HistoryItem> item = decodeBackForwardTree(url, title, originalURL, decoder); - // decodeBackForwardTree has its own stream version. An incompatible input stream version will return null here. - if (!item) - return 0; - - // at the end load userData - bool validUserData; - in >> validUserData; - if (validUserData) { - QVariant tmp; - in >> tmp; - item->setUserData(tmp); - } - - return item; -} - -QDataStream& WebCore::HistoryItem::saveState(QDataStream& out, int version) const -{ - ASSERT(version == 2); - - out << urlString() << title() << originalURLString(); - - QDataStreamCoder encoder(out); - encodeBackForwardTree(encoder); - - // save user data - if (userData().isValid()) - out << true << userData(); - else - out << false; - - return out; -} - -} // namespace WebCore |