[Qt][WK2] Commit the preedit string in the input method when focus is about to be...
[WebKit-https.git] / 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_hasCurrentIndex(false)
38     , m_currentIndex(0)
39     , m_capacity(DefaultCapacity)
40 {
41     ASSERT(m_page);
42 }
43
44 WebBackForwardList::~WebBackForwardList()
45 {
46     // A WebBackForwardList should never be destroyed unless it's associated page has been closed or is invalid.
47     ASSERT((!m_page && !m_hasCurrentIndex) || !m_page->isValid());
48 }
49
50 void WebBackForwardList::pageClosed()
51 {
52     // We should have always started out with an m_page and we should never close the page twice.
53     ASSERT(m_page);
54
55     if (m_page) {
56         size_t size = m_entries.size();
57         for (size_t i = 0; i < size; ++i) {
58             ASSERT(m_entries[i]);
59             if (!m_entries[i])
60                 continue;
61             m_page->backForwardRemovedItem(m_entries[i]->itemID());
62         }
63     }
64
65     m_page = 0;
66     m_entries.clear();
67     m_hasCurrentIndex = false;
68 }
69
70 void WebBackForwardList::addItem(WebBackForwardListItem* newItem)
71 {
72     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
73
74     if (!m_capacity || !newItem || !m_page)
75         return;
76
77     Vector<RefPtr<APIObject> > removedItems;
78     
79     if (m_hasCurrentIndex) {
80         // Toss everything in the forward list.
81         unsigned targetSize = m_currentIndex + 1;
82         removedItems.reserveCapacity(m_entries.size() - targetSize);
83         while (m_entries.size() > targetSize) {
84             m_page->backForwardRemovedItem(m_entries.last()->itemID());
85             removedItems.append(m_entries.last().release());
86             m_entries.removeLast();
87         }
88
89         // Toss the first item if the list is getting too big, as long as we're not using it
90         // (or even if we are, if we only want 1 entry).
91         if (m_entries.size() == m_capacity && (m_currentIndex || m_capacity == 1)) {
92             m_page->backForwardRemovedItem(m_entries[0]->itemID());
93             removedItems.append(m_entries[0].release());
94             m_entries.remove(0);
95
96             if (m_entries.isEmpty())
97                 m_hasCurrentIndex = false;
98             else
99                 m_currentIndex--;
100         }
101     } else {
102         // If we have no current item index we should also not have any entries.
103         ASSERT(m_entries.isEmpty());
104
105         // But just in case it does happen in practice we'll get back in to a consistent state now before adding the new item.
106         size_t size = m_entries.size();
107         for (size_t i = 0; i < size; ++i) {
108             ASSERT(m_entries[i]);
109             if (!m_entries[i])
110                 continue;
111             m_page->backForwardRemovedItem(m_entries[i]->itemID());
112             removedItems.append(m_entries[i].release());
113         }
114         m_entries.clear();
115     }
116     
117     if (!m_hasCurrentIndex) {
118         ASSERT(m_entries.isEmpty());
119         m_currentIndex = 0;
120         m_hasCurrentIndex = true;
121     } else
122         m_currentIndex++;
123
124     // m_current never be pointing more than 1 past the end of the entries Vector.
125     // If it is, something has gone wrong and we should not try to insert the new item.
126     ASSERT(m_currentIndex <= m_entries.size());
127     if (m_currentIndex <= m_entries.size())
128         m_entries.insert(m_currentIndex, newItem);
129
130     m_page->didChangeBackForwardList(newItem, &removedItems);
131 }
132
133 void WebBackForwardList::goToItem(WebBackForwardListItem* item)
134 {
135     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
136
137     if (!m_entries.size() || !item || !m_page || !m_hasCurrentIndex)
138         return;
139         
140     unsigned index = 0;
141     for (; index < m_entries.size(); ++index) {
142         if (m_entries[index] == item)
143             break;
144     }
145     if (index < m_entries.size()) {
146         m_currentIndex = index;
147         m_page->didChangeBackForwardList(0, 0);
148     }
149 }
150
151 WebBackForwardListItem* WebBackForwardList::currentItem()
152 {
153     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
154
155     return m_page && m_hasCurrentIndex ? m_entries[m_currentIndex].get() : 0;
156 }
157
158 WebBackForwardListItem* WebBackForwardList::backItem()
159 {
160     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
161
162     return m_page && m_hasCurrentIndex && m_currentIndex ? m_entries[m_currentIndex - 1].get() : 0;
163 }
164
165 WebBackForwardListItem* WebBackForwardList::forwardItem()
166 {
167     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
168
169     return m_page && m_hasCurrentIndex && m_entries.size() && m_currentIndex < m_entries.size() - 1 ? m_entries[m_currentIndex + 1].get() : 0;
170 }
171
172 WebBackForwardListItem* WebBackForwardList::itemAtIndex(int index)
173 {
174     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
175
176     if (!m_hasCurrentIndex || !m_page)
177         return 0;
178     
179     // Do range checks without doing math on index to avoid overflow.
180     if (index < -backListCount())
181         return 0;
182     
183     if (index > forwardListCount())
184         return 0;
185         
186     return m_entries[index + m_currentIndex].get();
187 }
188
189 int WebBackForwardList::backListCount() const
190 {
191     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
192
193     return m_page && m_hasCurrentIndex ? m_currentIndex : 0;
194 }
195
196 int WebBackForwardList::forwardListCount() const
197 {
198     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
199
200     return m_page && m_hasCurrentIndex ? m_entries.size() - (m_currentIndex + 1) : 0;
201 }
202
203 PassRefPtr<ImmutableArray> WebBackForwardList::backListAsImmutableArrayWithLimit(unsigned limit) const
204 {
205     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
206
207     if (!m_page || !m_hasCurrentIndex)
208         return ImmutableArray::create();
209
210     unsigned backListSize = static_cast<unsigned>(backListCount());
211     unsigned size = std::min(backListSize, limit);
212     if (!size)
213         return ImmutableArray::create();
214
215     Vector<RefPtr<APIObject> > vector;
216     vector.reserveInitialCapacity(size);
217
218     ASSERT(backListSize >= size);
219     for (unsigned i = backListSize - size; i < backListSize; ++i) {
220         ASSERT(m_entries[i]);
221         vector.uncheckedAppend(m_entries[i].get());
222     }
223
224     return ImmutableArray::adopt(vector);
225 }
226
227 PassRefPtr<ImmutableArray> WebBackForwardList::forwardListAsImmutableArrayWithLimit(unsigned limit) const
228 {
229     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
230
231     if (!m_page || !m_hasCurrentIndex)
232         return ImmutableArray::create();
233
234     unsigned size = std::min(static_cast<unsigned>(forwardListCount()), limit);
235     if (!size)
236         return ImmutableArray::create();
237
238     Vector<RefPtr<APIObject> > vector;
239     vector.reserveInitialCapacity(size);
240
241     unsigned last = m_currentIndex + size;
242     ASSERT(last < m_entries.size());
243     for (unsigned i = m_currentIndex + 1; i <= last; ++i) {
244         ASSERT(m_entries[i]);
245         vector.uncheckedAppend(m_entries[i].get());
246     }
247
248     return ImmutableArray::adopt(vector);
249 }
250
251 void WebBackForwardList::clear()
252 {
253     ASSERT(!m_hasCurrentIndex || m_currentIndex < m_entries.size());
254
255     size_t size = m_entries.size();
256     if (!m_page || size <= 1)
257         return;
258
259     RefPtr<WebBackForwardListItem> currentItem = this->currentItem();
260     Vector<RefPtr<APIObject> > removedItems;
261
262     if (!currentItem) {
263         // We should only ever have no current item if we also have no current item index.
264         ASSERT(!m_hasCurrentIndex);
265
266         // But just in case it does happen in practice we should get back into a consistent state now.
267         for (size_t i = 0; i < size; ++i) {
268             ASSERT(m_entries[i]);
269             if (!m_entries[i])
270                 continue;
271
272             m_page->backForwardRemovedItem(m_entries[i]->itemID());
273             removedItems.append(m_entries[i].release());
274         }
275
276         m_entries.clear();
277         m_hasCurrentIndex = false;
278         m_page->didChangeBackForwardList(0, &removedItems);
279
280         return;
281     }
282
283     for (size_t i = 0; i < size; ++i) {
284         ASSERT(m_entries[i]);
285         if (m_entries[i] && m_entries[i] != currentItem)
286             m_page->backForwardRemovedItem(m_entries[i]->itemID());
287     }
288
289     removedItems.reserveCapacity(size - 1);
290     for (size_t i = 0; i < size; ++i) {
291         if (i != m_currentIndex && m_hasCurrentIndex && m_entries[i])
292             removedItems.append(m_entries[i].release());
293     }
294
295     m_currentIndex = 0;
296
297     if (currentItem) {
298         m_entries.shrink(1);
299         m_entries[0] = currentItem.release();
300     } else {
301         m_entries.clear();
302         m_hasCurrentIndex = false;
303     }
304
305     m_page->didChangeBackForwardList(0, &removedItems);
306 }
307
308 } // namespace WebKit