Home | History | Annotate | Download | only in win
      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