diff options
author | Steve Block <steveblock@google.com> | 2011-05-06 11:45:16 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2011-05-12 13:44:10 +0100 |
commit | cad810f21b803229eb11403f9209855525a25d57 (patch) | |
tree | 29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/history | |
parent | 121b0cf4517156d0ac5111caf9830c51b69bae8f (diff) | |
download | external_webkit-cad810f21b803229eb11403f9209855525a25d57.zip external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2 |
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/history')
21 files changed, 3653 insertions, 0 deletions
diff --git a/Source/WebCore/history/BackForwardController.cpp b/Source/WebCore/history/BackForwardController.cpp new file mode 100644 index 0000000..d388f19 --- /dev/null +++ b/Source/WebCore/history/BackForwardController.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2010 Apple 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 INC. AND ITS CONTRIBUTORS ``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 INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "BackForwardController.h" + +#include "BackForwardListImpl.h" +#include "HistoryItem.h" +#include "Page.h" + +namespace WebCore { + +BackForwardController::BackForwardController(Page* page, PassRefPtr<BackForwardList> client) + : m_page(page) + , m_client(client) +{ + if (!m_client) + m_client = BackForwardListImpl::create(page); +} + +BackForwardController::~BackForwardController() +{ +} + +bool BackForwardController::canGoBackOrForward(int distance) const +{ + return m_page->canGoBackOrForward(distance); +} + +void BackForwardController::goBackOrForward(int distance) +{ + m_page->goBackOrForward(distance); +} + +bool BackForwardController::goBack() +{ + return m_page->goBack(); +} + +bool BackForwardController::goForward() +{ + return m_page->goForward(); +} + +void BackForwardController::addItem(PassRefPtr<HistoryItem> item) +{ + m_client->addItem(item); +} + +void BackForwardController::setCurrentItem(HistoryItem* item) +{ + m_client->goToItem(item); +} + +int BackForwardController::count() const +{ + return m_page->getHistoryLength(); +} + +int BackForwardController::backCount() const +{ + return m_client->backListCount(); +} + +int BackForwardController::forwardCount() const +{ + return m_client->forwardListCount(); +} + +HistoryItem* BackForwardController::itemAtIndex(int i) +{ + return m_client->itemAtIndex(i); +} + +bool BackForwardController::isActive() +{ + return m_client->isActive(); +} + +void BackForwardController::close() +{ + m_client->close(); +} + +} // namespace WebCore diff --git a/Source/WebCore/history/BackForwardController.h b/Source/WebCore/history/BackForwardController.h new file mode 100644 index 0000000..e89e32b --- /dev/null +++ b/Source/WebCore/history/BackForwardController.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2010 Apple 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 INC. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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 BackForwardController_h +#define BackForwardController_h + +#include <wtf/Noncopyable.h> +#include <wtf/Forward.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class BackForwardList; +class HistoryItem; +class Page; + +class BackForwardController : public Noncopyable { +public: + BackForwardController(Page*, PassRefPtr<BackForwardList>); + ~BackForwardController(); + + BackForwardList* client() const { return m_client.get(); } + + bool canGoBackOrForward(int distance) const; + void goBackOrForward(int distance); + + bool goBack(); + bool goForward(); + + void addItem(PassRefPtr<HistoryItem>); + void setCurrentItem(HistoryItem*); + + int count() const; + int backCount() const; + int forwardCount() const; + + HistoryItem* itemAtIndex(int); + + bool isActive(); + + void close(); + + HistoryItem* backItem() { return itemAtIndex(-1); } + HistoryItem* currentItem() { return itemAtIndex(0); } + HistoryItem* forwardItem() { return itemAtIndex(1); } + +private: + Page* m_page; + RefPtr<BackForwardList> m_client; +}; + +} // namespace WebCore + +#endif // BackForwardController_h diff --git a/Source/WebCore/history/BackForwardList.h b/Source/WebCore/history/BackForwardList.h new file mode 100644 index 0000000..212eadd --- /dev/null +++ b/Source/WebCore/history/BackForwardList.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2006, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * Copyright (C) 2009 Google, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BackForwardList_h +#define BackForwardList_h + +#include <wtf/Forward.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class HistoryItem; + +// FIXME: Rename this class to BackForwardClient, and rename the +// getter in Page accordingly. +class BackForwardList : public RefCounted<BackForwardList> { +public: + virtual ~BackForwardList() + { + } + + virtual void addItem(PassRefPtr<HistoryItem>) = 0; + + virtual void goToItem(HistoryItem*) = 0; + + virtual HistoryItem* itemAtIndex(int) = 0; + virtual int backListCount() = 0; + virtual int forwardListCount() = 0; + + virtual bool isActive() = 0; + + virtual void close() = 0; + +#if ENABLE(WML) + // FIXME: Rename this to just "clear" and change it so it's not + // WML-specific. This is the same operation as clearBackForwardList + // in the layout test controller; it would be reasonable to have it + // here even though HTML DOM interfaces don't require it. + virtual void clearWMLPageHistory() = 0; +#endif + + // FIXME: Delete these once all callers are using BackForwardController + // instead of calling this directly. + HistoryItem* backItem() { return itemAtIndex(-1); } + HistoryItem* currentItem() { return itemAtIndex(0); } + HistoryItem* forwardItem() { return itemAtIndex(1); } +}; + +} // namespace WebCore + +#endif // BackForwardList_h diff --git a/Source/WebCore/history/BackForwardListChromium.cpp b/Source/WebCore/history/BackForwardListChromium.cpp new file mode 100644 index 0000000..a22a147 --- /dev/null +++ b/Source/WebCore/history/BackForwardListChromium.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, 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. + */ + +#include "config.h" +#include "BackForwardListImpl.h" + +#include "HistoryItem.h" +#include "Logging.h" + +namespace WebCore { + +static const unsigned DefaultCapacity = 100; +static const unsigned NoCurrentItemIndex = UINT_MAX; + +BackForwardListImpl::BackForwardListImpl(Page* page) + : m_page(page) + , m_client(0) + , m_capacity(DefaultCapacity) + , m_closed(true) + , m_enabled(true) +{ +} + +BackForwardListImpl::~BackForwardListImpl() +{ + ASSERT(m_closed); +} + +void BackForwardListImpl::addItem(PassRefPtr<HistoryItem> prpItem) +{ + ASSERT(prpItem); + if (m_capacity == 0 || !m_enabled) + return; + + m_client->addItem(prpItem); +} + +void BackForwardListImpl::goToItem(HistoryItem* item) +{ + m_client->goToItem(item); +} + +int BackForwardListImpl::capacity() +{ + return m_capacity; +} + +void BackForwardListImpl::setCapacity(int size) +{ + m_capacity = size; +} + +bool BackForwardListImpl::enabled() +{ + return m_enabled; +} + +void BackForwardListImpl::setEnabled(bool enabled) +{ + m_enabled = enabled; + if (!enabled) { + int capacity = m_capacity; + setCapacity(0); + setCapacity(capacity); + } +} + +int BackForwardListImpl::backListCount() +{ + return m_client->backListCount(); +} + +int BackForwardListImpl::forwardListCount() +{ + return m_client->forwardListCount(); +} + +HistoryItem* BackForwardListImpl::itemAtIndex(int index) +{ + return m_client->itemAtIndex(index); +} + +HistoryItemVector& BackForwardListImpl::entries() +{ + static HistoryItemVector noEntries; + return noEntries; +} + +void BackForwardListImpl::close() +{ + if (m_client) + m_client->close(); + m_page = 0; + m_closed = true; +} + +bool BackForwardListImpl::closed() +{ + return m_closed; +} + +void BackForwardListImpl::goBack() +{ + ASSERT_NOT_REACHED(); +} + +void BackForwardListImpl::goForward() +{ + ASSERT_NOT_REACHED(); +} + +void BackForwardListImpl::backListWithLimit(int, HistoryItemVector&) +{ + ASSERT_NOT_REACHED(); +} + +void BackForwardListImpl::forwardListWithLimit(int, HistoryItemVector&) +{ + ASSERT_NOT_REACHED(); +} + +bool BackForwardListImpl::containsItem(HistoryItem*) +{ + ASSERT_NOT_REACHED(); + return false; +} + +void BackForwardListImpl::removeItem(HistoryItem*) +{ + ASSERT_NOT_REACHED(); +} + +} // namespace WebCore diff --git a/Source/WebCore/history/BackForwardListImpl.cpp b/Source/WebCore/history/BackForwardListImpl.cpp new file mode 100644 index 0000000..cdb888c --- /dev/null +++ b/Source/WebCore/history/BackForwardListImpl.cpp @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "BackForwardListImpl.h" + +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameLoaderClient.h" +#include "HistoryItem.h" +#include "Logging.h" +#include "Page.h" +#include "PageCache.h" +#include "SerializedScriptValue.h" + +using namespace std; + +namespace WebCore { + +static const unsigned DefaultCapacity = 100; +static const unsigned NoCurrentItemIndex = UINT_MAX; + +BackForwardListImpl::BackForwardListImpl(Page* page) + : m_page(page) + , m_current(NoCurrentItemIndex) + , m_capacity(DefaultCapacity) + , m_closed(true) + , m_enabled(true) +{ +} + +BackForwardListImpl::~BackForwardListImpl() +{ + ASSERT(m_closed); +} + +void BackForwardListImpl::addItem(PassRefPtr<HistoryItem> prpItem) +{ + ASSERT(prpItem); + if (m_capacity == 0 || !m_enabled) + return; + + // Toss anything in the forward list + if (m_current != NoCurrentItemIndex) { + unsigned targetSize = m_current + 1; + while (m_entries.size() > targetSize) { + RefPtr<HistoryItem> item = m_entries.last(); + m_entries.removeLast(); + m_entryHash.remove(item); + pageCache()->remove(item.get()); + } + } + + // Toss the first item if the list is getting too big, as long as we're not using it + // (or even if we are, if we only want 1 entry). + if (m_entries.size() == m_capacity && (m_current != 0 || m_capacity == 1)) { + RefPtr<HistoryItem> item = m_entries[0]; + m_entries.remove(0); + m_entryHash.remove(item); + pageCache()->remove(item.get()); + m_current--; + if (m_page) + m_page->mainFrame()->loader()->client()->dispatchDidRemoveBackForwardItem(item.get()); + } + + m_entryHash.add(prpItem.get()); + m_entries.insert(m_current + 1, prpItem); + m_current++; + if (m_page) + m_page->mainFrame()->loader()->client()->dispatchDidAddBackForwardItem(currentItem()); +} + +void BackForwardListImpl::goBack() +{ + ASSERT(m_current > 0); + if (m_current > 0) { + m_current--; + if (m_page) + m_page->mainFrame()->loader()->client()->dispatchDidChangeBackForwardIndex(); + } +} + +void BackForwardListImpl::goForward() +{ + ASSERT(m_current < m_entries.size() - 1); + if (m_current < m_entries.size() - 1) { + m_current++; + if (m_page) + m_page->mainFrame()->loader()->client()->dispatchDidChangeBackForwardIndex(); + } +} + +void BackForwardListImpl::goToItem(HistoryItem* item) +{ + if (!m_entries.size() || !item) + return; + + unsigned int index = 0; + for (; index < m_entries.size(); ++index) + if (m_entries[index] == item) + break; + if (index < m_entries.size()) { + m_current = index; + if (m_page) + m_page->mainFrame()->loader()->client()->dispatchDidChangeBackForwardIndex(); + } +} + +HistoryItem* BackForwardListImpl::backItem() +{ + if (m_current && m_current != NoCurrentItemIndex) + return m_entries[m_current - 1].get(); + return 0; +} + +HistoryItem* BackForwardListImpl::currentItem() +{ + if (m_current != NoCurrentItemIndex) + return m_entries[m_current].get(); + return 0; +} + +HistoryItem* BackForwardListImpl::forwardItem() +{ + if (m_entries.size() && m_current < m_entries.size() - 1) + return m_entries[m_current + 1].get(); + return 0; +} + +void BackForwardListImpl::backListWithLimit(int limit, HistoryItemVector& list) +{ + list.clear(); + if (m_current != NoCurrentItemIndex) { + unsigned first = max((int)m_current - limit, 0); + for (; first < m_current; ++first) + list.append(m_entries[first]); + } +} + +void BackForwardListImpl::forwardListWithLimit(int limit, HistoryItemVector& list) +{ + ASSERT(limit > -1); + list.clear(); + if (!m_entries.size()) + return; + + unsigned lastEntry = m_entries.size() - 1; + if (m_current < lastEntry) { + int last = min(m_current + limit, lastEntry); + limit = m_current + 1; + for (; limit <= last; ++limit) + list.append(m_entries[limit]); + } +} + +int BackForwardListImpl::capacity() +{ + return m_capacity; +} + +void BackForwardListImpl::setCapacity(int size) +{ + while (size < (int)m_entries.size()) { + RefPtr<HistoryItem> item = m_entries.last(); + m_entries.removeLast(); + m_entryHash.remove(item); + pageCache()->remove(item.get()); + } + + if (!size) + m_current = NoCurrentItemIndex; + else if (m_current > m_entries.size() - 1) { + m_current = m_entries.size() - 1; + if (m_page) + m_page->mainFrame()->loader()->client()->dispatchDidChangeBackForwardIndex(); + } + m_capacity = size; +} + +bool BackForwardListImpl::enabled() +{ + return m_enabled; +} + +void BackForwardListImpl::setEnabled(bool enabled) +{ + m_enabled = enabled; + if (!enabled) { + int capacity = m_capacity; + setCapacity(0); + setCapacity(capacity); + } +} + +int BackForwardListImpl::backListCount() +{ + return m_current == NoCurrentItemIndex ? 0 : m_current; +} + +int BackForwardListImpl::forwardListCount() +{ + return m_current == NoCurrentItemIndex ? 0 : (int)m_entries.size() - (m_current + 1); +} + +HistoryItem* BackForwardListImpl::itemAtIndex(int index) +{ + // Do range checks without doing math on index to avoid overflow. + if (index < -(int)m_current) + return 0; + + if (index > forwardListCount()) + return 0; + + return m_entries[index + m_current].get(); +} + +HistoryItemVector& BackForwardListImpl::entries() +{ + return m_entries; +} + +void BackForwardListImpl::close() +{ + int size = m_entries.size(); + for (int i = 0; i < size; ++i) + pageCache()->remove(m_entries[i].get()); + m_entries.clear(); + m_entryHash.clear(); + m_page = 0; + m_closed = true; +} + +bool BackForwardListImpl::closed() +{ + return m_closed; +} + +void BackForwardListImpl::removeItem(HistoryItem* item) +{ + if (!item) + return; + + for (unsigned i = 0; i < m_entries.size(); ++i) + if (m_entries[i] == item) { + m_entries.remove(i); + m_entryHash.remove(item); + if (m_current == NoCurrentItemIndex || m_current < i) + break; + if (m_current > i) + m_current--; + else { + size_t count = m_entries.size(); + if (m_current >= count) + m_current = count ? count - 1 : NoCurrentItemIndex; + } + break; + } +} + +bool BackForwardListImpl::containsItem(HistoryItem* entry) +{ + return m_entryHash.contains(entry); +} + +#if ENABLE(WML) +void BackForwardListImpl::clearWMLPageHistory() +{ + RefPtr<HistoryItem> currentItem = this->currentItem(); + + int size = m_entries.size(); + for (int i = 0; i < size; ++i) + pageCache()->remove(m_entries[i].get()); + + m_entries.clear(); + m_entryHash.clear(); + m_current = NoCurrentItemIndex; + + // Spec: The history stack may be reset to a state where it only contains the current card. + addItem(currentItem); +} +#endif + +}; // namespace WebCore diff --git a/Source/WebCore/history/BackForwardListImpl.h b/Source/WebCore/history/BackForwardListImpl.h new file mode 100644 index 0000000..30043fa --- /dev/null +++ b/Source/WebCore/history/BackForwardListImpl.h @@ -0,0 +1,126 @@ +/* + * 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: Change Chromium to use its own BackForwardList implementation +// and not use BackForwardListImpl at all, then remove this +// BackForwardListClient feature entirely and just don't use this +// class on Chromium. +#if PLATFORM(CHROMIUM) +// In the Chromium port, the back/forward list is managed externally. +// See BackForwardListChromium.cpp +class BackForwardListClient { +public: + virtual ~BackForwardListClient() { } + virtual void addItem(PassRefPtr<HistoryItem>) = 0; + virtual void goToItem(HistoryItem*) = 0; + virtual HistoryItem* itemAtIndex(int) = 0; + virtual int backListCount() = 0; + virtual int forwardListCount() = 0; + virtual void close() = 0; +}; +#endif + +// 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(); + +#if PLATFORM(CHROMIUM) + // Must be called before any other methods. + void setClient(BackForwardListClient* client) { m_client = client; } +#endif + + 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(); + +#if ENABLE(WML) + virtual void clearWMLPageHistory(); +#endif + +private: + BackForwardListImpl(Page*); + + virtual bool isActive() { return enabled() && capacity(); } + + Page* m_page; +#if PLATFORM(CHROMIUM) + BackForwardListClient* m_client; +#else + HistoryItemVector m_entries; + HistoryItemHashSet m_entryHash; + unsigned m_current; +#endif + 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 new file mode 100644 index 0000000..d21f958 --- /dev/null +++ b/Source/WebCore/history/CachedFrame.cpp @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2009 Apple 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. + */ + +#include "config.h" +#include "CachedPage.h" + +#include "CachedFramePlatformData.h" +#include "DocumentLoader.h" +#include "ExceptionCode.h" +#include "EventNames.h" +#include "Frame.h" +#include "FrameLoaderClient.h" +#include "FrameView.h" +#include "HistoryItem.h" +#include "Logging.h" +#include "PageTransitionEvent.h" +#include <wtf/text/CString.h> +#include <wtf/RefCountedLeakCounter.h> + +#if ENABLE(SVG) +#include "SVGDocumentExtensions.h" +#endif + +#if ENABLE(TOUCH_EVENTS) +#include "Chrome.h" +#include "ChromeClient.h" +#include "Page.h" +#endif + +namespace WebCore { + +#ifndef NDEBUG +static WTF::RefCountedLeakCounter& cachedFrameCounter() +{ + DEFINE_STATIC_LOCAL(WTF::RefCountedLeakCounter, counter, ("CachedFrame")); + return counter; +} +#endif + +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->loader()->url()) + , m_isMainFrame(!frame->tree()->parent()) +{ +} + +CachedFrameBase::~CachedFrameBase() +{ +#ifndef NDEBUG + cachedFrameCounter().decrement(); +#endif + // CachedFrames should always have had destroy() called by their parent CachedPage + ASSERT(!m_document); +} + +void CachedFrameBase::restore() +{ + ASSERT(m_document->view() == m_view); + + Frame* frame = m_view->frame(); + m_cachedFrameScriptData->restore(frame); + +#if ENABLE(SVG) + if (m_document->svgExtensions()) + m_document->accessSVGExtensions()->unpauseAnimations(); +#endif + + frame->animation()->resumeAnimationsForDocument(m_document.get()); + frame->eventHandler()->setMousePressNode(m_mousePressNode.get()); + m_document->resumeActiveDOMObjects(); + + // It is necessary to update any platform script objects after restoring the + // cached page. + frame->script()->updatePlatformScriptObjects(); + + frame->loader()->client()->didRestoreFromPageCache(); + + // Reconstruct the FrameTree + for (unsigned i = 0; i < m_childFrames.size(); ++i) + frame->tree()->appendChild(m_childFrames[i]->view()->frame()); + + // Open the child CachedFrames in their respective FrameLoaders. + for (unsigned i = 0; i < m_childFrames.size(); ++i) + m_childFrames[i]->open(); + + m_document->enqueuePageshowEvent(PageshowEventPersisted); + + HistoryItem* historyItem = frame->loader()->history()->currentItem(); + m_document->enqueuePopstateEvent(historyItem && historyItem->stateObject() ? historyItem->stateObject() : SerializedScriptValue::nullValue()); + +#if ENABLE(TOUCH_EVENTS) + if (m_document->hasListenerType(Document::TOUCH_LISTENER)) + m_document->page()->chrome()->client()->needTouchEvents(true); +#endif + + m_document->documentDidBecomeActive(); +} + +CachedFrame::CachedFrame(Frame* frame) + : CachedFrameBase(frame) +{ +#ifndef NDEBUG + cachedFrameCounter().increment(); +#endif + ASSERT(m_document); + ASSERT(m_documentLoader); + ASSERT(m_view); + + // Active DOM objects must be suspended before we cached the frame script data + m_document->suspendActiveDOMObjects(ActiveDOMObject::DocumentWillBecomeInactive); + m_cachedFrameScriptData = adoptPtr(new ScriptCachedFrameData(frame)); + + // Custom scrollbar renderers will get reattached when the document comes out of the page cache + m_view->detachCustomScrollbars(); + + m_document->documentWillBecomeInactive(); + frame->clearTimers(); + m_document->setInPageCache(true); + frame->loader()->stopLoading(UnloadEventPolicyUnloadAndPageHide); + + frame->loader()->client()->savePlatformDataToCachedFrame(this); + + // 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)); + + // 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()); + + if (!m_isMainFrame) + frame->page()->decrementFrameCount(); + + frame->loader()->client()->didSaveToPageCache(); + +#ifndef NDEBUG + if (m_isMainFrame) + LOG(PageCache, "Finished creating CachedFrame for main frame url '%s' and DocumentLoader %p\n", m_url.string().utf8().data(), m_documentLoader.get()); + else + 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 ENABLE(TOUCH_EVENTS) + if (m_document->hasListenerType(Document::TOUCH_LISTENER)) + m_document->page()->chrome()->client()->needTouchEvents(false); +#endif +} + +void CachedFrame::open() +{ + ASSERT(m_view); + m_view->frame()->loader()->open(*this); + + if (!m_isMainFrame) + m_view->frame()->page()->incrementFrameCount(); +} + +void CachedFrame::clear() +{ + if (!m_document) + return; + + // clear() should only be called for Frames representing documents that are no longer in the page cache. + // This means the CachedFrame has been: + // 1 - Successfully restore()'d by going back/forward. + // 2 - destroy()'ed because the PageCache is pruning or the WebView was closed. + ASSERT(!m_document->inPageCache()); + ASSERT(m_view); + ASSERT(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_cachedFramePlatformData.clear(); + m_cachedFrameScriptData.clear(); +} + +void CachedFrame::destroy() +{ + if (!m_document) + return; + + // 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()); + + if (!m_isMainFrame) { + m_view->frame()->detachFromPage(); + m_view->frame()->loader()->detachViewsAndDocumentLoader(); + } + + for (int i = m_childFrames.size() - 1; i >= 0; --i) + m_childFrames[i]->destroy(); + + if (m_cachedFramePlatformData) + m_cachedFramePlatformData->clear(); + + Frame::clearTimers(m_view.get(), m_document.get()); + + // FIXME: Why do we need to call removeAllEventListeners here? When the document is in page cache, this method won't work + // fully anyway, because the document won't be able to access its DOMWindow object (due to being frameless). + m_document->removeAllEventListeners(); + + m_document->setInPageCache(false); + // FIXME: We don't call willRemove here. Why is that OK? + m_document->detach(); + m_view->clearFrame(); + + clear(); +} + +void CachedFrame::setCachedFramePlatformData(PassOwnPtr<CachedFramePlatformData> data) +{ + m_cachedFramePlatformData = data; +} + +CachedFramePlatformData* CachedFrame::cachedFramePlatformData() +{ + return m_cachedFramePlatformData.get(); +} + +int CachedFrame::descendantFrameCount() const +{ + int count = m_childFrames.size(); + for (size_t i = 0; i < m_childFrames.size(); ++i) + count += m_childFrames[i]->descendantFrameCount(); + + return count; +} + +} // namespace WebCore diff --git a/Source/WebCore/history/CachedFrame.h b/Source/WebCore/history/CachedFrame.h new file mode 100644 index 0000000..b0d0d29 --- /dev/null +++ b/Source/WebCore/history/CachedFrame.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2009, 2010 Apple 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 CachedFrame_h +#define CachedFrame_h + +#include "KURL.h" +#include "ScriptCachedFrameData.h" +#include <wtf/PassOwnPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class CachedFrame; +class CachedFramePlatformData; +class Document; +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; } + DOMWindow* domWindow() const { return m_cachedFrameScriptData->domWindow(); } + bool isMainFrame() { return m_isMainFrame; } + +protected: + 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; + bool m_isMainFrame; + + CachedFrameVector m_childFrames; +}; + +class CachedFrame : public RefCounted<CachedFrame>, private CachedFrameBase { +public: + static PassRefPtr<CachedFrame> create(Frame* frame) { return adoptRef(new CachedFrame(frame)); } + + void open(); + void clear(); + void destroy(); + + void setCachedFramePlatformData(PassOwnPtr<CachedFramePlatformData>); + 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: + CachedFrame(Frame*); +}; + +} // namespace WebCore + +#endif // CachedFrame_h diff --git a/Source/WebCore/history/CachedFramePlatformData.h b/Source/WebCore/history/CachedFramePlatformData.h new file mode 100644 index 0000000..01da8e5 --- /dev/null +++ b/Source/WebCore/history/CachedFramePlatformData.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2007 Apple 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. + * 3. Neither the name of Apple Computer, 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 CachedFramePlatformData_h +#define CachedFramePlatformData_h + +namespace WebCore { + +// The purpose of this class is to give each platform a vessel to store platform data when a page +// goes into the Back/Forward page cache, and perform some action with that data when the page comes out. +// Each platform should subclass this class as neccessary + +class CachedFramePlatformData { +public: + virtual ~CachedFramePlatformData() { } + virtual void clear() { } +}; + +} // namespace WebCore + +#endif // CachedFramePlatformData_h diff --git a/Source/WebCore/history/CachedPage.cpp b/Source/WebCore/history/CachedPage.cpp new file mode 100644 index 0000000..acbfd31 --- /dev/null +++ b/Source/WebCore/history/CachedPage.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple 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. + */ + +#include "config.h" +#include "CachedPage.h" + +#include "FocusController.h" +#include "Frame.h" +#include "FrameView.h" +#include "Page.h" +#include <wtf/CurrentTime.h> +#include <wtf/RefCountedLeakCounter.h> + +using namespace JSC; + +namespace WebCore { + +#ifndef NDEBUG +static WTF::RefCountedLeakCounter cachedPageCounter("CachedPage"); +#endif + +PassRefPtr<CachedPage> CachedPage::create(Page* page) +{ + return adoptRef(new CachedPage(page)); +} + +CachedPage::CachedPage(Page* page) + : m_timeStamp(currentTime()) + , m_cachedMainFrame(CachedFrame::create(page->mainFrame())) +{ +#ifndef NDEBUG + cachedPageCounter.increment(); +#endif +} + +CachedPage::~CachedPage() +{ +#ifndef NDEBUG + cachedPageCounter.decrement(); +#endif + + destroy(); + ASSERT(!m_cachedMainFrame); +} + +void CachedPage::restore(Page* page) +{ + ASSERT(m_cachedMainFrame); + ASSERT(page && page->mainFrame() && page->mainFrame() == m_cachedMainFrame->view()->frame()); + ASSERT(!page->frameCount()); + + 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 (Node* node = focusedDocument->focusedNode()) { + if (node->isElementNode()) + static_cast<Element*>(node)->updateFocusAppearance(true); + } + + clear(); +} + +void CachedPage::clear() +{ + ASSERT(m_cachedMainFrame); + m_cachedMainFrame->clear(); + m_cachedMainFrame = 0; +} + +void CachedPage::destroy() +{ + if (m_cachedMainFrame) + m_cachedMainFrame->destroy(); + + m_cachedMainFrame = 0; +} + +} // namespace WebCore diff --git a/Source/WebCore/history/CachedPage.h b/Source/WebCore/history/CachedPage.h new file mode 100644 index 0000000..4741c79 --- /dev/null +++ b/Source/WebCore/history/CachedPage.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple 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 CachedPage_h +#define CachedPage_h + +#include "CachedFrame.h" + +namespace WebCore { + +class Document; +class DocumentLoader; +class Page; + +class CachedPage : public RefCounted<CachedPage> { +public: + static PassRefPtr<CachedPage> create(Page*); + ~CachedPage(); + + 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; } + + CachedFrame* cachedMainFrame() { return m_cachedMainFrame.get(); } + +private: + CachedPage(Page*); + + double m_timeStamp; + RefPtr<CachedFrame> m_cachedMainFrame; +}; + +} // namespace WebCore + +#endif // CachedPage_h + diff --git a/Source/WebCore/history/HistoryItem.cpp b/Source/WebCore/history/HistoryItem.cpp new file mode 100644 index 0000000..0995913 --- /dev/null +++ b/Source/WebCore/history/HistoryItem.cpp @@ -0,0 +1,847 @@ +/* + * Copyright (C) 2005, 2006, 2008, 2011 Apple 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. + */ + +#include "config.h" +#include "HistoryItem.h" + +#include "CachedPage.h" +#include "Document.h" +#include "IconDatabase.h" +#include "PageCache.h" +#include "ResourceRequest.h" +#include <stdio.h> +#include <wtf/CurrentTime.h> +#include <wtf/Decoder.h> +#include <wtf/Encoder.h> +#include <wtf/MathExtras.h> +#include <wtf/text/CString.h> + +namespace WebCore { + +const uint32_t backForwardTreeEncodingVersion = 0; + +static long long generateSequenceNumber() +{ + // Initialize to the current time to reduce the likelihood of generating + // identifiers that overlap with those from past/future browser sessions. + static long long next = static_cast<long long>(currentTime() * 1000000.0); + return ++next; +} + +static void defaultNotifyHistoryItemChanged(HistoryItem*) +{ +} + +void (*notifyHistoryItemChanged)(HistoryItem*) = defaultNotifyHistoryItemChanged; + +HistoryItem::HistoryItem() + : m_lastVisitedTime(0) + , m_lastVisitWasHTTPNonGet(false) + , m_lastVisitWasFailure(false) + , m_isTargetItem(false) + , m_visitCount(0) + , m_itemSequenceNumber(generateSequenceNumber()) + , m_documentSequenceNumber(generateSequenceNumber()) +{ +} + +HistoryItem::HistoryItem(const String& urlString, const String& title, double time) + : m_urlString(urlString) + , m_originalURLString(urlString) + , m_title(title) + , m_lastVisitedTime(time) + , m_lastVisitWasHTTPNonGet(false) + , m_lastVisitWasFailure(false) + , m_isTargetItem(false) + , m_visitCount(0) + , m_itemSequenceNumber(generateSequenceNumber()) + , m_documentSequenceNumber(generateSequenceNumber()) +{ + iconDatabase()->retainIconForPageURL(m_urlString); +} + +HistoryItem::HistoryItem(const String& urlString, const String& title, const String& alternateTitle, double time) + : m_urlString(urlString) + , m_originalURLString(urlString) + , m_title(title) + , m_displayTitle(alternateTitle) + , m_lastVisitedTime(time) + , m_lastVisitWasHTTPNonGet(false) + , m_lastVisitWasFailure(false) + , m_isTargetItem(false) + , m_visitCount(0) + , m_itemSequenceNumber(generateSequenceNumber()) + , m_documentSequenceNumber(generateSequenceNumber()) +{ + 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_lastVisitWasFailure(false) + , m_isTargetItem(false) + , m_visitCount(0) + , m_itemSequenceNumber(generateSequenceNumber()) + , m_documentSequenceNumber(generateSequenceNumber()) +{ + iconDatabase()->retainIconForPageURL(m_urlString); +} + +HistoryItem::~HistoryItem() +{ + ASSERT(!m_cachedPage); + iconDatabase()->releaseIconForPageURL(m_urlString); +#if PLATFORM(ANDROID) + if (m_bridge) + m_bridge->detachHistoryItem(); +#endif +} + +inline HistoryItem::HistoryItem(const HistoryItem& item) + : RefCounted<HistoryItem>() + , m_urlString(item.m_urlString) + , 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_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) +{ + if (item.m_formData) + m_formData = item.m_formData->copy(); + + unsigned size = item.m_children.size(); + m_children.reserveInitialCapacity(size); + for (unsigned i = 0; i < size; ++i) + m_children.uncheckedAppend(item.m_children[i]->copy()); + + if (item.m_redirectURLs) + m_redirectURLs = adoptPtr(new Vector<String>(*item.m_redirectURLs)); +} + +PassRefPtr<HistoryItem> HistoryItem::copy() const +{ + return adoptRef(new HistoryItem(*this)); +} + +const String& HistoryItem::urlString() const +{ + return m_urlString; +} + +// The first URL we loaded to get to where this history item points. Includes both client +// and server redirects. +const String& HistoryItem::originalURLString() const +{ + return m_originalURLString; +} + +const String& HistoryItem::title() const +{ + return m_title; +} + +const String& HistoryItem::alternateTitle() const +{ + return m_displayTitle; +} + +Image* HistoryItem::icon() const +{ + Image* result = iconDatabase()->iconForPageURL(m_urlString, IntSize(16, 16)); + return result ? result : iconDatabase()->defaultIcon(IntSize(16, 16)); +} + +double HistoryItem::lastVisitedTime() const +{ + return m_lastVisitedTime; +} + +KURL HistoryItem::url() const +{ + return KURL(ParsedURLString, m_urlString); +} + +KURL HistoryItem::originalURL() const +{ + return KURL(ParsedURLString, m_originalURLString); +} + +const String& HistoryItem::referrer() const +{ + return m_referrer; +} + +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; + notifyHistoryItemChanged(this); +} + +void HistoryItem::setURLString(const String& urlString) +{ + if (m_urlString != urlString) { + iconDatabase()->releaseIconForPageURL(m_urlString); + m_urlString = urlString; + iconDatabase()->retainIconForPageURL(m_urlString); + } + + notifyHistoryItemChanged(this); +} + +void HistoryItem::setURL(const KURL& url) +{ + pageCache()->remove(this); + setURLString(url.string()); + clearDocumentState(); +} + +void HistoryItem::setOriginalURLString(const String& urlString) +{ + m_originalURLString = urlString; + notifyHistoryItemChanged(this); +} + +void HistoryItem::setReferrer(const String& referrer) +{ + m_referrer = referrer; + notifyHistoryItemChanged(this); +} + +void HistoryItem::setTitle(const String& title) +{ + m_title = title; + notifyHistoryItemChanged(this); +} + +void HistoryItem::setTarget(const String& target) +{ + m_target = 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.prepend(m_visitCount); + + int daysElapsed = timeToDay(time) - timeToDay(m_lastVisitedTime); + + if (daysElapsed < 0) + daysElapsed = 0; + + Vector<int> padding; + padding.fill(0, daysElapsed); + m_dailyVisitCounts.prepend(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.prepend(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) +{ + m_title = title; + recordVisitAtTime(time, visitCountBehavior); +} + +int HistoryItem::visitCount() const +{ + return m_visitCount; +} + +void HistoryItem::recordInitialVisit() +{ + 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); +} + +void HistoryItem::setDocumentState(const Vector<String>& state) +{ + m_documentState = state; +#if PLATFORM(ANDROID) + notifyHistoryItemChanged(this); +#endif +} + +const Vector<String>& HistoryItem::documentState() const +{ + return m_documentState; +} + +void HistoryItem::clearDocumentState() +{ + m_documentState.clear(); +#if PLATFORM(ANDROID) + notifyHistoryItemChanged(this); +#endif +} + +bool HistoryItem::isTargetItem() const +{ + return m_isTargetItem; +} + +void HistoryItem::setIsTargetItem(bool flag) +{ + m_isTargetItem = flag; +#if PLATFORM(ANDROID) + notifyHistoryItemChanged(this); +#endif +} + +void HistoryItem::setStateObject(PassRefPtr<SerializedScriptValue> object) +{ + m_stateObject = object; +} + +void HistoryItem::addChildItem(PassRefPtr<HistoryItem> child) +{ + ASSERT(!childItemWithTarget(child->target())); + m_children.append(child); +#if PLATFORM(ANDROID) + notifyHistoryItemChanged(this); +#endif +} + +void HistoryItem::setChildItem(PassRefPtr<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; + return; + } + } + m_children.append(child); +} + +HistoryItem* HistoryItem::childItemWithTarget(const String& target) const +{ + unsigned size = m_children.size(); + for (unsigned i = 0; i < size; ++i) { + if (m_children[i]->target() == target) + return m_children[i].get(); + } + return 0; +} + +HistoryItem* HistoryItem::childItemWithDocumentSequenceNumber(long long number) const +{ + unsigned size = m_children.size(); + for (unsigned i = 0; i < size; ++i) { + if (m_children[i]->documentSequenceNumber() == number) + return m_children[i].get(); + } + 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; +} + +const HistoryItemVector& HistoryItem::children() const +{ + return m_children; +} + +bool HistoryItem::hasChildren() const +{ + return !m_children.isEmpty(); +} + +void HistoryItem::clearChildren() +{ + m_children.clear(); +} + +// 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 +{ + if (this == otherItem) + return false; + + if (stateObject() || otherItem->stateObject()) + 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 +{ + if (documentSequenceNumber() != otherItem->documentSequenceNumber()) + return false; + + 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)) + return false; + } + + return true; +} + +// 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 +{ + if (target() != otherItem->target()) + return false; + + if (children().size() != otherItem->children().size()) + return false; + + for (size_t i = 0; i < children().size(); i++) { + if (!otherItem->childItemWithTarget(children()[i]->target())) + return false; + } + + return true; +} + +String HistoryItem::formContentType() const +{ + return m_formContentType; +} + +void HistoryItem::setFormInfoFromRequest(const ResourceRequest& request) +{ + m_referrer = request.httpReferrer(); + + if (equalIgnoringCase(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_formContentType = String(); + } +#if PLATFORM(ANDROID) + notifyHistoryItemChanged(this); +#endif +} + +void HistoryItem::setFormData(PassRefPtr<FormData> formData) +{ + m_formData = formData; +} + +void HistoryItem::setFormContentType(const String& formContentType) +{ + m_formContentType = formContentType; +} + +FormData* HistoryItem::formData() +{ + return m_formData.get(); +} + +bool HistoryItem::isCurrentDocument(Document* doc) 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; +} + +void HistoryItem::addRedirectURL(const String& url) +{ + if (!m_redirectURLs) + m_redirectURLs = adoptPtr(new Vector<String>); + + // Our API allows us to store all the URLs in the redirect chain, but for + // now we only have a use for the final URL. + (*m_redirectURLs).resize(1); + (*m_redirectURLs)[0] = url; +} + +Vector<String>* HistoryItem::redirectURLs() const +{ + return m_redirectURLs.get(); +} + +void HistoryItem::setRedirectURLs(PassOwnPtr<Vector<String> > redirectURLs) +{ + m_redirectURLs = redirectURLs; +} + +void HistoryItem::encodeBackForwardTree(Encoder& encoder) const +{ + 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->encodeForBackForward(encoder); + + encoder.encodeInt64(m_itemSequenceNumber); + + encoder.encodeString(m_originalURLString); + + encoder.encodeString(m_referrer); + + encoder.encodeInt32(m_scrollPoint.x()); + encoder.encodeInt32(m_scrollPoint.y()); + + encoder.encodeBool(m_stateObject); + if (m_stateObject) { +#if !USE(V8) + encoder.encodeBytes(m_stateObject->data().data(), m_stateObject->data().size()); +#else + encoder.encodeString(m_stateObject->toWireString()); +#endif + } + + 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::decodeForBackForward(decoder); + if (!node->m_formData) + return 0; + } + + if (!decoder.decodeInt64(node->m_itemSequenceNumber)) + return 0; + + if (!decoder.decodeString(node->m_originalURLString)) + 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); + + bool hasStateObject; + if (!decoder.decodeBool(hasStateObject)) + return 0; + if (hasStateObject) { +#if !USE(V8) + Vector<uint8_t> bytes; + if (!decoder.decodeBytes(bytes)) + return 0; + node->m_stateObject = SerializedScriptValue::adopt(bytes); +#else + String string; + if (!decoder.decodeString(string)) + return 0; + node->m_stateObject = SerializedScriptValue::createFromWire(string); +#endif + } + + 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(); +} + +#ifndef NDEBUG + +int HistoryItem::showTree() const +{ + return showTreeWithIndent(0); +} + +int HistoryItem::showTreeWithIndent(unsigned indentLevel) const +{ + Vector<char> prefix; + for (unsigned i = 0; i < indentLevel; ++i) + prefix.append(" ", 2); + prefix.append("\0", 1); + + fprintf(stderr, "%s+-%s (%p)\n", prefix.data(), m_urlString.utf8().data(), this); + + int totalSubItems = 0; + for (unsigned i = 0; i < m_children.size(); ++i) + totalSubItems += m_children[i]->showTreeWithIndent(indentLevel + 1); + return totalSubItems + 1; +} + +#endif + +} // namespace WebCore + +#ifndef NDEBUG + +int showTree(const WebCore::HistoryItem* item) +{ + return item->showTree(); +} + +#endif diff --git a/Source/WebCore/history/HistoryItem.h b/Source/WebCore/history/HistoryItem.h new file mode 100644 index 0000000..19b33ad --- /dev/null +++ b/Source/WebCore/history/HistoryItem.h @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2006, 2008, 2011 Apple 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 HistoryItem_h +#define HistoryItem_h + +#include "IntPoint.h" +#include "PlatformString.h" +#include "SerializedScriptValue.h" +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> + +#if PLATFORM(MAC) +#import <wtf/RetainPtr.h> +typedef struct objc_object* id; +#endif + +#if PLATFORM(QT) +#include <QVariant> +#include <QByteArray> +#include <QDataStream> +#endif + +#if PLATFORM(ANDROID) +#include "AndroidWebHistoryBridge.h" +#endif + +namespace WebCore { + +class CachedPage; +class Document; +class FormData; +class HistoryItem; +class Image; +class KURL; +class ResourceRequest; + +typedef Vector<RefPtr<HistoryItem> > HistoryItemVector; + +extern void (*notifyHistoryItemChanged)(HistoryItem*); + +enum VisitCountBehavior { + IncreaseVisitCount, + DoNotIncreaseVisitCount +}; + +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) + { + return adoptRef(new HistoryItem(urlString, title, lastVisited)); + } + static PassRefPtr<HistoryItem> create(const String& urlString, const String& title, const String& alternateTitle, double lastVisited) + { + 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)); + } + + ~HistoryItem(); + + PassRefPtr<HistoryItem> copy() const; + + 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; } + + double lastVisitedTime() const; + + void setAlternateTitle(const String& alternateTitle); + const String& alternateTitle() const; + + Image* icon() const; + + const String& parent() const; + KURL url() const; + KURL originalURL() const; + const String& referrer() const; + const String& target() const; + bool isTargetItem() const; + + FormData* formData(); + 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(); + const Vector<String>& documentState() const; + 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); + + void setStateObject(PassRefPtr<SerializedScriptValue> object); + SerializedScriptValue* stateObject() const { return m_stateObject.get(); } + + void setItemSequenceNumber(long long number) { m_itemSequenceNumber = number; } + long long itemSequenceNumber() const { return m_itemSequenceNumber; } + + void setDocumentSequenceNumber(long long number) { m_documentSequenceNumber = number; } + long long documentSequenceNumber() const { return m_documentSequenceNumber; } + + void setFormInfoFromRequest(const ResourceRequest&); + void setFormData(PassRefPtr<FormData>); + 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; + void clearChildren(); + + 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); + + void addRedirectURL(const String&); + Vector<String>* redirectURLs() const; + void setRedirectURLs(PassOwnPtr<Vector<String> >); + + bool isCurrentDocument(Document*) const; + +#if PLATFORM(MAC) + id viewState() const; + 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); +#endif + +#if PLATFORM(QT) + QVariant userData() const { return m_userData; } + void setUserData(const QVariant& userData) { m_userData = userData; } + + bool restoreState(QDataStream& buffer, int version); + QDataStream& saveState(QDataStream& out, int version) const; +#endif + +#if PLATFORM(ANDROID) + void setBridge(AndroidWebHistoryBridge* bridge); + AndroidWebHistoryBridge* bridge() const; +#endif + +#ifndef NDEBUG + int showTree() const; + 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; } + +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); + + HistoryItem(const HistoryItem&); + + void padDailyCountsForNewVisit(double time); + void collapseDailyVisitsToWeekly(); + void recordVisitAtTime(double, VisitCountBehavior = IncreaseVisitCount); + + bool hasSameDocumentTree(HistoryItem* otherItem) const; + + HistoryItem* findTargetItem(); + + void encodeBackForwardTreeNode(Encoder&) const; + static PassRefPtr<HistoryItem> decodeBackForwardTreeNode(const String& urlString, const String& title, const String& originalURLString, Decoder&); + + /* When adding new member variables to this class, please notify the Qt team. + * qt/HistoryItemQt.cpp contains code to serialize history items. + */ + + 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; + Vector<String> m_documentState; + + HistoryItemVector m_children; + + bool m_lastVisitWasFailure; + bool m_isTargetItem; + int m_visitCount; + Vector<int> m_dailyVisitCounts; + Vector<int> m_weeklyVisitCounts; + + OwnPtr<Vector<String> > m_redirectURLs; + + int64_t m_itemSequenceNumber; + + // Support for HTML5 History + RefPtr<SerializedScriptValue> m_stateObject; + int64_t m_documentSequenceNumber; + + // info used to repost form data + RefPtr<FormData> m_formData; + String m_formContentType; + + // PageCache controls these fields. + HistoryItem* m_next; + HistoryItem* m_prev; + RefPtr<CachedPage> m_cachedPage; + +#if PLATFORM(MAC) + RetainPtr<id> m_viewState; + OwnPtr<HashMap<String, RetainPtr<id> > > m_transientProperties; +#endif + +#if PLATFORM(QT) + QVariant m_userData; +#endif + +#if PLATFORM(ANDROID) + RefPtr<AndroidWebHistoryBridge> m_bridge; +#endif + +}; //class HistoryItem + +} //namespace WebCore + +#ifndef NDEBUG +// Outside the WebCore namespace for ease of invocation from gdb. +extern "C" int showTree(const WebCore::HistoryItem*); +#endif + +#endif // HISTORYITEM_H diff --git a/Source/WebCore/history/PageCache.cpp b/Source/WebCore/history/PageCache.cpp new file mode 100644 index 0000000..7375a9c --- /dev/null +++ b/Source/WebCore/history/PageCache.cpp @@ -0,0 +1,479 @@ +/* + * Copyright (C) 2007 Apple 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. + */ + +#include "config.h" +#include "PageCache.h" + +#include "ApplicationCacheHost.h" +#include "BackForwardController.h" +#include "MemoryCache.h" +#include "CachedPage.h" +#include "DOMWindow.h" +#include "DeviceMotionController.h" +#include "DeviceOrientationController.h" +#include "Document.h" +#include "DocumentLoader.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameLoaderClient.h" +#include "FrameLoaderStateMachine.h" +#include "HistoryItem.h" +#include "Logging.h" +#include "Page.h" +#include "Settings.h" +#include "SharedWorkerRepository.h" +#include "SystemTime.h" +#include <wtf/CurrentTime.h> +#include <wtf/text/CString.h> +#include <wtf/text/StringConcatenate.h> + +using namespace std; + +namespace WebCore { + +static const double autoreleaseInterval = 3; + +#ifndef NDEBUG + +static String& pageCacheLogPrefix(int indentLevel) +{ + static int previousIndent = -1; + DEFINE_STATIC_LOCAL(String, prefix, ()); + + if (indentLevel != previousIndent) { + previousIndent = indentLevel; + prefix.truncate(0); + for (int i = 0; i < previousIndent; ++i) + prefix += " "; + } + + return prefix; +} + +static void pageCacheLog(const String& prefix, const String& message) +{ + LOG(PageCache, "%s%s", prefix.utf8().data(), message.utf8().data()); +} + +#define PCLOG(...) pageCacheLog(pageCacheLogPrefix(indentLevel), makeString(__VA_ARGS__)) + +static bool logCanCacheFrameDecision(Frame* frame, int indentLevel) +{ + // Only bother logging for frames that have actually loaded and have content. + if (frame->loader()->stateMachine()->creatingInitialEmptyDocument()) + return false; + KURL currentURL = frame->loader()->documentLoader() ? frame->loader()->documentLoader()->url() : KURL(); + if (currentURL.isEmpty()) + return false; + + PCLOG("+---"); + KURL newURL = frame->loader()->provisionalDocumentLoader() ? frame->loader()->provisionalDocumentLoader()->url() : KURL(); + 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:"); + + bool cannotCache = false; + + do { + if (!frame->loader()->documentLoader()) { + PCLOG(" -There is no DocumentLoader object"); + cannotCache = true; + break; + } + if (!frame->loader()->documentLoader()->mainDocumentError().isNull()) { + PCLOG(" -Main document has an error"); + cannotCache = true; + } + if (frame->loader()->subframeLoader()->containsPlugins()) { + PCLOG(" -Frame contains plugins"); + cannotCache = true; + } + if (frame->loader()->url().protocolIs("https")) { + PCLOG(" -Frame is HTTPS"); + cannotCache = true; + } + if (frame->domWindow() && frame->domWindow()->hasEventListeners(eventNames().unloadEvent)) { + PCLOG(" -Frame has an unload event listener"); + cannotCache = true; + } +#if ENABLE(DATABASE) + if (frame->document()->hasOpenDatabases()) { + PCLOG(" -Frame has open database handles"); + cannotCache = true; + } +#endif +#if ENABLE(SHARED_WORKERS) + if (SharedWorkerRepository::hasSharedWorkers(frame->document())) { + PCLOG(" -Frame has associated SharedWorkers"); + cannotCache = true; + } +#endif + if (frame->document()->usingGeolocation()) { + PCLOG(" -Frame uses Geolocation"); + cannotCache = true; + } + if (!frame->loader()->history()->currentItem()) { + PCLOG(" -No current history item"); + cannotCache = true; + } + if (frame->loader()->quickRedirectComing()) { + PCLOG(" -Quick redirect is coming"); + cannotCache = true; + } + if (frame->loader()->documentLoader()->isLoadingInAPISense()) { + PCLOG(" -DocumentLoader is still loading in API sense"); + cannotCache = true; + } + if (frame->loader()->documentLoader()->isStopping()) { + PCLOG(" -DocumentLoader is in the middle of stopping"); + cannotCache = true; + } + if (!frame->document()->canSuspendActiveDOMObjects()) { + PCLOG(" -The document cannot suspect its active DOM Objects"); + cannotCache = true; + } +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + if (!frame->loader()->documentLoader()->applicationCacheHost()->canCacheInPageCache()) { + PCLOG(" -The DocumentLoader uses an application cache"); + cannotCache = true; + } +#endif + if (!frame->loader()->client()->canCachePage()) { + PCLOG(" -The client says this frame cannot be cached"); + cannotCache = true; + } + } while (false); + + for (Frame* child = frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) + if (!logCanCacheFrameDecision(child, indentLevel + 1)) + cannotCache = true; + + PCLOG(cannotCache ? " Frame CANNOT be cached" : " Frame CAN be cached"); + PCLOG("+---"); + + return !cannotCache; +} + +static void logCanCachePageDecision(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; + PCLOG("--------\n Determining if page can be cached:"); + + bool cannotCache = !logCanCacheFrameDecision(page->mainFrame(), 1); + + FrameLoadType loadType = page->mainFrame()->loader()->loadType(); + if (!page->backForward()->isActive()) { + PCLOG(" -The back/forward list is disabled or has 0 capacity"); + cannotCache = true; + } + if (!page->settings()->usesPageCache()) { + PCLOG(" -Page settings says b/f cache disabled"); + cannotCache = true; + } +#if ENABLE(DEVICE_ORIENTATION) + if (page->deviceMotionController() && page->deviceMotionController()->isActive()) { + PCLOG(" -Page is using DeviceMotion"); + cannotCache = true; + } + if (page->deviceOrientationController() && page->deviceOrientationController()->isActive()) { + PCLOG(" -Page is using DeviceOrientation"); + cannotCache = true; + } +#endif + if (loadType == FrameLoadTypeReload) { + PCLOG(" -Load type is: Reload"); + cannotCache = true; + } + if (loadType == FrameLoadTypeReloadFromOrigin) { + PCLOG(" -Load type is: Reload from origin"); + cannotCache = true; + } + if (loadType == FrameLoadTypeSame) { + PCLOG(" -Load type is: Same"); + cannotCache = true; + } + + PCLOG(cannotCache ? " Page CANNOT be cached\n--------" : " Page CAN be cached\n--------"); +} + +#endif + +PageCache* pageCache() +{ + static PageCache* staticPageCache = new PageCache; + return staticPageCache; +} + +PageCache::PageCache() + : m_capacity(0) + , m_size(0) + , m_head(0) + , m_tail(0) + , m_autoreleaseTimer(this, &PageCache::releaseAutoreleasedPagesNowOrReschedule) +{ +} + +bool PageCache::canCachePageContainingThisFrame(Frame* frame) +{ + for (Frame* child = frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) { + if (!canCachePageContainingThisFrame(child)) + return false; + } + + return frame->loader()->documentLoader() + && frame->loader()->documentLoader()->mainDocumentError().isNull() + // FIXME: If we ever change this so that frames with plug-ins will be cached, + // we need to make sure that we don't cache frames that have outstanding NPObjects + // (objects created by the plug-in). Since there is no way to pause/resume a Netscape plug-in, + // they would need to be destroyed and then recreated, and there is no way that we can recreate + // the right NPObjects. See <rdar://problem/5197041> for more information. + && !frame->loader()->subframeLoader()->containsPlugins() + && !frame->loader()->url().protocolIs("https") + && (!frame->domWindow() || !frame->domWindow()->hasEventListeners(eventNames().unloadEvent)) +#if ENABLE(DATABASE) + && !frame->document()->hasOpenDatabases() +#endif +#if ENABLE(SHARED_WORKERS) + && !SharedWorkerRepository::hasSharedWorkers(frame->document()) +#endif + && !frame->document()->usingGeolocation() + && frame->loader()->history()->currentItem() + && !frame->loader()->quickRedirectComing() + && !frame->loader()->documentLoader()->isLoadingInAPISense() + && !frame->loader()->documentLoader()->isStopping() + && frame->document()->canSuspendActiveDOMObjects() +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + // FIXME: We should investigating caching frames that have an associated + // application cache. <rdar://problem/5917899> tracks that work. + && frame->loader()->documentLoader()->applicationCacheHost()->canCacheInPageCache() +#endif +#if ENABLE(WML) + && !frame->document()->containsWMLContent() + && !frame->document()->isWMLDocument() +#endif + && frame->loader()->client()->canCachePage(); +} + +bool PageCache::canCache(Page* page) +{ + if (!page) + return false; + +#ifndef 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. + // FIXME: <rdar://problem/4886592> - We should work out the complexities of caching pages with frames as they + // are the most interesting pages on the web, and often those that would benefit the most from caching! + FrameLoadType loadType = page->mainFrame()->loader()->loadType(); + + return canCachePageContainingThisFrame(page->mainFrame()) + && page->backForward()->isActive() + && page->settings()->usesPageCache() +#if ENABLE(DEVICE_ORIENTATION) + && !(page->deviceMotionController() && page->deviceMotionController()->isActive()) + && !(page->deviceOrientationController() && page->deviceOrientationController()->isActive()) +#endif + && loadType != FrameLoadTypeReload + && loadType != FrameLoadTypeReloadFromOrigin + && loadType != FrameLoadTypeSame; +} + +void PageCache::setCapacity(int capacity) +{ + ASSERT(capacity >= 0); + m_capacity = max(capacity, 0); + + prune(); +} + +int 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; + } + + return frameCount; +} + +int PageCache::autoreleasedPageCount() const +{ + return m_autoreleaseSet.size(); +} + +void PageCache::add(PassRefPtr<HistoryItem> prpItem, Page* page) +{ + ASSERT(prpItem); + ASSERT(page); + ASSERT(canCache(page)); + + HistoryItem* item = prpItem.releaseRef(); // Balanced in remove(). + + // Remove stale cache entry if necessary. + if (item->m_cachedPage) + remove(item); + + item->m_cachedPage = CachedPage::create(page); + addToLRUList(item); + ++m_size; + + prune(); +} + +CachedPage* PageCache::get(HistoryItem* item) +{ + if (!item) + return 0; + + if (CachedPage* cachedPage = item->m_cachedPage.get()) { + // FIXME: 1800 should not be hardcoded, it should come from + // WebKitBackForwardCacheExpirationIntervalKey in WebKit. + // Or we should remove WebKitBackForwardCacheExpirationIntervalKey. + if (currentTime() - cachedPage->timeStamp() <= 1800) + 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; +} + +void PageCache::remove(HistoryItem* item) +{ + // Safely ignore attempts to remove items not in the cache. + if (!item || !item->m_cachedPage) + return; + + autorelease(item->m_cachedPage.release()); + removeFromLRUList(item); + --m_size; + + item->deref(); // Balanced in add(). +} + +void PageCache::prune() +{ + while (m_size > m_capacity) { + ASSERT(m_tail && m_tail->m_cachedPage); + remove(m_tail); + } +} + +void PageCache::addToLRUList(HistoryItem* item) +{ + item->m_next = m_head; + item->m_prev = 0; + + if (m_head) { + ASSERT(m_tail); + m_head->m_prev = item; + } else { + ASSERT(!m_tail); + m_tail = item; + } + + m_head = item; +} + +void PageCache::removeFromLRUList(HistoryItem* item) +{ + 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; + } +} + +void PageCache::releaseAutoreleasedPagesNowOrReschedule(Timer<PageCache>* timer) +{ + double loadDelta = currentTime() - FrameLoader::timeOfLastCompletedLoad(); + float userDelta = userIdleTime(); + + // FIXME: <rdar://problem/5211190> This limit of 42 risks growing the page cache far beyond its nominal capacity. + if ((userDelta < 0.5 || loadDelta < 1.25) && m_autoreleaseSet.size() < 42) { + LOG(PageCache, "WebCorePageCache: Postponing releaseAutoreleasedPagesNowOrReschedule() - %f since last load, %f since last input, %i objects pending release", loadDelta, userDelta, m_autoreleaseSet.size()); + timer->startOneShot(autoreleaseInterval); + return; + } + + LOG(PageCache, "WebCorePageCache: Releasing page caches - %f seconds since last load, %f since last input, %i objects pending release", loadDelta, userDelta, m_autoreleaseSet.size()); + releaseAutoreleasedPagesNow(); +} + +void PageCache::releaseAutoreleasedPagesNow() +{ + m_autoreleaseTimer.stop(); + + // Postpone dead pruning until all our resources have gone dead. + cache()->setPruneEnabled(false); + + CachedPageSet tmp; + tmp.swap(m_autoreleaseSet); + + CachedPageSet::iterator end = tmp.end(); + for (CachedPageSet::iterator it = tmp.begin(); it != end; ++it) + (*it)->destroy(); + + // Now do the prune. + cache()->setPruneEnabled(true); + cache()->prune(); +} + +void PageCache::autorelease(PassRefPtr<CachedPage> page) +{ + ASSERT(page); + ASSERT(!m_autoreleaseSet.contains(page.get())); + m_autoreleaseSet.add(page); + if (!m_autoreleaseTimer.isActive()) + m_autoreleaseTimer.startOneShot(autoreleaseInterval); +} + +} // namespace WebCore diff --git a/Source/WebCore/history/PageCache.h b/Source/WebCore/history/PageCache.h new file mode 100644 index 0000000..71ae5ad --- /dev/null +++ b/Source/WebCore/history/PageCache.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2007 Apple 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 PageCache_h +#define PageCache_h + +#include "HistoryItem.h" +#include "Timer.h" +#include <wtf/Forward.h> +#include <wtf/HashSet.h> +#include <wtf/Noncopyable.h> + +namespace WebCore { + + class CachedPage; + class Frame; + class HistoryItem; + class Page; + + class PageCache : public Noncopyable { + public: + friend PageCache* pageCache(); + + static bool canCache(Page*); + + 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); + + void releaseAutoreleasedPagesNow(); + + int pageCount() const { return m_size; } + int frameCount() const; + int autoreleasedPageCount() const; + + private: + typedef HashSet<RefPtr<CachedPage> > CachedPageSet; + + PageCache(); // Use pageCache() instead. + ~PageCache(); // Not implemented to make sure nobody accidentally calls delete -- WebCore does not delete singletons. + + static bool canCachePageContainingThisFrame(Frame*); + + void addToLRUList(HistoryItem*); // Adds to the head of the list. + void removeFromLRUList(HistoryItem*); + + void prune(); + + void autorelease(PassRefPtr<CachedPage>); + void releaseAutoreleasedPagesNowOrReschedule(Timer<PageCache>*); + + int m_capacity; + int m_size; + + // LRU List + HistoryItem* m_head; + HistoryItem* m_tail; + + Timer<PageCache> m_autoreleaseTimer; + CachedPageSet m_autoreleaseSet; + }; + + // Function to obtain the global page cache. + PageCache* pageCache(); + +} // namespace WebCore + +#endif // PageCache_h diff --git a/Source/WebCore/history/android/AndroidWebHistoryBridge.h b/Source/WebCore/history/android/AndroidWebHistoryBridge.h new file mode 100644 index 0000000..a827b4a --- /dev/null +++ b/Source/WebCore/history/android/AndroidWebHistoryBridge.h @@ -0,0 +1,62 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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 THE COPYRIGHT HOLDERS ``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 THE COPYRIGHT OWNER 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 AndroidWebHistoryBridge_h +#define AndroidWebHistoryBridge_h + +#include <wtf/RefCounted.h> + +namespace WebCore { + +class HistoryItem; + +class AndroidWebHistoryBridge : public RefCounted<AndroidWebHistoryBridge> { +public: + AndroidWebHistoryBridge(HistoryItem* item) + : m_scale(0) + , m_textWrapScale(0) + , m_active(false) + , m_historyItem(item) { } + virtual ~AndroidWebHistoryBridge() { } + virtual void updateHistoryItem(HistoryItem* item) = 0; + + void setScale(float s) { m_scale = s; } + void setTextWrapScale(float s) { m_textWrapScale = s; } + float scale() const { return m_scale; } + float textWrapScale() const { return m_textWrapScale; } + void detachHistoryItem() { m_historyItem = 0; } + HistoryItem* historyItem() const { return m_historyItem; } + void setActive() { m_active = true; } + +protected: + float m_scale; + float m_textWrapScale; + bool m_active; + HistoryItem* m_historyItem; +}; + +} // namespace WebCore + +#endif // AndroidWebHistoryBridge_h diff --git a/Source/WebCore/history/android/HistoryItemAndroid.cpp b/Source/WebCore/history/android/HistoryItemAndroid.cpp new file mode 100644 index 0000000..7c0f4ba --- /dev/null +++ b/Source/WebCore/history/android/HistoryItemAndroid.cpp @@ -0,0 +1,46 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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 THE COPYRIGHT HOLDERS ``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 THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "HistoryItem.h" + +namespace WebCore { + +class AndroidWebHistoryBridge; + +AndroidWebHistoryBridge* HistoryItem::bridge() const +{ + if (!m_bridge) + return 0; + return m_bridge.get(); +} + +void HistoryItem::setBridge(AndroidWebHistoryBridge* bridge) +{ + m_bridge = adoptRef(bridge); +} + +} // namespace WebCore + diff --git a/Source/WebCore/history/cf/HistoryPropertyList.cpp b/Source/WebCore/history/cf/HistoryPropertyList.cpp new file mode 100644 index 0000000..fd28237 --- /dev/null +++ b/Source/WebCore/history/cf/HistoryPropertyList.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2009 Apple 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 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 INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "HistoryPropertyList.h" + +#include "HistoryItem.h" +#include <wtf/StringExtras.h> + +namespace WebCore { + +static const int currentFileVersion = 1; + +HistoryPropertyListWriter::HistoryPropertyListWriter() + : m_dailyVisitCountsKey("D") + , m_displayTitleKey("displayTitle") + , m_lastVisitWasFailureKey("lastVisitWasFailure") + , m_lastVisitWasHTTPNonGetKey("lastVisitWasHTTPNonGet") + , m_lastVisitedDateKey("lastVisitedDate") + , m_redirectURLsKey("redirectURLs") + , m_titleKey("title") + , m_urlKey("") + , m_visitCountKey("visitCount") + , m_weeklyVisitCountsKey("W") + , m_buffer(0) +{ +} + +UInt8* HistoryPropertyListWriter::buffer(size_t size) +{ + ASSERT(!m_buffer); + m_buffer = static_cast<UInt8*>(CFAllocatorAllocate(0, size, 0)); + m_bufferSize = size; + return m_buffer; +} + +RetainPtr<CFDataRef> HistoryPropertyListWriter::releaseData() +{ + UInt8* buffer = m_buffer; + if (!buffer) + return 0; + m_buffer = 0; + RetainPtr<CFDataRef> data(AdoptCF, CFDataCreateWithBytesNoCopy(0, buffer, m_bufferSize, 0)); + if (!data) { + CFAllocatorDeallocate(0, buffer); + return 0; + } + return data; +} + +void HistoryPropertyListWriter::writeObjects(BinaryPropertyListObjectStream& stream) +{ + size_t outerDictionaryStart = stream.writeDictionaryStart(); + + stream.writeString("WebHistoryFileVersion"); + stream.writeString("WebHistoryDates"); + + stream.writeInteger(currentFileVersion); + size_t outerDateArrayStart = stream.writeArrayStart(); + writeHistoryItems(stream); + stream.writeArrayEnd(outerDateArrayStart); + + stream.writeDictionaryEnd(outerDictionaryStart); +} + +void HistoryPropertyListWriter::writeHistoryItem(BinaryPropertyListObjectStream& stream, HistoryItem* item) +{ + size_t itemDictionaryStart = stream.writeDictionaryStart(); + + const String& title = item->title(); + const String& displayTitle = item->alternateTitle(); + double lastVisitedDate = item->lastVisitedTime(); + int visitCount = item->visitCount(); + Vector<String>* redirectURLs = item->redirectURLs(); + const Vector<int>& dailyVisitCounts = item->dailyVisitCounts(); + const Vector<int>& weeklyVisitCounts = item->weeklyVisitCounts(); + + // keys + stream.writeString(m_urlKey); + if (!title.isEmpty()) + stream.writeString(m_titleKey); + if (!displayTitle.isEmpty()) + stream.writeString(m_displayTitleKey); + if (lastVisitedDate) + stream.writeString(m_lastVisitedDateKey); + if (visitCount) + stream.writeString(m_visitCountKey); + if (item->lastVisitWasFailure()) + stream.writeString(m_lastVisitWasFailureKey); + if (item->lastVisitWasHTTPNonGet()) + stream.writeString(m_lastVisitWasHTTPNonGetKey); + if (redirectURLs) + stream.writeString(m_redirectURLsKey); + if (!dailyVisitCounts.isEmpty()) + stream.writeString(m_dailyVisitCountsKey); + if (!weeklyVisitCounts.isEmpty()) + stream.writeString(m_weeklyVisitCountsKey); + + // values + stream.writeUniqueString(item->urlString()); + if (!title.isEmpty()) + stream.writeString(title); + if (!displayTitle.isEmpty()) + stream.writeString(displayTitle); + if (lastVisitedDate) { + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%.1lf", lastVisitedDate); + stream.writeUniqueString(buffer); + } + if (visitCount) + stream.writeInteger(visitCount); + if (item->lastVisitWasFailure()) + stream.writeBooleanTrue(); + if (item->lastVisitWasHTTPNonGet()) { + ASSERT(item->urlString().startsWith("http:", false) || item->urlString().startsWith("https:", false)); + stream.writeBooleanTrue(); + } + if (redirectURLs) { + size_t redirectArrayStart = stream.writeArrayStart(); + size_t size = redirectURLs->size(); + ASSERT(size); + for (size_t i = 0; i < size; ++i) + stream.writeUniqueString(redirectURLs->at(i)); + stream.writeArrayEnd(redirectArrayStart); + } + if (size_t size = dailyVisitCounts.size()) + stream.writeIntegerArray(dailyVisitCounts.data(), size); + if (size_t size = weeklyVisitCounts.size()) + stream.writeIntegerArray(weeklyVisitCounts.data(), size); + + stream.writeDictionaryEnd(itemDictionaryStart); +} + +} diff --git a/Source/WebCore/history/cf/HistoryPropertyList.h b/Source/WebCore/history/cf/HistoryPropertyList.h new file mode 100644 index 0000000..fcb8c47 --- /dev/null +++ b/Source/WebCore/history/cf/HistoryPropertyList.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2009 Apple 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 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 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 HistoryPropertyList_h +#define HistoryPropertyList_h + +#include "BinaryPropertyList.h" +#include "PlatformString.h" +#include <wtf/RetainPtr.h> + +namespace WebCore { + +class HistoryItem; + +class HistoryPropertyListWriter : public BinaryPropertyListWriter { +public: + RetainPtr<CFDataRef> releaseData(); + +protected: + HistoryPropertyListWriter(); + + void writeHistoryItem(BinaryPropertyListObjectStream&, HistoryItem*); + +private: + virtual void writeHistoryItems(BinaryPropertyListObjectStream&) = 0; + + virtual void writeObjects(BinaryPropertyListObjectStream&); + virtual UInt8* buffer(size_t); + + const String m_dailyVisitCountsKey; + const String m_displayTitleKey; + const String m_lastVisitWasFailureKey; + const String m_lastVisitWasHTTPNonGetKey; + const String m_lastVisitedDateKey; + const String m_redirectURLsKey; + const String m_titleKey; + const String m_urlKey; + const String m_visitCountKey; + const String m_weeklyVisitCountsKey; + + UInt8* m_buffer; + size_t m_bufferSize; +}; + +} + +#endif diff --git a/Source/WebCore/history/mac/HistoryItemMac.mm b/Source/WebCore/history/mac/HistoryItemMac.mm new file mode 100644 index 0000000..09bf78d --- /dev/null +++ b/Source/WebCore/history/mac/HistoryItemMac.mm @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2006, 2008 Apple 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. + */ + +#include "config.h" +#include "HistoryItem.h" + +#include <wtf/text/StringHash.h> + +namespace WebCore { + +id HistoryItem::viewState() const +{ + return m_viewState.get(); +} + +void HistoryItem::setViewState(id statePList) +{ + id newState = [statePList copy]; + m_viewState = newState; + [newState release]; +} + +id HistoryItem::getTransientProperty(const String& key) const +{ + if (!m_transientProperties) + return nil; + return m_transientProperties->get(key).get(); +} + +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.set(new HashMap<String, RetainPtr<id> >); + m_transientProperties->set(key, value); + } +} + +} // namespace WebCore diff --git a/Source/WebCore/history/qt/HistoryItemQt.cpp b/Source/WebCore/history/qt/HistoryItemQt.cpp new file mode 100644 index 0000000..b3c7ba1 --- /dev/null +++ b/Source/WebCore/history/qt/HistoryItemQt.cpp @@ -0,0 +1,119 @@ +/* + 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/text/CString.h> + +bool WebCore::HistoryItem::restoreState(QDataStream& in, int version) +{ + // we only support version 1 for now + + if (version != 1) + return false; + + WTF::String url; + WTF::String title; + WTF::String altTitle; + WTF::String orginalUrl; + WTF::String referrer; + WTF::String target; + WTF::String parrent; + double lastVisitedTime; + bool validUserData; + WTF::String parent; + bool lastVisitWasHTTPNonGet; + bool lastVisitWasFailure; + bool isTargetItem; + int visitCount; + WTF::Vector<WTF::String> documentState; + WebCore::IntPoint scrollPoint; + WTF::Vector<int> weeklyVisitCounts; + WTF::Vector<int> dailyVisitCounts; + // bool loadFormdata; + // WTF::String formContentType; + // WTF::Vector<char> formData; + + in >> url >> title >> altTitle >> lastVisitedTime >> orginalUrl >> referrer >> target >> parent; + in >> lastVisitWasHTTPNonGet >> lastVisitWasFailure >> isTargetItem >> visitCount >> documentState; + in >> scrollPoint >> dailyVisitCounts >> weeklyVisitCounts; + /*in >> loadFormdata; + if (loadFormdata) { + in >> formContentType >> formData; + // direct assigned (!) + m_formContentType = formContentType; + m_formData = FormData::create(CString(formData)); + }*/ + // use setters + adoptVisitCounts(dailyVisitCounts, weeklyVisitCounts); + setScrollPoint(scrollPoint); + setDocumentState(documentState); + setVisitCount(visitCount); + setIsTargetItem(isTargetItem); + setLastVisitWasFailure(lastVisitWasFailure); + setLastVisitWasHTTPNonGet(lastVisitWasHTTPNonGet); + setParent(parent); + setTarget(target); + setReferrer(referrer); + setOriginalURLString(orginalUrl); + setURLString(url); + setLastVisitedTime(lastVisitedTime); + setTitle(title); + setAlternateTitle(altTitle); + + // at the end load userData + in >> validUserData; + if (validUserData) { + QVariant tmp; + in >> tmp; + setUserData(tmp); + } + + return in.status() == QDataStream::Ok; +} + +QDataStream& WebCore::HistoryItem::saveState(QDataStream& out, int version) const +{ + // we only support version 1 for now. + if (version != 1) + return out; + + out << urlString() << title() << alternateTitle() << lastVisitedTime(); + out << originalURLString() << referrer() << target() << parent(); + out << lastVisitWasHTTPNonGet() << lastVisitWasFailure() << isTargetItem(); + out << visitCount() << documentState() << scrollPoint(); + out << dailyVisitCounts() << weeklyVisitCounts(); + /*if (m_formData) { + out << true; + out << formContentType(); + out << m_formData->flatten(); + } else { + out << false; + }*/ + // save user data + if (userData().isValid()) + out << true << userData(); + else + out << false; + + return out; +} + |