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 "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 
     41 using namespace WebCore;
     42 
     43 // WebHistoryItem ----------------------------------------------------------------
     44 
     45 static HashMap<HistoryItem*, WebHistoryItem*>& historyItemWrappers()
     46 {
     47     static HashMap<HistoryItem*, WebHistoryItem*> staticHistoryItemWrappers;
     48     return staticHistoryItemWrappers;
     49 }
     50 
     51 WebHistoryItem::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 
     62 WebHistoryItem::~WebHistoryItem()
     63 {
     64     ASSERT(historyItemWrappers().contains(m_historyItem.get()));
     65     historyItemWrappers().remove(m_historyItem.get());
     66 
     67     gClassCount--;
     68     gClassNameCount.remove("WebHistoryItem");
     69 }
     70 
     71 WebHistoryItem* WebHistoryItem::createInstance()
     72 {
     73     WebHistoryItem* instance = new WebHistoryItem(HistoryItem::create());
     74     instance->AddRef();
     75     return instance;
     76 }
     77 
     78 WebHistoryItem* 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 
     93 static CFStringRef urlKey = CFSTR("");
     94 static CFStringRef lastVisitedDateKey = CFSTR("lastVisitedDate");
     95 static CFStringRef titleKey = CFSTR("title");
     96 static CFStringRef visitCountKey = CFSTR("visitCount");
     97 static CFStringRef lastVisitWasFailureKey = CFSTR("lastVisitWasFailure");
     98 static CFStringRef lastVisitWasHTTPNonGetKey = CFSTR("lastVisitWasHTTPNonGet");
     99 static CFStringRef redirectURLsKey = CFSTR("redirectURLs");
    100 static CFStringRef dailyVisitCountKey = CFSTR("D"); // short key to save space
    101 static CFStringRef weeklyVisitCountKey = CFSTR("W"); // short key to save space
    102 
    103 HRESULT 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 
    202 HRESULT 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 
    296 HRESULT STDMETHODCALLTYPE WebHistoryItem::hasURLString(BOOL *hasURL)
    297 {
    298     *hasURL = m_historyItem->urlString().isEmpty() ? FALSE : TRUE;
    299     return S_OK;
    300 }
    301 
    302 HRESULT STDMETHODCALLTYPE WebHistoryItem::visitCount(int *count)
    303 {
    304     *count = m_historyItem->visitCount();
    305     return S_OK;
    306 }
    307 
    308 HRESULT STDMETHODCALLTYPE WebHistoryItem::setVisitCount(int count)
    309 {
    310     m_historyItem->setVisitCount(count);
    311     return S_OK;
    312 }
    313 
    314 HRESULT 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 
    328 HRESULT STDMETHODCALLTYPE WebHistoryItem::setLastVisitedTimeInterval(DATE time)
    329 {
    330     m_historyItem->setLastVisitedTime(MarshallingHelpers::DATEToCFAbsoluteTime(time));
    331     return S_OK;
    332 }
    333 
    334 HRESULT STDMETHODCALLTYPE WebHistoryItem::setTitle(BSTR title)
    335 {
    336     m_historyItem->setTitle(String(title, SysStringLen(title)));
    337 
    338     return S_OK;
    339 }
    340 
    341 HRESULT STDMETHODCALLTYPE WebHistoryItem::RSSFeedReferrer(BSTR* url)
    342 {
    343     BString str(m_historyItem->referrer());
    344     *url = str.release();
    345 
    346     return S_OK;
    347 }
    348 
    349 HRESULT STDMETHODCALLTYPE WebHistoryItem::setRSSFeedReferrer(BSTR url)
    350 {
    351     m_historyItem->setReferrer(String(url, SysStringLen(url)));
    352 
    353     return S_OK;
    354 }
    355 
    356 HRESULT STDMETHODCALLTYPE WebHistoryItem::hasPageCache(BOOL* /*hasCache*/)
    357 {
    358     // FIXME - TODO
    359     ASSERT_NOT_REACHED();
    360     return E_NOTIMPL;
    361 }
    362 
    363 HRESULT STDMETHODCALLTYPE WebHistoryItem::setHasPageCache(BOOL /*hasCache*/)
    364 {
    365     // FIXME - TODO
    366     return E_NOTIMPL;
    367 }
    368 
    369 HRESULT 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 
    380 HRESULT 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 
    391 HRESULT 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 
    431 HRESULT 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 
    442 HRESULT STDMETHODCALLTYPE WebHistoryItem::setLastVisitWasFailure(BOOL wasFailure)
    443 {
    444     m_historyItem->setLastVisitWasFailure(wasFailure);
    445     return S_OK;
    446 }
    447 
    448 HRESULT 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 
    460 HRESULT STDMETHODCALLTYPE WebHistoryItem::setLastVisitWasHTTPNonGet(BOOL HTTPNonGet)
    461 {
    462     m_historyItem->setLastVisitWasHTTPNonGet(HTTPNonGet);
    463     return S_OK;
    464 }
    465 
    466 HRESULT 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 
    485 HRESULT STDMETHODCALLTYPE WebHistoryItem::visitedWithTitle(BSTR title, BOOL increaseVisitCount)
    486 {
    487     m_historyItem->visited(title, CFAbsoluteTimeGetCurrent(), increaseVisitCount ? IncreaseVisitCount : DoNotIncreaseVisitCount);
    488     return S_OK;
    489 }
    490 
    491 HRESULT 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 
    503 HRESULT 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 
    515 HRESULT STDMETHODCALLTYPE WebHistoryItem::recordInitialVisit()
    516 {
    517     m_historyItem->recordInitialVisit();
    518     return S_OK;
    519 }
    520 
    521 // IUnknown -------------------------------------------------------------------
    522 
    523 HRESULT 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 
    541 ULONG STDMETHODCALLTYPE WebHistoryItem::AddRef(void)
    542 {
    543     return ++m_refCount;
    544 }
    545 
    546 ULONG 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 
    557 HRESULT 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 
    569 HRESULT 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 
    580 HRESULT 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 
    591 HRESULT 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 
    602 HRESULT 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 
    612 HRESULT STDMETHODCALLTYPE WebHistoryItem::setAlternateTitle(
    613     /* [in] */ BSTR title)
    614 {
    615     m_alternateTitle = String(title, SysStringLen(title));
    616     return S_OK;
    617 }
    618 
    619 HRESULT 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 
    631 HRESULT STDMETHODCALLTYPE WebHistoryItem::icon(
    632     /* [out, retval] */ OLE_HANDLE* /*hBitmap*/)
    633 {
    634     ASSERT_NOT_REACHED();
    635     return E_NOTIMPL;
    636 }
    637 
    638 // WebHistoryItem -------------------------------------------------------------
    639 
    640 HistoryItem* WebHistoryItem::historyItem() const
    641 {
    642     return m_historyItem.get();
    643 }
    644