WebHistoryItem.mm revision 65f03d4f644ce73618e5f4f50dd694b26f55ae12
1/* 2 * Copyright (C) 2005, 2007, 2008 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 "WebHistoryItemInternal.h" 30#import "WebHistoryItemPrivate.h" 31 32#import "WebFrameInternal.h" 33#import "WebFrameView.h" 34#import "WebHTMLViewInternal.h" 35#import "WebIconDatabase.h" 36#import "WebKitLogging.h" 37#import "WebKitNSStringExtras.h" 38#import "WebNSArrayExtras.h" 39#import "WebNSDictionaryExtras.h" 40#import "WebNSObjectExtras.h" 41#import "WebNSURLExtras.h" 42#import "WebNSURLRequestExtras.h" 43#import "WebNSViewExtras.h" 44#import "WebPluginController.h" 45#import "WebTypesInternal.h" 46#import <WebCore/HistoryItem.h> 47#import <WebCore/Image.h> 48#import <WebCore/KURL.h> 49#import <WebCore/PageCache.h> 50#import <WebCore/PlatformString.h> 51#import <WebCore/ThreadCheck.h> 52#import <WebCore/WebCoreObjCExtras.h> 53#import <runtime/InitializeThreading.h> 54#import <wtf/Assertions.h> 55#import <wtf/StdLibExtras.h> 56#import <wtf/Threading.h> 57 58// Private keys used in the WebHistoryItem's dictionary representation. 59// see 3245793 for explanation of "lastVisitedDate" 60static NSString *lastVisitedTimeIntervalKey = @"lastVisitedDate"; 61static NSString *visitCountKey = @"visitCount"; 62static NSString *titleKey = @"title"; 63static NSString *childrenKey = @"children"; 64static NSString *displayTitleKey = @"displayTitle"; 65static NSString *lastVisitWasFailureKey = @"lastVisitWasFailure"; 66static NSString *lastVisitWasHTTPNonGetKey = @"lastVisitWasHTTPNonGet"; 67static NSString *redirectURLsKey = @"redirectURLs"; 68static NSString *dailyVisitCountKey = @"D"; // short key to save space 69static NSString *weeklyVisitCountKey = @"W"; // short key to save space 70 71// Notification strings. 72NSString *WebHistoryItemChangedNotification = @"WebHistoryItemChangedNotification"; 73 74using namespace WebCore; 75using namespace std; 76 77typedef HashMap<HistoryItem*, WebHistoryItem*> HistoryItemMap; 78 79static inline WebHistoryItemPrivate* kitPrivate(WebCoreHistoryItem* list) { return (WebHistoryItemPrivate*)list; } 80static inline WebCoreHistoryItem* core(WebHistoryItemPrivate* list) { return (WebCoreHistoryItem*)list; } 81 82static HistoryItemMap& historyItemWrappers() 83{ 84 DEFINE_STATIC_LOCAL(HistoryItemMap, historyItemWrappers, ()); 85 return historyItemWrappers; 86} 87 88void WKNotifyHistoryItemChanged(HistoryItem*) 89{ 90 [[NSNotificationCenter defaultCenter] 91 postNotificationName:WebHistoryItemChangedNotification object:nil userInfo:nil]; 92} 93 94@implementation WebHistoryItem 95 96+ (void)initialize 97{ 98 JSC::initializeThreading(); 99 WTF::initializeMainThreadToProcessMainThread(); 100#ifndef BUILDING_ON_TIGER 101 WebCoreObjCFinalizeOnMainThread(self); 102#endif 103} 104 105- (id)init 106{ 107 return [self initWithWebCoreHistoryItem:HistoryItem::create()]; 108} 109 110- (id)initWithURLString:(NSString *)URLString title:(NSString *)title lastVisitedTimeInterval:(NSTimeInterval)time 111{ 112 WebCoreThreadViolationCheckRoundOne(); 113 return [self initWithWebCoreHistoryItem:HistoryItem::create(URLString, title, time)]; 114} 115 116- (void)dealloc 117{ 118 if (WebCoreObjCScheduleDeallocateOnMainThread([WebHistoryItem class], self)) 119 return; 120 121 if (_private) { 122 HistoryItem* coreItem = core(_private); 123 coreItem->deref(); 124 historyItemWrappers().remove(coreItem); 125 } 126 [super dealloc]; 127} 128 129- (void)finalize 130{ 131 WebCoreThreadViolationCheckRoundOne(); 132 // FIXME: ~HistoryItem is what releases the history item's icon from the icon database 133 // It's probably not good to release icons from the database only when the object is garbage-collected. 134 // Need to change design so this happens at a predictable time. 135 if (_private) { 136 HistoryItem* coreItem = core(_private); 137 coreItem->deref(); 138 historyItemWrappers().remove(coreItem); 139 } 140 [super finalize]; 141} 142 143- (id)copyWithZone:(NSZone *)zone 144{ 145 WebCoreThreadViolationCheckRoundOne(); 146 WebHistoryItem *copy = (WebHistoryItem *)NSCopyObject(self, 0, zone); 147 RefPtr<HistoryItem> item = core(_private)->copy(); 148 copy->_private = kitPrivate(item.get()); 149 historyItemWrappers().set(item.release().releaseRef(), copy); 150 151 return copy; 152} 153 154// FIXME: Need to decide if this class ever returns URLs and decide on the name of this method 155- (NSString *)URLString 156{ 157 ASSERT_MAIN_THREAD(); 158 return nsStringNilIfEmpty(core(_private)->urlString()); 159} 160 161// The first URL we loaded to get to where this history item points. Includes both client 162// and server redirects. 163- (NSString *)originalURLString 164{ 165 ASSERT_MAIN_THREAD(); 166 return nsStringNilIfEmpty(core(_private)->originalURLString()); 167} 168 169- (NSString *)title 170{ 171 ASSERT_MAIN_THREAD(); 172 return nsStringNilIfEmpty(core(_private)->title()); 173} 174 175- (void)setAlternateTitle:(NSString *)alternateTitle 176{ 177 core(_private)->setAlternateTitle(alternateTitle); 178} 179 180- (NSString *)alternateTitle 181{ 182 return nsStringNilIfEmpty(core(_private)->alternateTitle()); 183} 184 185- (NSImage *)icon 186{ 187 return [[WebIconDatabase sharedIconDatabase] iconForURL:[self URLString] withSize:WebIconSmallSize]; 188 189 // FIXME: Ideally, this code should simply be the following - 190 // return core(_private)->icon()->getNSImage(); 191 // Once radar - 192 // <rdar://problem/4906567> - NSImage returned from WebCore::Image may be incorrect size 193 // is resolved 194} 195 196- (NSTimeInterval)lastVisitedTimeInterval 197{ 198 ASSERT_MAIN_THREAD(); 199 return core(_private)->lastVisitedTime(); 200} 201 202- (NSUInteger)hash 203{ 204 return [(NSString*)core(_private)->urlString() hash]; 205} 206 207- (BOOL)isEqual:(id)anObject 208{ 209 ASSERT_MAIN_THREAD(); 210 if (![anObject isMemberOfClass:[WebHistoryItem class]]) { 211 return NO; 212 } 213 214 return core(_private)->urlString() == core(((WebHistoryItem*)anObject)->_private)->urlString(); 215} 216 217- (NSString *)description 218{ 219 ASSERT_MAIN_THREAD(); 220 HistoryItem* coreItem = core(_private); 221 NSMutableString *result = [NSMutableString stringWithFormat:@"%@ %@", [super description], (NSString*)coreItem->urlString()]; 222 if (!coreItem->target().isEmpty()) { 223 NSString *target = coreItem->target(); 224 [result appendFormat:@" in \"%@\"", target]; 225 } 226 if (coreItem->isTargetItem()) { 227 [result appendString:@" *target*"]; 228 } 229 if (coreItem->formData()) { 230 [result appendString:@" *POST*"]; 231 } 232 233 if (coreItem->children().size()) { 234 const HistoryItemVector& children = coreItem->children(); 235 int currPos = [result length]; 236 unsigned size = children.size(); 237 for (unsigned i = 0; i < size; ++i) { 238 WebHistoryItem *child = kit(children[i].get()); 239 [result appendString:@"\n"]; 240 [result appendString:[child description]]; 241 } 242 // shift all the contents over. A bit slow, but hey, this is for debugging. 243 NSRange replRange = {currPos, [result length]-currPos}; 244 [result replaceOccurrencesOfString:@"\n" withString:@"\n " options:0 range:replRange]; 245 } 246 247 return result; 248} 249 250@end 251 252@interface WebWindowWatcher : NSObject 253@end 254 255 256@implementation WebHistoryItem (WebInternal) 257 258HistoryItem* core(WebHistoryItem *item) 259{ 260 if (!item) 261 return 0; 262 263 ASSERT(historyItemWrappers().get(core(item->_private)) == item); 264 265 return core(item->_private); 266} 267 268WebHistoryItem *kit(HistoryItem* item) 269{ 270 if (!item) 271 return nil; 272 273 WebHistoryItem *kitItem = historyItemWrappers().get(item); 274 if (kitItem) 275 return kitItem; 276 277 return [[[WebHistoryItem alloc] initWithWebCoreHistoryItem:item] autorelease]; 278} 279 280+ (WebHistoryItem *)entryWithURL:(NSURL *)URL 281{ 282 return [[[self alloc] initWithURL:URL title:nil] autorelease]; 283} 284 285static WebWindowWatcher *_windowWatcher = nil; 286 287+ (void)initWindowWatcherIfNecessary 288{ 289 if (_windowWatcher) 290 return; 291 _windowWatcher = [[WebWindowWatcher alloc] init]; 292 [[NSNotificationCenter defaultCenter] addObserver:_windowWatcher selector:@selector(windowWillClose:) 293 name:NSWindowWillCloseNotification object:nil]; 294} 295 296- (id)initWithURL:(NSURL *)URL target:(NSString *)target parent:(NSString *)parent title:(NSString *)title 297{ 298 return [self initWithWebCoreHistoryItem:HistoryItem::create(URL, target, parent, title)]; 299} 300 301- (id)initWithURLString:(NSString *)URLString title:(NSString *)title displayTitle:(NSString *)displayTitle lastVisitedTimeInterval:(NSTimeInterval)time 302{ 303 return [self initWithWebCoreHistoryItem:HistoryItem::create(URLString, title, displayTitle, time)]; 304} 305 306- (id)initWithWebCoreHistoryItem:(PassRefPtr<HistoryItem>)item 307{ 308 WebCoreThreadViolationCheckRoundOne(); 309 // Need to tell WebCore what function to call for the 310 // "History Item has Changed" notification - no harm in doing this 311 // everytime a WebHistoryItem is created 312 // Note: We also do this in [WebFrameView initWithFrame:] where we do 313 // other "init before WebKit is used" type things 314 WebCore::notifyHistoryItemChanged = WKNotifyHistoryItemChanged; 315 316 self = [super init]; 317 318 _private = kitPrivate(item.releaseRef()); 319 ASSERT(!historyItemWrappers().get(core(_private))); 320 historyItemWrappers().set(core(_private), self); 321 return self; 322} 323 324- (void)setTitle:(NSString *)title 325{ 326 core(_private)->setTitle(title); 327} 328 329- (void)setVisitCount:(int)count 330{ 331 core(_private)->setVisitCount(count); 332} 333 334- (void)setViewState:(id)statePList 335{ 336 core(_private)->setViewState(statePList); 337} 338 339- (void)_mergeAutoCompleteHints:(WebHistoryItem *)otherItem 340{ 341 ASSERT_ARG(otherItem, otherItem); 342 core(_private)->mergeAutoCompleteHints(core(otherItem->_private)); 343} 344 345- (id)initFromDictionaryRepresentation:(NSDictionary *)dict 346{ 347 ASSERT_MAIN_THREAD(); 348 NSString *URLString = [dict _webkit_stringForKey:@""]; 349 NSString *title = [dict _webkit_stringForKey:titleKey]; 350 351 // Do an existence check to avoid calling doubleValue on a nil string. Leave 352 // time interval at 0 if there's no value in dict. 353 NSString *timeIntervalString = [dict _webkit_stringForKey:lastVisitedTimeIntervalKey]; 354 NSTimeInterval lastVisited = timeIntervalString == nil ? 0 : [timeIntervalString doubleValue]; 355 356 self = [self initWithURLString:URLString title:title displayTitle:[dict _webkit_stringForKey:displayTitleKey] lastVisitedTimeInterval:lastVisited]; 357 358 // Check if we've read a broken URL from the file that has non-Latin1 chars. If so, try to convert 359 // as if it was from user typing. 360 if (![URLString canBeConvertedToEncoding:NSISOLatin1StringEncoding]) { 361 NSURL *tempURL = [NSURL _web_URLWithUserTypedString:URLString]; 362 ASSERT(tempURL); 363 NSString *newURLString = [tempURL _web_originalDataAsString]; 364 core(_private)->setURLString(newURLString); 365 core(_private)->setOriginalURLString(newURLString); 366 } 367 368 int visitCount = [dict _webkit_intForKey:visitCountKey]; 369 370 // Can't trust data on disk, and we've had at least one report of this (<rdar://6572300>). 371 if (visitCount < 0) { 372 LOG_ERROR("visit count for history item \"%@\" is negative (%d), will be reset to 1", URLString, visitCount); 373 visitCount = 1; 374 } 375 core(_private)->setVisitCount(visitCount); 376 377 if ([dict _webkit_boolForKey:lastVisitWasFailureKey]) 378 core(_private)->setLastVisitWasFailure(true); 379 380 BOOL lastVisitWasHTTPNonGet = [dict _webkit_boolForKey:lastVisitWasHTTPNonGetKey]; 381 NSString *tempURLString = [URLString lowercaseString]; 382 if (lastVisitWasHTTPNonGet && ([tempURLString hasPrefix:@"http:"] || [tempURLString hasPrefix:@"https:"])) 383 core(_private)->setLastVisitWasHTTPNonGet(lastVisitWasHTTPNonGet); 384 385 if (NSArray *redirectURLs = [dict _webkit_arrayForKey:redirectURLsKey]) { 386 NSUInteger size = [redirectURLs count]; 387 OwnPtr<Vector<String> > redirectURLsVector(new Vector<String>(size)); 388 for (NSUInteger i = 0; i < size; ++i) 389 (*redirectURLsVector)[i] = String([redirectURLs _webkit_stringAtIndex:i]); 390 core(_private)->setRedirectURLs(redirectURLsVector.release()); 391 } 392 393 NSArray *dailyCounts = [dict _webkit_arrayForKey:dailyVisitCountKey]; 394 NSArray *weeklyCounts = [dict _webkit_arrayForKey:weeklyVisitCountKey]; 395 if (dailyCounts || weeklyCounts) { 396 Vector<int> coreDailyCounts([dailyCounts count]); 397 Vector<int> coreWeeklyCounts([weeklyCounts count]); 398 399 // Daily and weekly counts < 0 are errors in the data read from disk, so reset to 0. 400 for (size_t i = 0; i < coreDailyCounts.size(); ++i) 401 coreDailyCounts[i] = max([[dailyCounts _webkit_numberAtIndex:i] intValue], 0); 402 for (size_t i = 0; i < coreWeeklyCounts.size(); ++i) 403 coreWeeklyCounts[i] = max([[weeklyCounts _webkit_numberAtIndex:i] intValue], 0); 404 405 core(_private)->adoptVisitCounts(coreDailyCounts, coreWeeklyCounts); 406 } 407 408 NSArray *childDicts = [dict objectForKey:childrenKey]; 409 if (childDicts) { 410 for (int i = [childDicts count] - 1; i >= 0; i--) { 411 WebHistoryItem *child = [[WebHistoryItem alloc] initFromDictionaryRepresentation:[childDicts objectAtIndex:i]]; 412 core(_private)->addChildItem(core(child->_private)); 413 [child release]; 414 } 415 } 416 417 return self; 418} 419 420- (NSPoint)scrollPoint 421{ 422 ASSERT_MAIN_THREAD(); 423 return core(_private)->scrollPoint(); 424} 425 426- (void)_visitedWithTitle:(NSString *)title increaseVisitCount:(BOOL)increaseVisitCount 427{ 428 core(_private)->visited(title, [NSDate timeIntervalSinceReferenceDate], increaseVisitCount ? IncreaseVisitCount : DoNotIncreaseVisitCount); 429} 430 431- (void)_recordInitialVisit 432{ 433 core(_private)->recordInitialVisit(); 434} 435 436@end 437 438@implementation WebHistoryItem (WebPrivate) 439 440- (id)initWithURL:(NSURL *)URL title:(NSString *)title 441{ 442 return [self initWithURLString:[URL _web_originalDataAsString] title:title lastVisitedTimeInterval:0]; 443} 444 445- (NSDictionary *)dictionaryRepresentation 446{ 447 ASSERT_MAIN_THREAD(); 448 NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:8]; 449 450 HistoryItem* coreItem = core(_private); 451 452 if (!coreItem->urlString().isEmpty()) 453 [dict setObject:(NSString*)coreItem->urlString() forKey:@""]; 454 if (!coreItem->title().isEmpty()) 455 [dict setObject:(NSString*)coreItem->title() forKey:titleKey]; 456 if (!coreItem->alternateTitle().isEmpty()) 457 [dict setObject:(NSString*)coreItem->alternateTitle() forKey:displayTitleKey]; 458 if (coreItem->lastVisitedTime() != 0.0) { 459 // Store as a string to maintain backward compatibility. (See 3245793) 460 [dict setObject:[NSString stringWithFormat:@"%.1lf", coreItem->lastVisitedTime()] 461 forKey:lastVisitedTimeIntervalKey]; 462 } 463 if (coreItem->visitCount()) 464 [dict setObject:[NSNumber numberWithInt:coreItem->visitCount()] forKey:visitCountKey]; 465 if (coreItem->lastVisitWasFailure()) 466 [dict setObject:[NSNumber numberWithBool:YES] forKey:lastVisitWasFailureKey]; 467 if (coreItem->lastVisitWasHTTPNonGet()) { 468 ASSERT(coreItem->urlString().startsWith("http:", false) || coreItem->urlString().startsWith("https:", false)); 469 [dict setObject:[NSNumber numberWithBool:YES] forKey:lastVisitWasHTTPNonGetKey]; 470 } 471 if (Vector<String>* redirectURLs = coreItem->redirectURLs()) { 472 size_t size = redirectURLs->size(); 473 ASSERT(size); 474 NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:size]; 475 for (size_t i = 0; i < size; ++i) 476 [result addObject:(NSString*)redirectURLs->at(i)]; 477 [dict setObject:result forKey:redirectURLsKey]; 478 [result release]; 479 } 480 481 const Vector<int>& dailyVisitCounts = coreItem->dailyVisitCounts(); 482 if (dailyVisitCounts.size()) { 483 NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:13]; 484 for (size_t i = 0; i < dailyVisitCounts.size(); ++i) 485 [array addObject:[NSNumber numberWithInt:dailyVisitCounts[i]]]; 486 [dict setObject:array forKey:dailyVisitCountKey]; 487 [array release]; 488 } 489 490 const Vector<int>& weeklyVisitCounts = coreItem->weeklyVisitCounts(); 491 if (weeklyVisitCounts.size()) { 492 NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:5]; 493 for (size_t i = 0; i < weeklyVisitCounts.size(); ++i) 494 [array addObject:[NSNumber numberWithInt:weeklyVisitCounts[i]]]; 495 [dict setObject:array forKey:weeklyVisitCountKey]; 496 [array release]; 497 } 498 499 if (coreItem->children().size()) { 500 const HistoryItemVector& children = coreItem->children(); 501 NSMutableArray *childDicts = [NSMutableArray arrayWithCapacity:children.size()]; 502 503 for (int i = children.size() - 1; i >= 0; i--) 504 [childDicts addObject:[kit(children[i].get()) dictionaryRepresentation]]; 505 [dict setObject: childDicts forKey:childrenKey]; 506 } 507 508 return dict; 509} 510 511- (NSString *)target 512{ 513 ASSERT_MAIN_THREAD(); 514 return nsStringNilIfEmpty(core(_private)->target()); 515} 516 517- (BOOL)isTargetItem 518{ 519 return core(_private)->isTargetItem(); 520} 521 522- (int)visitCount 523{ 524 ASSERT_MAIN_THREAD(); 525 return core(_private)->visitCount(); 526} 527 528- (NSString *)RSSFeedReferrer 529{ 530 return nsStringNilIfEmpty(core(_private)->referrer()); 531} 532 533- (void)setRSSFeedReferrer:(NSString *)referrer 534{ 535 core(_private)->setReferrer(referrer); 536} 537 538- (NSArray *)children 539{ 540 ASSERT_MAIN_THREAD(); 541 const HistoryItemVector& children = core(_private)->children(); 542 if (!children.size()) 543 return nil; 544 545 unsigned size = children.size(); 546 NSMutableArray *result = [[[NSMutableArray alloc] initWithCapacity:size] autorelease]; 547 548 for (unsigned i = 0; i < size; ++i) 549 [result addObject:kit(children[i].get())]; 550 551 return result; 552} 553 554- (void)setAlwaysAttemptToUsePageCache:(BOOL)flag 555{ 556 // Safari 2.0 uses this for SnapBack, so we stub it out to avoid a crash. 557} 558 559- (NSURL *)URL 560{ 561 ASSERT_MAIN_THREAD(); 562 const KURL& url = core(_private)->url(); 563 if (url.isEmpty()) 564 return nil; 565 return url; 566} 567 568// This should not be called directly for WebHistoryItems that are already included 569// in WebHistory. Use -[WebHistory setLastVisitedTimeInterval:forItem:] instead. 570- (void)_setLastVisitedTimeInterval:(NSTimeInterval)time 571{ 572 core(_private)->setLastVisitedTime(time); 573} 574 575// FIXME: <rdar://problem/4880065> - Push Global History into WebCore 576// Once that task is complete, this accessor can go away 577- (NSCalendarDate *)_lastVisitedDate 578{ 579 ASSERT_MAIN_THREAD(); 580 return [[[NSCalendarDate alloc] initWithTimeIntervalSinceReferenceDate:core(_private)->lastVisitedTime()] autorelease]; 581} 582 583- (WebHistoryItem *)targetItem 584{ 585 ASSERT_MAIN_THREAD(); 586 return kit(core(_private)->targetItem()); 587} 588 589+ (void)_releaseAllPendingPageCaches 590{ 591 pageCache()->releaseAutoreleasedPagesNow(); 592} 593 594- (id)_transientPropertyForKey:(NSString *)key 595{ 596 return core(_private)->getTransientProperty(key); 597} 598 599- (void)_setTransientProperty:(id)property forKey:(NSString *)key 600{ 601 core(_private)->setTransientProperty(key, property); 602} 603 604- (BOOL)lastVisitWasFailure 605{ 606 return core(_private)->lastVisitWasFailure(); 607} 608 609- (void)_setLastVisitWasFailure:(BOOL)failure 610{ 611 core(_private)->setLastVisitWasFailure(failure); 612} 613 614- (BOOL)_lastVisitWasHTTPNonGet 615{ 616 return core(_private)->lastVisitWasHTTPNonGet(); 617} 618 619- (NSArray *)_redirectURLs 620{ 621 Vector<String>* redirectURLs = core(_private)->redirectURLs(); 622 if (!redirectURLs) 623 return nil; 624 625 size_t size = redirectURLs->size(); 626 ASSERT(size); 627 NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:size]; 628 for (size_t i = 0; i < size; ++i) 629 [result addObject:(NSString*)redirectURLs->at(i)]; 630 return [result autorelease]; 631} 632 633- (size_t)_getDailyVisitCounts:(const int**)counts 634{ 635 HistoryItem* coreItem = core(_private); 636 *counts = coreItem->dailyVisitCounts().data(); 637 return coreItem->dailyVisitCounts().size(); 638} 639 640- (size_t)_getWeeklyVisitCounts:(const int**)counts 641{ 642 HistoryItem* coreItem = core(_private); 643 *counts = coreItem->weeklyVisitCounts().data(); 644 return coreItem->weeklyVisitCounts().size(); 645} 646 647@end 648 649 650// FIXME: <rdar://problem/4886761>. 651// This is a bizarre policy. We flush the page caches ANY time ANY window is closed? 652 653@implementation WebWindowWatcher 654 655- (void)windowWillClose:(NSNotification *)notification 656{ 657 if (!pthread_main_np()) { 658 [self performSelectorOnMainThread:_cmd withObject:notification waitUntilDone:NO]; 659 return; 660 } 661 662 pageCache()->releaseAutoreleasedPagesNow(); 663} 664 665@end 666