2011-01-05 Darin Adler <darin@apple.com>
[WebKit.git] / 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 "WebBackForwardList.h"
27
28 #include "WebPageProxy.h"
29
30 namespace WebKit {
31
32 static const unsigned DefaultCapacity = 100;
33 static const unsigned NoCurrentItemIndex = UINT_MAX;
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 }
43
44 WebBackForwardList::~WebBackForwardList()
45 {
46 }
47
48 void WebBackForwardList::pageClosed()
49 {
50     if (m_page) {
51         size_t size = m_entries.size();
52         for (size_t i = 0; i < size; ++i)
53             m_page->backForwardRemovedItem(m_entries[i]->itemID());
54     }
55
56     m_page = 0;
57 }
58
59 void WebBackForwardList::addItem(WebBackForwardListItem* newItem)
60 {
61     if (m_capacity == 0 || !m_enabled)
62         return;
63
64     // Toss anything in the forward list    
65     if (m_current != NoCurrentItemIndex) {
66         unsigned targetSize = m_current + 1;
67         while (m_entries.size() > targetSize) {
68             if (m_page)
69                 m_page->backForwardRemovedItem(m_entries.last()->itemID());
70             m_entries.removeLast();
71         }
72     }
73
74     // Toss the first item if the list is getting too big, as long as we're not using it
75     // (or even if we are, if we only want 1 entry).
76     if (m_entries.size() == m_capacity && (m_current != 0 || m_capacity == 1)) {
77         if (m_page)
78             m_page->backForwardRemovedItem(m_entries[0]->itemID());
79         m_entries.remove(0);
80         m_current--;
81     }
82
83     m_entries.insert(m_current + 1, newItem);
84     m_current++;
85
86     if (m_page)
87         m_page->didChangeBackForwardList();
88 }
89
90 void WebBackForwardList::goToItem(WebBackForwardListItem* item)
91 {
92     if (!m_entries.size() || !item)
93         return;
94         
95     unsigned index = 0;
96     for (; index < m_entries.size(); ++index) {
97         if (m_entries[index] == item)
98             break;
99     }
100     if (index < m_entries.size()) {
101         m_current = index;
102         if (m_page)
103             m_page->didChangeBackForwardList();
104     }
105 }
106
107 WebBackForwardListItem* WebBackForwardList::currentItem()
108 {
109     if (m_current != NoCurrentItemIndex)
110         return m_entries[m_current].get();
111     return 0;
112 }
113
114 WebBackForwardListItem* WebBackForwardList::backItem()
115 {
116     if (m_current && m_current != NoCurrentItemIndex)
117         return m_entries[m_current - 1].get();
118     return 0;
119 }
120
121 WebBackForwardListItem* WebBackForwardList::forwardItem()
122 {
123     if (m_entries.size() && m_current < m_entries.size() - 1)
124         return m_entries[m_current + 1].get();
125     return 0;
126 }
127
128 WebBackForwardListItem* WebBackForwardList::itemAtIndex(int index)
129 {
130     // Do range checks without doing math on index to avoid overflow.
131     if (index < -static_cast<int>(m_current))
132         return 0;
133     
134     if (index > forwardListCount())
135         return 0;
136         
137     return m_entries[index + m_current].get();
138 }
139
140 int WebBackForwardList::backListCount()
141 {
142     return m_current == NoCurrentItemIndex ? 0 : m_current;
143 }
144
145 int WebBackForwardList::forwardListCount()
146 {
147     return m_current == NoCurrentItemIndex ? 0 : static_cast<int>(m_entries.size()) - (m_current + 1);
148 }
149
150 PassRefPtr<ImmutableArray> WebBackForwardList::backListAsImmutableArrayWithLimit(unsigned limit)
151 {
152     unsigned backListSize = static_cast<unsigned>(backListCount());
153     unsigned size = std::min(backListSize, limit);
154     if (!size)
155         return ImmutableArray::create();
156
157     Vector<RefPtr<APIObject> > vector;
158     vector.reserveInitialCapacity(size);
159
160     ASSERT(backListSize >= size);
161     for (unsigned i = backListSize - size; i < backListSize; ++i)
162         vector.uncheckedAppend(m_entries[i].get());
163
164     return ImmutableArray::adopt(vector);
165 }
166
167 PassRefPtr<ImmutableArray> WebBackForwardList::forwardListAsImmutableArrayWithLimit(unsigned limit)
168 {
169     unsigned size = std::min(static_cast<unsigned>(forwardListCount()), limit);
170     if (!size)
171         return ImmutableArray::create();
172
173     Vector<RefPtr<APIObject> > vector;
174     vector.reserveInitialCapacity(size);
175
176     unsigned last = m_current + size;
177     ASSERT(last < m_entries.size());
178     for (unsigned i = m_current + 1; i <= last; ++i)
179         vector.uncheckedAppend(m_entries[i].get());
180
181     return ImmutableArray::adopt(vector);
182 }
183
184 void WebBackForwardList::clear()
185 {
186     size_t size = m_entries.size();
187     if (size <= 1)
188         return;
189
190     RefPtr<WebBackForwardListItem> currentItem = this->currentItem();
191
192     if (m_page) {
193         for (size_t i = 0; i < size; ++i) {
194             if (m_entries[i] != currentItem)
195                 m_page->backForwardRemovedItem(m_entries[i]->itemID());
196         }
197     }
198
199     m_entries.shrink(1);
200     m_entries[0] = currentItem.release();
201
202     m_current = 0;
203
204     if (m_page)
205         m_page->didChangeBackForwardList();
206 }
207
208 } // namespace WebKit