• 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 "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 
BackForwardListImpl(Page * page)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 
~BackForwardListImpl()55 BackForwardListImpl::~BackForwardListImpl()
56 {
57     ASSERT(m_closed);
58 }
59 
addItem(PassRefPtr<HistoryItem> prpItem)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 
goBack()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 
goForward()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 
goToItem(HistoryItem * item)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 
backItem()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 
currentItem()139 HistoryItem* BackForwardListImpl::currentItem()
140 {
141     if (m_current != NoCurrentItemIndex)
142         return m_entries[m_current].get();
143     return 0;
144 }
145 
forwardItem()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 
backListWithLimit(int limit,HistoryItemVector & list)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 
forwardListWithLimit(int limit,HistoryItemVector & list)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 
capacity()179 int BackForwardListImpl::capacity()
180 {
181     return m_capacity;
182 }
183 
setCapacity(int size)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 
enabled()203 bool BackForwardListImpl::enabled()
204 {
205     return m_enabled;
206 }
207 
setEnabled(bool enabled)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 
backListCount()218 int BackForwardListImpl::backListCount()
219 {
220     return m_current == NoCurrentItemIndex ? 0 : m_current;
221 }
222 
forwardListCount()223 int BackForwardListImpl::forwardListCount()
224 {
225     return m_current == NoCurrentItemIndex ? 0 : (int)m_entries.size() - (m_current + 1);
226 }
227 
itemAtIndex(int index)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 
entries()240 HistoryItemVector& BackForwardListImpl::entries()
241 {
242     return m_entries;
243 }
244 
close()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 
closed()256 bool BackForwardListImpl::closed()
257 {
258     return m_closed;
259 }
260 
removeItem(HistoryItem * item)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 
containsItem(HistoryItem * entry)283 bool BackForwardListImpl::containsItem(HistoryItem* entry)
284 {
285     return m_entryHash.contains(entry);
286 }
287 
288 #if ENABLE(WML)
clearWMLPageHistory()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