Home | History | Annotate | Download | only in UIProcess
      1 /*
      2  * Copyright (C) 2010 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     23  * THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "WebBackForwardList.h"
     28 
     29 #include "WebPageProxy.h"
     30 
     31 namespace WebKit {
     32 
     33 static const unsigned DefaultCapacity = 100;
     34 
     35 WebBackForwardList::WebBackForwardList(WebPageProxy* page)
     36     : m_page(page)
     37     , m_current(NoCurrentItemIndex)
     38     , m_capacity(DefaultCapacity)
     39     , m_closed(true)
     40     , m_enabled(true)
     41 {
     42     ASSERT(m_current == NoCurrentItemIndex || m_current < m_entries.size());
     43 }
     44 
     45 WebBackForwardList::~WebBackForwardList()
     46 {
     47 }
     48 
     49 void WebBackForwardList::pageClosed()
     50 {
     51     if (m_page) {
     52         size_t size = m_entries.size();
     53         for (size_t i = 0; i < size; ++i)
     54             m_page->backForwardRemovedItem(m_entries[i]->itemID());
     55     }
     56 
     57     m_page = 0;
     58 }
     59 
     60 void WebBackForwardList::addItem(WebBackForwardListItem* newItem)
     61 {
     62     ASSERT(m_current == NoCurrentItemIndex || m_current < m_entries.size());
     63 
     64     if (m_capacity == 0 || !m_enabled)
     65         return;
     66 
     67     Vector<RefPtr<APIObject> > removedItems;
     68 
     69     // Toss anything in the forward list
     70     if (m_current != NoCurrentItemIndex) {
     71         unsigned targetSize = m_current + 1;
     72         removedItems.reserveCapacity(m_entries.size() - targetSize);
     73         while (m_entries.size() > targetSize) {
     74             if (m_page)
     75                 m_page->backForwardRemovedItem(m_entries.last()->itemID());
     76             removedItems.append(m_entries.last().release());
     77             m_entries.removeLast();
     78         }
     79     }
     80 
     81     // Toss the first item if the list is getting too big, as long as we're not using it
     82     // (or even if we are, if we only want 1 entry).
     83     if (m_entries.size() == m_capacity && (m_current != 0 || m_capacity == 1)) {
     84         if (m_page)
     85             m_page->backForwardRemovedItem(m_entries[0]->itemID());
     86         removedItems.append(m_entries[0].release());
     87         m_entries.remove(0);
     88         m_current--;
     89     }
     90 
     91     m_entries.insert(m_current + 1, newItem);
     92     m_current++;
     93 
     94     if (m_page)
     95         m_page->didChangeBackForwardList(newItem, &removedItems);
     96 
     97     ASSERT(m_current == NoCurrentItemIndex || m_current < m_entries.size());
     98 }
     99 
    100 void WebBackForwardList::goToItem(WebBackForwardListItem* item)
    101 {
    102     ASSERT(m_current == NoCurrentItemIndex || m_current < m_entries.size());
    103 
    104     if (!m_entries.size() || !item)
    105         return;
    106 
    107     unsigned index = 0;
    108     for (; index < m_entries.size(); ++index) {
    109         if (m_entries[index] == item)
    110             break;
    111     }
    112     if (index < m_entries.size()) {
    113         m_current = index;
    114         if (m_page)
    115             m_page->didChangeBackForwardList(0, 0);
    116     }
    117 }
    118 
    119 WebBackForwardListItem* WebBackForwardList::currentItem()
    120 {
    121     ASSERT(m_current == NoCurrentItemIndex || m_current < m_entries.size());
    122 
    123     if (m_current != NoCurrentItemIndex)
    124         return m_entries[m_current].get();
    125     return 0;
    126 }
    127 
    128 WebBackForwardListItem* WebBackForwardList::backItem()
    129 {
    130     ASSERT(m_current == NoCurrentItemIndex || m_current < m_entries.size());
    131 
    132     if (m_current && m_current != NoCurrentItemIndex)
    133         return m_entries[m_current - 1].get();
    134     return 0;
    135 }
    136 
    137 WebBackForwardListItem* WebBackForwardList::forwardItem()
    138 {
    139     ASSERT(m_current == NoCurrentItemIndex || m_current < m_entries.size());
    140 
    141     if (m_entries.size() && m_current < m_entries.size() - 1)
    142         return m_entries[m_current + 1].get();
    143     return 0;
    144 }
    145 
    146 WebBackForwardListItem* WebBackForwardList::itemAtIndex(int index)
    147 {
    148     ASSERT(m_current == NoCurrentItemIndex || m_current < m_entries.size());
    149 
    150     // Do range checks without doing math on index to avoid overflow.
    151     if (index < -static_cast<int>(m_current))
    152         return 0;
    153 
    154     if (index > forwardListCount())
    155         return 0;
    156 
    157     return m_entries[index + m_current].get();
    158 }
    159 
    160 int WebBackForwardList::backListCount()
    161 {
    162     ASSERT(m_current == NoCurrentItemIndex || m_current < m_entries.size());
    163 
    164     return m_current == NoCurrentItemIndex ? 0 : m_current;
    165 }
    166 
    167 int WebBackForwardList::forwardListCount()
    168 {
    169     ASSERT(m_current == NoCurrentItemIndex || m_current < m_entries.size());
    170 
    171     return m_current == NoCurrentItemIndex ? 0 : static_cast<int>(m_entries.size()) - (m_current + 1);
    172 }
    173 
    174 PassRefPtr<ImmutableArray> WebBackForwardList::backListAsImmutableArrayWithLimit(unsigned limit)
    175 {
    176     ASSERT(m_current == NoCurrentItemIndex || m_current < m_entries.size());
    177 
    178     unsigned backListSize = static_cast<unsigned>(backListCount());
    179     unsigned size = std::min(backListSize, limit);
    180     if (!size)
    181         return ImmutableArray::create();
    182 
    183     Vector<RefPtr<APIObject> > vector;
    184     vector.reserveInitialCapacity(size);
    185 
    186     ASSERT(backListSize >= size);
    187     for (unsigned i = backListSize - size; i < backListSize; ++i)
    188         vector.uncheckedAppend(m_entries[i].get());
    189 
    190     return ImmutableArray::adopt(vector);
    191 }
    192 
    193 PassRefPtr<ImmutableArray> WebBackForwardList::forwardListAsImmutableArrayWithLimit(unsigned limit)
    194 {
    195     ASSERT(m_current == NoCurrentItemIndex || m_current < m_entries.size());
    196 
    197     unsigned size = std::min(static_cast<unsigned>(forwardListCount()), limit);
    198     if (!size)
    199         return ImmutableArray::create();
    200 
    201     Vector<RefPtr<APIObject> > vector;
    202     vector.reserveInitialCapacity(size);
    203 
    204     unsigned last = m_current + size;
    205     ASSERT(last < m_entries.size());
    206     for (unsigned i = m_current + 1; i <= last; ++i)
    207         vector.uncheckedAppend(m_entries[i].get());
    208 
    209     return ImmutableArray::adopt(vector);
    210 }
    211 
    212 void WebBackForwardList::clear()
    213 {
    214     ASSERT(m_current == NoCurrentItemIndex || m_current < m_entries.size());
    215 
    216     size_t size = m_entries.size();
    217     if (size <= 1)
    218         return;
    219 
    220     RefPtr<WebBackForwardListItem> currentItem = this->currentItem();
    221 
    222     if (m_page) {
    223         for (size_t i = 0; i < size; ++i) {
    224             if (m_entries[i] != currentItem)
    225                 m_page->backForwardRemovedItem(m_entries[i]->itemID());
    226         }
    227     }
    228 
    229     Vector<RefPtr<APIObject> > removedItems;
    230     removedItems.reserveCapacity(m_entries.size() - 1);
    231     for (size_t i = 0; i < m_entries.size(); ++i) {
    232         if (i != m_current)
    233             removedItems.append(m_entries[i].release());
    234     }
    235 
    236     m_entries.shrink(1);
    237     m_entries[0] = currentItem.release();
    238 
    239     m_current = 0;
    240 
    241     if (m_page)
    242         m_page->didChangeBackForwardList(0, &removedItems);
    243 }
    244 
    245 } // namespace WebKit
    246