diff options
Diffstat (limited to 'Source/WebKit/mac/History')
| -rw-r--r-- | Source/WebKit/mac/History/WebBackForwardList.h | 190 | ||||
| -rw-r--r-- | Source/WebKit/mac/History/WebBackForwardList.mm | 321 | ||||
| -rw-r--r-- | Source/WebKit/mac/History/WebBackForwardListInternal.h | 41 | ||||
| -rw-r--r-- | Source/WebKit/mac/History/WebBackForwardListPrivate.h | 42 | ||||
| -rw-r--r-- | Source/WebKit/mac/History/WebHistory.h | 165 | ||||
| -rw-r--r-- | Source/WebKit/mac/History/WebHistory.mm | 860 | ||||
| -rw-r--r-- | Source/WebKit/mac/History/WebHistoryInternal.h | 38 | ||||
| -rw-r--r-- | Source/WebKit/mac/History/WebHistoryItem.h | 126 | ||||
| -rw-r--r-- | Source/WebKit/mac/History/WebHistoryItem.mm | 659 | ||||
| -rw-r--r-- | Source/WebKit/mac/History/WebHistoryItemInternal.h | 61 | ||||
| -rw-r--r-- | Source/WebKit/mac/History/WebHistoryItemPrivate.h | 67 | ||||
| -rw-r--r-- | Source/WebKit/mac/History/WebHistoryPrivate.h | 58 | ||||
| -rw-r--r-- | Source/WebKit/mac/History/WebURLsWithTitles.h | 55 | ||||
| -rw-r--r-- | Source/WebKit/mac/History/WebURLsWithTitles.m | 107 |
14 files changed, 2790 insertions, 0 deletions
diff --git a/Source/WebKit/mac/History/WebBackForwardList.h b/Source/WebKit/mac/History/WebBackForwardList.h new file mode 100644 index 0000000..9806a64 --- /dev/null +++ b/Source/WebKit/mac/History/WebBackForwardList.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2003 Apple Computer, 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 <Foundation/Foundation.h> + +#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 +#define WebNSUInteger unsigned int +#else +#define WebNSUInteger NSUInteger +#endif + +@class WebHistoryItem; +@class WebBackForwardListPrivate; + +/*! + @class WebBackForwardList + WebBackForwardList holds an ordered list of WebHistoryItems that comprises the back and + forward lists. + + Note that the methods which modify instances of this class do not cause + navigation to happen in other layers of the stack; they are only for maintaining this data + structure. +*/ +@interface WebBackForwardList : NSObject { +@private + WebBackForwardListPrivate *_private; +} + +/*! + @method addItem: + @abstract Adds an entry to the list. + @param entry The entry to add. + @discussion The added entry is inserted immediately after the current entry. + If the current position in the list is not at the end of the list, elements in the + forward list will be dropped at this point. In addition, entries may be dropped to keep + the size of the list within the maximum size. +*/ +- (void)addItem:(WebHistoryItem *)item; + +/*! + @method goBack + @abstract Move the current pointer back to the entry before the current entry. +*/ +- (void)goBack; + +/*! + @method goForward + @abstract Move the current pointer ahead to the entry after the current entry. +*/ +- (void)goForward; + +/*! + @method goToItem: + @abstract Move the current pointer to the given entry. + @param item The history item to move the pointer to +*/ +- (void)goToItem:(WebHistoryItem *)item; + +/*! + @method backItem + @abstract Returns the entry right before the current entry. + @result The entry right before the current entry, or nil if there isn't one. +*/ +- (WebHistoryItem *)backItem; + +/*! + @method currentItem + @abstract Returns the current entry. + @result The current entry. +*/ +- (WebHistoryItem *)currentItem; + +/*! + @method forwardItem + @abstract Returns the entry right after the current entry. + @result The entry right after the current entry, or nil if there isn't one. +*/ +- (WebHistoryItem *)forwardItem; + +/*! + @method backListWithLimit: + @abstract Returns a portion of the list before the current entry. + @param limit A cap on the size of the array returned. + @result An array of items before the current entry, or nil if there are none. The entries are in the order that they were originally visited. +*/ +- (NSArray *)backListWithLimit:(int)limit; + +/*! + @method forwardListWithLimit: + @abstract Returns a portion of the list after the current entry. + @param limit A cap on the size of the array returned. + @result An array of items after the current entry, or nil if there are none. The entries are in the order that they were originally visited. +*/ +- (NSArray *)forwardListWithLimit:(int)limit; + +/*! + @method capacity + @abstract Returns the list's maximum size. + @result The list's maximum size. +*/ +- (int)capacity; + +/*! + @method setCapacity + @abstract Sets the list's maximum size. + @param size The new maximum size for the list. +*/ +- (void)setCapacity:(int)size; + +/*! + @method backListCount + @abstract Returns the back list's current count. + @result The number of items in the list. +*/ +- (int)backListCount; + +/*! + @method forwardListCount + @abstract Returns the forward list's current count. + @result The number of items in the list. +*/ +- (int)forwardListCount; + +/*! + @method containsItem: + @param item The item that will be checked for presence in the WebBackForwardList. + @result Returns YES if the item is in the list. +*/ +- (BOOL)containsItem:(WebHistoryItem *)item; + +/*! + @method itemAtIndex: + @abstract Returns an entry the given distance from the current entry. + @param index Index of the desired list item relative to the current item; 0 is current item, -1 is back item, 1 is forward item, etc. + @result The entry the given distance from the current entry. If index exceeds the limits of the list, nil is returned. +*/ +- (WebHistoryItem *)itemAtIndex:(int)index; + +@end + +@interface WebBackForwardList(WebBackForwardListDeprecated) + +// The following methods are deprecated, and exist for backward compatibility only. +// Use -[WebPreferences setUsesPageCache] and -[WebPreferences usesPageCache] +// instead. + +/*! + @method setPageCacheSize: + @abstract The size passed to this method determines whether the WebView + associated with this WebBackForwardList will use the shared page cache. + @param size If size is 0, the WebView associated with this WebBackForwardList + will not use the shared page cache. Otherwise, it will. +*/ +- (void)setPageCacheSize:(WebNSUInteger)size; + +/*! + @method pageCacheSize + @abstract Returns the size of the shared page cache, or 0. + @result The size of the shared page cache (in pages), or 0 if the WebView + associated with this WebBackForwardList will not use the shared page cache. +*/ +- (WebNSUInteger)pageCacheSize; +@end + +#undef WebNSUInteger diff --git a/Source/WebKit/mac/History/WebBackForwardList.mm b/Source/WebKit/mac/History/WebBackForwardList.mm new file mode 100644 index 0000000..e794c2f --- /dev/null +++ b/Source/WebKit/mac/History/WebBackForwardList.mm @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2005, 2007 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 "WebBackForwardList.h" +#import "WebBackForwardListInternal.h" + +#import "WebFrameInternal.h" +#import "WebHistoryItemInternal.h" +#import "WebHistoryItemPrivate.h" +#import "WebKitLogging.h" +#import "WebKitVersionChecks.h" +#import "WebNSObjectExtras.h" +#import "WebPreferencesPrivate.h" +#import "WebTypesInternal.h" +#import "WebViewPrivate.h" +#import <WebCore/BackForwardListImpl.h> +#import <WebCore/HistoryItem.h> +#import <WebCore/Page.h> +#import <WebCore/PageCache.h> +#import <WebCore/Settings.h> +#import <WebCore/ThreadCheck.h> +#import <WebCore/WebCoreObjCExtras.h> +#import <runtime/InitializeThreading.h> +#import <wtf/Assertions.h> +#import <wtf/RetainPtr.h> +#import <wtf/StdLibExtras.h> +#import <wtf/Threading.h> + +using namespace WebCore; + +typedef HashMap<BackForwardListImpl*, WebBackForwardList*> BackForwardListMap; + +// FIXME: Instead of this we could just create a class derived from BackForwardListImpl +// with a pointer to a WebBackForwardList in it. +static BackForwardListMap& backForwardLists() +{ + DEFINE_STATIC_LOCAL(BackForwardListMap, staticBackForwardLists, ()); + return staticBackForwardLists; +} + +@implementation WebBackForwardList (WebBackForwardListInternal) + +BackForwardListImpl* core(WebBackForwardList *webBackForwardList) +{ + if (!webBackForwardList) + return 0; + + return reinterpret_cast<BackForwardListImpl*>(webBackForwardList->_private); +} + +WebBackForwardList *kit(BackForwardListImpl* backForwardList) +{ + if (!backForwardList) + return nil; + + if (WebBackForwardList *webBackForwardList = backForwardLists().get(backForwardList)) + return webBackForwardList; + + return [[[WebBackForwardList alloc] initWithBackForwardList:backForwardList] autorelease]; +} + +- (id)initWithBackForwardList:(PassRefPtr<BackForwardListImpl>)backForwardList +{ + WebCoreThreadViolationCheckRoundOne(); + self = [super init]; + if (!self) + return nil; + + _private = reinterpret_cast<WebBackForwardListPrivate*>(backForwardList.releaseRef()); + backForwardLists().set(core(self), self); + return self; +} + +@end + +@implementation WebBackForwardList + ++ (void)initialize +{ + JSC::initializeThreading(); + WTF::initializeMainThreadToProcessMainThread(); +#ifndef BUILDING_ON_TIGER + WebCoreObjCFinalizeOnMainThread(self); +#endif +} + +- (id)init +{ + return [self initWithBackForwardList:BackForwardListImpl::create(0)]; +} + +- (void)dealloc +{ + if (WebCoreObjCScheduleDeallocateOnMainThread([WebBackForwardList class], self)) + return; + + BackForwardListImpl* backForwardList = core(self); + ASSERT(backForwardList); + if (backForwardList) { + ASSERT(backForwardList->closed()); + backForwardLists().remove(backForwardList); + backForwardList->deref(); + } + + [super dealloc]; +} + +- (void)finalize +{ + WebCoreThreadViolationCheckRoundOne(); + BackForwardListImpl* backForwardList = core(self); + ASSERT(backForwardList); + if (backForwardList) { + ASSERT(backForwardList->closed()); + backForwardLists().remove(backForwardList); + backForwardList->deref(); + } + + [super finalize]; +} + +- (void)_close +{ + core(self)->close(); +} + +- (void)addItem:(WebHistoryItem *)entry +{ + core(self)->addItem(core(entry)); + + // Since the assumed contract with WebBackForwardList is that it retains its WebHistoryItems, + // the following line prevents a whole class of problems where a history item will be created in + // a function, added to the BFlist, then used in the rest of that function. + [[entry retain] autorelease]; +} + +- (void)removeItem:(WebHistoryItem *)item +{ + core(self)->removeItem(core(item)); +} + +- (BOOL)containsItem:(WebHistoryItem *)item +{ + return core(self)->containsItem(core(item)); +} + +- (void)goBack +{ + core(self)->goBack(); +} + +- (void)goForward +{ + core(self)->goForward(); +} + +- (void)goToItem:(WebHistoryItem *)item +{ + core(self)->goToItem(core(item)); +} + +- (WebHistoryItem *)backItem +{ + return [[kit(core(self)->backItem()) retain] autorelease]; +} + +- (WebHistoryItem *)currentItem +{ + return [[kit(core(self)->currentItem()) retain] autorelease]; +} + +- (WebHistoryItem *)forwardItem +{ + return [[kit(core(self)->forwardItem()) retain] autorelease]; +} + +static NSArray* vectorToNSArray(HistoryItemVector& list) +{ + unsigned size = list.size(); + NSMutableArray *result = [[[NSMutableArray alloc] initWithCapacity:size] autorelease]; + for (unsigned i = 0; i < size; ++i) + [result addObject:kit(list[i].get())]; + + return result; +} + +static bool bumperCarBackForwardHackNeeded() +{ + static bool hackNeeded = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.freeverse.bumpercar"] && + !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_BUMPERCAR_BACK_FORWARD_QUIRK); + + return hackNeeded; +} + +- (NSArray *)backListWithLimit:(int)limit +{ + HistoryItemVector list; + core(self)->backListWithLimit(limit, list); + NSArray *result = vectorToNSArray(list); + + if (bumperCarBackForwardHackNeeded()) { + static NSArray *lastBackListArray = nil; + [lastBackListArray release]; + lastBackListArray = [result retain]; + } + + return result; +} + +- (NSArray *)forwardListWithLimit:(int)limit +{ + HistoryItemVector list; + core(self)->forwardListWithLimit(limit, list); + NSArray *result = vectorToNSArray(list); + + if (bumperCarBackForwardHackNeeded()) { + static NSArray *lastForwardListArray = nil; + [lastForwardListArray release]; + lastForwardListArray = [result retain]; + } + + return result; +} + +- (int)capacity +{ + return core(self)->capacity(); +} + +- (void)setCapacity:(int)size +{ + core(self)->setCapacity(size); +} + + +-(NSString *)description +{ + NSMutableString *result; + + result = [NSMutableString stringWithCapacity:512]; + + [result appendString:@"\n--------------------------------------------\n"]; + [result appendString:@"WebBackForwardList:\n"]; + + BackForwardListImpl* backForwardList = core(self); + HistoryItemVector& entries = backForwardList->entries(); + + unsigned size = entries.size(); + for (unsigned i = 0; i < size; ++i) { + if (entries[i] == backForwardList->currentItem()) { + [result appendString:@" >>>"]; + } else { + [result appendString:@" "]; + } + [result appendFormat:@"%2d) ", i]; + int currPos = [result length]; + [result appendString:[kit(entries[i].get()) description]]; + + // shift all the contents over. a bit slow, but this is for debugging + NSRange replRange = {currPos, [result length]-currPos}; + [result replaceOccurrencesOfString:@"\n" withString:@"\n " options:0 range:replRange]; + + [result appendString:@"\n"]; + } + + [result appendString:@"\n--------------------------------------------\n"]; + + return result; +} + +- (void)setPageCacheSize:(NSUInteger)size +{ + [kit(core(self)->page()) setUsesPageCache:size != 0]; +} + +- (NSUInteger)pageCacheSize +{ + return [kit(core(self)->page()) usesPageCache] ? pageCache()->capacity() : 0; +} + +- (int)backListCount +{ + return core(self)->backListCount(); +} + +- (int)forwardListCount +{ + return core(self)->forwardListCount(); +} + +- (WebHistoryItem *)itemAtIndex:(int)index +{ + return [[kit(core(self)->itemAtIndex(index)) retain] autorelease]; +} + +@end diff --git a/Source/WebKit/mac/History/WebBackForwardListInternal.h b/Source/WebKit/mac/History/WebBackForwardListInternal.h new file mode 100644 index 0000000..1afb833 --- /dev/null +++ b/Source/WebKit/mac/History/WebBackForwardListInternal.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2006, 2007 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 <WebKit/WebBackForwardList.h> +#import <wtf/PassRefPtr.h> + +namespace WebCore { + class BackForwardListImpl; +} + +WebCore::BackForwardListImpl* core(WebBackForwardList *); +WebBackForwardList *kit(WebCore::BackForwardListImpl*); + +@interface WebBackForwardList (WebBackForwardListInternal) +- (id)initWithBackForwardList:(PassRefPtr<WebCore::BackForwardListImpl>)backForwardList; +@end diff --git a/Source/WebKit/mac/History/WebBackForwardListPrivate.h b/Source/WebKit/mac/History/WebBackForwardListPrivate.h new file mode 100644 index 0000000..7e76e9b --- /dev/null +++ b/Source/WebKit/mac/History/WebBackForwardListPrivate.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2005 Apple Computer, 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 <Cocoa/Cocoa.h> + +#import <WebKit/WebBackForwardList.h> + +@interface WebBackForwardList (WebBackForwardListPrivate) + +/*! + @method removeItem: + @abstract Removes an entry from the list. + @param entry The entry to remove. Cannot be the current item. +*/ +- (void)removeItem:(WebHistoryItem *)item; + +@end diff --git a/Source/WebKit/mac/History/WebHistory.h b/Source/WebKit/mac/History/WebHistory.h new file mode 100644 index 0000000..8a6ec0b --- /dev/null +++ b/Source/WebKit/mac/History/WebHistory.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2003, 2004 Apple Computer, 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 <Foundation/Foundation.h> + +@class NSError; + +@class WebHistoryItem; +@class WebHistoryPrivate; + +/* + @discussion Notifications sent when history is modified. + @constant WebHistoryItemsAddedNotification Posted from addItems:. This + notification comes with a userInfo dictionary that contains the array of + items added. The key for the array is WebHistoryItemsKey. + @constant WebHistoryItemsRemovedNotification Posted from removeItems:. + This notification comes with a userInfo dictionary that contains the array of + items removed. The key for the array is WebHistoryItemsKey. + @constant WebHistoryAllItemsRemovedNotification Posted from removeAllItems + @constant WebHistoryLoadedNotification Posted from loadFromURL:error:. +*/ +extern NSString *WebHistoryItemsAddedNotification; +extern NSString *WebHistoryItemsRemovedNotification; +extern NSString *WebHistoryAllItemsRemovedNotification; +extern NSString *WebHistoryLoadedNotification; +extern NSString *WebHistorySavedNotification; + +extern NSString *WebHistoryItemsKey; + +/*! + @class WebHistory + @discussion WebHistory is used to track pages that have been loaded + by WebKit. +*/ +@interface WebHistory : NSObject { +@private + WebHistoryPrivate *_historyPrivate; +} + +/*! + @method optionalSharedHistory + @abstract Returns a shared WebHistory instance initialized with the default history file. + @result A WebHistory object. +*/ ++ (WebHistory *)optionalSharedHistory; + +/*! + @method setOptionalSharedHistory: + @param history The history to use for the global WebHistory. +*/ ++ (void)setOptionalSharedHistory:(WebHistory *)history; + +/*! + @method loadFromURL:error: + @param URL The URL to use to initialize the WebHistory. + @param error Set to nil or an NSError instance if an error occurred. + @abstract The designated initializer for WebHistory. + @result Returns YES if successful, NO otherwise. +*/ +- (BOOL)loadFromURL:(NSURL *)URL error:(NSError **)error; + +/*! + @method saveToURL:error: + @discussion Save history to URL. It is the client's responsibility to call this at appropriate times. + @param URL The URL to use to save the WebHistory. + @param error Set to nil or an NSError instance if an error occurred. + @result Returns YES if successful, NO otherwise. +*/ +- (BOOL)saveToURL:(NSURL *)URL error:(NSError **)error; + +/*! + @method addItems: + @param newItems An array of WebHistoryItems to add to the WebHistory. +*/ +- (void)addItems:(NSArray *)newItems; + +/*! + @method removeItems: + @param items An array of WebHistoryItems to remove from the WebHistory. +*/ +- (void)removeItems:(NSArray *)items; + +/*! + @method removeAllItems +*/ +- (void)removeAllItems; + +/*! + @method orderedLastVisitedDays + @discussion Get an array of NSCalendarDates, each one representing a unique day that contains one + or more history items, ordered from most recent to oldest. + @result Returns an array of NSCalendarDates for which history items exist in the WebHistory. +*/ +- (NSArray *)orderedLastVisitedDays; + +/*! + @method orderedItemsLastVisitedOnDay: + @discussion Get an array of WebHistoryItem that were last visited on the day represented by the + specified NSCalendarDate, ordered from most recent to oldest. + @param calendarDate A date identifying the unique day of interest. + @result Returns an array of WebHistoryItems last visited on the indicated day. +*/ +- (NSArray *)orderedItemsLastVisitedOnDay:(NSCalendarDate *)calendarDate; + +/*! + @method itemForURL: + @abstract Get an item for a specific URL + @param URL The URL of the history item to search for + @result Returns an item matching the URL +*/ +- (WebHistoryItem *)itemForURL:(NSURL *)URL; + +/*! + @method setHistoryItemLimit: + @discussion Limits the number of items that will be stored by the WebHistory. + @param limit The maximum number of items that will be stored by the WebHistory. +*/ +- (void)setHistoryItemLimit:(int)limit; + +/*! + @method historyItemLimit + @result The maximum number of items that will be stored by the WebHistory. +*/ +- (int)historyItemLimit; + +/*! + @method setHistoryAgeInDaysLimit: + @discussion setHistoryAgeInDaysLimit: sets the maximum number of days to be read from + stored history. + @param limit The maximum number of days to be read from stored history. +*/ +- (void)setHistoryAgeInDaysLimit:(int)limit; + +/*! + @method historyAgeInDaysLimit + @return Returns the maximum number of days to be read from stored history. +*/ +- (int)historyAgeInDaysLimit; + +@end diff --git a/Source/WebKit/mac/History/WebHistory.mm b/Source/WebKit/mac/History/WebHistory.mm new file mode 100644 index 0000000..00cee78 --- /dev/null +++ b/Source/WebKit/mac/History/WebHistory.mm @@ -0,0 +1,860 @@ +/* + * Copyright (C) 2005, 2008, 2009 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 "WebHistoryInternal.h" + +#import "WebHistoryItemInternal.h" +#import "WebKitLogging.h" +#import "WebNSURLExtras.h" +#import "WebTypesInternal.h" +#import <WebCore/HistoryItem.h> +#import <WebCore/HistoryPropertyList.h> +#import <WebCore/PageGroup.h> + +using namespace WebCore; +using namespace std; + +typedef int64_t WebHistoryDateKey; +typedef HashMap<WebHistoryDateKey, RetainPtr<NSMutableArray> > DateToEntriesMap; + +NSString *WebHistoryItemsAddedNotification = @"WebHistoryItemsAddedNotification"; +NSString *WebHistoryItemsRemovedNotification = @"WebHistoryItemsRemovedNotification"; +NSString *WebHistoryAllItemsRemovedNotification = @"WebHistoryAllItemsRemovedNotification"; +NSString *WebHistoryLoadedNotification = @"WebHistoryLoadedNotification"; +NSString *WebHistoryItemsDiscardedWhileLoadingNotification = @"WebHistoryItemsDiscardedWhileLoadingNotification"; +NSString *WebHistorySavedNotification = @"WebHistorySavedNotification"; +NSString *WebHistoryItemsKey = @"WebHistoryItems"; + +static WebHistory *_sharedHistory = nil; + +NSString *FileVersionKey = @"WebHistoryFileVersion"; +NSString *DatesArrayKey = @"WebHistoryDates"; + +#define currentFileVersion 1 + +class WebHistoryWriter : public HistoryPropertyListWriter { +public: + WebHistoryWriter(DateToEntriesMap*); + +private: + virtual void writeHistoryItems(BinaryPropertyListObjectStream&); + + DateToEntriesMap* m_entriesByDate; + Vector<int> m_dateKeys; +}; + +@interface WebHistoryPrivate : NSObject { +@private + NSMutableDictionary *_entriesByURL; + DateToEntriesMap* _entriesByDate; + NSMutableArray *_orderedLastVisitedDays; + BOOL itemLimitSet; + int itemLimit; + BOOL ageInDaysLimitSet; + int ageInDaysLimit; +} + +- (WebHistoryItem *)visitedURL:(NSURL *)url withTitle:(NSString *)title increaseVisitCount:(BOOL)increaseVisitCount; + +- (BOOL)addItem:(WebHistoryItem *)entry discardDuplicate:(BOOL)discardDuplicate; +- (void)addItems:(NSArray *)newEntries; +- (BOOL)removeItem:(WebHistoryItem *)entry; +- (BOOL)removeItems:(NSArray *)entries; +- (BOOL)removeAllItems; + +- (NSArray *)orderedLastVisitedDays; +- (NSArray *)orderedItemsLastVisitedOnDay:(NSCalendarDate *)calendarDate; +- (BOOL)containsURL:(NSURL *)URL; +- (WebHistoryItem *)itemForURL:(NSURL *)URL; +- (WebHistoryItem *)itemForURLString:(NSString *)URLString; +- (NSArray *)allItems; + +- (BOOL)loadFromURL:(NSURL *)URL collectDiscardedItemsInto:(NSMutableArray *)discardedItems error:(NSError **)error; +- (BOOL)saveToURL:(NSURL *)URL error:(NSError **)error; + +- (NSCalendarDate *)ageLimitDate; + +- (void)setHistoryItemLimit:(int)limit; +- (int)historyItemLimit; +- (void)setHistoryAgeInDaysLimit:(int)limit; +- (int)historyAgeInDaysLimit; + +- (void)addVisitedLinksToPageGroup:(PageGroup&)group; + +@end + +@implementation WebHistoryPrivate + +// MARK: OBJECT FRAMEWORK + ++ (void)initialize +{ + [[NSUserDefaults standardUserDefaults] registerDefaults: + [NSDictionary dictionaryWithObjectsAndKeys: + @"1000", @"WebKitHistoryItemLimit", + @"7", @"WebKitHistoryAgeInDaysLimit", + nil]]; +} + +- (id)init +{ + if (![super init]) + return nil; + + _entriesByURL = [[NSMutableDictionary alloc] init]; + _entriesByDate = new DateToEntriesMap; + + return self; +} + +- (void)dealloc +{ + [_entriesByURL release]; + [_orderedLastVisitedDays release]; + delete _entriesByDate; + [super dealloc]; +} + +- (void)finalize +{ + delete _entriesByDate; + [super finalize]; +} + +// MARK: MODIFYING CONTENTS + +static void getDayBoundaries(NSTimeInterval interval, NSTimeInterval& beginningOfDay, NSTimeInterval& beginningOfNextDay) +{ + CFTimeZoneRef timeZone = CFTimeZoneCopyDefault(); + CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(interval, timeZone); + date.hour = 0; + date.minute = 0; + date.second = 0; + beginningOfDay = CFGregorianDateGetAbsoluteTime(date, timeZone); + date.day += 1; + beginningOfNextDay = CFGregorianDateGetAbsoluteTime(date, timeZone); + CFRelease(timeZone); +} + +static inline NSTimeInterval beginningOfDay(NSTimeInterval date) +{ + static NSTimeInterval cachedBeginningOfDay = NAN; + static NSTimeInterval cachedBeginningOfNextDay; + if (!(date >= cachedBeginningOfDay && date < cachedBeginningOfNextDay)) + getDayBoundaries(date, cachedBeginningOfDay, cachedBeginningOfNextDay); + return cachedBeginningOfDay; +} + +static inline WebHistoryDateKey dateKey(NSTimeInterval date) +{ + // Converting from double (NSTimeInterval) to int64_t (WebHistoryDateKey) is + // safe here because all sensible dates are in the range -2**48 .. 2**47 which + // safely fits in an int64_t. + return beginningOfDay(date); +} + +// Returns whether the day is already in the list of days, +// and fills in *key with the key used to access its location +- (BOOL)findKey:(WebHistoryDateKey*)key forDay:(NSTimeInterval)date +{ + ASSERT_ARG(key, key); + *key = dateKey(date); + return _entriesByDate->contains(*key); +} + +- (void)insertItem:(WebHistoryItem *)entry forDateKey:(WebHistoryDateKey)dateKey +{ + ASSERT_ARG(entry, entry != nil); + ASSERT(_entriesByDate->contains(dateKey)); + + NSMutableArray *entriesForDate = _entriesByDate->get(dateKey).get(); + NSTimeInterval entryDate = [entry lastVisitedTimeInterval]; + + unsigned count = [entriesForDate count]; + + // The entries for each day are stored in a sorted array with the most recent entry first + // Check for the common cases of the entry being newer than all existing entries or the first entry of the day + if (!count || [[entriesForDate objectAtIndex:0] lastVisitedTimeInterval] < entryDate) { + [entriesForDate insertObject:entry atIndex:0]; + return; + } + // .. or older than all existing entries + if (count > 0 && [[entriesForDate objectAtIndex:count - 1] lastVisitedTimeInterval] >= entryDate) { + [entriesForDate insertObject:entry atIndex:count]; + return; + } + + unsigned low = 0; + unsigned high = count; + while (low < high) { + unsigned mid = low + (high - low) / 2; + if ([[entriesForDate objectAtIndex:mid] lastVisitedTimeInterval] >= entryDate) + low = mid + 1; + else + high = mid; + } + + // low is now the index of the first entry that is older than entryDate + [entriesForDate insertObject:entry atIndex:low]; +} + +- (BOOL)removeItemFromDateCaches:(WebHistoryItem *)entry +{ + WebHistoryDateKey dateKey; + BOOL foundDate = [self findKey:&dateKey forDay:[entry lastVisitedTimeInterval]]; + + if (!foundDate) + return NO; + + DateToEntriesMap::iterator it = _entriesByDate->find(dateKey); + NSMutableArray *entriesForDate = it->second.get(); + [entriesForDate removeObjectIdenticalTo:entry]; + + // remove this date entirely if there are no other entries on it + if ([entriesForDate count] == 0) { + _entriesByDate->remove(it); + // Clear _orderedLastVisitedDays so it will be regenerated when next requested. + [_orderedLastVisitedDays release]; + _orderedLastVisitedDays = nil; + } + + return YES; +} + +- (BOOL)removeItemForURLString:(NSString *)URLString +{ + WebHistoryItem *entry = [_entriesByURL objectForKey:URLString]; + if (!entry) + return NO; + + [_entriesByURL removeObjectForKey:URLString]; + +#if ASSERT_DISABLED + [self removeItemFromDateCaches:entry]; +#else + BOOL itemWasInDateCaches = [self removeItemFromDateCaches:entry]; + ASSERT(itemWasInDateCaches); +#endif + + if (![_entriesByURL count]) + PageGroup::removeAllVisitedLinks(); + + return YES; +} + +- (void)addItemToDateCaches:(WebHistoryItem *)entry +{ + WebHistoryDateKey dateKey; + if ([self findKey:&dateKey forDay:[entry lastVisitedTimeInterval]]) + // other entries already exist for this date + [self insertItem:entry forDateKey:dateKey]; + else { + // no other entries exist for this date + NSMutableArray *entries = [[NSMutableArray alloc] initWithObjects:&entry count:1]; + _entriesByDate->set(dateKey, entries); + [entries release]; + // Clear _orderedLastVisitedDays so it will be regenerated when next requested. + [_orderedLastVisitedDays release]; + _orderedLastVisitedDays = nil; + } +} + +- (WebHistoryItem *)visitedURL:(NSURL *)url withTitle:(NSString *)title increaseVisitCount:(BOOL)increaseVisitCount +{ + ASSERT(url); + ASSERT(title); + + NSString *URLString = [url _web_originalDataAsString]; + WebHistoryItem *entry = [_entriesByURL objectForKey:URLString]; + + if (entry) { + LOG(History, "Updating global history entry %@", entry); + // Remove the item from date caches before changing its last visited date. Otherwise we might get duplicate entries + // as seen in <rdar://problem/6570573>. + BOOL itemWasInDateCaches = [self removeItemFromDateCaches:entry]; + ASSERT_UNUSED(itemWasInDateCaches, itemWasInDateCaches); + + [entry _visitedWithTitle:title increaseVisitCount:increaseVisitCount]; + } else { + LOG(History, "Adding new global history entry for %@", url); + entry = [[WebHistoryItem alloc] initWithURLString:URLString title:title lastVisitedTimeInterval:[NSDate timeIntervalSinceReferenceDate]]; + [entry _recordInitialVisit]; + [_entriesByURL setObject:entry forKey:URLString]; + [entry release]; + } + + [self addItemToDateCaches:entry]; + + return entry; +} + +- (BOOL)addItem:(WebHistoryItem *)entry discardDuplicate:(BOOL)discardDuplicate +{ + ASSERT_ARG(entry, entry); + ASSERT_ARG(entry, [entry lastVisitedTimeInterval] != 0); + + NSString *URLString = [entry URLString]; + + WebHistoryItem *oldEntry = [_entriesByURL objectForKey:URLString]; + if (oldEntry) { + if (discardDuplicate) + return NO; + + // The last reference to oldEntry might be this dictionary, so we hold onto a reference + // until we're done with oldEntry. + [oldEntry retain]; + [self removeItemForURLString:URLString]; + + // If we already have an item with this URL, we need to merge info that drives the + // URL autocomplete heuristics from that item into the new one. + [entry _mergeAutoCompleteHints:oldEntry]; + [oldEntry release]; + } + + [self addItemToDateCaches:entry]; + [_entriesByURL setObject:entry forKey:URLString]; + + return YES; +} + +- (BOOL)removeItem:(WebHistoryItem *)entry +{ + NSString *URLString = [entry URLString]; + + // If this exact object isn't stored, then make no change. + // FIXME: Is this the right behavior if this entry isn't present, but another entry for the same URL is? + // Maybe need to change the API to make something like removeEntryForURLString public instead. + WebHistoryItem *matchingEntry = [_entriesByURL objectForKey:URLString]; + if (matchingEntry != entry) + return NO; + + [self removeItemForURLString:URLString]; + + return YES; +} + +- (BOOL)removeItems:(NSArray *)entries +{ + NSUInteger count = [entries count]; + if (!count) + return NO; + + for (NSUInteger index = 0; index < count; ++index) + [self removeItem:[entries objectAtIndex:index]]; + + return YES; +} + +- (BOOL)removeAllItems +{ + if (_entriesByDate->isEmpty()) + return NO; + + _entriesByDate->clear(); + [_entriesByURL removeAllObjects]; + + // Clear _orderedLastVisitedDays so it will be regenerated when next requested. + [_orderedLastVisitedDays release]; + _orderedLastVisitedDays = nil; + + PageGroup::removeAllVisitedLinks(); + + return YES; +} + +- (void)addItems:(NSArray *)newEntries +{ + // There is no guarantee that the incoming entries are in any particular + // order, but if this is called with a set of entries that were created by + // iterating through the results of orderedLastVisitedDays and orderedItemsLastVisitedOnDayy + // then they will be ordered chronologically from newest to oldest. We can make adding them + // faster (fewer compares) by inserting them from oldest to newest. + NSEnumerator *enumerator = [newEntries reverseObjectEnumerator]; + while (WebHistoryItem *entry = [enumerator nextObject]) + [self addItem:entry discardDuplicate:NO]; +} + +// MARK: DATE-BASED RETRIEVAL + +- (NSArray *)orderedLastVisitedDays +{ + if (!_orderedLastVisitedDays) { + Vector<int> daysAsTimeIntervals; + daysAsTimeIntervals.reserveCapacity(_entriesByDate->size()); + DateToEntriesMap::const_iterator end = _entriesByDate->end(); + for (DateToEntriesMap::const_iterator it = _entriesByDate->begin(); it != end; ++it) + daysAsTimeIntervals.append(it->first); + + sort(daysAsTimeIntervals.begin(), daysAsTimeIntervals.end()); + size_t count = daysAsTimeIntervals.size(); + _orderedLastVisitedDays = [[NSMutableArray alloc] initWithCapacity:count]; + for (int i = count - 1; i >= 0; i--) { + NSTimeInterval interval = daysAsTimeIntervals[i]; + NSCalendarDate *date = [[NSCalendarDate alloc] initWithTimeIntervalSinceReferenceDate:interval]; + [_orderedLastVisitedDays addObject:date]; + [date release]; + } + } + return _orderedLastVisitedDays; +} + +- (NSArray *)orderedItemsLastVisitedOnDay:(NSCalendarDate *)date +{ + WebHistoryDateKey dateKey; + if (![self findKey:&dateKey forDay:[date timeIntervalSinceReferenceDate]]) + return nil; + return _entriesByDate->get(dateKey).get(); +} + +// MARK: URL MATCHING + +- (WebHistoryItem *)itemForURLString:(NSString *)URLString +{ + return [_entriesByURL objectForKey:URLString]; +} + +- (BOOL)containsURL:(NSURL *)URL +{ + return [self itemForURLString:[URL _web_originalDataAsString]] != nil; +} + +- (WebHistoryItem *)itemForURL:(NSURL *)URL +{ + return [self itemForURLString:[URL _web_originalDataAsString]]; +} + +- (NSArray *)allItems +{ + return [_entriesByURL allValues]; +} + +// MARK: ARCHIVING/UNARCHIVING + +- (void)setHistoryAgeInDaysLimit:(int)limit +{ + ageInDaysLimitSet = YES; + ageInDaysLimit = limit; +} + +- (int)historyAgeInDaysLimit +{ + if (ageInDaysLimitSet) + return ageInDaysLimit; + return [[NSUserDefaults standardUserDefaults] integerForKey:@"WebKitHistoryAgeInDaysLimit"]; +} + +- (void)setHistoryItemLimit:(int)limit +{ + itemLimitSet = YES; + itemLimit = limit; +} + +- (int)historyItemLimit +{ + if (itemLimitSet) + return itemLimit; + return [[NSUserDefaults standardUserDefaults] integerForKey:@"WebKitHistoryItemLimit"]; +} + +// Return a date that marks the age limit for history entries saved to or +// loaded from disk. Any entry older than this item should be rejected. +- (NSCalendarDate *)ageLimitDate +{ + return [[NSCalendarDate calendarDate] dateByAddingYears:0 months:0 days:-[self historyAgeInDaysLimit] + hours:0 minutes:0 seconds:0]; +} + +- (BOOL)loadHistoryGutsFromURL:(NSURL *)URL savedItemsCount:(int *)numberOfItemsLoaded collectDiscardedItemsInto:(NSMutableArray *)discardedItems error:(NSError **)error +{ + *numberOfItemsLoaded = 0; + NSDictionary *dictionary = nil; + + // Optimize loading from local file, which is faster than using the general URL loading mechanism + if ([URL isFileURL]) { + dictionary = [NSDictionary dictionaryWithContentsOfFile:[URL path]]; + if (!dictionary) { +#if !LOG_DISABLED + if ([[NSFileManager defaultManager] fileExistsAtPath:[URL path]]) + LOG_ERROR("unable to read history from file %@; perhaps contents are corrupted", [URL path]); +#endif + // else file doesn't exist, which is normal the first time + return NO; + } + } else { + NSData *data = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:URL] returningResponse:nil error:error]; + if (data && [data length] > 0) { + dictionary = [NSPropertyListSerialization propertyListFromData:data + mutabilityOption:NSPropertyListImmutable + format:nil + errorDescription:nil]; + } + } + + // We used to support NSArrays here, but that was before Safari 1.0 shipped. We will no longer support + // that ancient format, so anything that isn't an NSDictionary is bogus. + if (![dictionary isKindOfClass:[NSDictionary class]]) + return NO; + + NSNumber *fileVersionObject = [dictionary objectForKey:FileVersionKey]; + int fileVersion; + // we don't trust data obtained from elsewhere, so double-check + if (!fileVersionObject || ![fileVersionObject isKindOfClass:[NSNumber class]]) { + LOG_ERROR("history file version can't be determined, therefore not loading"); + return NO; + } + fileVersion = [fileVersionObject intValue]; + if (fileVersion > currentFileVersion) { + LOG_ERROR("history file version is %d, newer than newest known version %d, therefore not loading", fileVersion, currentFileVersion); + return NO; + } + + NSArray *array = [dictionary objectForKey:DatesArrayKey]; + + int itemCountLimit = [self historyItemLimit]; + NSTimeInterval ageLimitDate = [[self ageLimitDate] timeIntervalSinceReferenceDate]; + NSEnumerator *enumerator = [array objectEnumerator]; + BOOL ageLimitPassed = NO; + BOOL itemLimitPassed = NO; + ASSERT(*numberOfItemsLoaded == 0); + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSDictionary *itemAsDictionary; + while ((itemAsDictionary = [enumerator nextObject]) != nil) { + WebHistoryItem *item = [[WebHistoryItem alloc] initFromDictionaryRepresentation:itemAsDictionary]; + + // item without URL is useless; data on disk must have been bad; ignore + if ([item URLString]) { + // Test against date limit. Since the items are ordered newest to oldest, we can stop comparing + // once we've found the first item that's too old. + if (!ageLimitPassed && [item lastVisitedTimeInterval] <= ageLimitDate) + ageLimitPassed = YES; + + if (ageLimitPassed || itemLimitPassed) + [discardedItems addObject:item]; + else { + if ([self addItem:item discardDuplicate:YES]) + ++(*numberOfItemsLoaded); + if (*numberOfItemsLoaded == itemCountLimit) + itemLimitPassed = YES; + + // Draining the autorelease pool every 50 iterations was found by experimentation to be optimal + if (*numberOfItemsLoaded % 50 == 0) { + [pool drain]; + pool = [[NSAutoreleasePool alloc] init]; + } + } + } + [item release]; + } + [pool drain]; + + return YES; +} + +- (BOOL)loadFromURL:(NSURL *)URL collectDiscardedItemsInto:(NSMutableArray *)discardedItems error:(NSError **)error +{ +#if !LOG_DISABLED + double start = CFAbsoluteTimeGetCurrent(); +#endif + + int numberOfItems; + if (![self loadHistoryGutsFromURL:URL savedItemsCount:&numberOfItems collectDiscardedItemsInto:discardedItems error:error]) + return NO; + +#if !LOG_DISABLED + double duration = CFAbsoluteTimeGetCurrent() - start; + LOG(Timing, "loading %d history entries from %@ took %f seconds", numberOfItems, URL, duration); +#endif + + return YES; +} + +- (NSData *)data +{ + if (_entriesByDate->isEmpty()) { + static NSData *emptyHistoryData = (NSData *)CFDataCreate(0, 0, 0); + return emptyHistoryData; + } + + // Ignores the date and item count limits; these are respected when loading instead of when saving, so + // that clients can learn of discarded items by listening to WebHistoryItemsDiscardedWhileLoadingNotification. + WebHistoryWriter writer(_entriesByDate); + writer.writePropertyList(); + return [[(NSData *)writer.releaseData().get() retain] autorelease]; +} + +- (BOOL)saveToURL:(NSURL *)URL error:(NSError **)error +{ +#if !LOG_DISABLED + double start = CFAbsoluteTimeGetCurrent(); +#endif + + BOOL result = [[self data] writeToURL:URL options:0 error:error]; + +#if !LOG_DISABLED + double duration = CFAbsoluteTimeGetCurrent() - start; + LOG(Timing, "saving history to %@ took %f seconds", URL, duration); +#endif + + return result; +} + +- (void)addVisitedLinksToPageGroup:(PageGroup&)group +{ + NSEnumerator *enumerator = [_entriesByURL keyEnumerator]; + while (NSString *url = [enumerator nextObject]) { + size_t length = [url length]; + const UChar* characters = CFStringGetCharactersPtr(reinterpret_cast<CFStringRef>(url)); + if (characters) + group.addVisitedLink(characters, length); + else { + Vector<UChar, 512> buffer(length); + [url getCharacters:buffer.data()]; + group.addVisitedLink(buffer.data(), length); + } + } +} + +@end + +@implementation WebHistory + ++ (WebHistory *)optionalSharedHistory +{ + return _sharedHistory; +} + ++ (void)setOptionalSharedHistory:(WebHistory *)history +{ + if (_sharedHistory == history) + return; + // FIXME: Need to think about multiple instances of WebHistory per application + // and correct synchronization of history file between applications. + [_sharedHistory release]; + _sharedHistory = [history retain]; + PageGroup::setShouldTrackVisitedLinks(history); + PageGroup::removeAllVisitedLinks(); +} + +- (id)init +{ + self = [super init]; + if (!self) + return nil; + _historyPrivate = [[WebHistoryPrivate alloc] init]; + return self; +} + +- (void)dealloc +{ + [_historyPrivate release]; + [super dealloc]; +} + +// MARK: MODIFYING CONTENTS + +- (void)_sendNotification:(NSString *)name entries:(NSArray *)entries +{ + NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:entries, WebHistoryItemsKey, nil]; + [[NSNotificationCenter defaultCenter] + postNotificationName:name object:self userInfo:userInfo]; +} + +- (void)removeItems:(NSArray *)entries +{ + if ([_historyPrivate removeItems:entries]) { + [self _sendNotification:WebHistoryItemsRemovedNotification + entries:entries]; + } +} + +- (void)removeAllItems +{ + NSArray *entries = [_historyPrivate allItems]; + if ([_historyPrivate removeAllItems]) + [self _sendNotification:WebHistoryAllItemsRemovedNotification entries:entries]; +} + +- (void)addItems:(NSArray *)newEntries +{ + [_historyPrivate addItems:newEntries]; + [self _sendNotification:WebHistoryItemsAddedNotification + entries:newEntries]; +} + +// MARK: DATE-BASED RETRIEVAL + +- (NSArray *)orderedLastVisitedDays +{ + return [_historyPrivate orderedLastVisitedDays]; +} + +- (NSArray *)orderedItemsLastVisitedOnDay:(NSCalendarDate *)date +{ + return [_historyPrivate orderedItemsLastVisitedOnDay:date]; +} + +// MARK: URL MATCHING + +- (BOOL)containsURL:(NSURL *)URL +{ + return [_historyPrivate containsURL:URL]; +} + +- (WebHistoryItem *)itemForURL:(NSURL *)URL +{ + return [_historyPrivate itemForURL:URL]; +} + +// MARK: SAVING TO DISK + +- (BOOL)loadFromURL:(NSURL *)URL error:(NSError **)error +{ + NSMutableArray *discardedItems = [[NSMutableArray alloc] init]; + if (![_historyPrivate loadFromURL:URL collectDiscardedItemsInto:discardedItems error:error]) { + [discardedItems release]; + return NO; + } + + [[NSNotificationCenter defaultCenter] + postNotificationName:WebHistoryLoadedNotification + object:self]; + + if ([discardedItems count]) + [self _sendNotification:WebHistoryItemsDiscardedWhileLoadingNotification entries:discardedItems]; + + [discardedItems release]; + return YES; +} + +- (BOOL)saveToURL:(NSURL *)URL error:(NSError **)error +{ + if (![_historyPrivate saveToURL:URL error:error]) + return NO; + [[NSNotificationCenter defaultCenter] + postNotificationName:WebHistorySavedNotification + object:self]; + return YES; +} + +- (void)setHistoryItemLimit:(int)limit +{ + [_historyPrivate setHistoryItemLimit:limit]; +} + +- (int)historyItemLimit +{ + return [_historyPrivate historyItemLimit]; +} + +- (void)setHistoryAgeInDaysLimit:(int)limit +{ + [_historyPrivate setHistoryAgeInDaysLimit:limit]; +} + +- (int)historyAgeInDaysLimit +{ + return [_historyPrivate historyAgeInDaysLimit]; +} + +@end + +@implementation WebHistory (WebPrivate) + +- (WebHistoryItem *)_itemForURLString:(NSString *)URLString +{ + return [_historyPrivate itemForURLString:URLString]; +} + +- (NSArray *)allItems +{ + return [_historyPrivate allItems]; +} + +- (NSData *)_data +{ + return [_historyPrivate data]; +} + ++ (void)_setVisitedLinkTrackingEnabled:(BOOL)visitedLinkTrackingEnabled +{ + PageGroup::setShouldTrackVisitedLinks(visitedLinkTrackingEnabled); +} + ++ (void)_removeAllVisitedLinks +{ + PageGroup::removeAllVisitedLinks(); +} + +@end + +@implementation WebHistory (WebInternal) + +- (void)_visitedURL:(NSURL *)url withTitle:(NSString *)title method:(NSString *)method wasFailure:(BOOL)wasFailure increaseVisitCount:(BOOL)increaseVisitCount +{ + WebHistoryItem *entry = [_historyPrivate visitedURL:url withTitle:title increaseVisitCount:increaseVisitCount]; + + HistoryItem* item = core(entry); + item->setLastVisitWasFailure(wasFailure); + + if ([method length]) + item->setLastVisitWasHTTPNonGet([method caseInsensitiveCompare:@"GET"] && (![[url scheme] caseInsensitiveCompare:@"http"] || ![[url scheme] caseInsensitiveCompare:@"https"])); + + item->setRedirectURLs(0); + + NSArray *entries = [[NSArray alloc] initWithObjects:entry, nil]; + [self _sendNotification:WebHistoryItemsAddedNotification entries:entries]; + [entries release]; +} + +- (void)_addVisitedLinksToPageGroup:(WebCore::PageGroup&)group +{ + [_historyPrivate addVisitedLinksToPageGroup:group]; +} + +@end + +WebHistoryWriter::WebHistoryWriter(DateToEntriesMap* entriesByDate) + : m_entriesByDate(entriesByDate) +{ + m_dateKeys.reserveCapacity(m_entriesByDate->size()); + DateToEntriesMap::const_iterator end = m_entriesByDate->end(); + for (DateToEntriesMap::const_iterator it = m_entriesByDate->begin(); it != end; ++it) + m_dateKeys.append(it->first); + sort(m_dateKeys.begin(), m_dateKeys.end()); +} + +void WebHistoryWriter::writeHistoryItems(BinaryPropertyListObjectStream& stream) +{ + for (int dateIndex = m_dateKeys.size() - 1; dateIndex >= 0; dateIndex--) { + NSArray *entries = m_entriesByDate->get(m_dateKeys[dateIndex]).get(); + NSUInteger entryCount = [entries count]; + for (NSUInteger entryIndex = 0; entryIndex < entryCount; ++entryIndex) + writeHistoryItem(stream, core([entries objectAtIndex:entryIndex])); + } +} diff --git a/Source/WebKit/mac/History/WebHistoryInternal.h b/Source/WebKit/mac/History/WebHistoryInternal.h new file mode 100644 index 0000000..39d91d5 --- /dev/null +++ b/Source/WebKit/mac/History/WebHistoryInternal.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 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 "WebHistoryPrivate.h" + +namespace WebCore { + class PageGroup; +} + +@interface WebHistory (WebInternal) +- (void)_visitedURL:(NSURL *)URL withTitle:(NSString *)title method:(NSString *)method wasFailure:(BOOL)wasFailure increaseVisitCount:(BOOL)increaseVisitCount; +- (void)_addVisitedLinksToPageGroup:(WebCore::PageGroup&)group; +@end diff --git a/Source/WebKit/mac/History/WebHistoryItem.h b/Source/WebKit/mac/History/WebHistoryItem.h new file mode 100644 index 0000000..4de4344 --- /dev/null +++ b/Source/WebKit/mac/History/WebHistoryItem.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2003 Apple Computer, 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 <Cocoa/Cocoa.h> + +@class WebHistoryItemPrivate; +@class NSURL; + +/* + @discussion Notification sent when history item is modified. + @constant WebHistoryItemChanged Posted from whenever the value of + either the item's title, alternate title, url strings, or last visited interval + changes. The userInfo will be nil. +*/ +extern NSString *WebHistoryItemChangedNotification; + +/*! + @class WebHistoryItem + @discussion WebHistoryItems are created by WebKit to represent pages visited. + The WebBackForwardList and WebHistory classes both use WebHistoryItems to represent + pages visited. With the exception of the displayTitle, the properties of + WebHistoryItems are set by WebKit. WebHistoryItems are normally never created directly. +*/ +@interface WebHistoryItem : NSObject <NSCopying> +{ +@private + WebHistoryItemPrivate *_private; +} + +/*! + @method initWithURLString:title:lastVisitedTimeInterval: + @param URLString The URL string for the item. + @param title The title to use for the item. This is normally the <title> of a page. + @param time The time used to indicate when the item was used. + @abstract Initialize a new WebHistoryItem + @discussion WebHistoryItems are normally created for you by the WebKit. + You may use this method to prepopulate a WebBackForwardList, or create + 'artificial' items to add to a WebBackForwardList. When first initialized + the URLString and originalURLString will be the same. +*/ +- (id)initWithURLString:(NSString *)URLString title:(NSString *)title lastVisitedTimeInterval:(NSTimeInterval)time; + +/*! + @method originalURLString + @abstract The string representation of the originial URL of this item. + This value is normally set by the WebKit. + @result The string corresponding to the initial URL of this item. +*/ +- (NSString *)originalURLString; + +/*! + @method URLString + @abstract The string representation of the URL represented by this item. + @discussion The URLString may be different than the originalURLString if the page + redirected to a new location. This value is normally set by the WebKit. + @result The string corresponding to the final URL of this item. +*/ +- (NSString *)URLString; + + +/*! + @method title + @abstract The title of the page represented by this item. + @discussion This title cannot be changed by the client. This value + is normally set by the WebKit when a page title for the item is received. + @result The title of this item. +*/ +- (NSString *)title; + +/*! + @method lastVisitedTimeInterval + @abstract The last time the page represented by this item was visited. The interval + is since the reference date as determined by NSDate. This value is normally set by + the WebKit. + @result The last time this item was visited. +*/ +- (NSTimeInterval)lastVisitedTimeInterval; + +/*! + @method setAlternateTitle: + @param alternateTitle The new display title for this item. + @abstract A title that may be used by the client to display this item. +*/ +- (void)setAlternateTitle:(NSString *)alternateTitle; + +/* + @method title + @abstract A title that may be used by the client to display this item. + @result The alternate title for this item. +*/ +- (NSString *)alternateTitle; + +/*! + @method icon + @abstract The favorite icon of the page represented by this item. + @discussion This icon returned will be determined by the WebKit. + @result The icon associated with this item's URL. +*/ +- (NSImage *)icon; + +@end diff --git a/Source/WebKit/mac/History/WebHistoryItem.mm b/Source/WebKit/mac/History/WebHistoryItem.mm new file mode 100644 index 0000000..530b18a --- /dev/null +++ b/Source/WebKit/mac/History/WebHistoryItem.mm @@ -0,0 +1,659 @@ +/* + * 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]; +} + +- (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().isEmpty()) { + 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 diff --git a/Source/WebKit/mac/History/WebHistoryItemInternal.h b/Source/WebKit/mac/History/WebHistoryItemInternal.h new file mode 100644 index 0000000..d324682 --- /dev/null +++ b/Source/WebKit/mac/History/WebHistoryItemInternal.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2006, 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 "WebBackForwardList.h" +#import "WebHistoryItemPrivate.h" +#import <wtf/Forward.h> + +namespace WebCore { + class HistoryItem; +} + +WebCore::HistoryItem* core(WebHistoryItem *item); +WebHistoryItem *kit(WebCore::HistoryItem* item); + +extern void WKNotifyHistoryItemChanged(WebCore::HistoryItem*); + +@interface WebHistoryItem (WebInternal) + ++ (WebHistoryItem *)entryWithURL:(NSURL *)URL; ++ (void)initWindowWatcherIfNecessary; + +- (id)initWithURL:(NSURL *)URL target:(NSString *)target parent:(NSString *)parent title:(NSString *)title; +- (id)initWithURLString:(NSString *)URLString title:(NSString *)title displayTitle:(NSString *)displayTitle lastVisitedTimeInterval:(NSTimeInterval)time; +- (id)initFromDictionaryRepresentation:(NSDictionary *)dict; +- (id)initWithWebCoreHistoryItem:(PassRefPtr<WebCore::HistoryItem>)item; + +- (void)_mergeAutoCompleteHints:(WebHistoryItem *)otherItem; +- (void)setTitle:(NSString *)title; +- (void)_visitedWithTitle:(NSString *)title increaseVisitCount:(BOOL)increaseVisitCount; +- (void)_recordInitialVisit; + +@end + +@interface WebBackForwardList (WebInternal) +- (void)_close; +@end diff --git a/Source/WebKit/mac/History/WebHistoryItemPrivate.h b/Source/WebKit/mac/History/WebHistoryItemPrivate.h new file mode 100644 index 0000000..0c079a7 --- /dev/null +++ b/Source/WebKit/mac/History/WebHistoryItemPrivate.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2005, 2006, 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 <WebKit/WebHistoryItem.h> + +@interface WebHistoryItem (WebPrivate) + ++ (void)_releaseAllPendingPageCaches; + +- (id)initWithURL:(NSURL *)URL title:(NSString *)title; + +- (NSURL *)URL; +- (int)visitCount; +- (BOOL)lastVisitWasFailure; +- (void)_setLastVisitWasFailure:(BOOL)failure; + +- (BOOL)_lastVisitWasHTTPNonGet; + +- (NSString *)RSSFeedReferrer; +- (void)setRSSFeedReferrer:(NSString *)referrer; +- (NSCalendarDate *)_lastVisitedDate; + +- (NSArray *)_redirectURLs; + +- (WebHistoryItem *)targetItem; +- (NSString *)target; +- (BOOL)isTargetItem; +- (NSArray *)children; +- (NSDictionary *)dictionaryRepresentation; + +// This should not be called directly for WebHistoryItems that are already included +// in WebHistory. Use -[WebHistory setLastVisitedTimeInterval:forItem:] instead. +- (void)_setLastVisitedTimeInterval:(NSTimeInterval)time; +// Transient properties may be of any ObjC type. They are intended to be used to store state per back/forward list entry. +// The properties will not be persisted; when the history item is removed, the properties will be lost. +- (id)_transientPropertyForKey:(NSString *)key; +- (void)_setTransientProperty:(id)property forKey:(NSString *)key; + +- (size_t)_getDailyVisitCounts:(const int**)counts; +- (size_t)_getWeeklyVisitCounts:(const int**)counts; + +@end diff --git a/Source/WebKit/mac/History/WebHistoryPrivate.h b/Source/WebKit/mac/History/WebHistoryPrivate.h new file mode 100644 index 0000000..b93472f --- /dev/null +++ b/Source/WebKit/mac/History/WebHistoryPrivate.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2005, 2008, 2009 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 <WebKit/WebHistory.h> + +/* + @constant WebHistoryItemsDiscardedWhileLoadingNotification Posted from loadFromURL:error:. + This notification comes with a userInfo dictionary that contains the array of + items discarded due to the date limit or item limit. The key for the array is WebHistoryItemsKey. +*/ +// FIXME: This notification should become public API. +extern NSString *WebHistoryItemsDiscardedWhileLoadingNotification; + +@interface WebHistory (WebPrivate) + +// FIXME: The following SPI is used by Safari. Should it be made into public API? +- (WebHistoryItem *)_itemForURLString:(NSString *)URLString; + +/*! + @method allItems + @result Returns an array of all WebHistoryItems in WebHistory, in an undefined order. +*/ +- (NSArray *)allItems; + +/*! + @method _data + @result A data object with the entire history in the same format used by the saveToURL:error: method. +*/ +- (NSData *)_data; + ++ (void)_setVisitedLinkTrackingEnabled:(BOOL)visitedLinkTrackingEnabled; ++ (void)_removeAllVisitedLinks; +@end diff --git a/Source/WebKit/mac/History/WebURLsWithTitles.h b/Source/WebKit/mac/History/WebURLsWithTitles.h new file mode 100644 index 0000000..905588e --- /dev/null +++ b/Source/WebKit/mac/History/WebURLsWithTitles.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2005 Apple Computer, 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 <Cocoa/Cocoa.h> + +#define WebURLsWithTitlesPboardType @"WebURLsWithTitlesPboardType" + +// Convenience class for getting URLs and associated titles on and off an NSPasteboard + +@interface WebURLsWithTitles : NSObject + +// Writes parallel arrays of URLs and titles to the pasteboard. These items can be retrieved by +// calling URLsFromPasteboard and titlesFromPasteboard. URLs must consist of NSURL objects. +// titles must consist of NSStrings, or be nil. If titles is nil, or if titles is a different +// length than URLs, empty strings will be used for all titles. If URLs is nil, this method +// returns without doing anything. You must declare an WebURLsWithTitlesPboardType data type +// for pasteboard before invoking this method, or it will return without doing anything. ++ (void)writeURLs:(NSArray *)URLs andTitles:(NSArray *)titles toPasteboard:(NSPasteboard *)pasteboard; + +// Reads an array of NSURLs off the pasteboard. Returns nil if pasteboard does not contain +// data of type WebURLsWithTitlesPboardType. This array consists of the URLs that correspond to +// the titles returned from titlesFromPasteboard. ++ (NSArray *)URLsFromPasteboard:(NSPasteboard *)pasteboard; + +// Reads an array of NSStrings off the pasteboard. Returns nil if pasteboard does not contain +// data of type WebURLsWithTitlesPboardType. This array consists of the titles that correspond to +// the URLs returned from URLsFromPasteboard. ++ (NSArray *)titlesFromPasteboard:(NSPasteboard *)pasteboard; + +@end diff --git a/Source/WebKit/mac/History/WebURLsWithTitles.m b/Source/WebKit/mac/History/WebURLsWithTitles.m new file mode 100644 index 0000000..df9ef75 --- /dev/null +++ b/Source/WebKit/mac/History/WebURLsWithTitles.m @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2005 Apple Computer, 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 "WebURLsWithTitles.h" + +#import <WebKit/WebNSURLExtras.h> +#import <WebKit/WebKitNSStringExtras.h> + +@implementation WebURLsWithTitles + ++ (NSArray *)arrayWithIFURLsWithTitlesPboardType +{ + // Make a canned array so we don't construct it on the fly over and over. + static NSArray *cannedArray = nil; + + if (cannedArray == nil) { + cannedArray = [[NSArray arrayWithObject:WebURLsWithTitlesPboardType] retain]; + } + + return cannedArray; +} + ++(void)writeURLs:(NSArray *)URLs andTitles:(NSArray *)titles toPasteboard:(NSPasteboard *)pasteboard +{ + NSMutableArray *URLStrings; + NSMutableArray *titlesOrEmptyStrings; + unsigned index, count; + + count = [URLs count]; + if (count == 0) { + return; + } + + if ([pasteboard availableTypeFromArray:[self arrayWithIFURLsWithTitlesPboardType]] == nil) { + return; + } + + if (count != [titles count]) { + titles = nil; + } + + URLStrings = [NSMutableArray arrayWithCapacity:count]; + titlesOrEmptyStrings = [NSMutableArray arrayWithCapacity:count]; + for (index = 0; index < count; ++index) { + [URLStrings addObject:[[URLs objectAtIndex:index] _web_originalDataAsString]]; + [titlesOrEmptyStrings addObject:(titles == nil) ? @"" : [[titles objectAtIndex:index] _webkit_stringByTrimmingWhitespace]]; + } + + [pasteboard setPropertyList:[NSArray arrayWithObjects:URLStrings, titlesOrEmptyStrings, nil] + forType:WebURLsWithTitlesPboardType]; +} + ++(NSArray *)titlesFromPasteboard:(NSPasteboard *)pasteboard +{ + if ([pasteboard availableTypeFromArray:[self arrayWithIFURLsWithTitlesPboardType]] == nil) { + return nil; + } + + return [[pasteboard propertyListForType:WebURLsWithTitlesPboardType] objectAtIndex:1]; +} + ++(NSArray *)URLsFromPasteboard:(NSPasteboard *)pasteboard +{ + NSArray *URLStrings; + NSMutableArray *URLs; + unsigned index, count; + + if ([pasteboard availableTypeFromArray:[self arrayWithIFURLsWithTitlesPboardType]] == nil) { + return nil; + } + + URLStrings = [[pasteboard propertyListForType:WebURLsWithTitlesPboardType] objectAtIndex:0]; + count = [URLStrings count]; + URLs = [NSMutableArray arrayWithCapacity:count]; + for (index = 0; index < count; ++index) { + [URLs addObject:[NSURL _web_URLWithDataAsString:[URLStrings objectAtIndex:index]]]; + } + + return URLs; +} + +@end |
