1/*
2 * Copyright (C) 2006, 2007 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 COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WebKitDLL.h"
28#include "WebBackForwardList.h"
29
30#include "WebFrame.h"
31#include "WebKit.h"
32#include "WebPreferences.h"
33
34#include <WebCore/BackForwardListImpl.h>
35#include <WebCore/COMPtr.h>
36#include <WebCore/HistoryItem.h>
37
38using std::min;
39using namespace WebCore;
40
41// WebBackForwardList ----------------------------------------------------------------
42
43// FIXME: Instead of this we could just create a class derived from BackForwardListImpl
44// with a pointer to a WebBackForwardList in it.
45static HashMap<BackForwardListImpl*, WebBackForwardList*>& backForwardListWrappers()
46{
47    static HashMap<BackForwardListImpl*, WebBackForwardList*> staticBackForwardListWrappers;
48    return staticBackForwardListWrappers;
49}
50
51WebBackForwardList::WebBackForwardList(PassRefPtr<BackForwardListImpl> backForwardList)
52    : m_refCount(0)
53    , m_backForwardList(backForwardList)
54{
55    ASSERT(!backForwardListWrappers().contains(m_backForwardList.get()));
56    backForwardListWrappers().set(m_backForwardList.get(), this);
57
58    gClassCount++;
59    gClassNameCount.add("WebBackForwardList");
60}
61
62WebBackForwardList::~WebBackForwardList()
63{
64    ASSERT(m_backForwardList->closed());
65
66    ASSERT(backForwardListWrappers().contains(m_backForwardList.get()));
67    backForwardListWrappers().remove(m_backForwardList.get());
68
69    gClassCount--;
70    gClassNameCount.remove("WebBackForwardList");
71}
72
73WebBackForwardList* WebBackForwardList::createInstance(PassRefPtr<BackForwardListImpl> backForwardList)
74{
75    WebBackForwardList* instance;
76
77    instance = backForwardListWrappers().get(backForwardList.get());
78
79    if (!instance)
80        instance = new WebBackForwardList(backForwardList);
81
82    instance->AddRef();
83    return instance;
84}
85
86// IUnknown -------------------------------------------------------------------
87
88HRESULT STDMETHODCALLTYPE WebBackForwardList::QueryInterface(REFIID riid, void** ppvObject)
89{
90    *ppvObject = 0;
91    if (IsEqualGUID(riid, IID_IUnknown))
92        *ppvObject = static_cast<IWebBackForwardList*>(this);
93    else if (IsEqualGUID(riid, IID_IWebBackForwardList))
94        *ppvObject = static_cast<IWebBackForwardList*>(this);
95    else if (IsEqualGUID(riid, IID_IWebBackForwardListPrivate))
96        *ppvObject = static_cast<IWebBackForwardListPrivate*>(this);
97    else
98        return E_NOINTERFACE;
99
100    AddRef();
101    return S_OK;
102}
103
104ULONG STDMETHODCALLTYPE WebBackForwardList::AddRef(void)
105{
106    return ++m_refCount;
107}
108
109ULONG STDMETHODCALLTYPE WebBackForwardList::Release(void)
110{
111    ULONG newRef = --m_refCount;
112    if (!newRef)
113        delete(this);
114
115    return newRef;
116}
117
118// IWebBackForwardList ---------------------------------------------------------
119
120HRESULT STDMETHODCALLTYPE WebBackForwardList::addItem(
121    /* [in] */ IWebHistoryItem* item)
122{
123    COMPtr<WebHistoryItem> webHistoryItem;
124
125    if (!item || FAILED(item->QueryInterface(&webHistoryItem)))
126        return E_FAIL;
127
128    m_backForwardList->addItem(webHistoryItem->historyItem());
129    return S_OK;
130}
131
132HRESULT STDMETHODCALLTYPE WebBackForwardList::goBack( void)
133{
134    m_backForwardList->goBack();
135    return S_OK;
136}
137
138HRESULT STDMETHODCALLTYPE WebBackForwardList::goForward( void)
139{
140    m_backForwardList->goForward();
141    return S_OK;
142}
143
144HRESULT STDMETHODCALLTYPE WebBackForwardList::goToItem(
145    /* [in] */ IWebHistoryItem* item)
146{
147    COMPtr<WebHistoryItem> webHistoryItem;
148
149    if (!item || FAILED(item->QueryInterface(&webHistoryItem)))
150        return E_FAIL;
151
152    m_backForwardList->goToItem(webHistoryItem->historyItem());
153    return S_OK;
154}
155
156HRESULT STDMETHODCALLTYPE WebBackForwardList::backItem(
157    /* [retval][out] */ IWebHistoryItem** item)
158{
159    if (!item)
160        return E_POINTER;
161
162    HistoryItem* historyItem = m_backForwardList->backItem();
163
164    if (!historyItem)
165        return E_FAIL;
166
167    *item = WebHistoryItem::createInstance(historyItem);
168    return S_OK;
169}
170
171HRESULT STDMETHODCALLTYPE WebBackForwardList::currentItem(
172    /* [retval][out] */ IWebHistoryItem** item)
173{
174    if (!item)
175        return E_POINTER;
176
177    HistoryItem* historyItem = m_backForwardList->currentItem();
178
179    if (!historyItem)
180        return E_FAIL;
181
182    *item = WebHistoryItem::createInstance(historyItem);
183    return S_OK;
184}
185
186HRESULT STDMETHODCALLTYPE WebBackForwardList::forwardItem(
187    /* [retval][out] */ IWebHistoryItem** item)
188{
189    if (!item)
190        return E_POINTER;
191
192    HistoryItem* historyItem = m_backForwardList->forwardItem();
193
194    if (!historyItem)
195        return E_FAIL;
196
197    *item = WebHistoryItem::createInstance(historyItem);
198    return S_OK;
199}
200
201HRESULT STDMETHODCALLTYPE WebBackForwardList::backListWithLimit(
202    /* [in] */ int limit,
203    /* [out] */ int* listCount,
204    /* [retval][out] */ IWebHistoryItem** list)
205{
206    HistoryItemVector historyItemVector;
207    m_backForwardList->backListWithLimit(limit, historyItemVector);
208
209    *listCount = static_cast<int>(historyItemVector.size());
210
211    if (list)
212        for (unsigned i = 0; i < historyItemVector.size(); i++)
213            list[i] = WebHistoryItem::createInstance(historyItemVector[i].get());
214
215    return S_OK;
216}
217
218HRESULT STDMETHODCALLTYPE WebBackForwardList::forwardListWithLimit(
219    /* [in] */ int limit,
220    /* [out] */ int* listCount,
221    /* [retval][out] */ IWebHistoryItem** list)
222{
223    HistoryItemVector historyItemVector;
224    m_backForwardList->forwardListWithLimit(limit, historyItemVector);
225
226    *listCount = static_cast<int>(historyItemVector.size());
227
228    if (list)
229        for (unsigned i = 0; i < historyItemVector.size(); i++)
230            list[i] = WebHistoryItem::createInstance(historyItemVector[i].get());
231
232    return S_OK;
233}
234
235HRESULT STDMETHODCALLTYPE WebBackForwardList::capacity(
236    /* [retval][out] */ int* result)
237{
238    *result = (int)m_backForwardList->capacity();
239    return S_OK;
240}
241
242HRESULT STDMETHODCALLTYPE WebBackForwardList::setCapacity(
243    /* [in] */ int size)
244{
245    if (size < 0)
246        return E_FAIL;
247
248    m_backForwardList->setCapacity(size);
249    return S_OK;
250}
251
252HRESULT STDMETHODCALLTYPE WebBackForwardList::backListCount(
253    /* [retval][out] */ int* count)
254{
255    *count = m_backForwardList->backListCount();
256    return S_OK;
257}
258
259HRESULT STDMETHODCALLTYPE WebBackForwardList::forwardListCount(
260    /* [retval][out] */ int* count)
261{
262    *count = m_backForwardList->forwardListCount();
263    return S_OK;
264}
265
266HRESULT STDMETHODCALLTYPE WebBackForwardList::containsItem(
267    /* [in] */ IWebHistoryItem* item,
268    /* [retval][out] */ BOOL* result)
269{
270    COMPtr<WebHistoryItem> webHistoryItem;
271
272    if (!item || FAILED(item->QueryInterface(&webHistoryItem)))
273        return E_FAIL;
274
275    *result = m_backForwardList->containsItem(webHistoryItem->historyItem());
276    return S_OK;
277}
278
279HRESULT STDMETHODCALLTYPE WebBackForwardList::itemAtIndex(
280    /* [in] */ int index,
281    /* [retval][out] */ IWebHistoryItem** item)
282{
283    if (!item)
284        return E_POINTER;
285
286    HistoryItem* historyItem = m_backForwardList->itemAtIndex(index);
287
288    if (!historyItem)
289        return E_FAIL;
290
291    *item = WebHistoryItem::createInstance(historyItem);
292    return S_OK;
293}
294
295// IWebBackForwardListPrivate --------------------------------------------------------
296
297HRESULT STDMETHODCALLTYPE WebBackForwardList::removeItem(
298    /* [in] */ IWebHistoryItem* item)
299{
300    COMPtr<WebHistoryItem> webHistoryItem;
301
302    if (!item || FAILED(item->QueryInterface(&webHistoryItem)))
303        return E_FAIL;
304
305    m_backForwardList->removeItem(webHistoryItem->historyItem());
306    return S_OK;
307}
308