1/* 2 * Copyright (C) 2005, 2007 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#import "WebBackForwardList.h" 30#import "WebBackForwardListInternal.h" 31 32#import "WebFrameInternal.h" 33#import "WebHistoryItemInternal.h" 34#import "WebHistoryItemPrivate.h" 35#import "WebKitLogging.h" 36#import "WebKitVersionChecks.h" 37#import "WebNSObjectExtras.h" 38#import "WebPreferencesPrivate.h" 39#import "WebTypesInternal.h" 40#import "WebViewPrivate.h" 41#import <WebCore/BackForwardList.h> 42#import <WebCore/HistoryItem.h> 43#import <WebCore/Page.h> 44#import <WebCore/PageCache.h> 45#import <WebCore/Settings.h> 46#import <WebCore/ThreadCheck.h> 47#import <WebCore/WebCoreObjCExtras.h> 48#import <runtime/InitializeThreading.h> 49#import <wtf/Assertions.h> 50#import <wtf/MainThread.h> 51#import <wtf/RetainPtr.h> 52#import <wtf/RunLoop.h> 53#import <wtf/StdLibExtras.h> 54 55using namespace WebCore; 56 57typedef HashMap<BackForwardList*, WebBackForwardList*> BackForwardListMap; 58 59// FIXME: Instead of this we could just create a class derived from BackForwardList 60// with a pointer to a WebBackForwardList in it. 61static BackForwardListMap& backForwardLists() 62{ 63 DEPRECATED_DEFINE_STATIC_LOCAL(BackForwardListMap, staticBackForwardLists, ()); 64 return staticBackForwardLists; 65} 66 67@implementation WebBackForwardList (WebBackForwardListInternal) 68 69BackForwardList* core(WebBackForwardList *webBackForwardList) 70{ 71 if (!webBackForwardList) 72 return 0; 73 74 return reinterpret_cast<BackForwardList*>(webBackForwardList->_private); 75} 76 77WebBackForwardList *kit(BackForwardList* backForwardList) 78{ 79 if (!backForwardList) 80 return nil; 81 82 if (WebBackForwardList *webBackForwardList = backForwardLists().get(backForwardList)) 83 return webBackForwardList; 84 85 return [[[WebBackForwardList alloc] initWithBackForwardList:backForwardList] autorelease]; 86} 87 88- (id)initWithBackForwardList:(PassRefPtr<BackForwardList>)backForwardList 89{ 90 WebCoreThreadViolationCheckRoundOne(); 91 self = [super init]; 92 if (!self) 93 return nil; 94 95 _private = reinterpret_cast<WebBackForwardListPrivate*>(backForwardList.leakRef()); 96 backForwardLists().set(core(self), self); 97 return self; 98} 99 100@end 101 102@implementation WebBackForwardList 103 104+ (void)initialize 105{ 106#if !PLATFORM(IOS) 107 JSC::initializeThreading(); 108 WTF::initializeMainThreadToProcessMainThread(); 109 RunLoop::initializeMainRunLoop(); 110#endif 111 WebCoreObjCFinalizeOnMainThread(self); 112} 113 114- (id)init 115{ 116 return [self initWithBackForwardList:BackForwardList::create(0)]; 117} 118 119- (void)dealloc 120{ 121 if (WebCoreObjCScheduleDeallocateOnMainThread([WebBackForwardList class], self)) 122 return; 123 124 BackForwardList* backForwardList = core(self); 125 ASSERT(backForwardList); 126 if (backForwardList) { 127 ASSERT(backForwardList->closed()); 128 backForwardLists().remove(backForwardList); 129 backForwardList->deref(); 130 } 131 132 [super dealloc]; 133} 134 135- (void)finalize 136{ 137 WebCoreThreadViolationCheckRoundOne(); 138 BackForwardList* backForwardList = core(self); 139 ASSERT(backForwardList); 140 if (backForwardList) { 141 ASSERT(backForwardList->closed()); 142 backForwardLists().remove(backForwardList); 143 backForwardList->deref(); 144 } 145 146 [super finalize]; 147} 148 149- (void)_close 150{ 151 core(self)->close(); 152} 153 154- (void)addItem:(WebHistoryItem *)entry 155{ 156 core(self)->addItem(core(entry)); 157 158 // Since the assumed contract with WebBackForwardList is that it retains its WebHistoryItems, 159 // the following line prevents a whole class of problems where a history item will be created in 160 // a function, added to the BFlist, then used in the rest of that function. 161 [[entry retain] autorelease]; 162} 163 164- (void)removeItem:(WebHistoryItem *)item 165{ 166 core(self)->removeItem(core(item)); 167} 168 169#if PLATFORM(IOS) 170 171// FIXME: Move into WebCore the code that deals directly with WebCore::BackForwardList. 172 173#define WebBackForwardListDictionaryEntriesKey @"entries" 174#define WebBackForwardListDictionaryCapacityKey @"capacity" 175#define WebBackForwardListDictionaryCurrentKey @"current" 176 177- (NSDictionary *)dictionaryRepresentation 178{ 179 BackForwardList *coreBFList = core(self); 180 181 HistoryItemVector historyItems = coreBFList->entries(); 182 unsigned size = historyItems.size(); 183 NSMutableArray *entriesArray = [[NSMutableArray alloc] initWithCapacity:size]; 184 for (unsigned i = 0; i < size; ++i) 185 [entriesArray addObject:[kit(historyItems[i].get()) dictionaryRepresentationIncludingChildren:NO]]; 186 187 NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys: 188 entriesArray, WebBackForwardListDictionaryEntriesKey, 189 [NSNumber numberWithUnsignedInt:coreBFList->current()], WebBackForwardListDictionaryCurrentKey, 190 [NSNumber numberWithInt:coreBFList->capacity()], WebBackForwardListDictionaryCapacityKey, 191 nil]; 192 193 [entriesArray release]; 194 195 return dictionary; 196} 197 198- (void)setToMatchDictionaryRepresentation:(NSDictionary *)dictionary 199{ 200 BackForwardList *coreBFList = core(self); 201 202 coreBFList->setCapacity([[dictionary objectForKey:WebBackForwardListDictionaryCapacityKey] intValue]); 203 204 for (NSDictionary *itemDictionary in [dictionary objectForKey:WebBackForwardListDictionaryEntriesKey]) { 205 WebHistoryItem *item = [[WebHistoryItem alloc] initFromDictionaryRepresentation:itemDictionary]; 206 coreBFList->addItem(core(item)); 207 [item release]; 208 } 209 210 unsigned currentIndex = [[dictionary objectForKey:WebBackForwardListDictionaryCurrentKey] unsignedIntValue]; 211 size_t listSize = coreBFList->entries().size(); 212 if (currentIndex >= listSize) 213 currentIndex = listSize - 1; 214 coreBFList->setCurrent(currentIndex); 215} 216#endif // PLATFORM(IOS) 217 218- (BOOL)containsItem:(WebHistoryItem *)item 219{ 220 return core(self)->containsItem(core(item)); 221} 222 223- (void)goBack 224{ 225 core(self)->goBack(); 226} 227 228- (void)goForward 229{ 230 core(self)->goForward(); 231} 232 233- (void)goToItem:(WebHistoryItem *)item 234{ 235 core(self)->goToItem(core(item)); 236} 237 238- (WebHistoryItem *)backItem 239{ 240 return [[kit(core(self)->backItem()) retain] autorelease]; 241} 242 243- (WebHistoryItem *)currentItem 244{ 245 return [[kit(core(self)->currentItem()) retain] autorelease]; 246} 247 248- (WebHistoryItem *)forwardItem 249{ 250 return [[kit(core(self)->forwardItem()) retain] autorelease]; 251} 252 253static NSArray* vectorToNSArray(HistoryItemVector& list) 254{ 255 unsigned size = list.size(); 256 NSMutableArray *result = [[[NSMutableArray alloc] initWithCapacity:size] autorelease]; 257 for (unsigned i = 0; i < size; ++i) 258 [result addObject:kit(list[i].get())]; 259 260 return result; 261} 262 263static bool bumperCarBackForwardHackNeeded() 264{ 265#if !PLATFORM(IOS) 266 static bool hackNeeded = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.freeverse.bumpercar"] && 267 !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_BUMPERCAR_BACK_FORWARD_QUIRK); 268 269 return hackNeeded; 270#else 271 return false; 272#endif 273} 274 275- (NSArray *)backListWithLimit:(int)limit 276{ 277 HistoryItemVector list; 278 core(self)->backListWithLimit(limit, list); 279 NSArray *result = vectorToNSArray(list); 280 281 if (bumperCarBackForwardHackNeeded()) { 282 static NSArray *lastBackListArray = nil; 283 [lastBackListArray release]; 284 lastBackListArray = [result retain]; 285 } 286 287 return result; 288} 289 290- (NSArray *)forwardListWithLimit:(int)limit 291{ 292 HistoryItemVector list; 293 core(self)->forwardListWithLimit(limit, list); 294 NSArray *result = vectorToNSArray(list); 295 296 if (bumperCarBackForwardHackNeeded()) { 297 static NSArray *lastForwardListArray = nil; 298 [lastForwardListArray release]; 299 lastForwardListArray = [result retain]; 300 } 301 302 return result; 303} 304 305- (int)capacity 306{ 307 return core(self)->capacity(); 308} 309 310- (void)setCapacity:(int)size 311{ 312 core(self)->setCapacity(size); 313} 314 315 316-(NSString *)description 317{ 318 NSMutableString *result; 319 320 result = [NSMutableString stringWithCapacity:512]; 321 322 [result appendString:@"\n--------------------------------------------\n"]; 323 [result appendString:@"WebBackForwardList:\n"]; 324 325 BackForwardList* backForwardList = core(self); 326 HistoryItemVector& entries = backForwardList->entries(); 327 328 unsigned size = entries.size(); 329 for (unsigned i = 0; i < size; ++i) { 330 if (entries[i] == backForwardList->currentItem()) { 331 [result appendString:@" >>>"]; 332 } else { 333 [result appendString:@" "]; 334 } 335 [result appendFormat:@"%2d) ", i]; 336 int currPos = [result length]; 337 [result appendString:[kit(entries[i].get()) description]]; 338 339 // shift all the contents over. a bit slow, but this is for debugging 340 NSRange replRange = { static_cast<NSUInteger>(currPos), [result length] - currPos }; 341 [result replaceOccurrencesOfString:@"\n" withString:@"\n " options:0 range:replRange]; 342 343 [result appendString:@"\n"]; 344 } 345 346 [result appendString:@"\n--------------------------------------------\n"]; 347 348 return result; 349} 350 351- (void)setPageCacheSize:(NSUInteger)size 352{ 353 [kit(core(self)->page()) setUsesPageCache:size != 0]; 354} 355 356- (NSUInteger)pageCacheSize 357{ 358 return [kit(core(self)->page()) usesPageCache] ? pageCache()->capacity() : 0; 359} 360 361- (int)backListCount 362{ 363 return core(self)->backListCount(); 364} 365 366- (int)forwardListCount 367{ 368 return core(self)->forwardListCount(); 369} 370 371- (WebHistoryItem *)itemAtIndex:(int)index 372{ 373 return [[kit(core(self)->itemAtIndex(index)) retain] autorelease]; 374} 375 376@end 377