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