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