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 Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#import "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/BackForwardListImpl.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/RetainPtr.h> 51#import <wtf/StdLibExtras.h> 52#import <wtf/Threading.h> 53 54using namespace WebCore; 55 56typedef HashMap<BackForwardListImpl*, WebBackForwardList*> BackForwardListMap; 57 58// FIXME: Instead of this we could just create a class derived from BackForwardListImpl 59// with a pointer to a WebBackForwardList in it. 60static BackForwardListMap& backForwardLists() 61{ 62 DEFINE_STATIC_LOCAL(BackForwardListMap, staticBackForwardLists, ()); 63 return staticBackForwardLists; 64} 65 66@implementation WebBackForwardList (WebBackForwardListInternal) 67 68BackForwardListImpl* core(WebBackForwardList *webBackForwardList) 69{ 70 if (!webBackForwardList) 71 return 0; 72 73 return reinterpret_cast<BackForwardListImpl*>(webBackForwardList->_private); 74} 75 76WebBackForwardList *kit(BackForwardListImpl* backForwardList) 77{ 78 if (!backForwardList) 79 return nil; 80 81 if (WebBackForwardList *webBackForwardList = backForwardLists().get(backForwardList)) 82 return webBackForwardList; 83 84 return [[[WebBackForwardList alloc] initWithBackForwardList:backForwardList] autorelease]; 85} 86 87- (id)initWithBackForwardList:(PassRefPtr<BackForwardListImpl>)backForwardList 88{ 89 WebCoreThreadViolationCheckRoundOne(); 90 self = [super init]; 91 if (!self) 92 return nil; 93 94 _private = reinterpret_cast<WebBackForwardListPrivate*>(backForwardList.releaseRef()); 95 backForwardLists().set(core(self), self); 96 return self; 97} 98 99@end 100 101@implementation WebBackForwardList 102 103+ (void)initialize 104{ 105 JSC::initializeThreading(); 106 WTF::initializeMainThreadToProcessMainThread(); 107#ifndef BUILDING_ON_TIGER 108 WebCoreObjCFinalizeOnMainThread(self); 109#endif 110} 111 112- (id)init 113{ 114 return [self initWithBackForwardList:BackForwardListImpl::create(0)]; 115} 116 117- (void)dealloc 118{ 119 if (WebCoreObjCScheduleDeallocateOnMainThread([WebBackForwardList class], self)) 120 return; 121 122 BackForwardListImpl* backForwardList = core(self); 123 ASSERT(backForwardList); 124 if (backForwardList) { 125 ASSERT(backForwardList->closed()); 126 backForwardLists().remove(backForwardList); 127 backForwardList->deref(); 128 } 129 130 [super dealloc]; 131} 132 133- (void)finalize 134{ 135 WebCoreThreadViolationCheckRoundOne(); 136 BackForwardListImpl* backForwardList = core(self); 137 ASSERT(backForwardList); 138 if (backForwardList) { 139 ASSERT(backForwardList->closed()); 140 backForwardLists().remove(backForwardList); 141 backForwardList->deref(); 142 } 143 144 [super finalize]; 145} 146 147- (void)_close 148{ 149 core(self)->close(); 150} 151 152- (void)addItem:(WebHistoryItem *)entry 153{ 154 core(self)->addItem(core(entry)); 155 156 // Since the assumed contract with WebBackForwardList is that it retains its WebHistoryItems, 157 // the following line prevents a whole class of problems where a history item will be created in 158 // a function, added to the BFlist, then used in the rest of that function. 159 [[entry retain] autorelease]; 160} 161 162- (void)removeItem:(WebHistoryItem *)item 163{ 164 core(self)->removeItem(core(item)); 165} 166 167- (BOOL)containsItem:(WebHistoryItem *)item 168{ 169 return core(self)->containsItem(core(item)); 170} 171 172- (void)goBack 173{ 174 core(self)->goBack(); 175} 176 177- (void)goForward 178{ 179 core(self)->goForward(); 180} 181 182- (void)goToItem:(WebHistoryItem *)item 183{ 184 core(self)->goToItem(core(item)); 185} 186 187- (WebHistoryItem *)backItem 188{ 189 return [[kit(core(self)->backItem()) retain] autorelease]; 190} 191 192- (WebHistoryItem *)currentItem 193{ 194 return [[kit(core(self)->currentItem()) retain] autorelease]; 195} 196 197- (WebHistoryItem *)forwardItem 198{ 199 return [[kit(core(self)->forwardItem()) retain] autorelease]; 200} 201 202static NSArray* vectorToNSArray(HistoryItemVector& list) 203{ 204 unsigned size = list.size(); 205 NSMutableArray *result = [[[NSMutableArray alloc] initWithCapacity:size] autorelease]; 206 for (unsigned i = 0; i < size; ++i) 207 [result addObject:kit(list[i].get())]; 208 209 return result; 210} 211 212static bool bumperCarBackForwardHackNeeded() 213{ 214 static bool hackNeeded = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.freeverse.bumpercar"] && 215 !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_BUMPERCAR_BACK_FORWARD_QUIRK); 216 217 return hackNeeded; 218} 219 220- (NSArray *)backListWithLimit:(int)limit 221{ 222 HistoryItemVector list; 223 core(self)->backListWithLimit(limit, list); 224 NSArray *result = vectorToNSArray(list); 225 226 if (bumperCarBackForwardHackNeeded()) { 227 static NSArray *lastBackListArray = nil; 228 [lastBackListArray release]; 229 lastBackListArray = [result retain]; 230 } 231 232 return result; 233} 234 235- (NSArray *)forwardListWithLimit:(int)limit 236{ 237 HistoryItemVector list; 238 core(self)->forwardListWithLimit(limit, list); 239 NSArray *result = vectorToNSArray(list); 240 241 if (bumperCarBackForwardHackNeeded()) { 242 static NSArray *lastForwardListArray = nil; 243 [lastForwardListArray release]; 244 lastForwardListArray = [result retain]; 245 } 246 247 return result; 248} 249 250- (int)capacity 251{ 252 return core(self)->capacity(); 253} 254 255- (void)setCapacity:(int)size 256{ 257 core(self)->setCapacity(size); 258} 259 260 261-(NSString *)description 262{ 263 NSMutableString *result; 264 265 result = [NSMutableString stringWithCapacity:512]; 266 267 [result appendString:@"\n--------------------------------------------\n"]; 268 [result appendString:@"WebBackForwardList:\n"]; 269 270 BackForwardListImpl* backForwardList = core(self); 271 HistoryItemVector& entries = backForwardList->entries(); 272 273 unsigned size = entries.size(); 274 for (unsigned i = 0; i < size; ++i) { 275 if (entries[i] == backForwardList->currentItem()) { 276 [result appendString:@" >>>"]; 277 } else { 278 [result appendString:@" "]; 279 } 280 [result appendFormat:@"%2d) ", i]; 281 int currPos = [result length]; 282 [result appendString:[kit(entries[i].get()) description]]; 283 284 // shift all the contents over. a bit slow, but this is for debugging 285 NSRange replRange = {currPos, [result length]-currPos}; 286 [result replaceOccurrencesOfString:@"\n" withString:@"\n " options:0 range:replRange]; 287 288 [result appendString:@"\n"]; 289 } 290 291 [result appendString:@"\n--------------------------------------------\n"]; 292 293 return result; 294} 295 296- (void)setPageCacheSize:(NSUInteger)size 297{ 298 [kit(core(self)->page()) setUsesPageCache:size != 0]; 299} 300 301- (NSUInteger)pageCacheSize 302{ 303 return [kit(core(self)->page()) usesPageCache] ? pageCache()->capacity() : 0; 304} 305 306- (int)backListCount 307{ 308 return core(self)->backListCount(); 309} 310 311- (int)forwardListCount 312{ 313 return core(self)->forwardListCount(); 314} 315 316- (WebHistoryItem *)itemAtIndex:(int)index 317{ 318 return [[kit(core(self)->itemAtIndex(index)) retain] autorelease]; 319} 320 321@end 322