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 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 "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/KURL.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 lastVisitedDateKey = CFSTR("lastVisitedDate"); 95static CFStringRef titleKey = CFSTR("title"); 96static CFStringRef visitCountKey = CFSTR("visitCount"); 97static CFStringRef lastVisitWasFailureKey = CFSTR("lastVisitWasFailure"); 98static CFStringRef lastVisitWasHTTPNonGetKey = CFSTR("lastVisitWasHTTPNonGet"); 99static CFStringRef redirectURLsKey = CFSTR("redirectURLs"); 100static CFStringRef dailyVisitCountKey = CFSTR("D"); // short key to save space 101static CFStringRef weeklyVisitCountKey = CFSTR("W"); // short key to save space 102 103HRESULT STDMETHODCALLTYPE WebHistoryItem::initFromDictionaryRepresentation(void* dictionary) 104{ 105 CFDictionaryRef dictionaryRef = (CFDictionaryRef) dictionary; 106 107 CFStringRef urlStringRef = (CFStringRef) CFDictionaryGetValue(dictionaryRef, urlKey); 108 if (urlStringRef && CFGetTypeID(urlStringRef) != CFStringGetTypeID()) 109 return E_FAIL; 110 111 CFStringRef lastVisitedRef = (CFStringRef) CFDictionaryGetValue(dictionaryRef, lastVisitedDateKey); 112 if (!lastVisitedRef || CFGetTypeID(lastVisitedRef) != CFStringGetTypeID()) 113 return E_FAIL; 114 CFAbsoluteTime lastVisitedTime = CFStringGetDoubleValue(lastVisitedRef); 115 116 CFStringRef titleRef = (CFStringRef) CFDictionaryGetValue(dictionaryRef, titleKey); 117 if (titleRef && CFGetTypeID(titleRef) != CFStringGetTypeID()) 118 return E_FAIL; 119 120 CFNumberRef visitCountRef = (CFNumberRef) CFDictionaryGetValue(dictionaryRef, visitCountKey); 121 if (!visitCountRef || CFGetTypeID(visitCountRef) != CFNumberGetTypeID()) 122 return E_FAIL; 123 int visitedCount = 0; 124 if (!CFNumberGetValue(visitCountRef, kCFNumberIntType, &visitedCount)) 125 return E_FAIL; 126 127 // Can't trust data on disk, and we've had at least one report of this (<rdar://6572300>). 128 if (visitedCount < 0) { 129 LOG_ERROR("visit count for history item \"%s\" is negative (%d), will be reset to 1", String(urlStringRef).utf8().data(), visitedCount); 130 visitedCount = 1; 131 } 132 133 CFBooleanRef lastVisitWasFailureRef = static_cast<CFBooleanRef>(CFDictionaryGetValue(dictionaryRef, lastVisitWasFailureKey)); 134 if (lastVisitWasFailureRef && CFGetTypeID(lastVisitWasFailureRef) != CFBooleanGetTypeID()) 135 return E_FAIL; 136 bool lastVisitWasFailure = lastVisitWasFailureRef && CFBooleanGetValue(lastVisitWasFailureRef); 137 138 CFBooleanRef lastVisitWasHTTPNonGetRef = static_cast<CFBooleanRef>(CFDictionaryGetValue(dictionaryRef, lastVisitWasHTTPNonGetKey)); 139 if (lastVisitWasHTTPNonGetRef && CFGetTypeID(lastVisitWasHTTPNonGetRef) != CFBooleanGetTypeID()) 140 return E_FAIL; 141 bool lastVisitWasHTTPNonGet = lastVisitWasHTTPNonGetRef && CFBooleanGetValue(lastVisitWasHTTPNonGetRef); 142 143 OwnPtr<Vector<String> > redirectURLsVector; 144 if (CFArrayRef redirectURLsRef = static_cast<CFArrayRef>(CFDictionaryGetValue(dictionaryRef, redirectURLsKey))) { 145 CFIndex size = CFArrayGetCount(redirectURLsRef); 146 redirectURLsVector = PassOwnPtr<Vector<String> >(new Vector<String>(size)); 147 for (CFIndex i = 0; i < size; ++i) 148 (*redirectURLsVector)[i] = String(static_cast<CFStringRef>(CFArrayGetValueAtIndex(redirectURLsRef, i))); 149 } 150 151 CFArrayRef dailyCounts = static_cast<CFArrayRef>(CFDictionaryGetValue(dictionaryRef, dailyVisitCountKey)); 152 if (dailyCounts && CFGetTypeID(dailyCounts) != CFArrayGetTypeID()) 153 dailyCounts = 0; 154 CFArrayRef weeklyCounts = static_cast<CFArrayRef>(CFDictionaryGetValue(dictionaryRef, weeklyVisitCountKey)); 155 if (weeklyCounts && CFGetTypeID(weeklyCounts) != CFArrayGetTypeID()) 156 weeklyCounts = 0; 157 158 std::auto_ptr<Vector<int> > dailyVector, weeklyVector; 159 if (dailyCounts || weeklyCounts) { 160 CFIndex dailySize = dailyCounts ? CFArrayGetCount(dailyCounts) : 0; 161 CFIndex weeklySize = weeklyCounts ? CFArrayGetCount(weeklyCounts) : 0; 162 dailyVector.reset(new Vector<int>(dailySize)); 163 weeklyVector.reset(new Vector<int>(weeklySize)); 164 165 // Daily and weekly counts < 0 are errors in the data read from disk, so reset to 0. 166 for (CFIndex i = 0; i < dailySize; ++i) { 167 CFNumberRef dailyCount = static_cast<CFNumberRef>(CFArrayGetValueAtIndex(dailyCounts, i)); 168 if (CFGetTypeID(dailyCount) == CFNumberGetTypeID()) 169 CFNumberGetValue(dailyCount, kCFNumberIntType, &(*dailyVector)[i]); 170 if ((*dailyVector)[i] < 0) 171 (*dailyVector)[i] = 0; 172 } 173 for (CFIndex i = 0; i < weeklySize; ++i) { 174 CFNumberRef weeklyCount = static_cast<CFNumberRef>(CFArrayGetValueAtIndex(weeklyCounts, i)); 175 if (CFGetTypeID(weeklyCount) == CFNumberGetTypeID()) 176 CFNumberGetValue(weeklyCount, kCFNumberIntType, &(*weeklyVector)[i]); 177 if ((*weeklyVector)[i] < 0) 178 (*weeklyVector)[i] = 0; 179 } 180 } 181 182 historyItemWrappers().remove(m_historyItem.get()); 183 m_historyItem = HistoryItem::create(urlStringRef, titleRef, lastVisitedTime); 184 historyItemWrappers().set(m_historyItem.get(), this); 185 186 m_historyItem->setVisitCount(visitedCount); 187 if (lastVisitWasFailure) 188 m_historyItem->setLastVisitWasFailure(true); 189 190 if (lastVisitWasHTTPNonGet && (protocolIs(m_historyItem->urlString(), "http") || protocolIs(m_historyItem->urlString(), "https"))) 191 m_historyItem->setLastVisitWasHTTPNonGet(true); 192 193 if (redirectURLsVector) 194 m_historyItem->setRedirectURLs(redirectURLsVector.release()); 195 196 if (dailyVector.get()) 197 m_historyItem->adoptVisitCounts(*dailyVector, *weeklyVector); 198 199 return S_OK; 200} 201 202HRESULT STDMETHODCALLTYPE WebHistoryItem::dictionaryRepresentation(void** dictionary) 203{ 204 CFDictionaryRef* dictionaryRef = (CFDictionaryRef*) dictionary; 205 static CFStringRef lastVisitedFormat = CFSTR("%.1lf"); 206 CFStringRef lastVisitedStringRef = 207 CFStringCreateWithFormat(0, 0, lastVisitedFormat, m_historyItem->lastVisitedTime()); 208 if (!lastVisitedStringRef) 209 return E_FAIL; 210 211 int keyCount = 0; 212 CFTypeRef keys[9]; 213 CFTypeRef values[9]; 214 215 if (!m_historyItem->urlString().isEmpty()) { 216 keys[keyCount] = urlKey; 217 values[keyCount++] = m_historyItem->urlString().createCFString(); 218 } 219 220 keys[keyCount] = lastVisitedDateKey; 221 values[keyCount++] = lastVisitedStringRef; 222 223 if (!m_historyItem->title().isEmpty()) { 224 keys[keyCount] = titleKey; 225 values[keyCount++] = m_historyItem->title().createCFString(); 226 } 227 228 keys[keyCount] = visitCountKey; 229 int visitCount = m_historyItem->visitCount(); 230 values[keyCount++] = CFNumberCreate(0, kCFNumberIntType, &visitCount); 231 232 if (m_historyItem->lastVisitWasFailure()) { 233 keys[keyCount] = lastVisitWasFailureKey; 234 values[keyCount++] = CFRetain(kCFBooleanTrue); 235 } 236 237 if (m_historyItem->lastVisitWasHTTPNonGet()) { 238 ASSERT(m_historyItem->urlString().startsWith("http:", false) || m_historyItem->urlString().startsWith("https:", false)); 239 keys[keyCount] = lastVisitWasHTTPNonGetKey; 240 values[keyCount++] = CFRetain(kCFBooleanTrue); 241 } 242 243 if (Vector<String>* redirectURLs = m_historyItem->redirectURLs()) { 244 size_t size = redirectURLs->size(); 245 ASSERT(size); 246 CFStringRef* items = new CFStringRef[size]; 247 for (size_t i = 0; i < size; ++i) 248 items[i] = redirectURLs->at(i).createCFString(); 249 CFArrayRef result = CFArrayCreate(0, (const void**)items, size, &kCFTypeArrayCallBacks); 250 for (size_t i = 0; i < size; ++i) 251 CFRelease(items[i]); 252 delete[] items; 253 254 keys[keyCount] = redirectURLsKey; 255 values[keyCount++] = result; 256 } 257 258 const Vector<int>& dailyVisitCount(m_historyItem->dailyVisitCounts()); 259 if (size_t size = dailyVisitCount.size()) { 260 Vector<CFNumberRef, 13> numbers(size); 261 for (size_t i = 0; i < size; ++i) 262 numbers[i] = CFNumberCreate(0, kCFNumberIntType, &dailyVisitCount[i]); 263 264 CFArrayRef result = CFArrayCreate(0, (const void**)numbers.data(), size, &kCFTypeArrayCallBacks); 265 266 for (size_t i = 0; i < size; ++i) 267 CFRelease(numbers[i]); 268 269 keys[keyCount] = dailyVisitCountKey; 270 values[keyCount++] = result; 271 } 272 273 const Vector<int>& weeklyVisitCount(m_historyItem->weeklyVisitCounts()); 274 if (size_t size = weeklyVisitCount.size()) { 275 Vector<CFNumberRef, 5> numbers(size); 276 for (size_t i = 0; i < size; ++i) 277 numbers[i] = CFNumberCreate(0, kCFNumberIntType, &weeklyVisitCount[i]); 278 279 CFArrayRef result = CFArrayCreate(0, (const void**)numbers.data(), size, &kCFTypeArrayCallBacks); 280 281 for (size_t i = 0; i < size; ++i) 282 CFRelease(numbers[i]); 283 284 keys[keyCount] = weeklyVisitCountKey; 285 values[keyCount++] = result; 286 } 287 288 *dictionaryRef = CFDictionaryCreate(0, keys, values, keyCount, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 289 290 for (int i = 0; i < keyCount; ++i) 291 CFRelease(values[i]); 292 293 return S_OK; 294} 295 296HRESULT STDMETHODCALLTYPE WebHistoryItem::hasURLString(BOOL *hasURL) 297{ 298 *hasURL = m_historyItem->urlString().isEmpty() ? FALSE : TRUE; 299 return S_OK; 300} 301 302HRESULT STDMETHODCALLTYPE WebHistoryItem::visitCount(int *count) 303{ 304 *count = m_historyItem->visitCount(); 305 return S_OK; 306} 307 308HRESULT STDMETHODCALLTYPE WebHistoryItem::setVisitCount(int count) 309{ 310 m_historyItem->setVisitCount(count); 311 return S_OK; 312} 313 314HRESULT STDMETHODCALLTYPE WebHistoryItem::mergeAutoCompleteHints(IWebHistoryItem* otherItem) 315{ 316 if (!otherItem) 317 return E_FAIL; 318 319 COMPtr<WebHistoryItem> otherWebHistoryItem(Query, otherItem); 320 if (!otherWebHistoryItem) 321 return E_FAIL; 322 323 m_historyItem->mergeAutoCompleteHints(otherWebHistoryItem->historyItem()); 324 325 return S_OK; 326} 327 328HRESULT STDMETHODCALLTYPE WebHistoryItem::setLastVisitedTimeInterval(DATE time) 329{ 330 m_historyItem->setLastVisitedTime(MarshallingHelpers::DATEToCFAbsoluteTime(time)); 331 return S_OK; 332} 333 334HRESULT STDMETHODCALLTYPE WebHistoryItem::setTitle(BSTR title) 335{ 336 m_historyItem->setTitle(String(title, SysStringLen(title))); 337 338 return S_OK; 339} 340 341HRESULT STDMETHODCALLTYPE WebHistoryItem::RSSFeedReferrer(BSTR* url) 342{ 343 BString str(m_historyItem->referrer()); 344 *url = str.release(); 345 346 return S_OK; 347} 348 349HRESULT STDMETHODCALLTYPE WebHistoryItem::setRSSFeedReferrer(BSTR url) 350{ 351 m_historyItem->setReferrer(String(url, SysStringLen(url))); 352 353 return S_OK; 354} 355 356HRESULT STDMETHODCALLTYPE WebHistoryItem::hasPageCache(BOOL* /*hasCache*/) 357{ 358 // FIXME - TODO 359 ASSERT_NOT_REACHED(); 360 return E_NOTIMPL; 361} 362 363HRESULT STDMETHODCALLTYPE WebHistoryItem::setHasPageCache(BOOL /*hasCache*/) 364{ 365 // FIXME - TODO 366 return E_NOTIMPL; 367} 368 369HRESULT STDMETHODCALLTYPE WebHistoryItem::target(BSTR* target) 370{ 371 if (!target) { 372 ASSERT_NOT_REACHED(); 373 return E_POINTER; 374 } 375 376 *target = BString(m_historyItem->target()).release(); 377 return S_OK; 378} 379 380HRESULT STDMETHODCALLTYPE WebHistoryItem::isTargetItem(BOOL* result) 381{ 382 if (!result) { 383 ASSERT_NOT_REACHED(); 384 return E_POINTER; 385 } 386 387 *result = m_historyItem->isTargetItem() ? TRUE : FALSE; 388 return S_OK; 389} 390 391HRESULT STDMETHODCALLTYPE WebHistoryItem::children(unsigned* outChildCount, SAFEARRAY** outChildren) 392{ 393 if (!outChildCount || !outChildren) { 394 ASSERT_NOT_REACHED(); 395 return E_POINTER; 396 } 397 398 *outChildCount = 0; 399 *outChildren = 0; 400 401 const HistoryItemVector& coreChildren = m_historyItem->children(); 402 if (coreChildren.isEmpty()) 403 return S_OK; 404 size_t childCount = coreChildren.size(); 405 406 SAFEARRAY* children = SafeArrayCreateVector(VT_UNKNOWN, 0, static_cast<ULONG>(childCount)); 407 if (!children) 408 return E_OUTOFMEMORY; 409 410 for (unsigned i = 0; i < childCount; ++i) { 411 COMPtr<WebHistoryItem> item(AdoptCOM, WebHistoryItem::createInstance(coreChildren[i])); 412 if (!item) { 413 SafeArrayDestroy(children); 414 return E_OUTOFMEMORY; 415 } 416 417 LONG longI = i; 418 HRESULT hr = SafeArrayPutElement(children, &longI, item.get()); 419 if (FAILED(hr)) { 420 SafeArrayDestroy(children); 421 return hr; 422 } 423 } 424 425 *outChildCount = static_cast<unsigned>(childCount); 426 *outChildren = children; 427 return S_OK; 428 429} 430 431HRESULT STDMETHODCALLTYPE WebHistoryItem::lastVisitWasFailure(BOOL* wasFailure) 432{ 433 if (!wasFailure) { 434 ASSERT_NOT_REACHED(); 435 return E_POINTER; 436 } 437 438 *wasFailure = m_historyItem->lastVisitWasFailure(); 439 return S_OK; 440} 441 442HRESULT STDMETHODCALLTYPE WebHistoryItem::setLastVisitWasFailure(BOOL wasFailure) 443{ 444 m_historyItem->setLastVisitWasFailure(wasFailure); 445 return S_OK; 446} 447 448HRESULT STDMETHODCALLTYPE WebHistoryItem::lastVisitWasHTTPNonGet(BOOL* HTTPNonGet) 449{ 450 if (!HTTPNonGet) { 451 ASSERT_NOT_REACHED(); 452 return E_POINTER; 453 } 454 455 *HTTPNonGet = m_historyItem->lastVisitWasHTTPNonGet(); 456 457 return S_OK; 458} 459 460HRESULT STDMETHODCALLTYPE WebHistoryItem::setLastVisitWasHTTPNonGet(BOOL HTTPNonGet) 461{ 462 m_historyItem->setLastVisitWasHTTPNonGet(HTTPNonGet); 463 return S_OK; 464} 465 466HRESULT STDMETHODCALLTYPE WebHistoryItem::redirectURLs(IEnumVARIANT** urls) 467{ 468 if (!urls) { 469 ASSERT_NOT_REACHED(); 470 return E_POINTER; 471 } 472 473 Vector<String>* urlVector = m_historyItem->redirectURLs(); 474 if (!urlVector) { 475 *urls = 0; 476 return S_OK; 477 } 478 479 COMPtr<COMEnumVariant<Vector<String> > > enumVariant(AdoptCOM, COMEnumVariant<Vector<String> >::createInstance(*urlVector)); 480 *urls = enumVariant.releaseRef(); 481 482 return S_OK; 483} 484 485HRESULT STDMETHODCALLTYPE WebHistoryItem::visitedWithTitle(BSTR title, BOOL increaseVisitCount) 486{ 487 m_historyItem->visited(title, CFAbsoluteTimeGetCurrent(), increaseVisitCount ? IncreaseVisitCount : DoNotIncreaseVisitCount); 488 return S_OK; 489} 490 491HRESULT STDMETHODCALLTYPE WebHistoryItem::getDailyVisitCounts(int* number, int** counts) 492{ 493 if (!number || !counts) { 494 ASSERT_NOT_REACHED(); 495 return E_POINTER; 496 } 497 498 *counts = const_cast<int*>(m_historyItem->dailyVisitCounts().data()); 499 *number = m_historyItem->dailyVisitCounts().size(); 500 return S_OK; 501} 502 503HRESULT STDMETHODCALLTYPE WebHistoryItem::getWeeklyVisitCounts(int* number, int** counts) 504{ 505 if (!number || !counts) { 506 ASSERT_NOT_REACHED(); 507 return E_POINTER; 508 } 509 510 *counts = const_cast<int*>(m_historyItem->weeklyVisitCounts().data()); 511 *number = m_historyItem->weeklyVisitCounts().size(); 512 return S_OK; 513} 514 515HRESULT STDMETHODCALLTYPE WebHistoryItem::recordInitialVisit() 516{ 517 m_historyItem->recordInitialVisit(); 518 return S_OK; 519} 520 521// IUnknown ------------------------------------------------------------------- 522 523HRESULT STDMETHODCALLTYPE WebHistoryItem::QueryInterface(REFIID riid, void** ppvObject) 524{ 525 *ppvObject = 0; 526 if (IsEqualGUID(riid, __uuidof(WebHistoryItem))) 527 *ppvObject = this; 528 else if (IsEqualGUID(riid, IID_IUnknown)) 529 *ppvObject = static_cast<IWebHistoryItem*>(this); 530 else if (IsEqualGUID(riid, IID_IWebHistoryItem)) 531 *ppvObject = static_cast<IWebHistoryItem*>(this); 532 else if (IsEqualGUID(riid, IID_IWebHistoryItemPrivate)) 533 *ppvObject = static_cast<IWebHistoryItemPrivate*>(this); 534 else 535 return E_NOINTERFACE; 536 537 AddRef(); 538 return S_OK; 539} 540 541ULONG STDMETHODCALLTYPE WebHistoryItem::AddRef(void) 542{ 543 return ++m_refCount; 544} 545 546ULONG STDMETHODCALLTYPE WebHistoryItem::Release(void) 547{ 548 ULONG newRef = --m_refCount; 549 if (!newRef) 550 delete(this); 551 552 return newRef; 553} 554 555// IWebHistoryItem ------------------------------------------------------------- 556 557HRESULT STDMETHODCALLTYPE WebHistoryItem::initWithURLString( 558 /* [in] */ BSTR urlString, 559 /* [in] */ BSTR title, 560 /* [in] */ DATE lastVisited) 561{ 562 historyItemWrappers().remove(m_historyItem.get()); 563 m_historyItem = HistoryItem::create(String(urlString, SysStringLen(urlString)), String(title, SysStringLen(title)), MarshallingHelpers::DATEToCFAbsoluteTime(lastVisited)); 564 historyItemWrappers().set(m_historyItem.get(), this); 565 566 return S_OK; 567} 568 569HRESULT STDMETHODCALLTYPE WebHistoryItem::originalURLString( 570 /* [retval][out] */ BSTR* url) 571{ 572 if (!url) 573 return E_POINTER; 574 575 BString str = m_historyItem->originalURLString(); 576 *url = str.release(); 577 return S_OK; 578} 579 580HRESULT STDMETHODCALLTYPE WebHistoryItem::URLString( 581 /* [retval][out] */ BSTR* url) 582{ 583 if (!url) 584 return E_POINTER; 585 586 BString str = m_historyItem->urlString(); 587 *url = str.release(); 588 return S_OK; 589} 590 591HRESULT STDMETHODCALLTYPE WebHistoryItem::title( 592 /* [retval][out] */ BSTR* pageTitle) 593{ 594 if (!pageTitle) 595 return E_POINTER; 596 597 BString str(m_historyItem->title()); 598 *pageTitle = str.release(); 599 return S_OK; 600} 601 602HRESULT STDMETHODCALLTYPE WebHistoryItem::lastVisitedTimeInterval( 603 /* [retval][out] */ DATE* lastVisited) 604{ 605 if (!lastVisited) 606 return E_POINTER; 607 608 *lastVisited = MarshallingHelpers::CFAbsoluteTimeToDATE(m_historyItem->lastVisitedTime()); 609 return S_OK; 610} 611 612HRESULT STDMETHODCALLTYPE WebHistoryItem::setAlternateTitle( 613 /* [in] */ BSTR title) 614{ 615 m_alternateTitle = String(title, SysStringLen(title)); 616 return S_OK; 617} 618 619HRESULT STDMETHODCALLTYPE WebHistoryItem::alternateTitle( 620 /* [retval][out] */ BSTR* title) 621{ 622 if (!title) { 623 ASSERT_NOT_REACHED(); 624 return E_POINTER; 625 } 626 627 *title = BString(m_alternateTitle).release(); 628 return S_OK; 629} 630 631HRESULT STDMETHODCALLTYPE WebHistoryItem::icon( 632 /* [out, retval] */ OLE_HANDLE* /*hBitmap*/) 633{ 634 ASSERT_NOT_REACHED(); 635 return E_NOTIMPL; 636} 637 638// WebHistoryItem ------------------------------------------------------------- 639 640HistoryItem* WebHistoryItem::historyItem() const 641{ 642 return m_historyItem.get(); 643} 644