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