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