Move URL from WebCore to WTF
[WebKit-https.git] / Source / WebKitLegacy / win / WebHistoryItem.cpp
1 /*
2  * Copyright (C) 2006-2008, 2015 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. ``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 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 "WebKitDLL.h"
27 #include "WebHistoryItem.h"
28
29 #include "COMEnumVariant.h"
30 #include "MarshallingHelpers.h"
31 #include "WebKit.h"
32 #include <WebCore/BString.h>
33 #include <WebCore/COMPtr.h>
34 #include <WebCore/HistoryItem.h>
35 #include <wtf/RetainPtr.h>
36 #include <wtf/URL.h>
37 #include <wtf/text/CString.h>
38
39 using namespace WebCore;
40
41 // WebHistoryItem ----------------------------------------------------------------
42
43 static HashMap<HistoryItem*, WebHistoryItem*>& historyItemWrappers()
44 {
45     static HashMap<HistoryItem*, WebHistoryItem*> staticHistoryItemWrappers;
46     return staticHistoryItemWrappers;
47 }
48
49 WebHistoryItem::WebHistoryItem(RefPtr<HistoryItem>&& historyItem)
50     : m_historyItem(WTFMove(historyItem))
51 {
52     ASSERT(!historyItemWrappers().contains(m_historyItem.get()));
53     historyItemWrappers().set(m_historyItem.get(), this);
54
55     gClassCount++;
56     gClassNameCount().add("WebHistoryItem");
57 }
58
59 WebHistoryItem::~WebHistoryItem()
60 {
61     ASSERT(historyItemWrappers().contains(m_historyItem.get()));
62     historyItemWrappers().remove(m_historyItem.get());
63
64     gClassCount--;
65     gClassNameCount().remove("WebHistoryItem");
66 }
67
68 WebHistoryItem* WebHistoryItem::createInstance()
69 {
70     WebHistoryItem* instance = new WebHistoryItem(HistoryItem::create());
71     instance->AddRef();
72     return instance;
73 }
74
75 WebHistoryItem* WebHistoryItem::createInstance(RefPtr<HistoryItem>&& historyItem)
76 {
77     WebHistoryItem* instance;
78
79     instance = historyItemWrappers().get(historyItem.get());
80
81     if (!instance)
82         instance = new WebHistoryItem(WTFMove(historyItem));
83
84     instance->AddRef();
85     return instance;
86 }
87
88 // IWebHistoryItemPrivate -----------------------------------------------------
89
90 static CFStringRef urlKey = CFSTR("");
91 static CFStringRef titleKey = CFSTR("title");
92 static CFStringRef lastVisitWasFailureKey = CFSTR("lastVisitWasFailure");
93 static CFStringRef redirectURLsKey = CFSTR("redirectURLs");
94
95 HRESULT WebHistoryItem::initFromDictionaryRepresentation(_In_opt_ void* dictionary)
96 {
97     CFDictionaryRef dictionaryRef = (CFDictionaryRef) dictionary;
98
99     CFStringRef urlStringRef = (CFStringRef) CFDictionaryGetValue(dictionaryRef, urlKey);
100     if (urlStringRef && CFGetTypeID(urlStringRef) != CFStringGetTypeID())
101         return E_FAIL;
102
103     CFStringRef titleRef = (CFStringRef) CFDictionaryGetValue(dictionaryRef, titleKey);
104     if (titleRef && CFGetTypeID(titleRef) != CFStringGetTypeID())
105         return E_FAIL;
106
107     CFBooleanRef lastVisitWasFailureRef = static_cast<CFBooleanRef>(CFDictionaryGetValue(dictionaryRef, lastVisitWasFailureKey));
108     if (lastVisitWasFailureRef && CFGetTypeID(lastVisitWasFailureRef) != CFBooleanGetTypeID())
109         return E_FAIL;
110     bool lastVisitWasFailure = lastVisitWasFailureRef && CFBooleanGetValue(lastVisitWasFailureRef);
111
112     std::unique_ptr<Vector<String>> redirectURLsVector;
113     if (CFArrayRef redirectURLsRef = static_cast<CFArrayRef>(CFDictionaryGetValue(dictionaryRef, redirectURLsKey))) {
114         CFIndex size = CFArrayGetCount(redirectURLsRef);
115         redirectURLsVector = std::make_unique<Vector<String>>(size);
116         for (CFIndex i = 0; i < size; ++i)
117             (*redirectURLsVector)[i] = String(static_cast<CFStringRef>(CFArrayGetValueAtIndex(redirectURLsRef, i)));
118     }
119
120     historyItemWrappers().remove(m_historyItem.get());
121     m_historyItem = HistoryItem::create(urlStringRef, titleRef);
122     historyItemWrappers().set(m_historyItem.get(), this);
123
124     if (lastVisitWasFailure)
125         m_historyItem->setLastVisitWasFailure(true);
126
127     return S_OK;
128 }
129
130 HRESULT WebHistoryItem::dictionaryRepresentation(__deref_out_opt void** dictionary)
131 {
132     CFDictionaryRef* dictionaryRef = (CFDictionaryRef*) dictionary;
133
134     size_t keyCount = 0;
135     CFTypeRef keys[9];
136     CFTypeRef values[9];
137
138     if (!m_historyItem->urlString().isEmpty()) {
139         keys[keyCount] = urlKey;
140         values[keyCount] = m_historyItem->urlString().createCFString().leakRef();
141         ++keyCount;
142     }
143
144     if (!m_historyItem->title().isEmpty()) {
145         keys[keyCount] = titleKey;
146         values[keyCount] = m_historyItem->title().createCFString().leakRef();
147         ++keyCount;
148     }
149
150     if (m_historyItem->lastVisitWasFailure()) {
151         keys[keyCount] = lastVisitWasFailureKey;
152         values[keyCount] = CFRetain(kCFBooleanTrue);
153         ++keyCount;
154     }
155
156     *dictionaryRef = CFDictionaryCreate(0, keys, values, keyCount, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
157     
158     for (int i = 0; i < keyCount; ++i)
159         CFRelease(values[i]);
160
161     return S_OK;
162 }
163
164 HRESULT WebHistoryItem::hasURLString(_Out_ BOOL* hasURL)
165 {
166     if (!hasURL)
167         return E_POINTER;
168     *hasURL = m_historyItem->urlString().isEmpty() ? FALSE : TRUE;
169     return S_OK;
170 }
171
172 // FIXME: This function should be removed from the IWebHistoryItem interface.
173 HRESULT WebHistoryItem::visitCount(_Out_ int* count)
174 {
175     if (!count)
176         return E_POINTER;
177     return E_NOTIMPL;
178 }
179
180 // FIXME: This function should be removed from the IWebHistoryItem interface.
181 HRESULT WebHistoryItem::setVisitCount(int count)
182 {
183     return E_NOTIMPL;
184
185 }
186
187 // FIXME: This function should be removed from the IWebHistoryItem interface.
188 HRESULT WebHistoryItem::mergeAutoCompleteHints(_In_opt_ IWebHistoryItem*)
189 {
190     return E_NOTIMPL;
191 }
192
193 // FIXME: This function should be removed from the IWebHistoryItem interface.
194 HRESULT WebHistoryItem::setLastVisitedTimeInterval(DATE time)
195 {
196     return E_NOTIMPL;
197 }
198
199 HRESULT WebHistoryItem::setTitle(_In_ BSTR title)
200 {
201     m_historyItem->setTitle(String(title, SysStringLen(title)));
202
203     return S_OK;
204 }
205
206 HRESULT WebHistoryItem::RSSFeedReferrer(__deref_out_opt BSTR* url)
207 {
208     if (!url)
209         return E_POINTER;
210
211     BString str(m_historyItem->referrer());
212     *url = str.release();
213
214     return S_OK;
215 }
216
217 HRESULT WebHistoryItem::setRSSFeedReferrer(_In_ BSTR url)
218 {
219     m_historyItem->setReferrer(String(url, SysStringLen(url)));
220
221     return S_OK;
222 }
223
224 HRESULT WebHistoryItem::hasPageCache(_Out_ BOOL* hasCache)
225 {
226     // FIXME - TODO
227     ASSERT_NOT_REACHED();
228     if (!hasCache)
229         return E_POINTER;
230     *hasCache = FALSE;
231     return E_NOTIMPL;
232 }
233
234 HRESULT WebHistoryItem::setHasPageCache(BOOL /*hasCache*/)
235 {
236     // FIXME - TODO
237     ASSERT_NOT_REACHED();
238     return E_NOTIMPL;
239 }
240
241 HRESULT WebHistoryItem::target(__deref_out_opt BSTR* target)
242 {
243     if (!target) {
244         ASSERT_NOT_REACHED();
245         return E_POINTER;
246     }
247
248     *target = BString(m_historyItem->target()).release();
249     return S_OK;
250 }
251
252 HRESULT WebHistoryItem::isTargetItem(_Out_ BOOL* result)
253 {
254     if (!result) {
255         ASSERT_NOT_REACHED();
256         return E_POINTER;
257     }
258
259     *result = m_historyItem->isTargetItem() ? TRUE : FALSE;
260     return S_OK;
261 }
262
263 HRESULT WebHistoryItem::children(unsigned* outChildCount, SAFEARRAY** outChildren)
264 {
265     if (!outChildCount || !outChildren) {
266         ASSERT_NOT_REACHED();
267         return E_POINTER;
268     }
269
270     *outChildCount = 0;
271     *outChildren = 0;
272
273     const auto& coreChildren = m_historyItem->children();
274     if (coreChildren.isEmpty())
275         return S_OK;
276     size_t childCount = coreChildren.size();
277
278     SAFEARRAY* children = SafeArrayCreateVector(VT_UNKNOWN, 0, static_cast<ULONG>(childCount));
279     if (!children)
280         return E_OUTOFMEMORY;
281
282     for (unsigned i = 0; i < childCount; ++i) {
283         COMPtr<WebHistoryItem> item(AdoptCOM, WebHistoryItem::createInstance(const_cast<HistoryItem*>(coreChildren[i].ptr())));
284         if (!item) {
285             SafeArrayDestroy(children);
286             return E_OUTOFMEMORY;
287         }
288
289         LONG longI = i;
290         HRESULT hr = SafeArrayPutElement(children, &longI, item.get());
291         if (FAILED(hr)) {
292             SafeArrayDestroy(children);
293             return hr;
294         }
295     }
296
297     *outChildCount = static_cast<unsigned>(childCount);
298     *outChildren = children;
299     return S_OK;
300
301 }
302
303 HRESULT WebHistoryItem::lastVisitWasFailure(_Out_ BOOL* wasFailure)
304 {
305     if (!wasFailure) {
306         ASSERT_NOT_REACHED();
307         return E_POINTER;
308     }
309
310     *wasFailure = m_historyItem->lastVisitWasFailure();
311     return S_OK;
312 }
313
314 HRESULT WebHistoryItem::setLastVisitWasFailure(BOOL wasFailure)
315 {
316     m_historyItem->setLastVisitWasFailure(wasFailure);
317     return S_OK;
318 }
319
320 // FIXME: This function should be removed from the IWebHistoryItem interface.
321 HRESULT WebHistoryItem::lastVisitWasHTTPNonGet(_Out_ BOOL* HTTPNonGet)
322 {
323     if (!HTTPNonGet)
324         return E_POINTER;
325     *HTTPNonGet = FALSE;
326     return E_NOTIMPL;
327 }
328
329 // FIXME: This function should be removed from the IWebHistoryItem interface.
330 HRESULT WebHistoryItem::setLastVisitWasHTTPNonGet(BOOL)
331 {
332     return E_NOTIMPL;
333 }
334
335 // FIXME: This function should be removed from the IWebHistoryItem interface.
336 HRESULT WebHistoryItem::redirectURLs(_COM_Outptr_opt_ IEnumVARIANT** urls)
337 {
338     return E_NOTIMPL;
339 }
340
341 // FIXME: This function should be removed from the IWebHistoryItem interface.
342 HRESULT WebHistoryItem::visitedWithTitle(_In_ BSTR title, BOOL increaseVisitCount)
343 {
344     return E_NOTIMPL;
345 }
346
347 // FIXME: This function should be removed from the IWebHistoryItem interface.
348 HRESULT WebHistoryItem::getDailyVisitCounts(_Out_ int* number, __deref_out_opt int** counts)
349 {
350     if (!number || !counts)
351         return E_POINTER;
352     return E_NOTIMPL;
353 }
354
355 // FIXME: This function should be removed from the IWebHistoryItem interface.
356 HRESULT WebHistoryItem::getWeeklyVisitCounts(_Out_ int* number, __deref_out_opt int** counts)
357 {
358     if (!number || !counts)
359         return E_POINTER;
360     return E_NOTIMPL;
361 }
362
363 // FIXME: This function should be removed from the IWebHistoryItem interface.
364 HRESULT WebHistoryItem::recordInitialVisit()
365 {
366     // FIXME: This function should be removed from the IWebHistoryItem interface.
367     return E_NOTIMPL;
368 }
369
370 // IUnknown -------------------------------------------------------------------
371
372 HRESULT WebHistoryItem::QueryInterface(_In_ REFIID riid, _COM_Outptr_ void** ppvObject)
373 {
374     if (!ppvObject)
375         return E_POINTER;
376     *ppvObject = nullptr;
377     if (IsEqualGUID(riid, __uuidof(WebHistoryItem)))
378         *ppvObject = this;
379     else if (IsEqualGUID(riid, IID_IUnknown))
380         *ppvObject = static_cast<IWebHistoryItem*>(this);
381     else if (IsEqualGUID(riid, IID_IWebHistoryItem))
382         *ppvObject = static_cast<IWebHistoryItem*>(this);
383     else if (IsEqualGUID(riid, IID_IWebHistoryItemPrivate))
384         *ppvObject = static_cast<IWebHistoryItemPrivate*>(this);
385     else
386         return E_NOINTERFACE;
387
388     AddRef();
389     return S_OK;
390 }
391
392 ULONG WebHistoryItem::AddRef()
393 {
394     return ++m_refCount;
395 }
396
397 ULONG WebHistoryItem::Release()
398 {
399     ULONG newRef = --m_refCount;
400     if (!newRef)
401         delete(this);
402
403     return newRef;
404 }
405
406 // IWebHistoryItem -------------------------------------------------------------
407
408 HRESULT WebHistoryItem::initWithURLString(_In_ BSTR urlString, _In_ BSTR title, DATE lastVisited)
409 {
410     historyItemWrappers().remove(m_historyItem.get());
411     m_historyItem = HistoryItem::create(String(urlString, SysStringLen(urlString)), String(title, SysStringLen(title)));
412     historyItemWrappers().set(m_historyItem.get(), this);
413
414     return S_OK;
415 }
416
417 HRESULT WebHistoryItem::originalURLString(__deref_opt_out BSTR* url)
418 {
419     if (!url)
420         return E_POINTER;
421
422     BString str = m_historyItem->originalURLString();
423     *url = str.release();
424     return S_OK;
425 }
426
427 HRESULT WebHistoryItem::URLString(__deref_opt_out BSTR* url)
428 {
429     if (!url)
430         return E_POINTER;
431
432     BString str = m_historyItem->urlString();
433     *url = str.release();
434     return S_OK;
435 }
436
437 HRESULT WebHistoryItem::title(__deref_opt_out BSTR* pageTitle)
438 {
439     if (!pageTitle)
440         return E_POINTER;
441
442     BString str(m_historyItem->title());
443     *pageTitle = str.release();
444     return S_OK;
445 }
446
447 // FIXME: This function should be removed from the IWebHistoryItem interface.
448 HRESULT WebHistoryItem::lastVisitedTimeInterval(_Out_ DATE* lastVisited)
449 {
450     if (!lastVisited)
451         return E_POINTER;
452     return E_NOTIMPL;
453 }
454
455 HRESULT WebHistoryItem::setAlternateTitle(_In_ BSTR title)
456 {
457     m_alternateTitle = String(title, SysStringLen(title));
458     return S_OK;
459 }
460
461 HRESULT WebHistoryItem::alternateTitle(__deref_opt_out BSTR* title)
462 {
463     if (!title) {
464         ASSERT_NOT_REACHED();
465         return E_POINTER;
466     }
467
468     *title = BString(m_alternateTitle).release();
469     return S_OK;
470 }
471
472 HRESULT WebHistoryItem::icon(__deref_opt_out HBITMAP* hBitmap)
473 {
474     ASSERT_NOT_REACHED();
475     if (!hBitmap)
476         return E_POINTER;
477     return E_NOTIMPL;
478 }
479
480 // WebHistoryItem -------------------------------------------------------------
481
482 HistoryItem* WebHistoryItem::historyItem() const
483 {
484     return m_historyItem.get();
485 }