Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ios/chrome/browser/snapshots/snapshot_cache.h" | 5 #import "ios/chrome/browser/snapshots/snapshot_cache.h" |
| 6 | 6 |
| 7 #import <UIKit/UIKit.h> | 7 #import <UIKit/UIKit.h> |
| 8 | 8 |
| 9 #include "base/critical_closure.h" | 9 #include "base/critical_closure.h" |
| 10 #include "base/files/file_enumerator.h" | 10 #include "base/files/file_enumerator.h" |
| 11 #include "base/files/file_path.h" | 11 #include "base/files/file_path.h" |
| 12 #include "base/files/file_util.h" | 12 #include "base/files/file_util.h" |
| 13 #include "base/location.h" | 13 #include "base/location.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/mac/bind_objc_block.h" | 15 #include "base/mac/bind_objc_block.h" |
| 16 #include "base/mac/scoped_cftyperef.h" | 16 #include "base/mac/scoped_cftyperef.h" |
| 17 #include "base/strings/sys_string_conversions.h" | 17 #include "base/strings/sys_string_conversions.h" |
| 18 #include "base/task_runner_util.h" | 18 #include "base/task_runner_util.h" |
| 19 #include "base/threading/thread_restrictions.h" | 19 #include "base/threading/thread_restrictions.h" |
| 20 #include "ios/chrome/browser/experimental_flags.h" | 20 #include "ios/chrome/browser/experimental_flags.h" |
| 21 #import "ios/chrome/browser/snapshots/snapshot_cache_internal.h" | |
| 21 #include "ios/chrome/browser/ui/ui_util.h" | 22 #include "ios/chrome/browser/ui/ui_util.h" |
| 22 #import "ios/chrome/browser/ui/uikit_ui_util.h" | 23 #import "ios/chrome/browser/ui/uikit_ui_util.h" |
| 23 #include "ios/web/public/web_thread.h" | 24 #include "ios/web/public/web_thread.h" |
| 24 | 25 |
| 25 @interface SnapshotCache () | 26 @interface SnapshotCache () |
| 26 + (base::FilePath)imagePathForSessionID:(NSString*)sessionID; | |
| 27 + (base::FilePath)greyImagePathForSessionID:(NSString*)sessionID; | |
| 28 // Returns the directory where the thumbnails are saved. | 27 // Returns the directory where the thumbnails are saved. |
| 29 + (base::FilePath)cacheDirectory; | 28 + (base::FilePath)cacheDirectory; |
| 30 // Returns the directory where the thumbnails were stored in M28 and earlier. | 29 // Returns the directory where the thumbnails were stored in M28 and earlier. |
| 31 - (base::FilePath)oldCacheDirectory; | 30 - (base::FilePath)oldCacheDirectory; |
| 32 // Remove all UIImages from |imageDictionary_|. | 31 // Remove all UIImages from |imageDictionary_|. |
| 33 - (void)handleEnterBackground; | 32 - (void)handleEnterBackground; |
| 34 // Remove all but adjacent UIImages from |imageDictionary_|. | 33 // Remove all but adjacent UIImages from |imageDictionary_|. |
| 35 - (void)handleLowMemory; | 34 - (void)handleLowMemory; |
| 36 // Restore adjacent UIImages to |imageDictionary_|. | 35 // Restore adjacent UIImages to |imageDictionary_|. |
| 37 - (void)handleBecomeActive; | 36 - (void)handleBecomeActive; |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 137 + (SnapshotCache*)sharedInstance { | 136 + (SnapshotCache*)sharedInstance { |
| 138 static SnapshotCache* instance = [[SnapshotCache alloc] init]; | 137 static SnapshotCache* instance = [[SnapshotCache alloc] init]; |
| 139 return instance; | 138 return instance; |
| 140 } | 139 } |
| 141 | 140 |
| 142 - (id)init { | 141 - (id)init { |
| 143 if ((self = [super init])) { | 142 if ((self = [super init])) { |
| 144 DCHECK_CURRENTLY_ON(web::WebThread::UI); | 143 DCHECK_CURRENTLY_ON(web::WebThread::UI); |
| 145 propertyReleaser_SnapshotCache_.Init(self, [SnapshotCache class]); | 144 propertyReleaser_SnapshotCache_.Init(self, [SnapshotCache class]); |
| 146 | 145 |
| 147 // Always use the LRUCache when the tab switcher is enabled. | 146 if ([self usesLRUCache]) { |
| 148 if (experimental_flags::IsTabSwitcherEnabled() || | |
| 149 experimental_flags::IsLRUSnapshotCacheEnabled()) { | |
| 150 lruCache_.reset( | 147 lruCache_.reset( |
| 151 [[LRUCache alloc] initWithCacheSize:kLRUCacheMaxCapacity]); | 148 [[LRUCache alloc] initWithCacheSize:kLRUCacheMaxCapacity]); |
| 152 } else { | 149 } else { |
| 153 imageDictionary_.reset( | 150 imageDictionary_.reset( |
| 154 [[NSMutableDictionary alloc] initWithCapacity:kCacheInitialCapacity]); | 151 [[NSMutableDictionary alloc] initWithCapacity:kCacheInitialCapacity]); |
| 155 } | 152 } |
| 156 | 153 [[NSNotificationCenter defaultCenter] |
| 157 if (!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()) { | 154 addObserver:self |
| 158 [[NSNotificationCenter defaultCenter] | 155 selector:@selector(handleLowMemory) |
| 159 addObserver:self | 156 name:UIApplicationDidReceiveMemoryWarningNotification |
| 160 selector:@selector(handleLowMemory) | 157 object:nil]; |
| 161 name:UIApplicationDidReceiveMemoryWarningNotification | 158 [[NSNotificationCenter defaultCenter] |
| 162 object:nil]; | 159 addObserver:self |
| 163 [[NSNotificationCenter defaultCenter] | 160 selector:@selector(handleEnterBackground) |
| 164 addObserver:self | 161 name:UIApplicationDidEnterBackgroundNotification |
| 165 selector:@selector(handleEnterBackground) | 162 object:nil]; |
| 166 name:UIApplicationDidEnterBackgroundNotification | 163 [[NSNotificationCenter defaultCenter] |
| 167 object:nil]; | 164 addObserver:self |
| 168 [[NSNotificationCenter defaultCenter] | 165 selector:@selector(handleBecomeActive) |
| 169 addObserver:self | 166 name:UIApplicationDidBecomeActiveNotification |
| 170 selector:@selector(handleBecomeActive) | 167 object:nil]; |
| 171 name:UIApplicationDidBecomeActiveNotification | |
| 172 object:nil]; | |
| 173 } | |
| 174 } | 168 } |
| 175 return self; | 169 return self; |
| 176 } | 170 } |
| 177 | 171 |
| 178 - (void)dealloc { | 172 - (void)dealloc { |
| 179 if (!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()) { | 173 [[NSNotificationCenter defaultCenter] |
| 180 [[NSNotificationCenter defaultCenter] | 174 removeObserver:self |
| 181 removeObserver:self | 175 name:UIApplicationDidReceiveMemoryWarningNotification |
| 182 name:UIApplicationDidReceiveMemoryWarningNotification | 176 object:nil]; |
| 183 object:nil]; | 177 [[NSNotificationCenter defaultCenter] |
| 184 [[NSNotificationCenter defaultCenter] | 178 removeObserver:self |
| 185 removeObserver:self | 179 name:UIApplicationDidEnterBackgroundNotification |
| 186 name:UIApplicationDidEnterBackgroundNotification | 180 object:nil]; |
| 187 object:nil]; | 181 [[NSNotificationCenter defaultCenter] |
| 188 [[NSNotificationCenter defaultCenter] | 182 removeObserver:self |
| 189 removeObserver:self | 183 name:UIApplicationDidBecomeActiveNotification |
| 190 name:UIApplicationDidBecomeActiveNotification | 184 object:nil]; |
| 191 object:nil]; | |
| 192 } | |
| 193 [super dealloc]; | 185 [super dealloc]; |
| 194 } | 186 } |
| 195 | 187 |
| 196 + (CGFloat)snapshotScaleForDevice { | 188 + (CGFloat)snapshotScaleForDevice { |
| 197 // On handset, the color snapshot is used for the stack view, so the scale of | 189 // On handset, the color snapshot is used for the stack view, so the scale of |
| 198 // the snapshot images should match the scale of the device. | 190 // the snapshot images should match the scale of the device. |
| 199 // On tablet, the color snapshot is only used to generate the grey snapshot, | 191 // On tablet, the color snapshot is only used to generate the grey snapshot, |
| 200 // which does not have to be high quality, so use scale of 1.0 on all tablets. | 192 // which does not have to be high quality, so use scale of 1.0 on all tablets. |
| 201 if (IsIPadIdiom()) { | 193 if (IsIPadIdiom()) { |
| 202 return 1.0; | 194 return 1.0; |
| 203 } | 195 } |
| 204 // Cap snapshot resolution to 2x to reduce the amount of memory they use. | 196 // Cap snapshot resolution to 2x to reduce the amount of memory they use. |
| 205 return MIN([UIScreen mainScreen].scale, 2.0); | 197 return MIN([UIScreen mainScreen].scale, 2.0); |
| 206 } | 198 } |
| 207 | 199 |
| 208 - (void)retrieveImageForSessionID:(NSString*)sessionID | 200 - (void)retrieveImageForSessionID:(NSString*)sessionID |
| 209 callback:(void (^)(UIImage*))callback { | 201 callback:(void (^)(UIImage*))callback { |
| 210 DCHECK_CURRENTLY_ON(web::WebThread::UI); | 202 DCHECK_CURRENTLY_ON(web::WebThread::UI); |
| 211 DCHECK(sessionID); | 203 DCHECK(sessionID); |
| 212 | 204 |
| 213 // Cache on iPad is enabled only when the tab switcher is enabled. | 205 if (![self inMemoryCacheIsEnabled] && !callback) |
| 214 if ((IsIPadIdiom() && !experimental_flags::IsTabSwitcherEnabled()) && | |
| 215 !callback) | |
| 216 return; | 206 return; |
| 217 | 207 |
| 218 UIImage* img = nil; | 208 UIImage* img = nil; |
| 219 if (lruCache_) | 209 if (lruCache_) |
| 220 img = [lruCache_ objectForKey:sessionID]; | 210 img = [lruCache_ objectForKey:sessionID]; |
| 221 else | 211 else |
| 222 img = [imageDictionary_ objectForKey:sessionID]; | 212 img = [imageDictionary_ objectForKey:sessionID]; |
| 223 | 213 |
| 224 if (img) { | 214 if (img) { |
| 225 if (callback) | 215 if (callback) |
| 226 callback(img); | 216 callback(img); |
| 227 return; | 217 return; |
| 228 } | 218 } |
| 229 | 219 |
| 230 base::PostTaskAndReplyWithResult( | 220 base::PostTaskAndReplyWithResult( |
| 231 web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE_USER_BLOCKING) | 221 web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE_USER_BLOCKING) |
| 232 .get(), | 222 .get(), |
| 233 FROM_HERE, base::BindBlock(^base::scoped_nsobject<UIImage>() { | 223 FROM_HERE, base::BindBlock(^base::scoped_nsobject<UIImage>() { |
| 234 // Retrieve the image on a high priority thread. | 224 // Retrieve the image on a high priority thread. |
| 235 return base::scoped_nsobject<UIImage>([ReadImageFromDisk( | 225 return base::scoped_nsobject<UIImage>([ReadImageFromDisk( |
| 236 [SnapshotCache imagePathForSessionID:sessionID]) retain]); | 226 [SnapshotCache imagePathForSessionID:sessionID]) retain]); |
| 237 }), | 227 }), |
| 238 base::BindBlock(^(base::scoped_nsobject<UIImage> image) { | 228 base::BindBlock(^(base::scoped_nsobject<UIImage> image) { |
| 239 // Cache on iPad is enabled only when the tab switcher is enabled. | 229 if ([self inMemoryCacheIsEnabled] && image) { |
| 240 if ((!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()) && | |
| 241 image) { | |
| 242 if (lruCache_) | 230 if (lruCache_) |
| 243 [lruCache_ setObject:image forKey:sessionID]; | 231 [lruCache_ setObject:image forKey:sessionID]; |
| 244 else | 232 else |
| 245 [imageDictionary_ setObject:image forKey:sessionID]; | 233 [imageDictionary_ setObject:image forKey:sessionID]; |
| 246 } | 234 } |
| 247 if (callback) | 235 if (callback) |
| 248 callback(image); | 236 callback(image); |
| 249 })); | 237 })); |
| 250 } | 238 } |
| 251 | 239 |
| 252 - (void)setImage:(UIImage*)img withSessionID:(NSString*)sessionID { | 240 - (void)setImage:(UIImage*)img withSessionID:(NSString*)sessionID { |
| 253 DCHECK_CURRENTLY_ON(web::WebThread::UI); | 241 DCHECK_CURRENTLY_ON(web::WebThread::UI); |
| 254 if (!img || !sessionID) | 242 if (!img || !sessionID) |
| 255 return; | 243 return; |
| 256 | 244 |
| 257 // Cache on iPad is enabled only when the tab switcher is enabled. | 245 if ([self inMemoryCacheIsEnabled]) { |
| 258 if (!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()) { | |
| 259 if (lruCache_) | 246 if (lruCache_) |
| 260 [lruCache_ setObject:img forKey:sessionID]; | 247 [lruCache_ setObject:img forKey:sessionID]; |
| 261 else | 248 else |
| 262 [imageDictionary_ setObject:img forKey:sessionID]; | 249 [imageDictionary_ setObject:img forKey:sessionID]; |
| 263 } | 250 } |
| 264 // Save the image to disk. | 251 // Save the image to disk. |
| 265 web::WebThread::PostBlockingPoolSequencedTask( | 252 web::WebThread::PostBlockingPoolSequencedTask( |
| 266 kSequenceToken, FROM_HERE, | 253 kSequenceToken, FROM_HERE, |
| 267 base::BindBlock(^{ | 254 base::BindBlock(^{ |
| 268 base::scoped_nsobject<UIImage> image([img retain]); | 255 base::scoped_nsobject<UIImage> image([img retain]); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 379 return; | 366 return; |
| 380 backgroundingImageSessionId_.reset([sessionID copy]); | 367 backgroundingImageSessionId_.reset([sessionID copy]); |
| 381 if (lruCache_) { | 368 if (lruCache_) { |
| 382 backgroundingColorImage_.reset([[lruCache_ objectForKey:sessionID] retain]); | 369 backgroundingColorImage_.reset([[lruCache_ objectForKey:sessionID] retain]); |
| 383 } else { | 370 } else { |
| 384 backgroundingColorImage_.reset( | 371 backgroundingColorImage_.reset( |
| 385 [[imageDictionary_ objectForKey:sessionID] retain]); | 372 [[imageDictionary_ objectForKey:sessionID] retain]); |
| 386 } | 373 } |
| 387 } | 374 } |
| 388 | 375 |
| 376 - (BOOL)inMemoryCacheIsEnabled { | |
| 377 // In-memory cache on iPad is enabled only when the tab switcher is enabled. | |
| 378 return !IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled(); | |
| 379 } | |
| 380 | |
| 381 - (BOOL)usesLRUCache { | |
| 382 // Always use the LRUCache when the tab switcher is enabled. | |
| 383 return experimental_flags::IsTabSwitcherEnabled() || | |
| 384 experimental_flags::IsLRUSnapshotCacheEnabled(); | |
| 385 } | |
| 386 | |
| 389 - (void)handleLowMemory { | 387 - (void)handleLowMemory { |
| 390 DCHECK(!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()); | |
| 391 DCHECK_CURRENTLY_ON(web::WebThread::UI); | 388 DCHECK_CURRENTLY_ON(web::WebThread::UI); |
| 392 base::scoped_nsobject<NSMutableDictionary> dictionary( | 389 base::scoped_nsobject<NSMutableDictionary> dictionary( |
| 393 [[NSMutableDictionary alloc] initWithCapacity:2]); | 390 [[NSMutableDictionary alloc] initWithCapacity:2]); |
| 394 for (NSString* sessionID in pinnedIDs_) { | 391 for (NSString* sessionID in pinnedIDs_) { |
| 395 UIImage* image = nil; | 392 UIImage* image = nil; |
| 396 if (lruCache_) | 393 if (lruCache_) |
| 397 image = [lruCache_ objectForKey:sessionID]; | 394 image = [lruCache_ objectForKey:sessionID]; |
| 398 else | 395 else |
| 399 image = [imageDictionary_ objectForKey:sessionID]; | 396 image = [imageDictionary_ objectForKey:sessionID]; |
| 400 if (image) | 397 if (image) |
| 401 [dictionary setObject:image forKey:sessionID]; | 398 [dictionary setObject:image forKey:sessionID]; |
| 402 } | 399 } |
| 403 if (lruCache_) { | 400 if (lruCache_) { |
| 404 [lruCache_ removeAllObjects]; | 401 [lruCache_ removeAllObjects]; |
| 405 for (NSString* sessionID in pinnedIDs_) | 402 for (NSString* sessionID in pinnedIDs_) |
| 406 [lruCache_ setObject:[dictionary objectForKey:sessionID] | 403 [lruCache_ setObject:[dictionary objectForKey:sessionID] |
| 407 forKey:sessionID]; | 404 forKey:sessionID]; |
| 408 } else { | 405 } else { |
| 409 imageDictionary_ = dictionary; | 406 imageDictionary_ = dictionary; |
| 410 } | 407 } |
| 411 } | 408 } |
| 412 | 409 |
| 413 - (void)handleEnterBackground { | 410 - (void)handleEnterBackground { |
| 414 DCHECK(!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()); | |
| 415 DCHECK_CURRENTLY_ON(web::WebThread::UI); | 411 DCHECK_CURRENTLY_ON(web::WebThread::UI); |
| 416 [imageDictionary_ removeAllObjects]; | 412 [imageDictionary_ removeAllObjects]; |
| 417 [lruCache_ removeAllObjects]; | 413 [lruCache_ removeAllObjects]; |
| 418 } | 414 } |
| 419 | 415 |
| 420 - (void)handleBecomeActive { | 416 - (void)handleBecomeActive { |
| 421 DCHECK(!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()); | |
| 422 DCHECK_CURRENTLY_ON(web::WebThread::UI); | 417 DCHECK_CURRENTLY_ON(web::WebThread::UI); |
| 423 for (NSString* sessionID in pinnedIDs_) | 418 for (NSString* sessionID in pinnedIDs_) |
| 424 [self retrieveImageForSessionID:sessionID callback:nil]; | 419 [self retrieveImageForSessionID:sessionID callback:nil]; |
| 425 } | 420 } |
| 426 | 421 |
| 427 - (void)saveGreyImage:(UIImage*)greyImage forKey:(NSString*)sessionID { | 422 - (void)saveGreyImage:(UIImage*)greyImage forKey:(NSString*)sessionID { |
| 428 DCHECK_CURRENTLY_ON(web::WebThread::UI); | 423 DCHECK_CURRENTLY_ON(web::WebThread::UI); |
| 429 if (greyImage) | 424 if (greyImage) |
| 430 [greyImageDictionary_ setObject:greyImage forKey:sessionID]; | 425 [greyImageDictionary_ setObject:greyImage forKey:sessionID]; |
| 431 if ([sessionID isEqualToString:mostRecentGreySessionId_]) { | 426 if ([sessionID isEqualToString:mostRecentGreySessionId_]) { |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 562 web::WebThread::PostBlockingPoolTask( | 557 web::WebThread::PostBlockingPoolTask( |
| 563 FROM_HERE, base::Bind(&ConvertAndSaveGreyImage, colorImagePath, | 558 FROM_HERE, base::Bind(&ConvertAndSaveGreyImage, colorImagePath, |
| 564 greyImagePath, backgroundingColorImage_)); | 559 greyImagePath, backgroundingColorImage_)); |
| 565 } | 560 } |
| 566 | 561 |
| 567 @end | 562 @end |
| 568 | 563 |
| 569 @implementation SnapshotCache (TestingAdditions) | 564 @implementation SnapshotCache (TestingAdditions) |
| 570 | 565 |
| 571 - (BOOL)hasImageInMemory:(NSString*)sessionID { | 566 - (BOOL)hasImageInMemory:(NSString*)sessionID { |
| 572 if (experimental_flags::IsLRUSnapshotCacheEnabled()) | 567 if ([self usesLRUCache]) |
|
sdefresne
2016/10/07 14:56:19
The test changed, is this expected?
jif
2016/10/24 15:10:03
Yes. It is now correct:
The LRU cache is used when
| |
| 573 return [lruCache_ objectForKey:sessionID] != nil; | 568 return [lruCache_ objectForKey:sessionID] != nil; |
| 574 else | 569 else |
| 575 return [imageDictionary_ objectForKey:sessionID] != nil; | 570 return [imageDictionary_ objectForKey:sessionID] != nil; |
| 576 } | 571 } |
| 572 | |
| 577 - (BOOL)hasGreyImageInMemory:(NSString*)sessionID { | 573 - (BOOL)hasGreyImageInMemory:(NSString*)sessionID { |
| 578 return [greyImageDictionary_ objectForKey:sessionID] != nil; | 574 return [greyImageDictionary_ objectForKey:sessionID] != nil; |
| 579 } | 575 } |
| 580 | 576 |
| 581 - (NSUInteger)lruCacheMaxSize { | 577 - (NSUInteger)lruCacheMaxSize { |
| 582 return [lruCache_ maxCacheSize]; | 578 return [lruCache_ maxCacheSize]; |
| 583 } | 579 } |
| 584 | 580 |
| 585 @end | 581 @end |
| OLD | NEW |