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