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