/* * 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 "WebBackForwardList.h" #include "WebPageProxy.h" namespace WebKit { static const unsigned DefaultCapacity = 100; static const unsigned NoCurrentItemIndex = UINT_MAX; WebBackForwardList::WebBackForwardList(WebPageProxy* page) : m_page(page) , m_current(NoCurrentItemIndex) , m_capacity(DefaultCapacity) , m_closed(true) , m_enabled(true) { } WebBackForwardList::~WebBackForwardList() { } void WebBackForwardList::pageClosed() { if (m_page) { size_t size = m_entries.size(); for (size_t i = 0; i < size; ++i) m_page->backForwardRemovedItem(m_entries[i]->itemID()); } m_page = 0; } void WebBackForwardList::addItem(WebBackForwardListItem* newItem) { 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) { if (m_page) m_page->backForwardRemovedItem(m_entries.last()->itemID()); m_entries.removeLast(); } } // Toss the first item if the list is getting too big, as long as we're not using it // (or even if we are, if we only want 1 entry). if (m_entries.size() == m_capacity && (m_current != 0 || m_capacity == 1)) { if (m_page) m_page->backForwardRemovedItem(m_entries[0]->itemID()); m_entries.remove(0); m_current--; } m_entries.insert(m_current + 1, newItem); m_current++; if (m_page) m_page->didChangeBackForwardList(); } void WebBackForwardList::goToItem(WebBackForwardListItem* item) { if (!m_entries.size() || !item) return; unsigned 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->didChangeBackForwardList(); } } WebBackForwardListItem* WebBackForwardList::currentItem() { if (m_current != NoCurrentItemIndex) return m_entries[m_current].get(); return 0; } WebBackForwardListItem* WebBackForwardList::backItem() { if (m_current && m_current != NoCurrentItemIndex) return m_entries[m_current - 1].get(); return 0; } WebBackForwardListItem* WebBackForwardList::forwardItem() { if (m_entries.size() && m_current < m_entries.size() - 1) return m_entries[m_current + 1].get(); return 0; } WebBackForwardListItem* WebBackForwardList::itemAtIndex(int index) { // Do range checks without doing math on index to avoid overflow. if (index < -static_cast(m_current)) return 0; if (index > forwardListCount()) return 0; return m_entries[index + m_current].get(); } int WebBackForwardList::backListCount() { return m_current == NoCurrentItemIndex ? 0 : m_current; } int WebBackForwardList::forwardListCount() { return m_current == NoCurrentItemIndex ? 0 : static_cast(m_entries.size()) - (m_current + 1); } PassRefPtr WebBackForwardList::backListAsImmutableArrayWithLimit(unsigned limit) { unsigned backListSize = static_cast(backListCount()); unsigned size = std::min(backListSize, limit); if (!size) return ImmutableArray::create(); Vector > vector; vector.reserveInitialCapacity(size); ASSERT(backListSize >= size); for (unsigned i = backListSize - size; i < backListSize; ++i) vector.uncheckedAppend(m_entries[i].get()); return ImmutableArray::adopt(vector); } PassRefPtr WebBackForwardList::forwardListAsImmutableArrayWithLimit(unsigned limit) { unsigned size = std::min(static_cast(forwardListCount()), limit); if (!size) return ImmutableArray::create(); Vector > vector; vector.reserveInitialCapacity(size); unsigned last = m_current + size; ASSERT(last < m_entries.size()); for (unsigned i = m_current + 1; i <= last; ++i) vector.uncheckedAppend(m_entries[i].get()); return ImmutableArray::adopt(vector); } void WebBackForwardList::clear() { size_t size = m_entries.size(); if (size <= 1) return; RefPtr currentItem = this->currentItem(); if (m_page) { for (size_t i = 0; i < size; ++i) { if (m_entries[i] != currentItem) m_page->backForwardRemovedItem(m_entries[i]->itemID()); } } m_entries.shrink(1); m_entries[0] = currentItem.release(); m_current = 0; if (m_page) m_page->didChangeBackForwardList(); } } // namespace WebKit