a4d866c5d793506686c638441a920066afc1f4b5
[WebKit-https.git] / Source / WebKit / mac / History / WebHistoryItem.mm
1 /*
2  * Copyright (C) 2005, 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #import "WebHistoryItemInternal.h"
30 #import "WebHistoryItemPrivate.h"
31
32 #import "WebFrameInternal.h"
33 #import "WebFrameView.h"
34 #import "WebHTMLViewInternal.h"
35 #import "WebIconDatabase.h"
36 #import "WebKitLogging.h"
37 #import "WebKitNSStringExtras.h"
38 #import "WebNSArrayExtras.h"
39 #import "WebNSDictionaryExtras.h"
40 #import "WebNSObjectExtras.h"
41 #import "WebNSURLExtras.h"
42 #import "WebNSURLRequestExtras.h"
43 #import "WebNSViewExtras.h"
44 #import "WebPluginController.h"
45 #import "WebTypesInternal.h"
46 #import <WebCore/HistoryItem.h>
47 #import <WebCore/Image.h>
48 #import <WebCore/URL.h>
49 #import <WebCore/PageCache.h>
50 #import <WebCore/ThreadCheck.h>
51 #import <WebCore/WebCoreObjCExtras.h>
52 #import <runtime/InitializeThreading.h>
53 #import <wtf/Assertions.h>
54 #import <wtf/MainThread.h>
55 #import <wtf/RunLoop.h>
56 #import <wtf/StdLibExtras.h>
57 #import <wtf/text/WTFString.h>
58
59 // Private keys used in the WebHistoryItem's dictionary representation.
60 // see 3245793 for explanation of "lastVisitedDate"
61 static NSString *lastVisitedTimeIntervalKey = @"lastVisitedDate";
62 static NSString *visitCountKey = @"visitCount";
63 static NSString *titleKey = @"title";
64 static NSString *childrenKey = @"children";
65 static NSString *displayTitleKey = @"displayTitle";
66 static NSString *lastVisitWasFailureKey = @"lastVisitWasFailure";
67 static NSString *lastVisitWasHTTPNonGetKey = @"lastVisitWasHTTPNonGet";
68 static NSString *redirectURLsKey = @"redirectURLs";
69 static NSString *dailyVisitCountKey = @"D"; // short key to save space
70 static NSString *weeklyVisitCountKey = @"W"; // short key to save space
71
72 // Notification strings.
73 NSString *WebHistoryItemChangedNotification = @"WebHistoryItemChangedNotification";
74
75 using namespace WebCore;
76
77 typedef HashMap<HistoryItem*, WebHistoryItem*> HistoryItemMap;
78
79 static inline WebHistoryItemPrivate* kitPrivate(WebCoreHistoryItem* list) { return (WebHistoryItemPrivate*)list; }
80 static inline WebCoreHistoryItem* core(WebHistoryItemPrivate* list) { return (WebCoreHistoryItem*)list; }
81
82 static HistoryItemMap& historyItemWrappers()
83 {
84     DEFINE_STATIC_LOCAL(HistoryItemMap, historyItemWrappers, ());
85     return historyItemWrappers;
86 }
87
88 void WKNotifyHistoryItemChanged(HistoryItem*)
89 {
90     [[NSNotificationCenter defaultCenter]
91         postNotificationName:WebHistoryItemChangedNotification object:nil userInfo:nil];
92 }
93
94 @implementation WebHistoryItem
95
96 + (void)initialize
97 {
98     JSC::initializeThreading();
99     WTF::initializeMainThreadToProcessMainThread();
100     RunLoop::initializeMainRunLoop();
101     WebCoreObjCFinalizeOnMainThread(self);
102 }
103
104 - (instancetype)init
105 {
106     return [self initWithWebCoreHistoryItem:HistoryItem::create()];
107 }
108
109 - (instancetype)initWithURLString:(NSString *)URLString title:(NSString *)title lastVisitedTimeInterval:(NSTimeInterval)time
110 {
111     WebCoreThreadViolationCheckRoundOne();
112     return [self initWithWebCoreHistoryItem:HistoryItem::create(URLString, title, time)];
113 }
114
115 - (void)dealloc
116 {
117     if (WebCoreObjCScheduleDeallocateOnMainThread([WebHistoryItem class], self))
118         return;
119
120     if (_private) {
121         HistoryItem* coreItem = core(_private);
122         coreItem->deref();
123         historyItemWrappers().remove(coreItem);
124     }
125     [super dealloc];
126 }
127
128 - (void)finalize
129 {
130     WebCoreThreadViolationCheckRoundOne();
131     // FIXME: ~HistoryItem is what releases the history item's icon from the icon database
132     // It's probably not good to release icons from the database only when the object is garbage-collected. 
133     // Need to change design so this happens at a predictable time.
134     if (_private) {
135         HistoryItem* coreItem = core(_private);
136         coreItem->deref();
137         historyItemWrappers().remove(coreItem);
138     }
139     [super finalize];
140 }
141
142 - (id)copyWithZone:(NSZone *)zone
143 {
144     WebCoreThreadViolationCheckRoundOne();
145     WebHistoryItem *copy = [[[self class] alloc] initWithWebCoreHistoryItem:core(_private)->copy()];
146     historyItemWrappers().set(core(copy->_private), copy);
147
148     return copy;
149 }
150
151 // FIXME: Need to decide if this class ever returns URLs and decide on the name of this method
152 - (NSString *)URLString
153 {
154     ASSERT_MAIN_THREAD();
155     return nsStringNilIfEmpty(core(_private)->urlString());
156 }
157
158 // The first URL we loaded to get to where this history item points.  Includes both client
159 // and server redirects.
160 - (NSString *)originalURLString
161 {
162     ASSERT_MAIN_THREAD();
163     return nsStringNilIfEmpty(core(_private)->originalURLString());
164 }
165
166 - (NSString *)title
167 {
168     ASSERT_MAIN_THREAD();
169     return nsStringNilIfEmpty(core(_private)->title());
170 }
171
172 - (void)setAlternateTitle:(NSString *)alternateTitle
173 {
174     core(_private)->setAlternateTitle(alternateTitle);
175 }
176
177 - (NSString *)alternateTitle
178 {
179     return nsStringNilIfEmpty(core(_private)->alternateTitle());
180 }
181
182 - (NSImage *)icon
183 {
184     return [[WebIconDatabase sharedIconDatabase] iconForURL:[self URLString] withSize:WebIconSmallSize];
185 }
186
187 - (NSTimeInterval)lastVisitedTimeInterval
188 {
189     ASSERT_MAIN_THREAD();
190     return core(_private)->lastVisitedTime();
191 }
192
193 - (NSUInteger)hash
194 {
195     return [(NSString*)core(_private)->urlString() hash];
196 }
197
198 - (BOOL)isEqual:(id)anObject
199 {
200     ASSERT_MAIN_THREAD();
201     if (![anObject isMemberOfClass:[WebHistoryItem class]]) {
202         return NO;
203     }
204     
205     return core(_private)->urlString() == core(((WebHistoryItem*)anObject)->_private)->urlString();
206 }
207
208 - (NSString *)description
209 {
210     ASSERT_MAIN_THREAD();
211     HistoryItem* coreItem = core(_private);
212     NSMutableString *result = [NSMutableString stringWithFormat:@"%@ %@", [super description], (NSString*)coreItem->urlString()];
213     if (!coreItem->target().isEmpty()) {
214         NSString *target = coreItem->target();
215         [result appendFormat:@" in \"%@\"", target];
216     }
217     if (coreItem->isTargetItem()) {
218         [result appendString:@" *target*"];
219     }
220     if (coreItem->formData()) {
221         [result appendString:@" *POST*"];
222     }
223     
224     if (coreItem->children().size()) {
225         const HistoryItemVector& children = coreItem->children();
226         int currPos = [result length];
227         unsigned size = children.size();        
228         for (unsigned i = 0; i < size; ++i) {
229             WebHistoryItem *child = kit(children[i].get());
230             [result appendString:@"\n"];
231             [result appendString:[child description]];
232         }
233         // shift all the contents over.  A bit slow, but hey, this is for debugging.
234         NSRange replRange = { static_cast<NSUInteger>(currPos), [result length] - currPos };
235         [result replaceOccurrencesOfString:@"\n" withString:@"\n    " options:0 range:replRange];
236     }
237     
238     return result;
239 }
240
241 @end
242
243 @implementation WebHistoryItem (WebInternal)
244
245 HistoryItem* core(WebHistoryItem *item)
246 {
247     if (!item)
248         return 0;
249     
250     ASSERT(historyItemWrappers().get(core(item->_private)) == item);
251
252     return core(item->_private);
253 }
254
255 WebHistoryItem *kit(HistoryItem* item)
256 {
257     if (!item)
258         return nil;
259         
260     WebHistoryItem *kitItem = historyItemWrappers().get(item);
261     if (kitItem)
262         return kitItem;
263     
264     return [[[WebHistoryItem alloc] initWithWebCoreHistoryItem:item] autorelease];
265 }
266
267 + (WebHistoryItem *)entryWithURL:(NSURL *)URL
268 {
269     return [[[self alloc] initWithURL:URL title:nil] autorelease];
270 }
271
272 - (id)initWithURL:(NSURL *)URL target:(NSString *)target parent:(NSString *)parent title:(NSString *)title
273 {
274     return [self initWithWebCoreHistoryItem:HistoryItem::create(URL, target, parent, title)];
275 }
276
277 - (id)initWithURLString:(NSString *)URLString title:(NSString *)title displayTitle:(NSString *)displayTitle lastVisitedTimeInterval:(NSTimeInterval)time
278 {
279     return [self initWithWebCoreHistoryItem:HistoryItem::create(URLString, title, displayTitle, time)];
280 }
281
282 - (id)initWithWebCoreHistoryItem:(PassRefPtr<HistoryItem>)item
283 {   
284     WebCoreThreadViolationCheckRoundOne();
285     // Need to tell WebCore what function to call for the 
286     // "History Item has Changed" notification - no harm in doing this
287     // everytime a WebHistoryItem is created
288     // Note: We also do this in [WebFrameView initWithFrame:] where we do
289     // other "init before WebKit is used" type things
290     WebCore::notifyHistoryItemChanged = WKNotifyHistoryItemChanged;
291     
292     self = [super init];
293     
294     _private = kitPrivate(item.leakRef());
295     ASSERT(!historyItemWrappers().get(core(_private)));
296     historyItemWrappers().set(core(_private), self);
297     return self;
298 }
299
300 - (void)setTitle:(NSString *)title
301 {
302     core(_private)->setTitle(title);
303 }
304
305 - (void)setVisitCount:(int)count
306 {
307     core(_private)->setVisitCount(count);
308 }
309
310 - (void)setViewState:(id)statePList
311 {
312     core(_private)->setViewState(statePList);
313 }
314
315 - (void)_mergeAutoCompleteHints:(WebHistoryItem *)otherItem
316 {
317     ASSERT_ARG(otherItem, otherItem);
318     core(_private)->mergeAutoCompleteHints(core(otherItem->_private));
319 }
320
321 - (id)initFromDictionaryRepresentation:(NSDictionary *)dict
322 {
323     ASSERT_MAIN_THREAD();
324     NSString *URLString = [dict _webkit_stringForKey:@""];
325     NSString *title = [dict _webkit_stringForKey:titleKey];
326
327     // Do an existence check to avoid calling doubleValue on a nil string. Leave
328     // time interval at 0 if there's no value in dict.
329     NSString *timeIntervalString = [dict _webkit_stringForKey:lastVisitedTimeIntervalKey];
330     NSTimeInterval lastVisited = timeIntervalString == nil ? 0 : [timeIntervalString doubleValue];
331
332     self = [self initWithURLString:URLString title:title displayTitle:[dict _webkit_stringForKey:displayTitleKey] lastVisitedTimeInterval:lastVisited];
333     
334     // Check if we've read a broken URL from the file that has non-Latin1 chars.  If so, try to convert
335     // as if it was from user typing.
336     if (![URLString canBeConvertedToEncoding:NSISOLatin1StringEncoding]) {
337         NSURL *tempURL = [NSURL _web_URLWithUserTypedString:URLString];
338         ASSERT(tempURL);
339         NSString *newURLString = [tempURL _web_originalDataAsString];
340         core(_private)->setURLString(newURLString);
341         core(_private)->setOriginalURLString(newURLString);
342     } 
343
344     int visitCount = [dict _webkit_intForKey:visitCountKey];
345     
346     // Can't trust data on disk, and we've had at least one report of this (<rdar://6572300>).
347     if (visitCount < 0) {
348         LOG_ERROR("visit count for history item \"%@\" is negative (%d), will be reset to 1", URLString, visitCount);
349         visitCount = 1;
350     }
351     core(_private)->setVisitCount(visitCount);
352
353     if ([dict _webkit_boolForKey:lastVisitWasFailureKey])
354         core(_private)->setLastVisitWasFailure(true);
355     
356     BOOL lastVisitWasHTTPNonGet = [dict _webkit_boolForKey:lastVisitWasHTTPNonGetKey];
357     NSString *tempURLString = [URLString lowercaseString];
358     if (lastVisitWasHTTPNonGet && ([tempURLString hasPrefix:@"http:"] || [tempURLString hasPrefix:@"https:"]))
359         core(_private)->setLastVisitWasHTTPNonGet(lastVisitWasHTTPNonGet);
360
361     if (NSArray *redirectURLs = [dict _webkit_arrayForKey:redirectURLsKey]) {
362         NSUInteger size = [redirectURLs count];
363         OwnPtr<Vector<String>> redirectURLsVector = adoptPtr(new Vector<String>(size));
364         for (NSUInteger i = 0; i < size; ++i)
365             (*redirectURLsVector)[i] = String([redirectURLs _webkit_stringAtIndex:i]);
366         core(_private)->setRedirectURLs(redirectURLsVector.release());
367     }
368
369     NSArray *dailyCounts = [dict _webkit_arrayForKey:dailyVisitCountKey];
370     NSArray *weeklyCounts = [dict _webkit_arrayForKey:weeklyVisitCountKey];
371     if (dailyCounts || weeklyCounts) {
372         Vector<int> coreDailyCounts([dailyCounts count]);
373         Vector<int> coreWeeklyCounts([weeklyCounts count]);
374
375         // Daily and weekly counts < 0 are errors in the data read from disk, so reset to 0.
376         for (size_t i = 0; i < coreDailyCounts.size(); ++i)
377             coreDailyCounts[i] = std::max([[dailyCounts _webkit_numberAtIndex:i] intValue], 0);
378         for (size_t i = 0; i < coreWeeklyCounts.size(); ++i)
379             coreWeeklyCounts[i] = std::max([[weeklyCounts _webkit_numberAtIndex:i] intValue], 0);
380     
381         core(_private)->adoptVisitCounts(coreDailyCounts, coreWeeklyCounts);
382     }
383
384     NSArray *childDicts = [dict objectForKey:childrenKey];
385     if (childDicts) {
386         for (int i = [childDicts count] - 1; i >= 0; i--) {
387             WebHistoryItem *child = [[WebHistoryItem alloc] initFromDictionaryRepresentation:[childDicts objectAtIndex:i]];
388             core(_private)->addChildItem(core(child->_private));
389             [child release];
390         }
391     }
392
393     return self;
394 }
395
396 - (NSPoint)scrollPoint
397 {
398     ASSERT_MAIN_THREAD();
399     return core(_private)->scrollPoint();
400 }
401
402 - (void)_visitedWithTitle:(NSString *)title increaseVisitCount:(BOOL)increaseVisitCount
403 {
404     core(_private)->visited(title, [NSDate timeIntervalSinceReferenceDate], increaseVisitCount ? IncreaseVisitCount : DoNotIncreaseVisitCount);
405 }
406
407 - (void)_recordInitialVisit
408 {
409     core(_private)->recordInitialVisit();
410 }
411
412 @end
413
414 @implementation WebHistoryItem (WebPrivate)
415
416 - (id)initWithURL:(NSURL *)URL title:(NSString *)title
417 {
418     return [self initWithURLString:[URL _web_originalDataAsString] title:title lastVisitedTimeInterval:0];
419 }
420
421 - (NSDictionary *)dictionaryRepresentation
422 {
423     ASSERT_MAIN_THREAD();
424     NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:8];
425
426     HistoryItem* coreItem = core(_private);
427     
428     if (!coreItem->urlString().isEmpty())
429         [dict setObject:(NSString*)coreItem->urlString() forKey:@""];
430     if (!coreItem->title().isEmpty())
431         [dict setObject:(NSString*)coreItem->title() forKey:titleKey];
432     if (!coreItem->alternateTitle().isEmpty())
433         [dict setObject:(NSString*)coreItem->alternateTitle() forKey:displayTitleKey];
434     if (coreItem->lastVisitedTime() != 0.0) {
435         // Store as a string to maintain backward compatibility. (See 3245793)
436         [dict setObject:[NSString stringWithFormat:@"%.1lf", coreItem->lastVisitedTime()]
437                  forKey:lastVisitedTimeIntervalKey];
438     }
439     if (coreItem->visitCount())
440         [dict setObject:[NSNumber numberWithInt:coreItem->visitCount()] forKey:visitCountKey];
441     if (coreItem->lastVisitWasFailure())
442         [dict setObject:[NSNumber numberWithBool:YES] forKey:lastVisitWasFailureKey];
443     if (coreItem->lastVisitWasHTTPNonGet()) {
444         ASSERT(coreItem->urlString().startsWith("http:", false) || coreItem->urlString().startsWith("https:", false));
445         [dict setObject:[NSNumber numberWithBool:YES] forKey:lastVisitWasHTTPNonGetKey];
446     }
447     if (Vector<String>* redirectURLs = coreItem->redirectURLs()) {
448         size_t size = redirectURLs->size();
449         ASSERT(size);
450         NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:size];
451         for (size_t i = 0; i < size; ++i)
452             [result addObject:(NSString*)redirectURLs->at(i)];
453         [dict setObject:result forKey:redirectURLsKey];
454         [result release];
455     }
456     
457     const Vector<int>& dailyVisitCounts = coreItem->dailyVisitCounts();
458     if (dailyVisitCounts.size()) {
459         NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:13];
460         for (size_t i = 0; i < dailyVisitCounts.size(); ++i)
461             [array addObject:[NSNumber numberWithInt:dailyVisitCounts[i]]];
462         [dict setObject:array forKey:dailyVisitCountKey];
463         [array release];
464     }
465     
466     const Vector<int>& weeklyVisitCounts = coreItem->weeklyVisitCounts();
467     if (weeklyVisitCounts.size()) {
468         NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:5];
469         for (size_t i = 0; i < weeklyVisitCounts.size(); ++i)
470             [array addObject:[NSNumber numberWithInt:weeklyVisitCounts[i]]];
471         [dict setObject:array forKey:weeklyVisitCountKey];
472         [array release];
473     }    
474     
475     if (coreItem->children().size()) {
476         const HistoryItemVector& children = coreItem->children();
477         NSMutableArray *childDicts = [NSMutableArray arrayWithCapacity:children.size()];
478         
479         for (int i = children.size() - 1; i >= 0; i--)
480             [childDicts addObject:[kit(children[i].get()) dictionaryRepresentation]];
481         [dict setObject: childDicts forKey:childrenKey];
482     }
483
484     return dict;
485 }
486
487 - (NSString *)target
488 {
489     ASSERT_MAIN_THREAD();
490     return nsStringNilIfEmpty(core(_private)->target());
491 }
492
493 - (BOOL)isTargetItem
494 {
495     return core(_private)->isTargetItem();
496 }
497
498 - (int)visitCount
499 {
500     ASSERT_MAIN_THREAD();
501     return core(_private)->visitCount();
502 }
503
504 - (NSString *)RSSFeedReferrer
505 {
506     return nsStringNilIfEmpty(core(_private)->referrer());
507 }
508
509 - (void)setRSSFeedReferrer:(NSString *)referrer
510 {
511     core(_private)->setReferrer(referrer);
512 }
513
514 - (NSArray *)children
515 {
516     ASSERT_MAIN_THREAD();
517     const HistoryItemVector& children = core(_private)->children();
518     if (!children.size())
519         return nil;
520
521     unsigned size = children.size();
522     NSMutableArray *result = [[[NSMutableArray alloc] initWithCapacity:size] autorelease];
523     
524     for (unsigned i = 0; i < size; ++i)
525         [result addObject:kit(children[i].get())];
526     
527     return result;
528 }
529
530 - (void)setAlwaysAttemptToUsePageCache:(BOOL)flag
531 {
532     // Safari 2.0 uses this for SnapBack, so we stub it out to avoid a crash.
533 }
534
535 - (NSURL *)URL
536 {
537     ASSERT_MAIN_THREAD();
538     const URL& url = core(_private)->url();
539     if (url.isEmpty())
540         return nil;
541     return url;
542 }
543
544 // This should not be called directly for WebHistoryItems that are already included
545 // in WebHistory. Use -[WebHistory setLastVisitedTimeInterval:forItem:] instead.
546 - (void)_setLastVisitedTimeInterval:(NSTimeInterval)time
547 {
548     core(_private)->setLastVisitedTime(time);
549 }
550
551 - (WebHistoryItem *)targetItem
552 {    
553     ASSERT_MAIN_THREAD();
554     return kit(core(_private)->targetItem());
555 }
556
557 + (void)_releaseAllPendingPageCaches
558 {
559 }
560
561 - (id)_transientPropertyForKey:(NSString *)key
562 {
563     return core(_private)->getTransientProperty(key);
564 }
565
566 - (void)_setTransientProperty:(id)property forKey:(NSString *)key
567 {
568     core(_private)->setTransientProperty(key, property);
569 }
570
571 - (BOOL)lastVisitWasFailure
572 {
573     return core(_private)->lastVisitWasFailure();
574 }
575
576 - (void)_setLastVisitWasFailure:(BOOL)failure
577 {
578     core(_private)->setLastVisitWasFailure(failure);
579 }
580
581 - (BOOL)_lastVisitWasHTTPNonGet
582 {
583     return core(_private)->lastVisitWasHTTPNonGet();
584 }
585
586 - (NSArray *)_redirectURLs
587 {
588     Vector<String>* redirectURLs = core(_private)->redirectURLs();
589     if (!redirectURLs)
590         return nil;
591
592     size_t size = redirectURLs->size();
593     ASSERT(size);
594     NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:size];
595     for (size_t i = 0; i < size; ++i)
596         [result addObject:(NSString*)redirectURLs->at(i)];
597     return [result autorelease];
598 }
599
600 - (size_t)_getDailyVisitCounts:(const int**)counts
601 {
602     HistoryItem* coreItem = core(_private);
603     *counts = coreItem->dailyVisitCounts().data();
604     return coreItem->dailyVisitCounts().size();
605 }
606
607 - (size_t)_getWeeklyVisitCounts:(const int**)counts
608 {
609     HistoryItem* coreItem = core(_private);
610     *counts = coreItem->weeklyVisitCounts().data();
611     return coreItem->weeklyVisitCounts().size();
612 }
613
614 - (BOOL)_isInPageCache
615 {
616     return core(_private)->isInPageCache();
617 }
618
619 - (BOOL)_hasCachedPageExpired
620 {
621     return core(_private)->hasCachedPageExpired();
622 }
623
624 @end