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 246