--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WebKit/mac/History/WebHistoryItem.mm Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,665 @@
+/*
+ * Copyright (C) 2005, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "WebHistoryItemInternal.h"
+#import "WebHistoryItemPrivate.h"
+
+#import "WebFrameInternal.h"
+#import "WebFrameView.h"
+#import "WebHTMLViewInternal.h"
+#import "WebIconDatabase.h"
+#import "WebKitLogging.h"
+#import "WebKitNSStringExtras.h"
+#import "WebNSArrayExtras.h"
+#import "WebNSDictionaryExtras.h"
+#import "WebNSObjectExtras.h"
+#import "WebNSURLExtras.h"
+#import "WebNSURLRequestExtras.h"
+#import "WebNSViewExtras.h"
+#import "WebPluginController.h"
+#import "WebTypesInternal.h"
+#import <WebCore/HistoryItem.h>
+#import <WebCore/Image.h>
+#import <WebCore/KURL.h>
+#import <WebCore/PageCache.h>
+#import <WebCore/PlatformString.h>
+#import <WebCore/ThreadCheck.h>
+#import <WebCore/WebCoreObjCExtras.h>
+#import <runtime/InitializeThreading.h>
+#import <wtf/Assertions.h>
+#import <wtf/StdLibExtras.h>
+#import <wtf/Threading.h>
+
+// Private keys used in the WebHistoryItem's dictionary representation.
+// see 3245793 for explanation of "lastVisitedDate"
+static NSString *lastVisitedTimeIntervalKey = @"lastVisitedDate";
+static NSString *visitCountKey = @"visitCount";
+static NSString *titleKey = @"title";
+static NSString *childrenKey = @"children";
+static NSString *displayTitleKey = @"displayTitle";
+static NSString *lastVisitWasFailureKey = @"lastVisitWasFailure";
+static NSString *lastVisitWasHTTPNonGetKey = @"lastVisitWasHTTPNonGet";
+static NSString *redirectURLsKey = @"redirectURLs";
+static NSString *dailyVisitCountKey = @"D"; // short key to save space
+static NSString *weeklyVisitCountKey = @"W"; // short key to save space
+
+// Notification strings.
+NSString *WebHistoryItemChangedNotification = @"WebHistoryItemChangedNotification";
+
+using namespace WebCore;
+using namespace std;
+
+typedef HashMap<HistoryItem*, WebHistoryItem*> HistoryItemMap;
+
+static inline WebHistoryItemPrivate* kitPrivate(WebCoreHistoryItem* list) { return (WebHistoryItemPrivate*)list; }
+static inline WebCoreHistoryItem* core(WebHistoryItemPrivate* list) { return (WebCoreHistoryItem*)list; }
+
+static HistoryItemMap& historyItemWrappers()
+{
+ DEFINE_STATIC_LOCAL(HistoryItemMap, historyItemWrappers, ());
+ return historyItemWrappers;
+}
+
+void WKNotifyHistoryItemChanged(HistoryItem*)
+{
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName:WebHistoryItemChangedNotification object:nil userInfo:nil];
+}
+
+@implementation WebHistoryItem
+
++ (void)initialize
+{
+ JSC::initializeThreading();
+ WTF::initializeMainThreadToProcessMainThread();
+#ifndef BUILDING_ON_TIGER
+ WebCoreObjCFinalizeOnMainThread(self);
+#endif
+}
+
+- (id)init
+{
+ return [self initWithWebCoreHistoryItem:HistoryItem::create()];
+}
+
+- (id)initWithURLString:(NSString *)URLString title:(NSString *)title lastVisitedTimeInterval:(NSTimeInterval)time
+{
+ WebCoreThreadViolationCheckRoundOne();
+ return [self initWithWebCoreHistoryItem:HistoryItem::create(URLString, title, time)];
+}
+
+- (void)dealloc
+{
+ if (WebCoreObjCScheduleDeallocateOnMainThread([WebHistoryItem class], self))
+ return;
+
+ if (_private) {
+ HistoryItem* coreItem = core(_private);
+ coreItem->deref();
+ historyItemWrappers().remove(coreItem);
+ }
+ [super dealloc];
+}
+
+- (void)finalize
+{
+ WebCoreThreadViolationCheckRoundOne();
+ // FIXME: ~HistoryItem is what releases the history item's icon from the icon database
+ // It's probably not good to release icons from the database only when the object is garbage-collected.
+ // Need to change design so this happens at a predictable time.
+ if (_private) {
+ HistoryItem* coreItem = core(_private);
+ coreItem->deref();
+ historyItemWrappers().remove(coreItem);
+ }
+ [super finalize];
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+ WebCoreThreadViolationCheckRoundOne();
+ WebHistoryItem *copy = (WebHistoryItem *)NSCopyObject(self, 0, zone);
+ RefPtr<HistoryItem> item = core(_private)->copy();
+ copy->_private = kitPrivate(item.get());
+ historyItemWrappers().set(item.release().releaseRef(), copy);
+
+ return copy;
+}
+
+// FIXME: Need to decide if this class ever returns URLs and decide on the name of this method
+- (NSString *)URLString
+{
+ ASSERT_MAIN_THREAD();
+ return nsStringNilIfEmpty(core(_private)->urlString());
+}
+
+// The first URL we loaded to get to where this history item points. Includes both client
+// and server redirects.
+- (NSString *)originalURLString
+{
+ ASSERT_MAIN_THREAD();
+ return nsStringNilIfEmpty(core(_private)->originalURLString());
+}
+
+- (NSString *)title
+{
+ ASSERT_MAIN_THREAD();
+ return nsStringNilIfEmpty(core(_private)->title());
+}
+
+- (void)setAlternateTitle:(NSString *)alternateTitle
+{
+ core(_private)->setAlternateTitle(alternateTitle);
+}
+
+- (NSString *)alternateTitle
+{
+ return nsStringNilIfEmpty(core(_private)->alternateTitle());
+}
+
+- (NSImage *)icon
+{
+ return [[WebIconDatabase sharedIconDatabase] iconForURL:[self URLString] withSize:WebIconSmallSize];
+
+ // FIXME: Ideally, this code should simply be the following -
+ // return core(_private)->icon()->getNSImage();
+ // Once radar -
+ // <rdar://problem/4906567> - NSImage returned from WebCore::Image may be incorrect size
+ // is resolved
+}
+
+- (NSTimeInterval)lastVisitedTimeInterval
+{
+ ASSERT_MAIN_THREAD();
+ return core(_private)->lastVisitedTime();
+}
+
+- (NSUInteger)hash
+{
+ return [(NSString*)core(_private)->urlString() hash];
+}
+
+- (BOOL)isEqual:(id)anObject
+{
+ ASSERT_MAIN_THREAD();
+ if (![anObject isMemberOfClass:[WebHistoryItem class]]) {
+ return NO;
+ }
+
+ return core(_private)->urlString() == core(((WebHistoryItem*)anObject)->_private)->urlString();
+}
+
+- (NSString *)description
+{
+ ASSERT_MAIN_THREAD();
+ HistoryItem* coreItem = core(_private);
+ NSMutableString *result = [NSMutableString stringWithFormat:@"%@ %@", [super description], (NSString*)coreItem->urlString()];
+ if (coreItem->target()) {
+ NSString *target = coreItem->target();
+ [result appendFormat:@" in \"%@\"", target];
+ }
+ if (coreItem->isTargetItem()) {
+ [result appendString:@" *target*"];
+ }
+ if (coreItem->formData()) {
+ [result appendString:@" *POST*"];
+ }
+
+ if (coreItem->children().size()) {
+ const HistoryItemVector& children = coreItem->children();
+ int currPos = [result length];
+ unsigned size = children.size();
+ for (unsigned i = 0; i < size; ++i) {
+ WebHistoryItem *child = kit(children[i].get());
+ [result appendString:@"\n"];
+ [result appendString:[child description]];
+ }
+ // shift all the contents over. A bit slow, but hey, this is for debugging.
+ NSRange replRange = {currPos, [result length]-currPos};
+ [result replaceOccurrencesOfString:@"\n" withString:@"\n " options:0 range:replRange];
+ }
+
+ return result;
+}
+
+@end
+
+@interface WebWindowWatcher : NSObject
+@end
+
+
+@implementation WebHistoryItem (WebInternal)
+
+HistoryItem* core(WebHistoryItem *item)
+{
+ if (!item)
+ return 0;
+
+ ASSERT(historyItemWrappers().get(core(item->_private)) == item);
+
+ return core(item->_private);
+}
+
+WebHistoryItem *kit(HistoryItem* item)
+{
+ if (!item)
+ return nil;
+
+ WebHistoryItem *kitItem = historyItemWrappers().get(item);
+ if (kitItem)
+ return kitItem;
+
+ return [[[WebHistoryItem alloc] initWithWebCoreHistoryItem:item] autorelease];
+}
+
++ (WebHistoryItem *)entryWithURL:(NSURL *)URL
+{
+ return [[[self alloc] initWithURL:URL title:nil] autorelease];
+}
+
+static WebWindowWatcher *_windowWatcher = nil;
+
++ (void)initWindowWatcherIfNecessary
+{
+ if (_windowWatcher)
+ return;
+ _windowWatcher = [[WebWindowWatcher alloc] init];
+ [[NSNotificationCenter defaultCenter] addObserver:_windowWatcher selector:@selector(windowWillClose:)
+ name:NSWindowWillCloseNotification object:nil];
+}
+
+- (id)initWithURL:(NSURL *)URL target:(NSString *)target parent:(NSString *)parent title:(NSString *)title
+{
+ return [self initWithWebCoreHistoryItem:HistoryItem::create(URL, target, parent, title)];
+}
+
+- (id)initWithURLString:(NSString *)URLString title:(NSString *)title displayTitle:(NSString *)displayTitle lastVisitedTimeInterval:(NSTimeInterval)time
+{
+ return [self initWithWebCoreHistoryItem:HistoryItem::create(URLString, title, displayTitle, time)];
+}
+
+- (id)initWithWebCoreHistoryItem:(PassRefPtr<HistoryItem>)item
+{
+ WebCoreThreadViolationCheckRoundOne();
+ // Need to tell WebCore what function to call for the
+ // "History Item has Changed" notification - no harm in doing this
+ // everytime a WebHistoryItem is created
+ // Note: We also do this in [WebFrameView initWithFrame:] where we do
+ // other "init before WebKit is used" type things
+ WebCore::notifyHistoryItemChanged = WKNotifyHistoryItemChanged;
+
+ self = [super init];
+
+ _private = kitPrivate(item.releaseRef());
+ ASSERT(!historyItemWrappers().get(core(_private)));
+ historyItemWrappers().set(core(_private), self);
+ return self;
+}
+
+- (void)setTitle:(NSString *)title
+{
+ core(_private)->setTitle(title);
+}
+
+- (void)setVisitCount:(int)count
+{
+ core(_private)->setVisitCount(count);
+}
+
+- (void)setViewState:(id)statePList
+{
+ core(_private)->setViewState(statePList);
+}
+
+- (void)_mergeAutoCompleteHints:(WebHistoryItem *)otherItem
+{
+ ASSERT_ARG(otherItem, otherItem);
+ core(_private)->mergeAutoCompleteHints(core(otherItem->_private));
+}
+
+- (id)initFromDictionaryRepresentation:(NSDictionary *)dict
+{
+ ASSERT_MAIN_THREAD();
+ NSString *URLString = [dict _webkit_stringForKey:@""];
+ NSString *title = [dict _webkit_stringForKey:titleKey];
+
+ // Do an existence check to avoid calling doubleValue on a nil string. Leave
+ // time interval at 0 if there's no value in dict.
+ NSString *timeIntervalString = [dict _webkit_stringForKey:lastVisitedTimeIntervalKey];
+ NSTimeInterval lastVisited = timeIntervalString == nil ? 0 : [timeIntervalString doubleValue];
+
+ self = [self initWithURLString:URLString title:title displayTitle:[dict _webkit_stringForKey:displayTitleKey] lastVisitedTimeInterval:lastVisited];
+
+ // Check if we've read a broken URL from the file that has non-Latin1 chars. If so, try to convert
+ // as if it was from user typing.
+ if (![URLString canBeConvertedToEncoding:NSISOLatin1StringEncoding]) {
+ NSURL *tempURL = [NSURL _web_URLWithUserTypedString:URLString];
+ ASSERT(tempURL);
+ NSString *newURLString = [tempURL _web_originalDataAsString];
+ core(_private)->setURLString(newURLString);
+ core(_private)->setOriginalURLString(newURLString);
+ }
+
+ int visitCount = [dict _webkit_intForKey:visitCountKey];
+
+ // Can't trust data on disk, and we've had at least one report of this (<rdar://6572300>).
+ if (visitCount < 0) {
+ LOG_ERROR("visit count for history item \"%@\" is negative (%d), will be reset to 1", URLString, visitCount);
+ visitCount = 1;
+ }
+ core(_private)->setVisitCount(visitCount);
+
+ if ([dict _webkit_boolForKey:lastVisitWasFailureKey])
+ core(_private)->setLastVisitWasFailure(true);
+
+ BOOL lastVisitWasHTTPNonGet = [dict _webkit_boolForKey:lastVisitWasHTTPNonGetKey];
+ NSString *tempURLString = [URLString lowercaseString];
+ if (lastVisitWasHTTPNonGet && ([tempURLString hasPrefix:@"http:"] || [tempURLString hasPrefix:@"https:"]))
+ core(_private)->setLastVisitWasHTTPNonGet(lastVisitWasHTTPNonGet);
+
+ if (NSArray *redirectURLs = [dict _webkit_arrayForKey:redirectURLsKey]) {
+ NSUInteger size = [redirectURLs count];
+ OwnPtr<Vector<String> > redirectURLsVector(new Vector<String>(size));
+ for (NSUInteger i = 0; i < size; ++i)
+ (*redirectURLsVector)[i] = String([redirectURLs _webkit_stringAtIndex:i]);
+ core(_private)->setRedirectURLs(redirectURLsVector.release());
+ }
+
+ NSArray *dailyCounts = [dict _webkit_arrayForKey:dailyVisitCountKey];
+ NSArray *weeklyCounts = [dict _webkit_arrayForKey:weeklyVisitCountKey];
+ if (dailyCounts || weeklyCounts) {
+ Vector<int> coreDailyCounts([dailyCounts count]);
+ Vector<int> coreWeeklyCounts([weeklyCounts count]);
+
+ // Daily and weekly counts < 0 are errors in the data read from disk, so reset to 0.
+ for (size_t i = 0; i < coreDailyCounts.size(); ++i)
+ coreDailyCounts[i] = max([[dailyCounts _webkit_numberAtIndex:i] intValue], 0);
+ for (size_t i = 0; i < coreWeeklyCounts.size(); ++i)
+ coreWeeklyCounts[i] = max([[weeklyCounts _webkit_numberAtIndex:i] intValue], 0);
+
+ core(_private)->adoptVisitCounts(coreDailyCounts, coreWeeklyCounts);
+ }
+
+ NSArray *childDicts = [dict objectForKey:childrenKey];
+ if (childDicts) {
+ for (int i = [childDicts count] - 1; i >= 0; i--) {
+ WebHistoryItem *child = [[WebHistoryItem alloc] initFromDictionaryRepresentation:[childDicts objectAtIndex:i]];
+ core(_private)->addChildItem(core(child->_private));
+ [child release];
+ }
+ }
+
+ return self;
+}
+
+- (NSPoint)scrollPoint
+{
+ ASSERT_MAIN_THREAD();
+ return core(_private)->scrollPoint();
+}
+
+- (void)_visitedWithTitle:(NSString *)title increaseVisitCount:(BOOL)increaseVisitCount
+{
+ core(_private)->visited(title, [NSDate timeIntervalSinceReferenceDate], increaseVisitCount ? IncreaseVisitCount : DoNotIncreaseVisitCount);
+}
+
+- (void)_recordInitialVisit
+{
+ core(_private)->recordInitialVisit();
+}
+
+@end
+
+@implementation WebHistoryItem (WebPrivate)
+
+- (id)initWithURL:(NSURL *)URL title:(NSString *)title
+{
+ return [self initWithURLString:[URL _web_originalDataAsString] title:title lastVisitedTimeInterval:0];
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+ ASSERT_MAIN_THREAD();
+ NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:8];
+
+ HistoryItem* coreItem = core(_private);
+
+ if (!coreItem->urlString().isEmpty())
+ [dict setObject:(NSString*)coreItem->urlString() forKey:@""];
+ if (!coreItem->title().isEmpty())
+ [dict setObject:(NSString*)coreItem->title() forKey:titleKey];
+ if (!coreItem->alternateTitle().isEmpty())
+ [dict setObject:(NSString*)coreItem->alternateTitle() forKey:displayTitleKey];
+ if (coreItem->lastVisitedTime() != 0.0) {
+ // Store as a string to maintain backward compatibility. (See 3245793)
+ [dict setObject:[NSString stringWithFormat:@"%.1lf", coreItem->lastVisitedTime()]
+ forKey:lastVisitedTimeIntervalKey];
+ }
+ if (coreItem->visitCount())
+ [dict setObject:[NSNumber numberWithInt:coreItem->visitCount()] forKey:visitCountKey];
+ if (coreItem->lastVisitWasFailure())
+ [dict setObject:[NSNumber numberWithBool:YES] forKey:lastVisitWasFailureKey];
+ if (coreItem->lastVisitWasHTTPNonGet()) {
+ ASSERT(coreItem->urlString().startsWith("http:", false) || coreItem->urlString().startsWith("https:", false));
+ [dict setObject:[NSNumber numberWithBool:YES] forKey:lastVisitWasHTTPNonGetKey];
+ }
+ if (Vector<String>* redirectURLs = coreItem->redirectURLs()) {
+ size_t size = redirectURLs->size();
+ ASSERT(size);
+ NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:size];
+ for (size_t i = 0; i < size; ++i)
+ [result addObject:(NSString*)redirectURLs->at(i)];
+ [dict setObject:result forKey:redirectURLsKey];
+ [result release];
+ }
+
+ const Vector<int>& dailyVisitCounts = coreItem->dailyVisitCounts();
+ if (dailyVisitCounts.size()) {
+ NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:13];
+ for (size_t i = 0; i < dailyVisitCounts.size(); ++i)
+ [array addObject:[NSNumber numberWithInt:dailyVisitCounts[i]]];
+ [dict setObject:array forKey:dailyVisitCountKey];
+ [array release];
+ }
+
+ const Vector<int>& weeklyVisitCounts = coreItem->weeklyVisitCounts();
+ if (weeklyVisitCounts.size()) {
+ NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:5];
+ for (size_t i = 0; i < weeklyVisitCounts.size(); ++i)
+ [array addObject:[NSNumber numberWithInt:weeklyVisitCounts[i]]];
+ [dict setObject:array forKey:weeklyVisitCountKey];
+ [array release];
+ }
+
+ if (coreItem->children().size()) {
+ const HistoryItemVector& children = coreItem->children();
+ NSMutableArray *childDicts = [NSMutableArray arrayWithCapacity:children.size()];
+
+ for (int i = children.size() - 1; i >= 0; i--)
+ [childDicts addObject:[kit(children[i].get()) dictionaryRepresentation]];
+ [dict setObject: childDicts forKey:childrenKey];
+ }
+
+ return dict;
+}
+
+- (NSString *)target
+{
+ ASSERT_MAIN_THREAD();
+ return nsStringNilIfEmpty(core(_private)->target());
+}
+
+- (BOOL)isTargetItem
+{
+ return core(_private)->isTargetItem();
+}
+
+- (int)visitCount
+{
+ ASSERT_MAIN_THREAD();
+ return core(_private)->visitCount();
+}
+
+- (NSString *)RSSFeedReferrer
+{
+ return nsStringNilIfEmpty(core(_private)->referrer());
+}
+
+- (void)setRSSFeedReferrer:(NSString *)referrer
+{
+ core(_private)->setReferrer(referrer);
+}
+
+- (NSArray *)children
+{
+ ASSERT_MAIN_THREAD();
+ const HistoryItemVector& children = core(_private)->children();
+ if (!children.size())
+ return nil;
+
+ unsigned size = children.size();
+ NSMutableArray *result = [[[NSMutableArray alloc] initWithCapacity:size] autorelease];
+
+ for (unsigned i = 0; i < size; ++i)
+ [result addObject:kit(children[i].get())];
+
+ return result;
+}
+
+- (void)setAlwaysAttemptToUsePageCache:(BOOL)flag
+{
+ // Safari 2.0 uses this for SnapBack, so we stub it out to avoid a crash.
+}
+
+- (NSURL *)URL
+{
+ ASSERT_MAIN_THREAD();
+ const KURL& url = core(_private)->url();
+ if (url.isEmpty())
+ return nil;
+ return url;
+}
+
+// This should not be called directly for WebHistoryItems that are already included
+// in WebHistory. Use -[WebHistory setLastVisitedTimeInterval:forItem:] instead.
+- (void)_setLastVisitedTimeInterval:(NSTimeInterval)time
+{
+ core(_private)->setLastVisitedTime(time);
+}
+
+// FIXME: <rdar://problem/4880065> - Push Global History into WebCore
+// Once that task is complete, this accessor can go away
+- (NSCalendarDate *)_lastVisitedDate
+{
+ ASSERT_MAIN_THREAD();
+ return [[[NSCalendarDate alloc] initWithTimeIntervalSinceReferenceDate:core(_private)->lastVisitedTime()] autorelease];
+}
+
+- (WebHistoryItem *)targetItem
+{
+ ASSERT_MAIN_THREAD();
+ return kit(core(_private)->targetItem());
+}
+
++ (void)_releaseAllPendingPageCaches
+{
+ pageCache()->releaseAutoreleasedPagesNow();
+}
+
+- (id)_transientPropertyForKey:(NSString *)key
+{
+ return core(_private)->getTransientProperty(key);
+}
+
+- (void)_setTransientProperty:(id)property forKey:(NSString *)key
+{
+ core(_private)->setTransientProperty(key, property);
+}
+
+- (BOOL)lastVisitWasFailure
+{
+ return core(_private)->lastVisitWasFailure();
+}
+
+- (void)_setLastVisitWasFailure:(BOOL)failure
+{
+ core(_private)->setLastVisitWasFailure(failure);
+}
+
+- (BOOL)_lastVisitWasHTTPNonGet
+{
+ return core(_private)->lastVisitWasHTTPNonGet();
+}
+
+- (NSArray *)_redirectURLs
+{
+ Vector<String>* redirectURLs = core(_private)->redirectURLs();
+ if (!redirectURLs)
+ return nil;
+
+ size_t size = redirectURLs->size();
+ ASSERT(size);
+ NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:size];
+ for (size_t i = 0; i < size; ++i)
+ [result addObject:(NSString*)redirectURLs->at(i)];
+ return [result autorelease];
+}
+
+- (size_t)_getDailyVisitCounts:(const int**)counts
+{
+ HistoryItem* coreItem = core(_private);
+ *counts = coreItem->dailyVisitCounts().data();
+ return coreItem->dailyVisitCounts().size();
+}
+
+- (size_t)_getWeeklyVisitCounts:(const int**)counts
+{
+ HistoryItem* coreItem = core(_private);
+ *counts = coreItem->weeklyVisitCounts().data();
+ return coreItem->weeklyVisitCounts().size();
+}
+
+@end
+
+
+// FIXME: <rdar://problem/4886761>.
+// This is a bizarre policy. We flush the page caches ANY time ANY window is closed?
+
+@implementation WebWindowWatcher
+
+- (void)windowWillClose:(NSNotification *)notification
+{
+ if (!pthread_main_np()) {
+ [self performSelectorOnMainThread:_cmd withObject:notification waitUntilDone:NO];
+ return;
+ }
+
+ pageCache()->releaseAutoreleasedPagesNow();
+}
+
+@end