• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
historyItemWrappers()45 static HashMap<HistoryItem*, WebHistoryItem*>& historyItemWrappers()
46 {
47     static HashMap<HistoryItem*, WebHistoryItem*> staticHistoryItemWrappers;
48     return staticHistoryItemWrappers;
49 }
50 
WebHistoryItem(PassRefPtr<HistoryItem> historyItem)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 
~WebHistoryItem()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 
createInstance()71 WebHistoryItem* WebHistoryItem::createInstance()
72 {
73     WebHistoryItem* instance = new WebHistoryItem(HistoryItem::create());
74     instance->AddRef();
75     return instance;
76 }
77 
createInstance(PassRefPtr<HistoryItem> historyItem)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 
initFromDictionaryRepresentation(void * dictionary)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 
dictionaryRepresentation(void ** dictionary)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 
hasURLString(BOOL * hasURL)296 HRESULT STDMETHODCALLTYPE WebHistoryItem::hasURLString(BOOL *hasURL)
297 {
298     *hasURL = m_historyItem->urlString().isEmpty() ? FALSE : TRUE;
299     return S_OK;
300 }
301 
visitCount(int * count)302 HRESULT STDMETHODCALLTYPE WebHistoryItem::visitCount(int *count)
303 {
304     *count = m_historyItem->visitCount();
305     return S_OK;
306 }
307 
setVisitCount(int count)308 HRESULT STDMETHODCALLTYPE WebHistoryItem::setVisitCount(int count)
309 {
310     m_historyItem->setVisitCount(count);
311     return S_OK;
312 }
313 
mergeAutoCompleteHints(IWebHistoryItem * otherItem)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 
setLastVisitedTimeInterval(DATE time)328 HRESULT STDMETHODCALLTYPE WebHistoryItem::setLastVisitedTimeInterval(DATE time)
329 {
330     m_historyItem->setLastVisitedTime(MarshallingHelpers::DATEToCFAbsoluteTime(time));
331     return S_OK;
332 }
333 
setTitle(BSTR title)334 HRESULT STDMETHODCALLTYPE WebHistoryItem::setTitle(BSTR title)
335 {
336     m_historyItem->setTitle(String(title, SysStringLen(title)));
337 
338     return S_OK;
339 }
340 
RSSFeedReferrer(BSTR * url)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 
setRSSFeedReferrer(BSTR url)349 HRESULT STDMETHODCALLTYPE WebHistoryItem::setRSSFeedReferrer(BSTR url)
350 {
351     m_historyItem->setReferrer(String(url, SysStringLen(url)));
352 
353     return S_OK;
354 }
355 
hasPageCache(BOOL *)356 HRESULT STDMETHODCALLTYPE WebHistoryItem::hasPageCache(BOOL* /*hasCache*/)
357 {
358     // FIXME - TODO
359     ASSERT_NOT_REACHED();
360     return E_NOTIMPL;
361 }
362 
setHasPageCache(BOOL)363 HRESULT STDMETHODCALLTYPE WebHistoryItem::setHasPageCache(BOOL /*hasCache*/)
364 {
365     // FIXME - TODO
366     return E_NOTIMPL;
367 }
368 
target(BSTR * target)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 
isTargetItem(BOOL * result)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 
children(unsigned * outChildCount,SAFEARRAY ** outChildren)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 
lastVisitWasFailure(BOOL * wasFailure)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 
setLastVisitWasFailure(BOOL wasFailure)442 HRESULT STDMETHODCALLTYPE WebHistoryItem::setLastVisitWasFailure(BOOL wasFailure)
443 {
444     m_historyItem->setLastVisitWasFailure(wasFailure);
445     return S_OK;
446 }
447 
lastVisitWasHTTPNonGet(BOOL * HTTPNonGet)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 
setLastVisitWasHTTPNonGet(BOOL HTTPNonGet)460 HRESULT STDMETHODCALLTYPE WebHistoryItem::setLastVisitWasHTTPNonGet(BOOL HTTPNonGet)
461 {
462     m_historyItem->setLastVisitWasHTTPNonGet(HTTPNonGet);
463     return S_OK;
464 }
465 
redirectURLs(IEnumVARIANT ** urls)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 
visitedWithTitle(BSTR title,BOOL increaseVisitCount)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 
getDailyVisitCounts(int * number,int ** counts)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 
getWeeklyVisitCounts(int * number,int ** counts)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 
recordInitialVisit()515 HRESULT STDMETHODCALLTYPE WebHistoryItem::recordInitialVisit()
516 {
517     m_historyItem->recordInitialVisit();
518     return S_OK;
519 }
520 
521 // IUnknown -------------------------------------------------------------------
522 
QueryInterface(REFIID riid,void ** ppvObject)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 
AddRef(void)541 ULONG STDMETHODCALLTYPE WebHistoryItem::AddRef(void)
542 {
543     return ++m_refCount;
544 }
545 
Release(void)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 
initWithURLString(BSTR urlString,BSTR title,DATE lastVisited)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 
originalURLString(BSTR * url)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 
URLString(BSTR * url)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 
title(BSTR * pageTitle)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 
lastVisitedTimeInterval(DATE * lastVisited)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 
setAlternateTitle(BSTR title)612 HRESULT STDMETHODCALLTYPE WebHistoryItem::setAlternateTitle(
613     /* [in] */ BSTR title)
614 {
615     m_alternateTitle = String(title, SysStringLen(title));
616     return S_OK;
617 }
618 
alternateTitle(BSTR * title)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 
icon(OLE_HANDLE *)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 
historyItem() const640 HistoryItem* WebHistoryItem::historyItem() const
641 {
642     return m_historyItem.get();
643 }
644