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/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/RetainPtr.h> 51 #import <wtf/StdLibExtras.h> 52 53 using namespace WebCore; 54 55 typedef HashMap<BackForwardList*, WebBackForwardList*> BackForwardListMap; 56 57 static BackForwardListMap& backForwardLists() 58 { 59 DEFINE_STATIC_LOCAL(BackForwardListMap, staticBackForwardLists, ()); 60 return staticBackForwardLists; 61 } 62 63 @implementation WebBackForwardList (WebBackForwardListInternal) 64 65 BackForwardList* core(WebBackForwardList *webBackForwardList) 66 { 67 if (!webBackForwardList) 68 return 0; 69 70 return reinterpret_cast<BackForwardList*>(webBackForwardList->_private); 71 } 72 73 WebBackForwardList *kit(BackForwardList* backForwardList) 74 { 75 if (!backForwardList) 76 return nil; 77 78 if (WebBackForwardList *webBackForwardList = backForwardLists().get(backForwardList)) 79 return webBackForwardList; 80 81 return [[[WebBackForwardList alloc] initWithBackForwardList:backForwardList] autorelease]; 82 } 83 84 - (id)initWithBackForwardList:(PassRefPtr<BackForwardList>)backForwardList 85 { 86 WebCoreThreadViolationCheckRoundOne(); 87 self = [super init]; 88 if (!self) 89 return nil; 90 91 _private = reinterpret_cast<WebBackForwardListPrivate*>(backForwardList.releaseRef()); 92 backForwardLists().set(core(self), self); 93 return self; 94 } 95 96 @end 97 98 @implementation WebBackForwardList 99 100 + (void)initialize 101 { 102 JSC::initializeThreading(); 103 #ifndef BUILDING_ON_TIGER 104 WebCoreObjCFinalizeOnMainThread(self); 105 #endif 106 } 107 108 - (id)init 109 { 110 return [self initWithBackForwardList:BackForwardList::create(0)]; 111 } 112 113 - (void)dealloc 114 { 115 if (WebCoreObjCScheduleDeallocateOnMainThread([WebBackForwardList class], self)) 116 return; 117 118 BackForwardList* backForwardList = core(self); 119 ASSERT(backForwardList); 120 if (backForwardList) { 121 ASSERT(backForwardList->closed()); 122 backForwardLists().remove(backForwardList); 123 backForwardList->deref(); 124 } 125 126 [super dealloc]; 127 } 128 129 - (void)finalize 130 { 131 WebCoreThreadViolationCheckRoundOne(); 132 BackForwardList* backForwardList = core(self); 133 ASSERT(backForwardList); 134 if (backForwardList) { 135 ASSERT(backForwardList->closed()); 136 backForwardLists().remove(backForwardList); 137 backForwardList->deref(); 138 } 139 140 [super finalize]; 141 } 142 143 - (void)_close 144 { 145 core(self)->close(); 146 } 147 148 - (void)addItem:(WebHistoryItem *)entry 149 { 150 core(self)->addItem(core(entry)); 151 152 // Since the assumed contract with WebBackForwardList is that it retains its WebHistoryItems, 153 // the following line prevents a whole class of problems where a history item will be created in 154 // a function, added to the BFlist, then used in the rest of that function. 155 [[entry retain] autorelease]; 156 } 157 158 - (void)removeItem:(WebHistoryItem *)item 159 { 160 core(self)->removeItem(core(item)); 161 } 162 163 - (BOOL)containsItem:(WebHistoryItem *)item 164 { 165 return core(self)->containsItem(core(item)); 166 } 167 168 - (void)goBack 169 { 170 core(self)->goBack(); 171 } 172 173 - (void)goForward 174 { 175 core(self)->goForward(); 176 } 177 178 - (void)goToItem:(WebHistoryItem *)item 179 { 180 core(self)->goToItem(core(item)); 181 } 182 183 - (WebHistoryItem *)backItem 184 { 185 return [[kit(core(self)->backItem()) retain] autorelease]; 186 } 187 188 - (WebHistoryItem *)currentItem 189 { 190 return [[kit(core(self)->currentItem()) retain] autorelease]; 191 } 192 193 - (WebHistoryItem *)forwardItem 194 { 195 return [[kit(core(self)->forwardItem()) retain] autorelease]; 196 } 197 198 static NSArray* vectorToNSArray(HistoryItemVector& list) 199 { 200 unsigned size = list.size(); 201 NSMutableArray *result = [[[NSMutableArray alloc] initWithCapacity:size] autorelease]; 202 for (unsigned i = 0; i < size; ++i) 203 [result addObject:kit(list[i].get())]; 204 205 return result; 206 } 207 208 static bool bumperCarBackForwardHackNeeded() 209 { 210 static bool hackNeeded = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.freeverse.bumpercar"] && 211 !WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_BUMPERCAR_BACK_FORWARD_QUIRK); 212 213 return hackNeeded; 214 } 215 216 - (NSArray *)backListWithLimit:(int)limit 217 { 218 HistoryItemVector list; 219 core(self)->backListWithLimit(limit, list); 220 NSArray *result = vectorToNSArray(list); 221 222 if (bumperCarBackForwardHackNeeded()) { 223 static NSArray *lastBackListArray = nil; 224 [lastBackListArray release]; 225 lastBackListArray = [result retain]; 226 } 227 228 return result; 229 } 230 231 - (NSArray *)forwardListWithLimit:(int)limit 232 { 233 HistoryItemVector list; 234 core(self)->forwardListWithLimit(limit, list); 235 NSArray *result = vectorToNSArray(list); 236 237 if (bumperCarBackForwardHackNeeded()) { 238 static NSArray *lastForwardListArray = nil; 239 [lastForwardListArray release]; 240 lastForwardListArray = [result retain]; 241 } 242 243 return result; 244 } 245 246 - (int)capacity 247 { 248 return core(self)->capacity(); 249 } 250 251 - (void)setCapacity:(int)size 252 { 253 core(self)->setCapacity(size); 254 } 255 256 257 -(NSString *)description 258 { 259 NSMutableString *result; 260 261 result = [NSMutableString stringWithCapacity:512]; 262 263 [result appendString:@"\n--------------------------------------------\n"]; 264 [result appendString:@"WebBackForwardList:\n"]; 265 266 BackForwardList* backForwardList = core(self); 267 HistoryItemVector& entries = backForwardList->entries(); 268 269 unsigned size = entries.size(); 270 for (unsigned i = 0; i < size; ++i) { 271 if (entries[i] == backForwardList->currentItem()) { 272 [result appendString:@" >>>"]; 273 } else { 274 [result appendString:@" "]; 275 } 276 [result appendFormat:@"%2d) ", i]; 277 int currPos = [result length]; 278 [result appendString:[kit(entries[i].get()) description]]; 279 280 // shift all the contents over. a bit slow, but this is for debugging 281 NSRange replRange = {currPos, [result length]-currPos}; 282 [result replaceOccurrencesOfString:@"\n" withString:@"\n " options:0 range:replRange]; 283 284 [result appendString:@"\n"]; 285 } 286 287 [result appendString:@"\n--------------------------------------------\n"]; 288 289 return result; 290 } 291 292 - (void)setPageCacheSize:(NSUInteger)size 293 { 294 [kit(core(self)->page()) setUsesPageCache:size != 0]; 295 } 296 297 - (NSUInteger)pageCacheSize 298 { 299 return [kit(core(self)->page()) usesPageCache] ? pageCache()->capacity() : 0; 300 } 301 302 - (int)backListCount 303 { 304 return core(self)->backListCount(); 305 } 306 307 - (int)forwardListCount 308 { 309 return core(self)->forwardListCount(); 310 } 311 312 - (WebHistoryItem *)itemAtIndex:(int)index 313 { 314 return [[kit(core(self)->itemAtIndex(index)) retain] autorelease]; 315 } 316 317 @end 318