1/* 2 * Copyright (C) 2010, 2011 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 "WebBackForwardListProxy.h" 28 29#include "DataReference.h" 30#include "EncoderAdapter.h" 31#include "WebCoreArgumentCoders.h" 32#include "WebPage.h" 33#include "WebPageProxyMessages.h" 34#include "WebProcess.h" 35#include "WebProcessProxyMessages.h" 36#include <WebCore/HistoryItem.h> 37#include <wtf/HashMap.h> 38 39using namespace WebCore; 40 41namespace WebKit { 42 43static const unsigned DefaultCapacity = 100; 44static const unsigned NoCurrentItemIndex = UINT_MAX; 45 46// FIXME <rdar://problem/8819268>: This leaks all HistoryItems that go into these maps. 47// We need to clear up the life time of these objects. 48 49typedef HashMap<uint64_t, RefPtr<HistoryItem> > IDToHistoryItemMap; 50typedef HashMap<RefPtr<HistoryItem>, uint64_t> HistoryItemToIDMap; 51 52static IDToHistoryItemMap& idToHistoryItemMap() 53{ 54 DEFINE_STATIC_LOCAL(IDToHistoryItemMap, map, ()); 55 return map; 56} 57 58static HistoryItemToIDMap& historyItemToIDMap() 59{ 60 DEFINE_STATIC_LOCAL(HistoryItemToIDMap, map, ()); 61 return map; 62} 63 64static uint64_t uniqueHistoryItemID = 1; 65 66static uint64_t generateHistoryItemID() 67{ 68 // These IDs exist in the WebProcess for items created by the WebProcess. 69 // The IDs generated here need to never collide with the IDs created in WebBackForwardList in the UIProcess. 70 // We accomplish this by starting from 3, and only ever using odd ids. 71 uniqueHistoryItemID += 2; 72 return uniqueHistoryItemID; 73} 74 75void WebBackForwardListProxy::setHighestItemIDFromUIProcess(uint64_t itemID) 76{ 77 if (itemID <= uniqueHistoryItemID) 78 return; 79 80 if (itemID % 2) 81 uniqueHistoryItemID = itemID; 82 else 83 uniqueHistoryItemID = itemID + 1; 84} 85 86static void updateBackForwardItem(uint64_t itemID, HistoryItem* item) 87{ 88 EncoderAdapter encoder; 89 item->encodeBackForwardTree(encoder); 90 91 WebProcess::shared().connection()->send(Messages::WebProcessProxy::AddBackForwardItem(itemID, 92 item->originalURLString(), item->urlString(), item->title(), encoder.data()), 0); 93} 94 95void WebBackForwardListProxy::addItemFromUIProcess(uint64_t itemID, PassRefPtr<WebCore::HistoryItem> prpItem) 96{ 97 RefPtr<HistoryItem> item = prpItem; 98 99 // This item/itemID pair should not already exist in our maps. 100 ASSERT(!historyItemToIDMap().contains(item.get())); 101 ASSERT(!idToHistoryItemMap().contains(itemID)); 102 103 historyItemToIDMap().set(item, itemID); 104 idToHistoryItemMap().set(itemID, item); 105} 106 107static void WK2NotifyHistoryItemChanged(HistoryItem* item) 108{ 109 uint64_t itemID = historyItemToIDMap().get(item); 110 if (!itemID) 111 return; 112 113 updateBackForwardItem(itemID, item); 114} 115 116HistoryItem* WebBackForwardListProxy::itemForID(uint64_t itemID) 117{ 118 return idToHistoryItemMap().get(itemID).get(); 119} 120 121uint64_t WebBackForwardListProxy::idForItem(HistoryItem* item) 122{ 123 ASSERT(item); 124 return historyItemToIDMap().get(item); 125} 126 127void WebBackForwardListProxy::removeItem(uint64_t itemID) 128{ 129 IDToHistoryItemMap::iterator it = idToHistoryItemMap().find(itemID); 130 if (it == idToHistoryItemMap().end()) 131 return; 132 historyItemToIDMap().remove(it->second); 133 idToHistoryItemMap().remove(it); 134} 135 136WebBackForwardListProxy::WebBackForwardListProxy(WebPage* page) 137 : m_page(page) 138{ 139 WebCore::notifyHistoryItemChanged = WK2NotifyHistoryItemChanged; 140} 141 142void WebBackForwardListProxy::addItem(PassRefPtr<HistoryItem> prpItem) 143{ 144 RefPtr<HistoryItem> item = prpItem; 145 146 ASSERT(!historyItemToIDMap().contains(item)); 147 148 if (!m_page) 149 return; 150 151 uint64_t itemID = generateHistoryItemID(); 152 153 ASSERT(!idToHistoryItemMap().contains(itemID)); 154 155 historyItemToIDMap().set(item, itemID); 156 idToHistoryItemMap().set(itemID, item); 157 158 updateBackForwardItem(itemID, item.get()); 159 m_page->send(Messages::WebPageProxy::BackForwardAddItem(itemID)); 160} 161 162void WebBackForwardListProxy::goToItem(HistoryItem* item) 163{ 164 if (!m_page) 165 return; 166 167 m_page->send(Messages::WebPageProxy::BackForwardGoToItem(historyItemToIDMap().get(item))); 168} 169 170HistoryItem* WebBackForwardListProxy::itemAtIndex(int itemIndex) 171{ 172 if (!m_page) 173 return 0; 174 175 uint64_t itemID = 0; 176 if (!WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::BackForwardItemAtIndex(itemIndex), Messages::WebPageProxy::BackForwardItemAtIndex::Reply(itemID), m_page->pageID())) 177 return 0; 178 179 if (!itemID) 180 return 0; 181 182 return idToHistoryItemMap().get(itemID).get(); 183} 184 185int WebBackForwardListProxy::backListCount() 186{ 187 if (!m_page) 188 return 0; 189 190 int backListCount = 0; 191 if (!WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::BackForwardBackListCount(), Messages::WebPageProxy::BackForwardBackListCount::Reply(backListCount), m_page->pageID())) 192 return 0; 193 194 return backListCount; 195} 196 197int WebBackForwardListProxy::forwardListCount() 198{ 199 if (!m_page) 200 return 0; 201 202 int forwardListCount = 0; 203 if (!WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::BackForwardForwardListCount(), Messages::WebPageProxy::BackForwardForwardListCount::Reply(forwardListCount), m_page->pageID())) 204 return 0; 205 206 return forwardListCount; 207} 208 209void WebBackForwardListProxy::close() 210{ 211 m_page = 0; 212} 213 214bool WebBackForwardListProxy::isActive() 215{ 216 // FIXME: Should check the the list is enabled and has non-zero capacity. 217 return true; 218} 219 220void WebBackForwardListProxy::clear() 221{ 222 m_page->send(Messages::WebPageProxy::BackForwardClear()); 223} 224 225#if ENABLE(WML) 226void WebBackForwardListProxy::clearWMLPageHistory() 227{ 228} 229#endif 230 231} // namespace WebKit 232