Home | History | Annotate | Download | only in history
      1 /*
      2  * Copyright (C) 2005, 2006 Apple Computer, Inc.  All rights reserved.
      3  * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 #include "BackForwardListImpl.h"
     29 
     30 #include "Frame.h"
     31 #include "FrameLoader.h"
     32 #include "FrameLoaderClient.h"
     33 #include "HistoryItem.h"
     34 #include "Logging.h"
     35 #include "Page.h"
     36 #include "PageCache.h"
     37 #include "SerializedScriptValue.h"
     38 
     39 using namespace std;
     40 
     41 namespace WebCore {
     42 
     43 static const unsigned DefaultCapacity = 100;
     44 static const unsigned NoCurrentItemIndex = UINT_MAX;
     45 
     46 BackForwardListImpl::BackForwardListImpl(Page* page)
     47     : m_page(page)
     48     , m_current(NoCurrentItemIndex)
     49     , m_capacity(DefaultCapacity)
     50     , m_closed(true)
     51     , m_enabled(true)
     52 {
     53 }
     54 
     55 BackForwardListImpl::~BackForwardListImpl()
     56 {
     57     ASSERT(m_closed);
     58 }
     59 
     60 void BackForwardListImpl::addItem(PassRefPtr<HistoryItem> prpItem)
     61 {
     62     ASSERT(prpItem);
     63     if (m_capacity == 0 || !m_enabled)
     64         return;
     65 
     66     // Toss anything in the forward list
     67     if (m_current != NoCurrentItemIndex) {
     68         unsigned targetSize = m_current + 1;
     69         while (m_entries.size() > targetSize) {
     70             RefPtr<HistoryItem> item = m_entries.last();
     71             m_entries.removeLast();
     72             m_entryHash.remove(item);
     73             pageCache()->remove(item.get());
     74         }
     75     }
     76 
     77     // Toss the first item if the list is getting too big, as long as we're not using it
     78     // (or even if we are, if we only want 1 entry).
     79     if (m_entries.size() == m_capacity && (m_current != 0 || m_capacity == 1)) {
     80         RefPtr<HistoryItem> item = m_entries[0];
     81         m_entries.remove(0);
     82         m_entryHash.remove(item);
     83         pageCache()->remove(item.get());
     84         m_current--;
     85         if (m_page)
     86             m_page->mainFrame()->loader()->client()->dispatchDidRemoveBackForwardItem(item.get());
     87     }
     88 
     89     m_entryHash.add(prpItem.get());
     90     m_entries.insert(m_current + 1, prpItem);
     91     m_current++;
     92     if (m_page)
     93         m_page->mainFrame()->loader()->client()->dispatchDidAddBackForwardItem(currentItem());
     94 }
     95 
     96 void BackForwardListImpl::goBack()
     97 {
     98     ASSERT(m_current > 0);
     99     if (m_current > 0) {
    100         m_current--;
    101         if (m_page)
    102             m_page->mainFrame()->loader()->client()->dispatchDidChangeBackForwardIndex();
    103     }
    104 }
    105 
    106 void BackForwardListImpl::goForward()
    107 {
    108     ASSERT(m_current < m_entries.size() - 1);
    109     if (m_current < m_entries.size() - 1) {
    110         m_current++;
    111         if (m_page)
    112             m_page->mainFrame()->loader()->client()->dispatchDidChangeBackForwardIndex();
    113     }
    114 }
    115 
    116 void BackForwardListImpl::goToItem(HistoryItem* item)
    117 {
    118     if (!m_entries.size() || !item)
    119         return;
    120 
    121     unsigned int index = 0;
    122     for (; index < m_entries.size(); ++index)
    123         if (m_entries[index] == item)
    124             break;
    125     if (index < m_entries.size()) {
    126         m_current = index;
    127         if (m_page)
    128             m_page->mainFrame()->loader()->client()->dispatchDidChangeBackForwardIndex();
    129     }
    130 }
    131 
    132 HistoryItem* BackForwardListImpl::backItem()
    133 {
    134     if (m_current && m_current != NoCurrentItemIndex)
    135         return m_entries[m_current - 1].get();
    136     return 0;
    137 }
    138 
    139 HistoryItem* BackForwardListImpl::currentItem()
    140 {
    141     if (m_current != NoCurrentItemIndex)
    142         return m_entries[m_current].get();
    143     return 0;
    144 }
    145 
    146 HistoryItem* BackForwardListImpl::forwardItem()
    147 {
    148     if (m_entries.size() && m_current < m_entries.size() - 1)
    149         return m_entries[m_current + 1].get();
    150     return 0;
    151 }
    152 
    153 void BackForwardListImpl::backListWithLimit(int limit, HistoryItemVector& list)
    154 {
    155     list.clear();
    156     if (m_current != NoCurrentItemIndex) {
    157         unsigned first = max((int)m_current - limit, 0);
    158         for (; first < m_current; ++first)
    159             list.append(m_entries[first]);
    160     }
    161 }
    162 
    163 void BackForwardListImpl::forwardListWithLimit(int limit, HistoryItemVector& list)
    164 {
    165     ASSERT(limit > -1);
    166     list.clear();
    167     if (!m_entries.size())
    168         return;
    169 
    170     unsigned lastEntry = m_entries.size() - 1;
    171     if (m_current < lastEntry) {
    172         int last = min(m_current + limit, lastEntry);
    173         limit = m_current + 1;
    174         for (; limit <= last; ++limit)
    175             list.append(m_entries[limit]);
    176     }
    177 }
    178 
    179 int BackForwardListImpl::capacity()
    180 {
    181     return m_capacity;
    182 }
    183 
    184 void BackForwardListImpl::setCapacity(int size)
    185 {
    186     while (size < (int)m_entries.size()) {
    187         RefPtr<HistoryItem> item = m_entries.last();
    188         m_entries.removeLast();
    189         m_entryHash.remove(item);
    190         pageCache()->remove(item.get());
    191     }
    192 
    193     if (!size)
    194         m_current = NoCurrentItemIndex;
    195     else if (m_current > m_entries.size() - 1) {
    196         m_current = m_entries.size() - 1;
    197         if (m_page)
    198             m_page->mainFrame()->loader()->client()->dispatchDidChangeBackForwardIndex();
    199     }
    200     m_capacity = size;
    201 }
    202 
    203 bool BackForwardListImpl::enabled()
    204 {
    205     return m_enabled;
    206 }
    207 
    208 void BackForwardListImpl::setEnabled(bool enabled)
    209 {
    210     m_enabled = enabled;
    211     if (!enabled) {
    212         int capacity = m_capacity;
    213         setCapacity(0);
    214         setCapacity(capacity);
    215     }
    216 }
    217 
    218 int BackForwardListImpl::backListCount()
    219 {
    220     return m_current == NoCurrentItemIndex ? 0 : m_current;
    221 }
    222 
    223 int BackForwardListImpl::forwardListCount()
    224 {
    225     return m_current == NoCurrentItemIndex ? 0 : (int)m_entries.size() - (m_current + 1);
    226 }
    227 
    228 HistoryItem* BackForwardListImpl::itemAtIndex(int index)
    229 {
    230     // Do range checks without doing math on index to avoid overflow.
    231     if (index < -(int)m_current)
    232         return 0;
    233 
    234     if (index > forwardListCount())
    235         return 0;
    236 
    237     return m_entries[index + m_current].get();
    238 }
    239 
    240 HistoryItemVector& BackForwardListImpl::entries()
    241 {
    242     return m_entries;
    243 }
    244 
    245 void BackForwardListImpl::close()
    246 {
    247     int size = m_entries.size();
    248     for (int i = 0; i < size; ++i)
    249         pageCache()->remove(m_entries[i].get());
    250     m_entries.clear();
    251     m_entryHash.clear();
    252     m_page = 0;
    253     m_closed = true;
    254 }
    255 
    256 bool BackForwardListImpl::closed()
    257 {
    258     return m_closed;
    259 }
    260 
    261 void BackForwardListImpl::removeItem(HistoryItem* item)
    262 {
    263     if (!item)
    264         return;
    265 
    266     for (unsigned i = 0; i < m_entries.size(); ++i)
    267         if (m_entries[i] == item) {
    268             m_entries.remove(i);
    269             m_entryHash.remove(item);
    270             if (m_current == NoCurrentItemIndex || m_current < i)
    271                 break;
    272             if (m_current > i)
    273                 m_current--;
    274             else {
    275                 size_t count = m_entries.size();
    276                 if (m_current >= count)
    277                     m_current = count ? count - 1 : NoCurrentItemIndex;
    278             }
    279             break;
    280         }
    281 }
    282 
    283 bool BackForwardListImpl::containsItem(HistoryItem* entry)
    284 {
    285     return m_entryHash.contains(entry);
    286 }
    287 
    288 #if ENABLE(WML)
    289 void BackForwardListImpl::clearWMLPageHistory()
    290 {
    291     RefPtr<HistoryItem> currentItem = this->currentItem();
    292 
    293     int size = m_entries.size();
    294     for (int i = 0; i < size; ++i)
    295         pageCache()->remove(m_entries[i].get());
    296 
    297     m_entries.clear();
    298     m_entryHash.clear();
    299     m_current = NoCurrentItemIndex;
    300 
    301     // Spec: The history stack may be reset to a state where it only contains the current card.
    302     addItem(currentItem);
    303 }
    304 #endif
    305 
    306 }; // namespace WebCore
    307