| Index: ios/chrome/browser/snapshots/web_controller_snapshot_helper.mm
|
| diff --git a/ios/chrome/browser/snapshots/web_controller_snapshot_helper.mm b/ios/chrome/browser/snapshots/web_controller_snapshot_helper.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8ff35086c3e364196d02300c1fc2810be77f88cb
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/snapshots/web_controller_snapshot_helper.mm
|
| @@ -0,0 +1,266 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#import "ios/chrome/browser/snapshots/web_controller_snapshot_helper.h"
|
| +
|
| +#import "base/ios/weak_nsobject.h"
|
| +#import "base/mac/scoped_nsobject.h"
|
| +#import "ios/chrome/browser/snapshots/snapshot_manager.h"
|
| +#import "ios/chrome/browser/tabs/tab.h"
|
| +#import "ios/chrome/browser/ui/fullscreen_controller.h"
|
| +#import "ios/chrome/browser/ui/uikit_ui_util.h"
|
| +#import "ios/web/web_state/ui/crw_web_controller.h"
|
| +
|
| +@interface WebControllerSnapshotHelper ()
|
| +
|
| +// Takes a snapshot image for the WebController's current page. Returns an
|
| +// autoreleased image cropped and scaled appropriately. Returns a default image
|
| +// if a snapshot cannot be generated.
|
| +- (UIImage*)generateSnapshotOrDefaultForWebController:
|
| + (CRWWebController*)webController
|
| + withOverlays:(NSArray*)overlays
|
| + visibleFrameOnly:(BOOL)visibleFrameOnly;
|
| +
|
| +// Returns the cached snapshot if there is one matching the given parameters.
|
| +// Returns nil otherwise or if there is no |_coalescingSnapshotContext|.
|
| +- (UIImage*)cachedSnapshotWithOverlays:(NSArray*)overlays
|
| + visibleFrameOnly:(BOOL)visibleFrameOnly;
|
| +
|
| +// Caches |snapshot| for the given |overlays| and |visibleFrameOnly|. Does
|
| +// nothing if there is no |_coalescingSnapshotContext|.
|
| +- (void)setCachedSnapshot:(UIImage*)snapshot
|
| + withOverlays:(NSArray*)overlays
|
| + visibleFrameOnly:(BOOL)visibleFrameOnly;
|
| +@end
|
| +
|
| +// Class that contains information used when caching snapshots of a web page.
|
| +@interface CoalescingSnapshotContext : NSObject
|
| +
|
| +// Returns the cached snapshot if there is one matching the given parameters.
|
| +// Returns nil otherwise.
|
| +- (UIImage*)cachedSnapshotWithOverlays:(NSArray*)overlays
|
| + visibleFrameOnly:(BOOL)visibleFrameOnly;
|
| +
|
| +// Caches |snapshot| for the given |overlays| and |visibleFrameOnly|.
|
| +- (void)setCachedSnapshot:(UIImage*)snapshot
|
| + withOverlays:(NSArray*)overlays
|
| + visibleFrameOnly:(BOOL)visibleFrameOnly;
|
| +
|
| +@end
|
| +
|
| +@implementation CoalescingSnapshotContext {
|
| + base::scoped_nsobject<UIImage> _cachedSnapshot;
|
| +}
|
| +
|
| +// Returns whether a snapshot should be cached in a page loaded context.
|
| +// Note: Returns YES if |overlays| is nil or empty and if |visibleFrameOnly| is
|
| +// YES as this is the only case when the snapshot taken by the CRWWebController
|
| +// is reused.
|
| +- (BOOL)shouldCacheSnapshotWithOverlays:(NSArray*)overlays
|
| + visibleFrameOnly:(BOOL)visibleFrameOnly {
|
| + return ![overlays count] && visibleFrameOnly;
|
| +}
|
| +
|
| +- (UIImage*)cachedSnapshotWithOverlays:(NSArray*)overlays
|
| + visibleFrameOnly:(BOOL)visibleFrameOnly {
|
| + if ([self shouldCacheSnapshotWithOverlays:overlays
|
| + visibleFrameOnly:visibleFrameOnly]) {
|
| + return _cachedSnapshot;
|
| + }
|
| + return nil;
|
| +}
|
| +
|
| +- (void)setCachedSnapshot:(UIImage*)snapshot
|
| + withOverlays:(NSArray*)overlays
|
| + visibleFrameOnly:(BOOL)visibleFrameOnly {
|
| + if ([self shouldCacheSnapshotWithOverlays:overlays
|
| + visibleFrameOnly:visibleFrameOnly]) {
|
| + DCHECK(!_cachedSnapshot);
|
| + _cachedSnapshot.reset([snapshot retain]);
|
| + }
|
| +}
|
| +
|
| +@end
|
| +
|
| +@implementation WebControllerSnapshotHelper {
|
| + base::scoped_nsobject<CoalescingSnapshotContext> _coalescingSnapshotContext;
|
| + base::scoped_nsobject<SnapshotManager> _snapshotManager;
|
| + base::WeakNSObject<CRWWebController> _webController;
|
| + // Owns this WebControllerSnapshotHelper.
|
| + base::WeakNSObject<Tab> _tab;
|
| +}
|
| +
|
| +- (instancetype)init {
|
| + NOTREACHED();
|
| + return nil;
|
| +}
|
| +
|
| +- (instancetype)initWithSnapshotManager:(SnapshotManager*)snapshotManager
|
| + tab:(Tab*)tab {
|
| + self = [super init];
|
| + if (self) {
|
| + DCHECK(snapshotManager);
|
| + DCHECK(tab);
|
| + DCHECK([tab currentSessionID]);
|
| + DCHECK([tab webController]);
|
| + _snapshotManager.reset([snapshotManager retain]);
|
| + _webController.reset([tab webController]);
|
| + _tab.reset(tab);
|
| + }
|
| + return self;
|
| +}
|
| +
|
| +- (void)setSnapshotCoalescingEnabled:(BOOL)snapshotCoalescingEnabled {
|
| + if (snapshotCoalescingEnabled) {
|
| + DCHECK(!_coalescingSnapshotContext);
|
| + _coalescingSnapshotContext.reset([[CoalescingSnapshotContext alloc] init]);
|
| + } else {
|
| + DCHECK(_coalescingSnapshotContext);
|
| + _coalescingSnapshotContext.reset();
|
| + }
|
| +}
|
| +
|
| +- (UIImage*)generateSnapshotOrDefaultForWebController:
|
| + (CRWWebController*)webController
|
| + withOverlays:(NSArray*)overlays
|
| + visibleFrameOnly:(BOOL)visibleFrameOnly {
|
| + UIImage* result = [self generateSnapshotForWebController:webController
|
| + withOverlays:overlays
|
| + visibleFrameOnly:visibleFrameOnly];
|
| + return result ? result : [[self class] defaultSnapshotImage];
|
| +}
|
| +
|
| +- (void)retrieveSnapshotForWebController:(CRWWebController*)webController
|
| + sessionID:(NSString*)sessionID
|
| + withOverlays:(NSArray*)overlays
|
| + callback:(void (^)(UIImage* image))callback {
|
| + [_snapshotManager
|
| + retrieveImageForSessionID:sessionID
|
| + callback:^(UIImage* image) {
|
| + if (image) {
|
| + callback(image);
|
| + } else {
|
| + callback([self
|
| + updateSnapshotForWebController:webController
|
| + sessionID:sessionID
|
| + withOverlays:overlays
|
| + visibleFrameOnly:YES]);
|
| + }
|
| + }];
|
| +}
|
| +
|
| +- (void)retrieveGreySnapshotForWebController:(CRWWebController*)webController
|
| + sessionID:(NSString*)sessionID
|
| + withOverlays:(NSArray*)overlays
|
| + callback:
|
| + (void (^)(UIImage* image))callback {
|
| + [_snapshotManager
|
| + retrieveGreyImageForSessionID:sessionID
|
| + callback:^(UIImage* image) {
|
| + if (image) {
|
| + callback(image);
|
| + } else {
|
| + callback(GreyImage([self
|
| + updateSnapshotForWebController:webController
|
| + sessionID:sessionID
|
| + withOverlays:overlays
|
| + visibleFrameOnly:YES]));
|
| + }
|
| + }];
|
| +}
|
| +
|
| +- (UIImage*)updateSnapshotForWebController:(CRWWebController*)webController
|
| + sessionID:(NSString*)sessionID
|
| + withOverlays:(NSArray*)overlays
|
| + visibleFrameOnly:(BOOL)visibleFrameOnly {
|
| + // TODO(crbug.com/661641): This is a temporary solution to make sure the
|
| + // webController retained by us is the same being passed in in this method.
|
| + // Remove this when all uses of the "CRWWebController" are dropped from the
|
| + // methods names since it is already retained by us and not necessary to be
|
| + // passed in.
|
| + DCHECK_EQ([_tab webController], webController);
|
| + UIImage* snapshot =
|
| + [self generateSnapshotOrDefaultForWebController:webController
|
| + withOverlays:overlays
|
| + visibleFrameOnly:visibleFrameOnly];
|
| + // If the snapshot is the default one, return it without caching it.
|
| + if (snapshot == [[self class] defaultSnapshotImage])
|
| + return snapshot;
|
| +
|
| + UIImage* snapshotToCache = nil;
|
| + // TODO(crbug.com/370994): Remove all code that references a Tab's delegates
|
| + // from this file.
|
| + if (visibleFrameOnly || ![_tab fullScreenControllerDelegate]) {
|
| + snapshotToCache = snapshot;
|
| + } else {
|
| + // Crops the bottom of the fullscreen snapshot.
|
| + CGRect cropRect =
|
| + CGRectMake(0, [[_tab fullScreenControllerDelegate] headerHeight],
|
| + [snapshot size].width, [snapshot size].height);
|
| + snapshotToCache = CropImage(snapshot, cropRect);
|
| + }
|
| + [_snapshotManager setImage:snapshotToCache withSessionID:sessionID];
|
| + return snapshot;
|
| +}
|
| +
|
| +- (UIImage*)generateSnapshotForWebController:(CRWWebController*)webController
|
| + withOverlays:(NSArray*)overlays
|
| + visibleFrameOnly:(BOOL)visibleFrameOnly {
|
| + if (![webController canUseViewForGeneratingOverlayPlaceholderView])
|
| + return nil;
|
| + CGRect visibleFrame = (visibleFrameOnly ? [_tab snapshotContentArea]
|
| + : [webController.view bounds]);
|
| + if (CGRectIsEmpty(visibleFrame))
|
| + return nil;
|
| + UIImage* snapshot = [self cachedSnapshotWithOverlays:overlays
|
| + visibleFrameOnly:visibleFrameOnly];
|
| + if (!snapshot) {
|
| + [_tab willUpdateSnapshot];
|
| + snapshot = [_snapshotManager generateSnapshotForView:webController.view
|
| + withRect:visibleFrame
|
| + overlays:overlays];
|
| + [self setCachedSnapshot:snapshot
|
| + withOverlays:overlays
|
| + visibleFrameOnly:visibleFrameOnly];
|
| + }
|
| + return snapshot;
|
| +}
|
| +
|
| +// TODO(crbug.com/661642): This code is shared with SnapshotManager. Remove this
|
| +// and add it as part of WebDelegate delegate API such that a default image is
|
| +// returned immediately.
|
| ++ (UIImage*)defaultSnapshotImage {
|
| + static UIImage* defaultImage = nil;
|
| +
|
| + if (!defaultImage) {
|
| + CGRect frame = CGRectMake(0, 0, 2, 2);
|
| + UIGraphicsBeginImageContext(frame.size);
|
| + [[UIColor whiteColor] setFill];
|
| + CGContextFillRect(UIGraphicsGetCurrentContext(), frame);
|
| +
|
| + UIImage* result = UIGraphicsGetImageFromCurrentImageContext();
|
| + UIGraphicsEndImageContext();
|
| +
|
| + defaultImage =
|
| + [[result stretchableImageWithLeftCapWidth:1 topCapHeight:1] retain];
|
| + }
|
| + return defaultImage;
|
| +}
|
| +
|
| +- (void)setCachedSnapshot:(UIImage*)snapshot
|
| + withOverlays:(NSArray*)overlays
|
| + visibleFrameOnly:(BOOL)visibleFrameOnly {
|
| + return [_coalescingSnapshotContext setCachedSnapshot:snapshot
|
| + withOverlays:overlays
|
| + visibleFrameOnly:visibleFrameOnly];
|
| +}
|
| +
|
| +- (UIImage*)cachedSnapshotWithOverlays:(NSArray*)overlays
|
| + visibleFrameOnly:(BOOL)visibleFrameOnly {
|
| + return
|
| + [_coalescingSnapshotContext cachedSnapshotWithOverlays:overlays
|
| + visibleFrameOnly:visibleFrameOnly];
|
| +}
|
| +
|
| +@end
|
|
|