• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "BackForwardList.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 
BackForwardList(Page * page)46 BackForwardList::BackForwardList(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 
~BackForwardList()55 BackForwardList::~BackForwardList()
56 {
57     ASSERT(m_closed);
58 }
59 
addItem(PassRefPtr<HistoryItem> prpItem)60 void BackForwardList::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         m_page->mainFrame()->loader()->client()->dispatchDidRemoveBackForwardItem(item.get());
86     }
87 
88     m_entryHash.add(prpItem.get());
89     m_entries.insert(m_current + 1, prpItem);
90     m_current++;
91     m_page->mainFrame()->loader()->client()->dispatchDidAddBackForwardItem(currentItem());
92 }
93 
goBack()94 void BackForwardList::goBack()
95 {
96     ASSERT(m_current > 0);
97     if (m_current > 0) {
98         m_current--;
99         m_page->mainFrame()->loader()->client()->dispatchDidChangeBackForwardIndex();
100     }
101 }
102 
goForward()103 void BackForwardList::goForward()
104 {
105     ASSERT(m_current < m_entries.size() - 1);
106     if (m_current < m_entries.size() - 1) {
107         m_current++;
108         m_page->mainFrame()->loader()->client()->dispatchDidChangeBackForwardIndex();
109     }
110 }
111 
goToItem(HistoryItem * item)112 void BackForwardList::goToItem(HistoryItem* item)
113 {
114     if (!m_entries.size() || !item)
115         return;
116 
117     unsigned int index = 0;
118     for (; index < m_entries.size(); ++index)
119         if (m_entries[index] == item)
120             break;
121     if (index < m_entries.size()) {
122         m_current = index;
123         m_page->mainFrame()->loader()->client()->dispatchDidChangeBackForwardIndex();
124     }
125 }
126 
backItem()127 HistoryItem* BackForwardList::backItem()
128 {
129     if (m_current && m_current != NoCurrentItemIndex)
130         return m_entries[m_current - 1].get();
131     return 0;
132 }
133 
currentItem()134 HistoryItem* BackForwardList::currentItem()
135 {
136     if (m_current != NoCurrentItemIndex)
137         return m_entries[m_current].get();
138     return 0;
139 }
140 
forwardItem()141 HistoryItem* BackForwardList::forwardItem()
142 {
143     if (m_entries.size() && m_current < m_entries.size() - 1)
144         return m_entries[m_current + 1].get();
145     return 0;
146 }
147 
backListWithLimit(int limit,HistoryItemVector & list)148 void BackForwardList::backListWithLimit(int limit, HistoryItemVector& list)
149 {
150     list.clear();
151     if (m_current != NoCurrentItemIndex) {
152         unsigned first = max((int)m_current - limit, 0);
153         for (; first < m_current; ++first)
154             list.append(m_entries[first]);
155     }
156 }
157 
forwardListWithLimit(int limit,HistoryItemVector & list)158 void BackForwardList::forwardListWithLimit(int limit, HistoryItemVector& list)
159 {
160     ASSERT(limit > -1);
161     list.clear();
162     if (!m_entries.size())
163         return;
164 
165     unsigned lastEntry = m_entries.size() - 1;
166     if (m_current < lastEntry) {
167         int last = min(m_current + limit, lastEntry);
168         limit = m_current + 1;
169         for (; limit <= last; ++limit)
170             list.append(m_entries[limit]);
171     }
172 }
173 
capacity()174 int BackForwardList::capacity()
175 {
176     return m_capacity;
177 }
178 
setCapacity(int size)179 void BackForwardList::setCapacity(int size)
180 {
181     while (size < (int)m_entries.size()) {
182         RefPtr<HistoryItem> item = m_entries.last();
183         m_entries.removeLast();
184         m_entryHash.remove(item);
185         pageCache()->remove(item.get());
186     }
187 
188     if (!size)
189         m_current = NoCurrentItemIndex;
190     else if (m_current > m_entries.size() - 1) {
191         m_current = m_entries.size() - 1;
192         m_page->mainFrame()->loader()->client()->dispatchDidChangeBackForwardIndex();
193     }
194     m_capacity = size;
195 }
196 
enabled()197 bool BackForwardList::enabled()
198 {
199     return m_enabled;
200 }
201 
setEnabled(bool enabled)202 void BackForwardList::setEnabled(bool enabled)
203 {
204     m_enabled = enabled;
205     if (!enabled) {
206         int capacity = m_capacity;
207         setCapacity(0);
208         setCapacity(capacity);
209     }
210 }
211 
backListCount()212 int BackForwardList::backListCount()
213 {
214     return m_current == NoCurrentItemIndex ? 0 : m_current;
215 }
216 
forwardListCount()217 int BackForwardList::forwardListCount()
218 {
219     return m_current == NoCurrentItemIndex ? 0 : (int)m_entries.size() - (m_current + 1);
220 }
221 
itemAtIndex(int index)222 HistoryItem* BackForwardList::itemAtIndex(int index)
223 {
224     // Do range checks without doing math on index to avoid overflow.
225     if (index < -(int)m_current)
226         return 0;
227 
228     if (index > forwardListCount())
229         return 0;
230 
231     return m_entries[index + m_current].get();
232 }
233 
entries()234 HistoryItemVector& BackForwardList::entries()
235 {
236     return m_entries;
237 }
238 
pushStateItem(PassRefPtr<HistoryItem> newItem)239 void BackForwardList::pushStateItem(PassRefPtr<HistoryItem> newItem)
240 {
241     ASSERT(newItem);
242     ASSERT(newItem->stateObject());
243 
244     RefPtr<HistoryItem> current = currentItem();
245     ASSERT(current);
246 
247     addItem(newItem);
248 
249     if (!current->stateObject())
250         current->setStateObject(SerializedScriptValue::create());
251 }
252 
close()253 void BackForwardList::close()
254 {
255     int size = m_entries.size();
256     for (int i = 0; i < size; ++i)
257         pageCache()->remove(m_entries[i].get());
258     m_entries.clear();
259     m_entryHash.clear();
260     m_page = 0;
261     m_closed = true;
262 }
263 
closed()264 bool BackForwardList::closed()
265 {
266     return m_closed;
267 }
268 
removeItem(HistoryItem * item)269 void BackForwardList::removeItem(HistoryItem* item)
270 {
271     if (!item)
272         return;
273 
274     for (unsigned i = 0; i < m_entries.size(); ++i)
275         if (m_entries[i] == item) {
276             m_entries.remove(i);
277             m_entryHash.remove(item);
278             if (m_current == NoCurrentItemIndex || m_current < i)
279                 break;
280             if (m_current > i)
281                 m_current--;
282             else {
283                 size_t count = m_entries.size();
284                 if (m_current >= count)
285                     m_current = count ? count - 1 : NoCurrentItemIndex;
286             }
287             break;
288         }
289 }
290 
containsItem(HistoryItem * entry)291 bool BackForwardList::containsItem(HistoryItem* entry)
292 {
293     return m_entryHash.contains(entry);
294 }
295 
296 #if ENABLE(WML)
clearWMLPageHistory()297 void BackForwardList::clearWMLPageHistory()
298 {
299     RefPtr<HistoryItem> currentItem = this->currentItem();
300 
301     int size = m_entries.size();
302     for (int i = 0; i < size; ++i)
303         pageCache()->remove(m_entries[i].get());
304 
305     m_entries.clear();
306     m_entryHash.clear();
307     m_current = NoCurrentItemIndex;
308 
309     // Spec: The history stack may be reset to a state where it only contains the current card.
310     addItem(currentItem);
311 }
312 #endif
313 
314 }; // namespace WebCore
315