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" |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
137 + (SnapshotCache*)sharedInstance { | 137 + (SnapshotCache*)sharedInstance { |
138 static SnapshotCache* instance = [[SnapshotCache alloc] init]; | 138 static SnapshotCache* instance = [[SnapshotCache alloc] init]; |
139 return instance; | 139 return instance; |
140 } | 140 } |
141 | 141 |
142 - (id)init { | 142 - (id)init { |
143 if ((self = [super init])) { | 143 if ((self = [super init])) { |
144 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); | 144 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); |
145 propertyReleaser_SnapshotCache_.Init(self, [SnapshotCache class]); | 145 propertyReleaser_SnapshotCache_.Init(self, [SnapshotCache class]); |
146 | 146 |
147 if (!IsIPadIdiom()) { | 147 // Always use the LRUCache when the tab switcher is enabled. |
148 if (experimental_flags::IsLRUSnapshotCacheEnabled()) { | 148 if (experimental_flags::IsTabSwitcherEnabled() || |
149 lruCache_.reset( | 149 experimental_flags::IsLRUSnapshotCacheEnabled()) { |
150 [[LRUCache alloc] initWithCacheSize:kLRUCacheMaxCapacity]); | 150 lruCache_.reset( |
151 } else { | 151 [[LRUCache alloc] initWithCacheSize:kLRUCacheMaxCapacity]); |
152 imageDictionary_.reset([[NSMutableDictionary alloc] | 152 } else { |
153 initWithCapacity:kCacheInitialCapacity]); | 153 imageDictionary_.reset( |
154 } | 154 [[NSMutableDictionary alloc] initWithCapacity:kCacheInitialCapacity]); |
| 155 } |
155 | 156 |
| 157 if (!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()) { |
156 [[NSNotificationCenter defaultCenter] | 158 [[NSNotificationCenter defaultCenter] |
157 addObserver:self | 159 addObserver:self |
158 selector:@selector(handleLowMemory) | 160 selector:@selector(handleLowMemory) |
159 name:UIApplicationDidReceiveMemoryWarningNotification | 161 name:UIApplicationDidReceiveMemoryWarningNotification |
160 object:nil]; | 162 object:nil]; |
161 [[NSNotificationCenter defaultCenter] | 163 [[NSNotificationCenter defaultCenter] |
162 addObserver:self | 164 addObserver:self |
163 selector:@selector(handleEnterBackground) | 165 selector:@selector(handleEnterBackground) |
164 name:UIApplicationDidEnterBackgroundNotification | 166 name:UIApplicationDidEnterBackgroundNotification |
165 object:nil]; | 167 object:nil]; |
166 [[NSNotificationCenter defaultCenter] | 168 [[NSNotificationCenter defaultCenter] |
167 addObserver:self | 169 addObserver:self |
168 selector:@selector(handleBecomeActive) | 170 selector:@selector(handleBecomeActive) |
169 name:UIApplicationDidBecomeActiveNotification | 171 name:UIApplicationDidBecomeActiveNotification |
170 object:nil]; | 172 object:nil]; |
171 } | 173 } |
172 } | 174 } |
173 return self; | 175 return self; |
174 } | 176 } |
175 | 177 |
176 - (void)dealloc { | 178 - (void)dealloc { |
177 if (!IsIPadIdiom()) { | 179 if (!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()) { |
178 [[NSNotificationCenter defaultCenter] | 180 [[NSNotificationCenter defaultCenter] |
179 removeObserver:self | 181 removeObserver:self |
180 name:UIApplicationDidReceiveMemoryWarningNotification | 182 name:UIApplicationDidReceiveMemoryWarningNotification |
181 object:nil]; | 183 object:nil]; |
182 [[NSNotificationCenter defaultCenter] | 184 [[NSNotificationCenter defaultCenter] |
183 removeObserver:self | 185 removeObserver:self |
184 name:UIApplicationDidEnterBackgroundNotification | 186 name:UIApplicationDidEnterBackgroundNotification |
185 object:nil]; | 187 object:nil]; |
186 [[NSNotificationCenter defaultCenter] | 188 [[NSNotificationCenter defaultCenter] |
187 removeObserver:self | 189 removeObserver:self |
(...skipping 12 matching lines...) Expand all Loading... |
200 return 1.0; | 202 return 1.0; |
201 } | 203 } |
202 // Cap snapshot resolution to 2x to reduce the amount of memory they use. | 204 // Cap snapshot resolution to 2x to reduce the amount of memory they use. |
203 return MIN([UIScreen mainScreen].scale, 2.0); | 205 return MIN([UIScreen mainScreen].scale, 2.0); |
204 } | 206 } |
205 | 207 |
206 - (void)retrieveImageForSessionID:(NSString*)sessionID | 208 - (void)retrieveImageForSessionID:(NSString*)sessionID |
207 callback:(void (^)(UIImage*))callback { | 209 callback:(void (^)(UIImage*))callback { |
208 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); | 210 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); |
209 DCHECK(sessionID); | 211 DCHECK(sessionID); |
210 // iPad does not cache images, so if there is no callback we can avoid an | 212 |
211 // expensive read from storage. | 213 // Cache on iPad is enabled only when the tab switcher is enabled. |
212 if (IsIPadIdiom() && !callback) | 214 if ((IsIPadIdiom() && !experimental_flags::IsTabSwitcherEnabled()) && |
| 215 !callback) |
213 return; | 216 return; |
214 | 217 |
215 UIImage* img = nil; | 218 UIImage* img = nil; |
216 if (lruCache_) | 219 if (lruCache_) |
217 img = [lruCache_ objectForKey:sessionID]; | 220 img = [lruCache_ objectForKey:sessionID]; |
218 else | 221 else |
219 img = [imageDictionary_ objectForKey:sessionID]; | 222 img = [imageDictionary_ objectForKey:sessionID]; |
220 | 223 |
221 if (img) { | 224 if (img) { |
222 if (callback) | 225 if (callback) |
223 callback(img); | 226 callback(img); |
224 return; | 227 return; |
225 } | 228 } |
226 | 229 |
227 base::PostTaskAndReplyWithResult( | 230 base::PostTaskAndReplyWithResult( |
228 web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE_USER_BLOCKING) | 231 web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE_USER_BLOCKING) |
229 .get(), | 232 .get(), |
230 FROM_HERE, base::BindBlock(^base::scoped_nsobject<UIImage>() { | 233 FROM_HERE, base::BindBlock(^base::scoped_nsobject<UIImage>() { |
231 // Retrieve the image on a high priority thread. | 234 // Retrieve the image on a high priority thread. |
232 return base::scoped_nsobject<UIImage>([ReadImageFromDisk( | 235 return base::scoped_nsobject<UIImage>([ReadImageFromDisk( |
233 [SnapshotCache imagePathForSessionID:sessionID]) retain]); | 236 [SnapshotCache imagePathForSessionID:sessionID]) retain]); |
234 }), | 237 }), |
235 base::BindBlock(^(base::scoped_nsobject<UIImage> image) { | 238 base::BindBlock(^(base::scoped_nsobject<UIImage> image) { |
236 // The iPad tab switcher is currently using its own memory cache so the | 239 // Cache on iPad is enabled only when the tab switcher is enabled. |
237 // image is not stored in memory here if running on iPad. | 240 if ((!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()) && |
238 // The same logic is used on image writes (code below). | 241 image) { |
239 if (!IsIPadIdiom() && image) { | |
240 if (lruCache_) | 242 if (lruCache_) |
241 [lruCache_ setObject:image forKey:sessionID]; | 243 [lruCache_ setObject:image forKey:sessionID]; |
242 else | 244 else |
243 [imageDictionary_ setObject:image forKey:sessionID]; | 245 [imageDictionary_ setObject:image forKey:sessionID]; |
244 } | 246 } |
245 if (callback) | 247 if (callback) |
246 callback(image); | 248 callback(image); |
247 })); | 249 })); |
248 } | 250 } |
249 | 251 |
250 - (void)setImage:(UIImage*)img withSessionID:(NSString*)sessionID { | 252 - (void)setImage:(UIImage*)img withSessionID:(NSString*)sessionID { |
251 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); | 253 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); |
252 if (!img || !sessionID) | 254 if (!img || !sessionID) |
253 return; | 255 return; |
254 | 256 |
255 // The iPad tab switcher is currently using its own memory cache so the image | 257 // Cache on iPad is enabled only when the tab switcher is enabled. |
256 // is not stored in memory here if running on iPad. | 258 if (!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()) { |
257 // The same logic is used on image reads (code above). | |
258 if (!IsIPadIdiom()) { | |
259 if (lruCache_) | 259 if (lruCache_) |
260 [lruCache_ setObject:img forKey:sessionID]; | 260 [lruCache_ setObject:img forKey:sessionID]; |
261 else | 261 else |
262 [imageDictionary_ setObject:img forKey:sessionID]; | 262 [imageDictionary_ setObject:img forKey:sessionID]; |
263 } | 263 } |
264 // Save the image to disk. | 264 // Save the image to disk. |
265 web::WebThread::PostBlockingPoolSequencedTask( | 265 web::WebThread::PostBlockingPoolSequencedTask( |
266 kSequenceToken, FROM_HERE, | 266 kSequenceToken, FROM_HERE, |
267 base::BindBlock(^{ | 267 base::BindBlock(^{ |
268 base::scoped_nsobject<UIImage> image([img retain]); | 268 base::scoped_nsobject<UIImage> image([img retain]); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 backgroundingImageSessionId_.reset([sessionID copy]); | 380 backgroundingImageSessionId_.reset([sessionID copy]); |
381 if (lruCache_) { | 381 if (lruCache_) { |
382 backgroundingColorImage_.reset([[lruCache_ objectForKey:sessionID] retain]); | 382 backgroundingColorImage_.reset([[lruCache_ objectForKey:sessionID] retain]); |
383 } else { | 383 } else { |
384 backgroundingColorImage_.reset( | 384 backgroundingColorImage_.reset( |
385 [[imageDictionary_ objectForKey:sessionID] retain]); | 385 [[imageDictionary_ objectForKey:sessionID] retain]); |
386 } | 386 } |
387 } | 387 } |
388 | 388 |
389 - (void)handleLowMemory { | 389 - (void)handleLowMemory { |
390 DCHECK(!IsIPadIdiom()); | 390 DCHECK(!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()); |
391 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); | 391 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); |
392 NSMutableDictionary* dictionary = | 392 NSMutableDictionary* dictionary = |
393 [[NSMutableDictionary alloc] initWithCapacity:2]; | 393 [[NSMutableDictionary alloc] initWithCapacity:2]; |
394 for (NSString* sessionID in pinnedIDs_) { | 394 for (NSString* sessionID in pinnedIDs_) { |
395 UIImage* image = nil; | 395 UIImage* image = nil; |
396 if (lruCache_) | 396 if (lruCache_) |
397 image = [lruCache_ objectForKey:sessionID]; | 397 image = [lruCache_ objectForKey:sessionID]; |
398 else | 398 else |
399 image = [imageDictionary_ objectForKey:sessionID]; | 399 image = [imageDictionary_ objectForKey:sessionID]; |
400 if (image) | 400 if (image) |
401 [dictionary setObject:image forKey:sessionID]; | 401 [dictionary setObject:image forKey:sessionID]; |
402 } | 402 } |
403 if (lruCache_) { | 403 if (lruCache_) { |
404 [lruCache_ removeAllObjects]; | 404 [lruCache_ removeAllObjects]; |
405 for (NSString* sessionID in pinnedIDs_) | 405 for (NSString* sessionID in pinnedIDs_) |
406 [lruCache_ setObject:dictionary[sessionID] forKey:sessionID]; | 406 [lruCache_ setObject:dictionary[sessionID] forKey:sessionID]; |
407 } else { | 407 } else { |
408 imageDictionary_.reset(dictionary); | 408 imageDictionary_.reset(dictionary); |
409 } | 409 } |
410 } | 410 } |
411 | 411 |
412 - (void)handleEnterBackground { | 412 - (void)handleEnterBackground { |
413 DCHECK(!IsIPadIdiom()); | 413 DCHECK(!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()); |
414 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); | 414 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); |
415 [imageDictionary_ removeAllObjects]; | 415 [imageDictionary_ removeAllObjects]; |
416 [lruCache_ removeAllObjects]; | 416 [lruCache_ removeAllObjects]; |
417 } | 417 } |
418 | 418 |
419 - (void)handleBecomeActive { | 419 - (void)handleBecomeActive { |
420 DCHECK(!IsIPadIdiom()); | 420 DCHECK(!IsIPadIdiom() || experimental_flags::IsTabSwitcherEnabled()); |
421 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); | 421 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); |
422 for (NSString* sessionID in pinnedIDs_) | 422 for (NSString* sessionID in pinnedIDs_) |
423 [self retrieveImageForSessionID:sessionID callback:nil]; | 423 [self retrieveImageForSessionID:sessionID callback:nil]; |
424 } | 424 } |
425 | 425 |
426 - (void)saveGreyImage:(UIImage*)greyImage forKey:(NSString*)sessionID { | 426 - (void)saveGreyImage:(UIImage*)greyImage forKey:(NSString*)sessionID { |
427 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); | 427 DCHECK_CURRENTLY_ON_WEB_THREAD(web::WebThread::UI); |
428 if (greyImage) | 428 if (greyImage) |
429 [greyImageDictionary_ setObject:greyImage forKey:sessionID]; | 429 [greyImageDictionary_ setObject:greyImage forKey:sessionID]; |
430 if ([sessionID isEqualToString:mostRecentGreySessionId_]) { | 430 if ([sessionID isEqualToString:mostRecentGreySessionId_]) { |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
575 } | 575 } |
576 - (BOOL)hasGreyImageInMemory:(NSString*)sessionID { | 576 - (BOOL)hasGreyImageInMemory:(NSString*)sessionID { |
577 return [greyImageDictionary_ objectForKey:sessionID] != nil; | 577 return [greyImageDictionary_ objectForKey:sessionID] != nil; |
578 } | 578 } |
579 | 579 |
580 - (NSUInteger)lruCacheMaxSize { | 580 - (NSUInteger)lruCacheMaxSize { |
581 return [lruCache_ maxCacheSize]; | 581 return [lruCache_ maxCacheSize]; |
582 } | 582 } |
583 | 583 |
584 @end | 584 @end |
OLD | NEW |