• 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 "HistoryItem.h"
31 #include "Logging.h"
32 #include "PageCache.h"
33 #ifdef ANDROID_HISTORY_CLIENT
34 #include "Frame.h"
35 #include "FrameLoader.h"
36 #include "FrameLoaderClient.h"
37 #include "Page.h"
38 #endif
39 
40 using namespace std;
41 
42 namespace WebCore {
43 
44 static const unsigned DefaultCapacity = 100;
45 static const unsigned NoCurrentItemIndex = UINT_MAX;
46 
BackForwardList(Page * page)47 BackForwardList::BackForwardList(Page* page)
48     : m_page(page)
49     , m_current(NoCurrentItemIndex)
50     , m_capacity(DefaultCapacity)
51     , m_closed(true)
52     , m_enabled(true)
53 {
54 }
55 
~BackForwardList()56 BackForwardList::~BackForwardList()
57 {
58     ASSERT(m_closed);
59 }
60 
addItem(PassRefPtr<HistoryItem> prpItem)61 void BackForwardList::addItem(PassRefPtr<HistoryItem> prpItem)
62 {
63     ASSERT(prpItem);
64     if (m_capacity == 0 || !m_enabled)
65         return;
66 
67     // Toss anything in the forward list
68     if (m_current != NoCurrentItemIndex) {
69         unsigned targetSize = m_current + 1;
70         while (m_entries.size() > targetSize) {
71             RefPtr<HistoryItem> item = m_entries.last();
72             m_entries.removeLast();
73             m_entryHash.remove(item);
74             pageCache()->remove(item.get());
75         }
76     }
77 
78     // Toss the first item if the list is getting too big, as long as we're not using it
79     // (or even if we are, if we only want 1 entry).
80     if (m_entries.size() == m_capacity && (m_current != 0 || m_capacity == 1)) {
81         RefPtr<HistoryItem> item = m_entries[0];
82         m_entries.remove(0);
83         m_entryHash.remove(item);
84         pageCache()->remove(item.get());
85         m_current--;
86 #ifdef ANDROID_HISTORY_CLIENT
87         m_page->mainFrame()->loader()->client()->dispatchDidRemoveHistoryItem(item.get(), 0);
88 #endif
89     }
90 
91     m_entries.append(prpItem);
92     m_entryHash.add(m_entries.last());
93     m_current++;
94 #ifdef ANDROID_HISTORY_CLIENT
95     m_page->mainFrame()->loader()->client()->dispatchDidAddHistoryItem(currentItem());
96 #endif
97 }
98 
goBack()99 void BackForwardList::goBack()
100 {
101     ASSERT(m_current > 0);
102 #ifdef ANDROID_HISTORY_CLIENT
103     if (m_current > 0) {
104         m_current--;
105         m_page->mainFrame()->loader()->client()->dispatchDidChangeHistoryIndex(this);
106     }
107 #else
108     if (m_current > 0)
109         m_current--;
110 #endif
111 }
112 
goForward()113 void BackForwardList::goForward()
114 {
115     ASSERT(m_current < m_entries.size() - 1);
116 #ifdef ANDROID_HISTORY_CLIENT
117     if (m_current < m_entries.size() - 1) {
118         m_current++;
119         m_page->mainFrame()->loader()->client()->dispatchDidChangeHistoryIndex(this);
120     }
121 #else
122     if (m_current < m_entries.size() - 1)
123         m_current++;
124 #endif
125 }
126 
goToItem(HistoryItem * item)127 void BackForwardList::goToItem(HistoryItem* item)
128 {
129     if (!m_entries.size() || !item)
130         return;
131 
132     unsigned int index = 0;
133     for (; index < m_entries.size(); ++index)
134         if (m_entries[index] == item)
135             break;
136 #ifdef ANDROID_HISTORY_CLIENT
137     if (index < m_entries.size()) {
138         m_current = index;
139         m_page->mainFrame()->loader()->client()->dispatchDidChangeHistoryIndex(this);
140     }
141 #else
142     if (index < m_entries.size())
143         m_current = index;
144 #endif
145 }
146 
backItem()147 HistoryItem* BackForwardList::backItem()
148 {
149     if (m_current && m_current != NoCurrentItemIndex)
150         return m_entries[m_current - 1].get();
151     return 0;
152 }
153 
currentItem()154 HistoryItem* BackForwardList::currentItem()
155 {
156     if (m_current != NoCurrentItemIndex)
157         return m_entries[m_current].get();
158     return 0;
159 }
160 
forwardItem()161 HistoryItem* BackForwardList::forwardItem()
162 {
163     if (m_entries.size() && m_current < m_entries.size() - 1)
164         return m_entries[m_current + 1].get();
165     return 0;
166 }
167 
backListWithLimit(int limit,HistoryItemVector & list)168 void BackForwardList::backListWithLimit(int limit, HistoryItemVector& list)
169 {
170     list.clear();
171     if (m_current != NoCurrentItemIndex) {
172         unsigned first = max((int)m_current - limit, 0);
173         for (; first < m_current; ++first)
174             list.append(m_entries[first]);
175     }
176 }
177 
forwardListWithLimit(int limit,HistoryItemVector & list)178 void BackForwardList::forwardListWithLimit(int limit, HistoryItemVector& list)
179 {
180     ASSERT(limit > -1);
181     list.clear();
182     if (!m_entries.size())
183         return;
184 
185     unsigned lastEntry = m_entries.size() - 1;
186     if (m_current < lastEntry) {
187         int last = min(m_current + limit, lastEntry);
188         limit = m_current + 1;
189         for (; limit <= last; ++limit)
190             list.append(m_entries[limit]);
191     }
192 }
193 
capacity()194 int BackForwardList::capacity()
195 {
196     return m_capacity;
197 }
198 
setCapacity(int size)199 void BackForwardList::setCapacity(int size)
200 {
201     while (size < (int)m_entries.size()) {
202         RefPtr<HistoryItem> item = m_entries.last();
203         m_entries.removeLast();
204         m_entryHash.remove(item);
205         pageCache()->remove(item.get());
206     }
207 
208     if (!size)
209         m_current = NoCurrentItemIndex;
210 #ifdef ANDROID_HISTORY_CLIENT
211     else if (m_current > m_entries.size() - 1) {
212         m_current = m_entries.size() - 1;
213         m_page->mainFrame()->loader()->client()->dispatchDidChangeHistoryIndex(this);
214     }
215 #else
216     else if (m_current > m_entries.size() - 1)
217         m_current = m_entries.size() - 1;
218 #endif
219 
220     m_capacity = size;
221 }
222 
enabled()223 bool BackForwardList::enabled()
224 {
225     return m_enabled;
226 }
227 
setEnabled(bool enabled)228 void BackForwardList::setEnabled(bool enabled)
229 {
230     m_enabled = enabled;
231     if (!enabled) {
232         int capacity = m_capacity;
233         setCapacity(0);
234         setCapacity(capacity);
235     }
236 }
237 
backListCount()238 int BackForwardList::backListCount()
239 {
240     return m_current == NoCurrentItemIndex ? 0 : m_current;
241 }
242 
forwardListCount()243 int BackForwardList::forwardListCount()
244 {
245     return m_current == NoCurrentItemIndex ? 0 : (int)m_entries.size() - (m_current + 1);
246 }
247 
itemAtIndex(int index)248 HistoryItem* BackForwardList::itemAtIndex(int index)
249 {
250     // Do range checks without doing math on index to avoid overflow.
251     if (index < -(int)m_current)
252         return 0;
253 
254     if (index > forwardListCount())
255         return 0;
256 
257     return m_entries[index + m_current].get();
258 }
259 
entries()260 HistoryItemVector& BackForwardList::entries()
261 {
262     return m_entries;
263 }
264 
close()265 void BackForwardList::close()
266 {
267     int size = m_entries.size();
268     for (int i = 0; i < size; ++i)
269         pageCache()->remove(m_entries[i].get());
270     m_entries.clear();
271     m_entryHash.clear();
272     m_page = 0;
273     m_closed = true;
274 }
275 
closed()276 bool BackForwardList::closed()
277 {
278     return m_closed;
279 }
280 
removeItem(HistoryItem * item)281 void BackForwardList::removeItem(HistoryItem* item)
282 {
283     if (!item)
284         return;
285 
286     for (unsigned i = 0; i < m_entries.size(); ++i)
287         if (m_entries[i] == item) {
288             m_entries.remove(i);
289             m_entryHash.remove(item);
290             if (m_current == NoCurrentItemIndex || m_current < i)
291                 break;
292             if (m_current > i)
293                 m_current--;
294             else {
295                 size_t count = m_entries.size();
296                 if (m_current >= count)
297                     m_current = count ? count-1 : NoCurrentItemIndex;
298             }
299             break;
300         }
301 }
302 
containsItem(HistoryItem * entry)303 bool BackForwardList::containsItem(HistoryItem* entry)
304 {
305     return m_entryHash.contains(entry);
306 }
307 
308 #if ENABLE(WML)
clearWMLPageHistory()309 void BackForwardList::clearWMLPageHistory()
310 {
311     RefPtr<HistoryItem> currentItem = this->currentItem();
312 
313     int size = m_entries.size();
314     for (int i = 0; i < size; ++i)
315         pageCache()->remove(m_entries[i].get());
316 
317     m_entries.clear();
318     m_entryHash.clear();
319     m_current = NoCurrentItemIndex;
320 
321     // Spec: The history stack may be reset to a state where it only contains the current card.
322     addItem(currentItem);
323 }
324 #endif
325 
326 }; // namespace WebCore
327