Commit be8ca312 authored by Sylvain Defresne's avatar Sylvain Defresne Committed by Commit Bot

Delete SnapshotManager class.

Refactor Tab (and its unit test) and WebControllerSnapshotHelper to
directly use SnapshotCache (accessed via the SnapshotCacheFactory).

Move -generateSnapshotForView:withRect:overlays: method (and helper
functions) to WebControllerSnapshotHelper.

Bug: 661642, 620465
Change-Id: Ie8cde629b99ca39b30cd1bc3354dac441cd5e562
Cq-Include-Trybots: master.tryserver.chromium.mac:ios-simulator-cronet;master.tryserver.chromium.mac:ios-simulator-full-configs
Reviewed-on: https://chromium-review.googlesource.com/810768Reviewed-by: default avatarJustin Cohen <justincohen@chromium.org>
Commit-Queue: Sylvain Defresne <sdefresne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#522388}
parent 840d3b21
......@@ -16,8 +16,6 @@ source_set("snapshots") {
"snapshot_cache_web_state_list_observer.mm",
"snapshot_constants.h",
"snapshot_constants.mm",
"snapshot_manager.h",
"snapshot_manager.mm",
"snapshot_overlay.h",
"snapshot_overlay.mm",
"snapshots_util.h",
......@@ -66,6 +64,7 @@ source_set("snapshots_internal") {
deps = [
":snapshots",
"//base",
"//ios/chrome/browser/browser_state",
"//ios/chrome/browser/tabs",
"//ios/chrome/browser/ui",
"//ios/web",
......
......@@ -30,6 +30,10 @@ class SnapshotCacheFactory : public BrowserStateKeyedServiceFactory {
static SnapshotCacheFactory* GetInstance();
// Returns the default factory used to build SnapshotCaches. Can be
// registered with SetTestingFactory to use real instances during testing.
static TestingFactoryFunction GetDefaultFactory();
private:
friend struct base::DefaultSingletonTraits<SnapshotCacheFactory>;
......
......@@ -49,7 +49,11 @@ void SnapshotCacheWrapper::Shutdown() {
[snapshot_cache_ shutdown];
snapshot_cache_ = nil;
}
std::unique_ptr<KeyedService> BuildSnapshotCacheWrapper(web::BrowserState*) {
return std::make_unique<SnapshotCacheWrapper>([[SnapshotCache alloc] init]);
}
} // namespace
// static
SnapshotCache* SnapshotCacheFactory::GetForBrowserState(
......@@ -64,6 +68,12 @@ SnapshotCacheFactory* SnapshotCacheFactory::GetInstance() {
return base::Singleton<SnapshotCacheFactory>::get();
}
// static
BrowserStateKeyedServiceFactory::TestingFactoryFunction
SnapshotCacheFactory::GetDefaultFactory() {
return &BuildSnapshotCacheWrapper;
}
SnapshotCacheFactory::SnapshotCacheFactory()
: BrowserStateKeyedServiceFactory(
"SnapshotCache",
......@@ -73,7 +83,7 @@ SnapshotCacheFactory::~SnapshotCacheFactory() = default;
std::unique_ptr<KeyedService> SnapshotCacheFactory::BuildServiceInstanceFor(
web::BrowserState* context) const {
return base::MakeUnique<SnapshotCacheWrapper>([[SnapshotCache alloc] init]);
return BuildSnapshotCacheWrapper(context);
}
web::BrowserState* SnapshotCacheFactory::GetBrowserStateToUse(
......
// Copyright 2012 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.
#ifndef IOS_CHROME_BROWSER_SNAPSHOTS_SNAPSHOT_MANAGER_H_
#define IOS_CHROME_BROWSER_SNAPSHOTS_SNAPSHOT_MANAGER_H_
#import <UIKit/UIKit.h>
namespace web {
class WebState;
}
// Snapshot manager for contents of a tab. A snapshot is a full-screen image
// of the contents of the page at the current scroll offset and zoom level,
// used to stand in for the web view if it has been purged from memory or when
// quickly switching tabs. Uses |SnapshotCache| to cache (and persist)
// snapshots.
//
// The snapshots are identified by a "session id" which is unique per tab. This
// allows quick identification and replacement as a tab changes pages.
@interface SnapshotManager : NSObject
// Designated initializer. The |webState| must not be null.
- (instancetype)initWithWebState:(web::WebState*)webState
NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
// Takes a snapshot for the supplied view (which should correspond to the given
// type of web view). Returns an autoreleased image cropped and scaled
// appropriately.
// The image is not yet cached.
// The image can also contain overlays (if |overlays| is not nil and not empty).
- (UIImage*)generateSnapshotForView:(UIView*)view
withRect:(CGRect)rect
overlays:(NSArray*)overlays;
// Retrieve a cached snapshot for the |sessionID| and return it via the callback
// if it exists. The callback is guaranteed to be called synchronously if the
// image is in memory. It will be called asynchronously if the image is on disk
// or with nil if the image is not present at all.
- (void)retrieveImageForSessionID:(NSString*)sessionID
callback:(void (^)(UIImage*))callback;
// Request the session's grey snapshot. If the image is already loaded in
// memory, this will immediately call back on |callback|. Otherwise, the grey
// image will be loaded off disk or created by converting an existing color
// snapshot to grey.
- (void)retrieveGreyImageForSessionID:(NSString*)sessionID
callback:(void (^)(UIImage*))callback;
// Stores the supplied thumbnail for the specified |sessionID|.
- (void)setImage:(UIImage*)image withSessionID:(NSString*)sessionID;
// Removes the cached thumbnail for the specified |sessionID|.
- (void)removeImageWithSessionID:(NSString*)sessionID;
// Request the grey image from the in-memory cache only.
- (void)greyImageForSessionID:(NSString*)sessionID
callback:(void (^)(UIImage*))callback;
@end
#endif // IOS_CHROME_BROWSER_SNAPSHOTS_SNAPSHOT_MANAGER_H_
// Copyright 2012 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/snapshot_manager.h"
#import <QuartzCore/QuartzCore.h>
#import <WebKit/WebKit.h>
#include "base/logging.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#import "ios/chrome/browser/snapshots/snapshot_cache.h"
#import "ios/chrome/browser/snapshots/snapshot_cache_factory.h"
#import "ios/chrome/browser/snapshots/snapshot_overlay.h"
#import "ios/web/public/web_state/web_state.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// Returns YES if |view| or any view it contains is a WKWebView.
BOOL ViewHierarchyContainsWKWebView(UIView* view) {
if ([view isKindOfClass:[WKWebView class]])
return YES;
for (UIView* subview in view.subviews) {
if (ViewHierarchyContainsWKWebView(subview))
return YES;
}
return NO;
}
} // namespace
@implementation SnapshotManager {
web::WebState* _webState;
}
- (instancetype)initWithWebState:(web::WebState*)webState {
if ((self = [super init])) {
DCHECK(webState);
_webState = webState;
}
return self;
}
- (UIImage*)generateSnapshotForView:(UIView*)view
withRect:(CGRect)rect
overlays:(NSArray*)overlays {
DCHECK(view);
CGSize size = rect.size;
DCHECK(std::isnormal(size.width) && (size.width > 0))
<< ": size.width=" << size.width;
DCHECK(std::isnormal(size.height) && (size.height > 0))
<< ": size.height=" << size.height;
const CGFloat kScale = [[self snapshotCache] snapshotScaleForDevice];
UIGraphicsBeginImageContextWithOptions(size, YES, kScale);
CGContext* context = UIGraphicsGetCurrentContext();
if (!context) {
NOTREACHED();
return nil;
}
// -drawViewHierarchyInRect:afterScreenUpdates:YES is buggy as of iOS 8.3.
// Using it afterScreenUpdates:YES creates unexpected GPU glitches, screen
// redraws during animations, broken pinch to dismiss on tablet, etc. For now
// only using this with WKWebView, which depends on -drawViewHierarchyInRect.
// TODO(justincohen): Remove this (and always use drawViewHierarchyInRect)
// once the iOS 8 bugs have been fixed.
BOOL useDrawViewHierarchy = ViewHierarchyContainsWKWebView(view);
BOOL snapshotSuccess = YES;
CGContextSaveGState(context);
CGContextTranslateCTM(context, -rect.origin.x, -rect.origin.y);
if (useDrawViewHierarchy) {
snapshotSuccess =
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO];
} else {
[[view layer] renderInContext:context];
}
if ([overlays count]) {
for (SnapshotOverlay* overlay in overlays) {
// Render the overlay view at the desired offset. It is achieved
// by shifting origin of context because view frame is ignored when
// drawing to context.
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0, overlay.yOffset);
if (useDrawViewHierarchy) {
[overlay.view drawViewHierarchyInRect:overlay.view.bounds
afterScreenUpdates:YES];
} else {
[[overlay.view layer] renderInContext:context];
}
CGContextRestoreGState(context);
}
}
UIImage* image = nil;
if (snapshotSuccess)
image = UIGraphicsGetImageFromCurrentImageContext();
CGContextRestoreGState(context);
UIGraphicsEndImageContext();
return image;
}
- (void)retrieveImageForSessionID:(NSString*)sessionID
callback:(void (^)(UIImage*))callback {
[[self snapshotCache] retrieveImageForSessionID:sessionID callback:callback];
}
- (void)retrieveGreyImageForSessionID:(NSString*)sessionID
callback:(void (^)(UIImage*))callback {
[[self snapshotCache] retrieveGreyImageForSessionID:sessionID
callback:callback];
}
- (void)setImage:(UIImage*)image withSessionID:(NSString*)sessionID {
[[self snapshotCache] setImage:image withSessionID:sessionID];
}
- (void)removeImageWithSessionID:(NSString*)sessionID {
[[self snapshotCache] removeImageWithSessionID:sessionID];
}
- (void)greyImageForSessionID:(NSString*)sessionID
callback:(void (^)(UIImage*))callback {
[[self snapshotCache] greyImageForSessionID:sessionID callback:callback];
}
#pragma mark - Private methods.
- (SnapshotCache*)snapshotCache {
return SnapshotCacheFactory::GetForBrowserState(
ios::ChromeBrowserState::FromBrowserState(_webState->GetBrowserState()));
}
@end
......@@ -8,24 +8,21 @@
#import <UIKit/UIKit.h>
@class CRWWebController;
@class SnapshotManager;
@class SnapshotOverlay;
@class Tab;
// A class that takes care of creating, storing and returning snapshots of a
// WebController's web page.
// TODO(crbug.com/661642): There is a lot of overlap/common functionality
// between this class and SnapshotManager, coalesce these 2 classes.
@interface WebControllerSnapshotHelper : NSObject
// Designated initializer. |snapshotManager|, |sessionID|, |webController|
// should not be nil.
// Designated initializer. |tab| must not be nil.
// TODO(crbug.com/661641): Since we already retain a CRWWebController* and that
// is the same which is passed to these methods, remove the CRWWebController
// param from the following methods.
// TODO(crbug.com/380819): Replace the need to use Tab directly here by using a
// delegate pattern.
- (instancetype)initWithSnapshotManager:(SnapshotManager*)snapshotManager
tab:(Tab*)tab;
- (instancetype)initWithTab:(Tab*)tab NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
// If |snapshotCoalescingEnabled| is YES snapshots of the web page are
// coalesced until this method is called with |snapshotCoalescingEnabled| set to
......@@ -38,7 +35,7 @@
// overlayed), can be nil.
- (void)retrieveSnapshotForWebController:(CRWWebController*)webController
sessionID:(NSString*)sessionID
withOverlays:(NSArray*)overlays
withOverlays:(NSArray<SnapshotOverlay*>*)overlays
callback:(void (^)(UIImage* image))callback;
// Gets a grey snapshot for the webController's current page, calling |callback|
......@@ -46,7 +43,8 @@
// (views currently overlayed), can be nil.
- (void)retrieveGreySnapshotForWebController:(CRWWebController*)webController
sessionID:(NSString*)sessionID
withOverlays:(NSArray*)overlays
withOverlays:
(NSArray<SnapshotOverlay*>*)overlays
callback:(void (^)(UIImage* image))callback;
// Invalidates the cached snapshot for the controller's current session and
......@@ -57,7 +55,7 @@
// overlayed), can be nil.
- (UIImage*)updateSnapshotForWebController:(CRWWebController*)webController
sessionID:(NSString*)sessionID
withOverlays:(NSArray*)overlays
withOverlays:(NSArray<SnapshotOverlay*>*)overlays
visibleFrameOnly:(BOOL)visibleFrameOnly;
// Takes a snapshot image for the current page including optional infobars.
......@@ -68,7 +66,8 @@
// |overlays| is the array of SnapshotOverlay objects (views currently
// overlayed), can be nil.
- (UIImage*)generateSnapshotForWebController:(CRWWebController*)webController
withOverlays:(NSArray*)overlays
withOverlays:
(NSArray<SnapshotOverlay*>*)overlays
visibleFrameOnly:(BOOL)visibleFrameOnly;
@end
......
......@@ -4,7 +4,10 @@
#import "ios/chrome/browser/snapshots/web_controller_snapshot_helper.h"
#import "ios/chrome/browser/snapshots/snapshot_manager.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#import "ios/chrome/browser/snapshots/snapshot_cache.h"
#import "ios/chrome/browser/snapshots/snapshot_cache_factory.h"
#import "ios/chrome/browser/snapshots/snapshot_overlay.h"
#import "ios/chrome/browser/tabs/tab.h"
#import "ios/chrome/browser/tabs/tab_headers_delegate.h"
#import "ios/chrome/browser/tabs/tab_private.h"
......@@ -15,39 +18,30 @@
#error "This file requires ARC support."
#endif
@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
namespace {
// Returns YES if |view| or any view it contains is a WKWebView.
BOOL ViewHierarchyContainsWKWebView(UIView* view) {
if ([view isKindOfClass:[WKWebView class]])
return YES;
for (UIView* subview in view.subviews) {
if (ViewHierarchyContainsWKWebView(subview))
return YES;
}
return NO;
}
} // namespace
// 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
- (UIImage*)cachedSnapshotWithOverlays:(NSArray<SnapshotOverlay*>*)overlays
visibleFrameOnly:(BOOL)visibleFrameOnly;
// Caches |snapshot| for the given |overlays| and |visibleFrameOnly|.
- (void)setCachedSnapshot:(UIImage*)snapshot
withOverlays:(NSArray*)overlays
withOverlays:(NSArray<SnapshotOverlay*>*)overlays
visibleFrameOnly:(BOOL)visibleFrameOnly;
@end
......@@ -60,12 +54,12 @@
// 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
- (BOOL)shouldCacheSnapshotWithOverlays:(NSArray<SnapshotOverlay*>*)overlays
visibleFrameOnly:(BOOL)visibleFrameOnly {
return ![overlays count] && visibleFrameOnly;
}
- (UIImage*)cachedSnapshotWithOverlays:(NSArray*)overlays
- (UIImage*)cachedSnapshotWithOverlays:(NSArray<SnapshotOverlay*>*)overlays
visibleFrameOnly:(BOOL)visibleFrameOnly {
if ([self shouldCacheSnapshotWithOverlays:overlays
visibleFrameOnly:visibleFrameOnly]) {
......@@ -75,7 +69,7 @@
}
- (void)setCachedSnapshot:(UIImage*)snapshot
withOverlays:(NSArray*)overlays
withOverlays:(NSArray<SnapshotOverlay*>*)overlays
visibleFrameOnly:(BOOL)visibleFrameOnly {
if ([self shouldCacheSnapshotWithOverlays:overlays
visibleFrameOnly:visibleFrameOnly]) {
......@@ -86,28 +80,50 @@
@end
@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<SnapshotOverlay*>*)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<SnapshotOverlay*>*)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<SnapshotOverlay*>*)overlays
visibleFrameOnly:(BOOL)visibleFrameOnly;
// Takes a snapshot for the supplied view (which should correspond to the given
// type of web view). Returns an autoreleased image cropped and scaled
// appropriately.
// The image is not yet cached.
// The image can also contain overlays (if |overlays| is not nil and not empty).
- (UIImage*)generateSnapshotForView:(UIView*)view
withRect:(CGRect)rect
overlays:(NSArray<SnapshotOverlay*>*)overlays;
@end
@implementation WebControllerSnapshotHelper {
CoalescingSnapshotContext* _coalescingSnapshotContext;
SnapshotManager* _snapshotManager;
__weak CRWWebController* _webController;
// Owns this WebControllerSnapshotHelper.
__weak Tab* _tab;
}
- (instancetype)init {
NOTREACHED();
return nil;
}
- (instancetype)initWithSnapshotManager:(SnapshotManager*)snapshotManager
tab:(Tab*)tab {
self = [super init];
if (self) {
DCHECK(snapshotManager);
- (instancetype)initWithTab:(Tab*)tab {
if ((self = [super init])) {
DCHECK(tab);
DCHECK(tab.tabId);
DCHECK([tab webController]);
_snapshotManager = snapshotManager;
_webController = [tab webController];
_tab = tab;
}
......@@ -124,21 +140,11 @@
}
}
- (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
withOverlays:(NSArray<SnapshotOverlay*>*)overlays
callback:(void (^)(UIImage* image))callback {
[_snapshotManager
[[self snapshotCache]
retrieveImageForSessionID:sessionID
callback:^(UIImage* image) {
if (image) {
......@@ -153,12 +159,12 @@
}];
}
- (void)retrieveGreySnapshotForWebController:(CRWWebController*)webController
sessionID:(NSString*)sessionID
withOverlays:(NSArray*)overlays
callback:
(void (^)(UIImage* image))callback {
[_snapshotManager
- (void)
retrieveGreySnapshotForWebController:(CRWWebController*)webController
sessionID:(NSString*)sessionID
withOverlays:(NSArray<SnapshotOverlay*>*)overlays
callback:(void (^)(UIImage* image))callback {
[[self snapshotCache]
retrieveGreyImageForSessionID:sessionID
callback:^(UIImage* image) {
if (image) {
......@@ -175,7 +181,7 @@
- (UIImage*)updateSnapshotForWebController:(CRWWebController*)webController
sessionID:(NSString*)sessionID
withOverlays:(NSArray*)overlays
withOverlays:(NSArray<SnapshotOverlay*>*)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.
......@@ -203,12 +209,13 @@
[snapshot size].width, [snapshot size].height);
snapshotToCache = CropImage(snapshot, cropRect);
}
[_snapshotManager setImage:snapshotToCache withSessionID:sessionID];
[[self snapshotCache] setImage:snapshotToCache withSessionID:sessionID];
return snapshot;
}
- (UIImage*)generateSnapshotForWebController:(CRWWebController*)webController
withOverlays:(NSArray*)overlays
withOverlays:
(NSArray<SnapshotOverlay*>*)overlays
visibleFrameOnly:(BOOL)visibleFrameOnly {
if (![webController canUseViewForGeneratingOverlayPlaceholderView])
return nil;
......@@ -220,9 +227,9 @@
visibleFrameOnly:visibleFrameOnly];
if (!snapshot) {
[_tab willUpdateSnapshot];
snapshot = [_snapshotManager generateSnapshotForView:webController.view
withRect:visibleFrame
overlays:overlays];
snapshot = [self generateSnapshotForView:webController.view
withRect:visibleFrame
overlays:overlays];
[self setCachedSnapshot:snapshot
withOverlays:overlays
visibleFrameOnly:visibleFrameOnly];
......@@ -230,9 +237,94 @@
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.
#pragma mark - Private methods
- (UIImage*)
generateSnapshotOrDefaultForWebController:(CRWWebController*)webController
withOverlays:(NSArray<SnapshotOverlay*>*)overlays
visibleFrameOnly:(BOOL)visibleFrameOnly {
UIImage* result = [self generateSnapshotForWebController:webController
withOverlays:overlays
visibleFrameOnly:visibleFrameOnly];
return result ? result : [[self class] defaultSnapshotImage];
}
- (UIImage*)cachedSnapshotWithOverlays:(NSArray<SnapshotOverlay*>*)overlays
visibleFrameOnly:(BOOL)visibleFrameOnly {
return
[_coalescingSnapshotContext cachedSnapshotWithOverlays:overlays
visibleFrameOnly:visibleFrameOnly];
}
- (void)setCachedSnapshot:(UIImage*)snapshot
withOverlays:(NSArray<SnapshotOverlay*>*)overlays
visibleFrameOnly:(BOOL)visibleFrameOnly {
return [_coalescingSnapshotContext setCachedSnapshot:snapshot
withOverlays:overlays
visibleFrameOnly:visibleFrameOnly];
}
- (UIImage*)generateSnapshotForView:(UIView*)view
withRect:(CGRect)rect
overlays:(NSArray<SnapshotOverlay*>*)overlays {
DCHECK(view);
CGSize size = rect.size;
DCHECK(std::isnormal(size.width) && (size.width > 0))
<< ": size.width=" << size.width;
DCHECK(std::isnormal(size.height) && (size.height > 0))
<< ": size.height=" << size.height;
const CGFloat kScale = [[self snapshotCache] snapshotScaleForDevice];
UIGraphicsBeginImageContextWithOptions(size, YES, kScale);
CGContext* context = UIGraphicsGetCurrentContext();
if (!context) {
NOTREACHED();
return nil;
}
// -drawViewHierarchyInRect:afterScreenUpdates:YES is buggy as of iOS 8.3.
// Using it afterScreenUpdates:YES creates unexpected GPU glitches, screen
// redraws during animations, broken pinch to dismiss on tablet, etc. For now
// only using this with WKWebView, which depends on -drawViewHierarchyInRect.
// TODO(justincohen): Remove this (and always use drawViewHierarchyInRect)
// once the iOS 8 bugs have been fixed.
BOOL useDrawViewHierarchy = ViewHierarchyContainsWKWebView(view);
BOOL snapshotSuccess = YES;
CGContextSaveGState(context);
CGContextTranslateCTM(context, -rect.origin.x, -rect.origin.y);
if (useDrawViewHierarchy) {
snapshotSuccess =
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO];
} else {
[[view layer] renderInContext:context];
}
if ([overlays count]) {
for (SnapshotOverlay* overlay in overlays) {
// Render the overlay view at the desired offset. It is achieved
// by shifting origin of context because view frame is ignored when
// drawing to context.
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0, overlay.yOffset);
if (useDrawViewHierarchy) {
[overlay.view drawViewHierarchyInRect:overlay.view.bounds
afterScreenUpdates:YES];
} else {
[[overlay.view layer] renderInContext:context];
}
CGContextRestoreGState(context);
}
}
UIImage* image = nil;
if (snapshotSuccess)
image = UIGraphicsGetImageFromCurrentImageContext();
CGContextRestoreGState(context);
UIGraphicsEndImageContext();
return image;
}
// TODO(crbug.com/661642): This code is shared with CRWWebController. 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;
......@@ -250,19 +342,10 @@
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];
- (SnapshotCache*)snapshotCache {
return SnapshotCacheFactory::GetForBrowserState(
ios::ChromeBrowserState::FromBrowserState(
_webController.webState->GetBrowserState()));
}
@end
......@@ -60,7 +60,8 @@
#include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
#include "ios/chrome/browser/search_engines/template_url_service_factory.h"
#include "ios/chrome/browser/sessions/ios_chrome_session_tab_helper.h"
#import "ios/chrome/browser/snapshots/snapshot_manager.h"
#import "ios/chrome/browser/snapshots/snapshot_cache.h"
#import "ios/chrome/browser/snapshots/snapshot_cache_factory.h"
#import "ios/chrome/browser/snapshots/snapshot_overlay_provider.h"
#import "ios/chrome/browser/snapshots/web_controller_snapshot_helper.h"
#import "ios/chrome/browser/tabs/legacy_tab_helper.h"
......@@ -191,9 +192,6 @@ bool IsItemRedirectItem(web::NavigationItem* item) {
UIImageView* _pagePlaceholder;
}
// Handles caching and retrieving of snapshots.
@property(nonatomic, strong) SnapshotManager* snapshotManager;
// Returns the OpenInController for this tab.
- (OpenInController*)openInController;
......@@ -268,7 +266,6 @@ void TabInfoBarObserver::OnInfoBarReplaced(infobars::InfoBar* old_infobar,
@synthesize tabHeadersDelegate = tabHeadersDelegate_;
@synthesize legacyFullscreenControllerDelegate =
legacyFullscreenControllerDelegate_;
@synthesize snapshotManager = _snapshotManager;
- (instancetype)initWithWebState:(web::WebState*)webState {
DCHECK(webState);
......@@ -286,10 +283,8 @@ void TabInfoBarObserver::OnInfoBarReplaced(infobars::InfoBar* old_infobar,
[self updateLastVisitedTimestamp];
[[self webController] setDelegate:self];
_snapshotManager = [[SnapshotManager alloc] initWithWebState:webState];
_webControllerSnapshotHelper = [[WebControllerSnapshotHelper alloc]
initWithSnapshotManager:_snapshotManager
tab:self];
_webControllerSnapshotHelper =
[[WebControllerSnapshotHelper alloc] initWithTab:self];
}
return self;
}
......@@ -1029,8 +1024,9 @@ void TabInfoBarObserver::OnInfoBarReplaced(infobars::InfoBar* old_infobar,
// In other cases, such as during startup, either disk access or a greyspace
// conversion is required, as there will be no grey snapshots in memory.
if (useGreyImageCache_) {
[self.snapshotManager greyImageForSessionID:sessionID
callback:completionHandler];
[SnapshotCacheFactory::GetForBrowserState(self.browserState)
greyImageForSessionID:sessionID
callback:completionHandler];
} else {
[_webControllerSnapshotHelper
retrieveGreySnapshotForWebController:self.webController
......@@ -1090,7 +1086,8 @@ void TabInfoBarObserver::OnInfoBarReplaced(infobars::InfoBar* old_infobar,
- (void)removeSnapshot {
DCHECK(self.tabId);
[self.snapshotManager removeImageWithSessionID:self.tabId];
[SnapshotCacheFactory::GetForBrowserState(self.browserState)
removeImageWithSessionID:self.tabId];
}
#pragma mark - CRWWebDelegate and CRWWebStateObserver protocol methods
......
......@@ -24,7 +24,8 @@
#import "ios/chrome/browser/chrome_url_util.h"
#include "ios/chrome/browser/history/history_service_factory.h"
#include "ios/chrome/browser/history/history_tab_helper.h"
#import "ios/chrome/browser/snapshots/snapshot_manager.h"
#import "ios/chrome/browser/snapshots/snapshot_cache.h"
#import "ios/chrome/browser/snapshots/snapshot_cache_factory.h"
#import "ios/chrome/browser/tabs/legacy_tab_helper.h"
#import "ios/chrome/browser/tabs/tab.h"
#import "ios/chrome/browser/tabs/tab_helper_util.h"
......@@ -52,11 +53,21 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gtest_mac.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#import "third_party/ocmock/gtest_support.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// When C++ exceptions are disabled, the C++ library defines |try| and
// |catch| so as to allow exception-expecting C++ code to build properly when
// language support for exceptions is not present. These macros interfere
// with the use of |@try| and |@catch| in Objective-C files such as this one.
// Undefine these macros here, after everything has been #included, since
// there will be no C++ uses and only Objective-C uses from this point on.
#undef try
#undef catch
namespace {
const char kAppSettingsUrl[] = "app-settings://";
const char kNewTabUrl[] = "chrome://newtab/";
......@@ -74,10 +85,6 @@ const char kInvalidFilenameUrl[] = "http://www.hostname.com/";
const char kValidFilenameUrl[] = "http://www.hostname.com/filename.pdf";
} // namespace
@interface Tab (Testing)
@property(nonatomic, strong) SnapshotManager* snapshotManager;
@end
@interface ArrayTabModel : TabModel {
@private
NSMutableArray* _tabsForTesting;
......@@ -166,6 +173,9 @@ class TabTest : public BlockCleanupTest {
// Set up the testing profiles.
TestChromeBrowserState::Builder test_cbs_builder;
test_cbs_builder.AddTestingFactory(
SnapshotCacheFactory::GetInstance(),
SnapshotCacheFactory::GetDefaultFactory());
chrome_browser_state_ = test_cbs_builder.Build();
chrome_browser_state_->CreateBookmarkModel(false);
bookmarks::test::WaitForBookmarkModelToLoad(
......@@ -408,26 +418,29 @@ TEST_F(TabTest, GetSuggestedFilenameFromDefaultName) {
EXPECT_NSEQ(@"Document.pdf", [[tab_ openInController] suggestedFilename]);
}
TEST_F(TabTest, SnapshotIsNotRemovedDuringShutdown) {
id mockSnapshotManager = OCMClassMock([SnapshotManager class]);
tab_.snapshotManager = mockSnapshotManager;
[[mockSnapshotManager reject] removeImageWithSessionID:[OCMArg any]];
web_state_impl_.reset();
}
TEST_F(TabTest, ClosingWebStateDoesNotRemoveSnapshot) {
id mockSnapshotManager = OCMClassMock([SnapshotManager class]);
tab_.snapshotManager = mockSnapshotManager;
[[mockSnapshotManager reject] removeImageWithSessionID:[OCMArg any]];
web_state_impl_.reset();
id partialMock = OCMPartialMock(
SnapshotCacheFactory::GetForBrowserState(tab_.browserState));
[[partialMock reject] removeImageWithSessionID:tab_.tabId];
// Use @try/@catch as -reject raises an exception.
@try {
web_state_impl_.reset();
EXPECT_OCMOCK_VERIFY(partialMock);
} @catch (NSException* exception) {
// The exception is raised when -removeImageWithSessionID: is invoked. As
// this should not happen, mark the test as failed.
GTEST_FAIL();
}
}
TEST_F(TabTest, CallingRemoveSnapshotRemovesSnapshot) {
id mockSnapshotManager = OCMClassMock([SnapshotManager class]);
tab_.snapshotManager = mockSnapshotManager;
id partialMock = OCMPartialMock(
SnapshotCacheFactory::GetForBrowserState(tab_.browserState));
OCMExpect([partialMock removeImageWithSessionID:tab_.tabId]);
[tab_ removeSnapshot];
[[mockSnapshotManager verify] removeImageWithSessionID:[OCMArg any]];
web_state_impl_.reset();
EXPECT_OCMOCK_VERIFY(partialMock);
}
} // namespace
......@@ -10,7 +10,6 @@
#include "base/macros.h"
#include "base/strings/sys_string_conversions.h"
#import "base/test/ios/wait_util.h"
#import "ios/chrome/browser/snapshots/snapshot_manager.h"
#import "ios/chrome/browser/tabs/tab.h"
#import "ios/chrome/browser/tabs/tab_model.h"
#include "ios/chrome/browser/test/perf_test_with_bvc_ios.h"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment