OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #import "ios/chrome/browser/snapshots/web_controller_snapshot_helper.h" |
| 6 |
| 7 #import "base/ios/weak_nsobject.h" |
| 8 #import "base/mac/scoped_nsobject.h" |
| 9 #import "ios/chrome/browser/snapshots/snapshot_manager.h" |
| 10 #import "ios/chrome/browser/tabs/tab.h" |
| 11 #import "ios/chrome/browser/ui/fullscreen_controller.h" |
| 12 #import "ios/chrome/browser/ui/uikit_ui_util.h" |
| 13 #import "ios/web/web_state/ui/crw_web_controller.h" |
| 14 |
| 15 @interface WebControllerSnapshotHelper () |
| 16 |
| 17 // Takes a snapshot image for the WebController's current page. Returns an |
| 18 // autoreleased image cropped and scaled appropriately. Returns a default image |
| 19 // if a snapshot cannot be generated. |
| 20 - (UIImage*)generateSnapshotOrDefaultForWebController: |
| 21 (CRWWebController*)webController |
| 22 withOverlays:(NSArray*)overlays |
| 23 visibleFrameOnly:(BOOL)visibleFrameOnly; |
| 24 |
| 25 // Returns the cached snapshot if there is one matching the given parameters. |
| 26 // Returns nil otherwise or if there is no |_coalescingSnapshotContext|. |
| 27 - (UIImage*)cachedSnapshotWithOverlays:(NSArray*)overlays |
| 28 visibleFrameOnly:(BOOL)visibleFrameOnly; |
| 29 |
| 30 // Caches |snapshot| for the given |overlays| and |visibleFrameOnly|. Does |
| 31 // nothing if there is no |_coalescingSnapshotContext|. |
| 32 - (void)setCachedSnapshot:(UIImage*)snapshot |
| 33 withOverlays:(NSArray*)overlays |
| 34 visibleFrameOnly:(BOOL)visibleFrameOnly; |
| 35 @end |
| 36 |
| 37 // Class that contains information used when caching snapshots of a web page. |
| 38 @interface CoalescingSnapshotContext : NSObject |
| 39 |
| 40 // Returns the cached snapshot if there is one matching the given parameters. |
| 41 // Returns nil otherwise. |
| 42 - (UIImage*)cachedSnapshotWithOverlays:(NSArray*)overlays |
| 43 visibleFrameOnly:(BOOL)visibleFrameOnly; |
| 44 |
| 45 // Caches |snapshot| for the given |overlays| and |visibleFrameOnly|. |
| 46 - (void)setCachedSnapshot:(UIImage*)snapshot |
| 47 withOverlays:(NSArray*)overlays |
| 48 visibleFrameOnly:(BOOL)visibleFrameOnly; |
| 49 |
| 50 @end |
| 51 |
| 52 @implementation CoalescingSnapshotContext { |
| 53 base::scoped_nsobject<UIImage> _cachedSnapshot; |
| 54 } |
| 55 |
| 56 // Returns whether a snapshot should be cached in a page loaded context. |
| 57 // Note: Returns YES if |overlays| is nil or empty and if |visibleFrameOnly| is |
| 58 // YES as this is the only case when the snapshot taken by the CRWWebController |
| 59 // is reused. |
| 60 - (BOOL)shouldCacheSnapshotWithOverlays:(NSArray*)overlays |
| 61 visibleFrameOnly:(BOOL)visibleFrameOnly { |
| 62 return ![overlays count] && visibleFrameOnly; |
| 63 } |
| 64 |
| 65 - (UIImage*)cachedSnapshotWithOverlays:(NSArray*)overlays |
| 66 visibleFrameOnly:(BOOL)visibleFrameOnly { |
| 67 if ([self shouldCacheSnapshotWithOverlays:overlays |
| 68 visibleFrameOnly:visibleFrameOnly]) { |
| 69 return _cachedSnapshot; |
| 70 } |
| 71 return nil; |
| 72 } |
| 73 |
| 74 - (void)setCachedSnapshot:(UIImage*)snapshot |
| 75 withOverlays:(NSArray*)overlays |
| 76 visibleFrameOnly:(BOOL)visibleFrameOnly { |
| 77 if ([self shouldCacheSnapshotWithOverlays:overlays |
| 78 visibleFrameOnly:visibleFrameOnly]) { |
| 79 DCHECK(!_cachedSnapshot); |
| 80 _cachedSnapshot.reset([snapshot retain]); |
| 81 } |
| 82 } |
| 83 |
| 84 @end |
| 85 |
| 86 @implementation WebControllerSnapshotHelper { |
| 87 base::scoped_nsobject<CoalescingSnapshotContext> _coalescingSnapshotContext; |
| 88 base::scoped_nsobject<SnapshotManager> _snapshotManager; |
| 89 base::WeakNSObject<CRWWebController> _webController; |
| 90 // Owns this WebControllerSnapshotHelper. |
| 91 base::WeakNSObject<Tab> _tab; |
| 92 } |
| 93 |
| 94 - (instancetype)init { |
| 95 NOTREACHED(); |
| 96 return nil; |
| 97 } |
| 98 |
| 99 - (instancetype)initWithSnapshotManager:(SnapshotManager*)snapshotManager |
| 100 tab:(Tab*)tab { |
| 101 self = [super init]; |
| 102 if (self) { |
| 103 DCHECK(snapshotManager); |
| 104 DCHECK(tab); |
| 105 DCHECK([tab currentSessionID]); |
| 106 DCHECK([tab webController]); |
| 107 _snapshotManager.reset([snapshotManager retain]); |
| 108 _webController.reset([tab webController]); |
| 109 _tab.reset(tab); |
| 110 } |
| 111 return self; |
| 112 } |
| 113 |
| 114 - (void)setSnapshotCoalescingEnabled:(BOOL)snapshotCoalescingEnabled { |
| 115 if (snapshotCoalescingEnabled) { |
| 116 DCHECK(!_coalescingSnapshotContext); |
| 117 _coalescingSnapshotContext.reset([[CoalescingSnapshotContext alloc] init]); |
| 118 } else { |
| 119 DCHECK(_coalescingSnapshotContext); |
| 120 _coalescingSnapshotContext.reset(); |
| 121 } |
| 122 } |
| 123 |
| 124 - (UIImage*)generateSnapshotOrDefaultForWebController: |
| 125 (CRWWebController*)webController |
| 126 withOverlays:(NSArray*)overlays |
| 127 visibleFrameOnly:(BOOL)visibleFrameOnly { |
| 128 UIImage* result = [self generateSnapshotForWebController:webController |
| 129 withOverlays:overlays |
| 130 visibleFrameOnly:visibleFrameOnly]; |
| 131 return result ? result : [[self class] defaultSnapshotImage]; |
| 132 } |
| 133 |
| 134 - (void)retrieveSnapshotForWebController:(CRWWebController*)webController |
| 135 sessionID:(NSString*)sessionID |
| 136 withOverlays:(NSArray*)overlays |
| 137 callback:(void (^)(UIImage* image))callback { |
| 138 [_snapshotManager |
| 139 retrieveImageForSessionID:sessionID |
| 140 callback:^(UIImage* image) { |
| 141 if (image) { |
| 142 callback(image); |
| 143 } else { |
| 144 callback([self |
| 145 updateSnapshotForWebController:webController |
| 146 sessionID:sessionID |
| 147 withOverlays:overlays |
| 148 visibleFrameOnly:YES]); |
| 149 } |
| 150 }]; |
| 151 } |
| 152 |
| 153 - (void)retrieveGreySnapshotForWebController:(CRWWebController*)webController |
| 154 sessionID:(NSString*)sessionID |
| 155 withOverlays:(NSArray*)overlays |
| 156 callback: |
| 157 (void (^)(UIImage* image))callback { |
| 158 [_snapshotManager |
| 159 retrieveGreyImageForSessionID:sessionID |
| 160 callback:^(UIImage* image) { |
| 161 if (image) { |
| 162 callback(image); |
| 163 } else { |
| 164 callback(GreyImage([self |
| 165 updateSnapshotForWebController:webController |
| 166 sessionID:sessionID |
| 167 withOverlays:overlays |
| 168 visibleFrameOnly:YES])); |
| 169 } |
| 170 }]; |
| 171 } |
| 172 |
| 173 - (UIImage*)updateSnapshotForWebController:(CRWWebController*)webController |
| 174 sessionID:(NSString*)sessionID |
| 175 withOverlays:(NSArray*)overlays |
| 176 visibleFrameOnly:(BOOL)visibleFrameOnly { |
| 177 // TODO(crbug.com/661641): This is a temporary solution to make sure the |
| 178 // webController retained by us is the same being passed in in this method. |
| 179 // Remove this when all uses of the "CRWWebController" are dropped from the |
| 180 // methods names since it is already retained by us and not necessary to be |
| 181 // passed in. |
| 182 DCHECK_EQ([_tab webController], webController); |
| 183 UIImage* snapshot = |
| 184 [self generateSnapshotOrDefaultForWebController:webController |
| 185 withOverlays:overlays |
| 186 visibleFrameOnly:visibleFrameOnly]; |
| 187 // If the snapshot is the default one, return it without caching it. |
| 188 if (snapshot == [[self class] defaultSnapshotImage]) |
| 189 return snapshot; |
| 190 |
| 191 UIImage* snapshotToCache = nil; |
| 192 // TODO(crbug.com/370994): Remove all code that references a Tab's delegates |
| 193 // from this file. |
| 194 if (visibleFrameOnly || ![_tab fullScreenControllerDelegate]) { |
| 195 snapshotToCache = snapshot; |
| 196 } else { |
| 197 // Crops the bottom of the fullscreen snapshot. |
| 198 CGRect cropRect = |
| 199 CGRectMake(0, [[_tab fullScreenControllerDelegate] headerHeight], |
| 200 [snapshot size].width, [snapshot size].height); |
| 201 snapshotToCache = CropImage(snapshot, cropRect); |
| 202 } |
| 203 [_snapshotManager setImage:snapshotToCache withSessionID:sessionID]; |
| 204 return snapshot; |
| 205 } |
| 206 |
| 207 - (UIImage*)generateSnapshotForWebController:(CRWWebController*)webController |
| 208 withOverlays:(NSArray*)overlays |
| 209 visibleFrameOnly:(BOOL)visibleFrameOnly { |
| 210 if (![webController canUseViewForGeneratingOverlayPlaceholderView]) |
| 211 return nil; |
| 212 CGRect visibleFrame = (visibleFrameOnly ? [_tab snapshotContentArea] |
| 213 : [webController.view bounds]); |
| 214 if (CGRectIsEmpty(visibleFrame)) |
| 215 return nil; |
| 216 UIImage* snapshot = [self cachedSnapshotWithOverlays:overlays |
| 217 visibleFrameOnly:visibleFrameOnly]; |
| 218 if (!snapshot) { |
| 219 [_tab willUpdateSnapshot]; |
| 220 snapshot = [_snapshotManager generateSnapshotForView:webController.view |
| 221 withRect:visibleFrame |
| 222 overlays:overlays]; |
| 223 [self setCachedSnapshot:snapshot |
| 224 withOverlays:overlays |
| 225 visibleFrameOnly:visibleFrameOnly]; |
| 226 } |
| 227 return snapshot; |
| 228 } |
| 229 |
| 230 // TODO(crbug.com/661642): This code is shared with SnapshotManager. Remove this |
| 231 // and add it as part of WebDelegate delegate API such that a default image is |
| 232 // returned immediately. |
| 233 + (UIImage*)defaultSnapshotImage { |
| 234 static UIImage* defaultImage = nil; |
| 235 |
| 236 if (!defaultImage) { |
| 237 CGRect frame = CGRectMake(0, 0, 2, 2); |
| 238 UIGraphicsBeginImageContext(frame.size); |
| 239 [[UIColor whiteColor] setFill]; |
| 240 CGContextFillRect(UIGraphicsGetCurrentContext(), frame); |
| 241 |
| 242 UIImage* result = UIGraphicsGetImageFromCurrentImageContext(); |
| 243 UIGraphicsEndImageContext(); |
| 244 |
| 245 defaultImage = |
| 246 [[result stretchableImageWithLeftCapWidth:1 topCapHeight:1] retain]; |
| 247 } |
| 248 return defaultImage; |
| 249 } |
| 250 |
| 251 - (void)setCachedSnapshot:(UIImage*)snapshot |
| 252 withOverlays:(NSArray*)overlays |
| 253 visibleFrameOnly:(BOOL)visibleFrameOnly { |
| 254 return [_coalescingSnapshotContext setCachedSnapshot:snapshot |
| 255 withOverlays:overlays |
| 256 visibleFrameOnly:visibleFrameOnly]; |
| 257 } |
| 258 |
| 259 - (UIImage*)cachedSnapshotWithOverlays:(NSArray*)overlays |
| 260 visibleFrameOnly:(BOOL)visibleFrameOnly { |
| 261 return |
| 262 [_coalescingSnapshotContext cachedSnapshotWithOverlays:overlays |
| 263 visibleFrameOnly:visibleFrameOnly]; |
| 264 } |
| 265 |
| 266 @end |
OLD | NEW |