• 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 "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 
historyItemWrappers()49 static HashMap<HistoryItem*, WebHistoryItem*>& historyItemWrappers()
50 {
51     static HashMap<HistoryItem*, WebHistoryItem*> staticHistoryItemWrappers;
52     return staticHistoryItemWrappers;
53 }
54 
WebHistoryItem(PassRefPtr<HistoryItem> historyItem)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 
~WebHistoryItem()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 
createInstance()75 WebHistoryItem* WebHistoryItem::createInstance()
76 {
77     WebHistoryItem* instance = new WebHistoryItem(HistoryItem::create());
78     instance->AddRef();
79     return instance;
80 }
81 
createInstance(PassRefPtr<HistoryItem> historyItem)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 
initFromDictionaryRepresentation(void * dictionary)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 
dictionaryRepresentation(void ** dictionary)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 
hasURLString(BOOL * hasURL)300 HRESULT STDMETHODCALLTYPE WebHistoryItem::hasURLString(BOOL *hasURL)
301 {
302     *hasURL = m_historyItem->urlString().isEmpty() ? FALSE : TRUE;
303     return S_OK;
304 }
305 
visitCount(int * count)306 HRESULT STDMETHODCALLTYPE WebHistoryItem::visitCount(int *count)
307 {
308     *count = m_historyItem->visitCount();
309     return S_OK;
310 }
311 
setVisitCount(int count)312 HRESULT STDMETHODCALLTYPE WebHistoryItem::setVisitCount(int count)
313 {
314     m_historyItem->setVisitCount(count);
315     return S_OK;
316 }
317 
mergeAutoCompleteHints(IWebHistoryItem * otherItem)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 
setLastVisitedTimeInterval(DATE time)332 HRESULT STDMETHODCALLTYPE WebHistoryItem::setLastVisitedTimeInterval(DATE time)
333 {
334     m_historyItem->setLastVisitedTime(MarshallingHelpers::DATEToCFAbsoluteTime(time));
335     return S_OK;
336 }
337 
setTitle(BSTR title)338 HRESULT STDMETHODCALLTYPE WebHistoryItem::setTitle(BSTR title)
339 {
340     m_historyItem->setTitle(String(title, SysStringLen(title)));
341 
342     return S_OK;
343 }
344 
RSSFeedReferrer(BSTR * url)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 
setRSSFeedReferrer(BSTR url)353 HRESULT STDMETHODCALLTYPE WebHistoryItem::setRSSFeedReferrer(BSTR url)
354 {
355     m_historyItem->setReferrer(String(url, SysStringLen(url)));
356 
357     return S_OK;
358 }
359 
hasPageCache(BOOL *)360 HRESULT STDMETHODCALLTYPE WebHistoryItem::hasPageCache(BOOL* /*hasCache*/)
361 {
362     // FIXME - TODO
363     ASSERT_NOT_REACHED();
364     return E_NOTIMPL;
365 }
366 
setHasPageCache(BOOL)367 HRESULT STDMETHODCALLTYPE WebHistoryItem::setHasPageCache(BOOL /*hasCache*/)
368 {
369     // FIXME - TODO
370     return E_NOTIMPL;
371 }
372 
target(BSTR * target)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 
isTargetItem(BOOL * result)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 
children(unsigned * outChildCount,SAFEARRAY ** outChildren)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 
lastVisitWasFailure(BOOL * wasFailure)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 
setLastVisitWasFailure(BOOL wasFailure)446 HRESULT STDMETHODCALLTYPE WebHistoryItem::setLastVisitWasFailure(BOOL wasFailure)
447 {
448     m_historyItem->setLastVisitWasFailure(wasFailure);
449     return S_OK;
450 }
451 
lastVisitWasHTTPNonGet(BOOL * HTTPNonGet)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 
setLastVisitWasHTTPNonGet(BOOL HTTPNonGet)464 HRESULT STDMETHODCALLTYPE WebHistoryItem::setLastVisitWasHTTPNonGet(BOOL HTTPNonGet)
465 {
466     m_historyItem->setLastVisitWasHTTPNonGet(HTTPNonGet);
467     return S_OK;
468 }
469 
redirectURLs(IEnumVARIANT ** urls)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 
visitedWithTitle(BSTR title,BOOL increaseVisitCount)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 
getDailyVisitCounts(int * number,int ** counts)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 
getWeeklyVisitCounts(int * number,int ** counts)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 
recordInitialVisit()519 HRESULT STDMETHODCALLTYPE WebHistoryItem::recordInitialVisit()
520 {
521     m_historyItem->recordInitialVisit();
522     return S_OK;
523 }
524 
525 // IUnknown -------------------------------------------------------------------
526 
QueryInterface(REFIID riid,void ** ppvObject)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 
AddRef(void)545 ULONG STDMETHODCALLTYPE WebHistoryItem::AddRef(void)
546 {
547     return ++m_refCount;
548 }
549 
Release(void)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 
initWithURLString(BSTR urlString,BSTR title,DATE lastVisited)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 
originalURLString(BSTR * url)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 
URLString(BSTR * url)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 
title(BSTR * pageTitle)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 
lastVisitedTimeInterval(DATE * lastVisited)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 
setAlternateTitle(BSTR title)616 HRESULT STDMETHODCALLTYPE WebHistoryItem::setAlternateTitle(
617     /* [in] */ BSTR title)
618 {
619     m_alternateTitle = String(title, SysStringLen(title));
620     return S_OK;
621 }
622 
alternateTitle(BSTR * title)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 
icon(OLE_HANDLE *)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 
historyItem() const644 HistoryItem* WebHistoryItem::historyItem() const
645 {
646     return m_historyItem.get();
647 }
648