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 54 using namespace WebCore; 55 56 typedef 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. 60 static BackForwardListMap& backForwardLists() 61 { 62 DEFINE_STATIC_LOCAL(BackForwardListMap, staticBackForwardLists, ()); 63 return staticBackForwardLists; 64 } 65 66 @implementation WebBackForwardList (WebBackForwardListInternal) 67 68 BackForwardListImpl* core(WebBackForwardList *webBackForwardList) 69 { 70 if (!webBackForwardList) 71 return 0; 72 73 return reinterpret_cast<BackForwardListImpl*>(webBackForwardList->_private); 74 } 75 76 WebBackForwardList *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 202 static 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 212 static 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