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 39 using namespace WebCore; 40 41 namespace WebKit { 42 43 static const unsigned DefaultCapacity = 100; 44 static 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 49 typedef HashMap<uint64_t, RefPtr<HistoryItem> > IDToHistoryItemMap; 50 typedef HashMap<RefPtr<HistoryItem>, uint64_t> HistoryItemToIDMap; 51 52 static IDToHistoryItemMap& idToHistoryItemMap() 53 { 54 DEFINE_STATIC_LOCAL(IDToHistoryItemMap, map, ()); 55 return map; 56 } 57 58 static HistoryItemToIDMap& historyItemToIDMap() 59 { 60 DEFINE_STATIC_LOCAL(HistoryItemToIDMap, map, ()); 61 return map; 62 } 63 64 static uint64_t uniqueHistoryItemID = 1; 65 66 static 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 75 void 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 86 static 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 95 void 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 107 static void WK2NotifyHistoryItemChanged(HistoryItem* item) 108 { 109 uint64_t itemID = historyItemToIDMap().get(item); 110 if (!itemID) 111 return; 112 113 updateBackForwardItem(itemID, item); 114 } 115 116 HistoryItem* WebBackForwardListProxy::itemForID(uint64_t itemID) 117 { 118 return idToHistoryItemMap().get(itemID).get(); 119 } 120 121 uint64_t WebBackForwardListProxy::idForItem(HistoryItem* item) 122 { 123 ASSERT(item); 124 return historyItemToIDMap().get(item); 125 } 126 127 void 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 136 WebBackForwardListProxy::WebBackForwardListProxy(WebPage* page) 137 : m_page(page) 138 { 139 WebCore::notifyHistoryItemChanged = WK2NotifyHistoryItemChanged; 140 } 141 142 void 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 162 void WebBackForwardListProxy::goToItem(HistoryItem* item) 163 { 164 if (!m_page) 165 return; 166 167 m_page->send(Messages::WebPageProxy::BackForwardGoToItem(historyItemToIDMap().get(item))); 168 } 169 170 HistoryItem* 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 185 int 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 197 int 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 209 void WebBackForwardListProxy::close() 210 { 211 m_page = 0; 212 } 213 214 bool WebBackForwardListProxy::isActive() 215 { 216 // FIXME: Should check the the list is enabled and has non-zero capacity. 217 return true; 218 } 219 220 void WebBackForwardListProxy::clear() 221 { 222 m_page->send(Messages::WebPageProxy::BackForwardClear()); 223 } 224 225 #if ENABLE(WML) 226 void WebBackForwardListProxy::clearWMLPageHistory() 227 { 228 } 229 #endif 230 231 } // namespace WebKit 232