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