initial import
[vuplus_webkit] / Source / WebKit2 / UIProcess / WebBackForwardList.cpp
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