summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkkhorimoto <kkhorimoto@chromium.org>2015-06-18 18:21:12 -0700
committerCommit bot <commit-bot@chromium.org>2015-06-19 01:21:32 +0000
commitc5bbbbfedd1369a7fddca5fde9a8b643befc9cd2 (patch)
tree40ee7b59ff4242cee66825cf28cffd1bb1634703
parent29d8e3b989cb4938640639ce90de488e5ca90c12 (diff)
downloadchromium_src-c5bbbbfedd1369a7fddca5fde9a8b643befc9cd2.zip
chromium_src-c5bbbbfedd1369a7fddca5fde9a8b643befc9cd2.tar.gz
chromium_src-c5bbbbfedd1369a7fddca5fde9a8b643befc9cd2.tar.bz2
Created CRWContentView.
This class consolidates the logic for displaying scrollable content and hooking the scroll view up with the scroll view proxy. Notable changes: - Interstitials and the Sad Tab are now both implemented using CRWContentViews. - The CRWWebViewProxy API has been changed to take a single CRWContentView instead of a web view and a scroll view. - WebInterstitial::SetSize() has been removed since WebState already handles resizing transient content views before display. BUG=478181 Review URL: https://codereview.chromium.org/1183243002 Cr-Commit-Position: refs/heads/master@{#335188}
-rw-r--r--ios/web/interstitials/html_web_interstitial_impl.h8
-rw-r--r--ios/web/interstitials/html_web_interstitial_impl.mm20
-rw-r--r--ios/web/interstitials/native_web_interstitial_impl.h14
-rw-r--r--ios/web/interstitials/native_web_interstitial_impl.mm32
-rw-r--r--ios/web/interstitials/web_interstitial_impl.h6
-rw-r--r--ios/web/interstitials/web_interstitial_impl.mm4
-rw-r--r--ios/web/ios_web.gyp7
-rw-r--r--ios/web/public/interstitials/web_interstitial.h3
-rw-r--r--ios/web/public/test/test_web_state.h1
-rw-r--r--ios/web/public/test/test_web_view_content_view.h23
-rw-r--r--ios/web/public/test/test_web_view_content_view.mm40
-rw-r--r--ios/web/public/web_state/crw_web_view_proxy.h1
-rw-r--r--ios/web/public/web_state/crw_web_view_scroll_view_proxy.h1
-rw-r--r--ios/web/public/web_state/ui/crw_content_view.h28
-rw-r--r--ios/web/public/web_state/ui/crw_generic_content_view.h26
-rw-r--r--ios/web/public/web_state/ui/crw_web_view_content_view.h27
-rw-r--r--ios/web/public/web_state/web_state.h7
-rw-r--r--ios/web/test/web_test.mm1
-rw-r--r--ios/web/web_state/crw_web_view_proxy_impl.h11
-rw-r--r--ios/web/web_state/crw_web_view_proxy_impl.mm33
-rw-r--r--ios/web/web_state/ui/crw_generic_content_view.mm74
-rw-r--r--ios/web/web_state/ui/crw_ui_web_view_web_controller.mm7
-rw-r--r--ios/web/web_state/ui/crw_web_controller.h24
-rw-r--r--ios/web/web_state/ui/crw_web_controller.mm210
-rw-r--r--ios/web/web_state/ui/crw_web_controller_container_view.h45
-rw-r--r--ios/web/web_state/ui/crw_web_controller_container_view.mm126
-rw-r--r--ios/web/web_state/ui/crw_web_controller_container_view_unittest.mm10
-rw-r--r--ios/web/web_state/ui/crw_web_controller_unittest.mm22
-rw-r--r--ios/web/web_state/ui/crw_web_view_content_view.mm56
-rw-r--r--ios/web/web_state/ui/crw_wk_web_view_web_controller.mm7
-rw-r--r--ios/web/web_state/web_state_impl.h13
-rw-r--r--ios/web/web_state/web_state_impl.mm55
32 files changed, 690 insertions, 252 deletions
diff --git a/ios/web/interstitials/html_web_interstitial_impl.h b/ios/web/interstitials/html_web_interstitial_impl.h
index 7bda180..8e469a9 100644
--- a/ios/web/interstitials/html_web_interstitial_impl.h
+++ b/ios/web/interstitials/html_web_interstitial_impl.h
@@ -32,12 +32,8 @@ class HtmlWebInterstitialImpl : public WebInterstitialImpl {
// receives a JavaScript command.
void CommandReceivedFromWebView(NSString* command);
- // WebInterstitial implementation:
- void SetSize(const gfx::Size& size) override;
-
// WebInterstitialImpl implementation:
- UIView* GetView() const override;
- UIScrollView* GetScrollView() const override;
+ CRWContentView* GetContentView() const override;
protected:
// WebInterstitialImpl implementation:
@@ -56,6 +52,8 @@ class HtmlWebInterstitialImpl : public WebInterstitialImpl {
// The CRWSimpleWebViewController that contains the web view used to show the
// content. View needs to be resized by the caller.
base::scoped_nsprotocol<id<CRWSimpleWebViewController>> web_view_controller_;
+ // The CRWContentView used to display |web_view_controller_|'s view.
+ base::scoped_nsobject<CRWContentView> content_view_;
};
} // namespace web
diff --git a/ios/web/interstitials/html_web_interstitial_impl.mm b/ios/web/interstitials/html_web_interstitial_impl.mm
index 4a23631..4a2d091 100644
--- a/ios/web/interstitials/html_web_interstitial_impl.mm
+++ b/ios/web/interstitials/html_web_interstitial_impl.mm
@@ -8,6 +8,7 @@
#include "base/strings/sys_string_conversions.h"
#include "ios/web/interstitials/web_interstitial_facade_delegate.h"
#include "ios/web/public/interstitials/web_interstitial_delegate.h"
+#include "ios/web/public/web_state/ui/crw_web_view_content_view.h"
#import "ios/web/web_state/ui/crw_simple_web_view_controller.h"
#include "ios/web/web_state/web_state_impl.h"
#import "ios/web/web_state/web_view_creation_utils.h"
@@ -82,22 +83,12 @@ void HtmlWebInterstitialImpl::CommandReceivedFromWebView(NSString* command) {
delegate_->CommandReceived(base::SysNSStringToUTF8(command));
}
-void HtmlWebInterstitialImpl::SetSize(const gfx::Size& size) {
- CGRect frame = [web_view_controller_ view].frame;
- frame.size = size.ToCGSize();
- [[web_view_controller_ view] setFrame:frame];
-}
-
-UIView* HtmlWebInterstitialImpl::GetView() const {
- return [web_view_controller_ view];
-}
-
-UIScrollView* HtmlWebInterstitialImpl::GetScrollView() const {
- return [web_view_controller_ scrollView];
+CRWContentView* HtmlWebInterstitialImpl::GetContentView() const {
+ return content_view_.get();
}
void HtmlWebInterstitialImpl::PrepareForDisplay() {
- if (!web_view_controller_) {
+ if (!content_view_) {
web_view_controller_delegate_.reset(
[[CRWWebInterstitialImplCRWSimpleWebViewDelegate alloc]
initWithInterstitial:this]);
@@ -111,6 +102,9 @@ void HtmlWebInterstitialImpl::PrepareForDisplay() {
NSString* html = base::SysUTF8ToNSString(delegate_->GetHtmlContents());
[web_view_controller_ loadHTMLString:html
baseURL:net::NSURLWithGURL(GetUrl())];
+ content_view_.reset([[CRWWebViewContentView alloc]
+ initWithWebView:[web_view_controller_ view]
+ scrollView:[web_view_controller_ scrollView]]);
}
}
diff --git a/ios/web/interstitials/native_web_interstitial_impl.h b/ios/web/interstitials/native_web_interstitial_impl.h
index 87179d8..5957ea9 100644
--- a/ios/web/interstitials/native_web_interstitial_impl.h
+++ b/ios/web/interstitials/native_web_interstitial_impl.h
@@ -23,12 +23,8 @@ class NativeWebInterstitialImpl : public WebInterstitialImpl {
scoped_ptr<NativeWebInterstitialDelegate> delegate);
~NativeWebInterstitialImpl() override;
- // WebInterstitial implementation:
- void SetSize(const gfx::Size& size) override;
-
// WebInterstitialImpl implementation:
- UIView* GetView() const override;
- UIScrollView* GetScrollView() const override;
+ CRWContentView* GetContentView() const override;
protected:
// WebInterstitialImpl implementation:
@@ -40,12 +36,8 @@ class NativeWebInterstitialImpl : public WebInterstitialImpl {
private:
// The native interstitial delegate.
scoped_ptr<NativeWebInterstitialDelegate> delegate_;
- // The top-level view containing the scroll view.
- base::scoped_nsobject<UIView> container_view_;
- // The scroll view used to display |content_view_|.
- base::scoped_nsobject<UIScrollView> scroll_view_;
- // The content view provided by |delegate_|.
- base::WeakNSObject<UIView> content_view_;
+ // The transient content view containing interstitial content.
+ base::scoped_nsobject<CRWContentView> content_view_;
};
} // namespace web
diff --git a/ios/web/interstitials/native_web_interstitial_impl.mm b/ios/web/interstitials/native_web_interstitial_impl.mm
index f205d48..1a86b23 100644
--- a/ios/web/interstitials/native_web_interstitial_impl.mm
+++ b/ios/web/interstitials/native_web_interstitial_impl.mm
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "ios/web/public/interstitials/web_interstitial_delegate.h"
+#import "ios/web/public/web_state/ui/crw_generic_content_view.h"
#include "ios/web/web_state/web_state_impl.h"
#include "ui/gfx/geometry/size.h"
@@ -31,37 +32,14 @@ NativeWebInterstitialImpl::NativeWebInterstitialImpl(
NativeWebInterstitialImpl::~NativeWebInterstitialImpl() {
}
-void NativeWebInterstitialImpl::SetSize(const gfx::Size& size) {
- if (!content_view_)
- return;
-
- // Resize container and scroll view.
- CGSize cgSize = size.ToCGSize();
- [container_view_ setFrame:{[container_view_ frame].origin, cgSize}];
- [scroll_view_ setFrame:[container_view_ bounds]];
-
- // Resize content.
- CGSize contentSize = [content_view_ sizeThatFits:cgSize];
- [content_view_ setFrame:{CGPointZero, contentSize}];
- [scroll_view_ setContentSize:contentSize];
-}
-
-UIView* NativeWebInterstitialImpl::GetView() const {
- return container_view_.get();
-}
-
-UIScrollView* NativeWebInterstitialImpl::GetScrollView() const {
- return scroll_view_.get();
+CRWContentView* NativeWebInterstitialImpl::GetContentView() const {
+ return content_view_.get();
}
void NativeWebInterstitialImpl::PrepareForDisplay() {
if (!content_view_) {
- container_view_.reset([[UIView alloc] initWithFrame:CGRectZero]);
- scroll_view_.reset([[UIScrollView alloc] initWithFrame:CGRectZero]);
- content_view_.reset(delegate_->GetContentView());
- [scroll_view_ addSubview:content_view_];
- [scroll_view_ setBackgroundColor:delegate_->GetScrollViewBackgroundColor()];
- [container_view_ addSubview:scroll_view_];
+ content_view_.reset([[CRWGenericContentView alloc]
+ initWithView:delegate_->GetContentView()]);
}
}
diff --git a/ios/web/interstitials/web_interstitial_impl.h b/ios/web/interstitials/web_interstitial_impl.h
index a438264..c1826ca 100644
--- a/ios/web/interstitials/web_interstitial_impl.h
+++ b/ios/web/interstitials/web_interstitial_impl.h
@@ -8,6 +8,7 @@
#import <UIKit/UIKit.h>
#import "ios/web/public/interstitials/web_interstitial.h"
+#include "ios/web/public/web_state/ui/crw_content_view.h"
#include "ios/web/public/web_state/web_state_observer.h"
#import "ios/web/web_state/ui/web_view_js_utils.h"
#include "url/gurl.h"
@@ -32,9 +33,8 @@ class WebInterstitialImpl : public WebInterstitial, public WebStateObserver {
WebInterstitialImpl(WebStateImpl* web_state, const GURL& url);
~WebInterstitialImpl() override;
- // Returns the view and scroll view used to display the interstitial content.
- virtual UIView* GetView() const = 0;
- virtual UIScrollView* GetScrollView() const = 0;
+ // Returns the transient content view used to display interstitial content.
+ virtual CRWContentView* GetContentView() const = 0;
// Returns the url corresponding to this interstitial.
const GURL& GetUrl() const;
diff --git a/ios/web/interstitials/web_interstitial_impl.mm b/ios/web/interstitials/web_interstitial_impl.mm
index 3e14856..b40a189 100644
--- a/ios/web/interstitials/web_interstitial_impl.mm
+++ b/ios/web/interstitials/web_interstitial_impl.mm
@@ -46,11 +46,11 @@ WebInterstitialFacadeDelegate* WebInterstitialImpl::GetFacadeDelegate() const {
void WebInterstitialImpl::Show() {
PrepareForDisplay();
- GetWebStateImpl()->DisplayWebInterstitial(this);
+ GetWebStateImpl()->ShowWebInterstitial(this);
}
void WebInterstitialImpl::Hide() {
- GetWebStateImpl()->DismissWebInterstitial();
+ GetWebStateImpl()->ClearTransientContentView();
}
void WebInterstitialImpl::DontProceed() {
diff --git a/ios/web/ios_web.gyp b/ios/web/ios_web.gyp
index 5b0f50b..7e7eddd 100644
--- a/ios/web/ios_web.gyp
+++ b/ios/web/ios_web.gyp
@@ -184,8 +184,11 @@
'public/web_state/js/crw_js_injection_receiver.h',
'public/web_state/page_display_state.h',
'public/web_state/page_display_state.mm',
+ 'public/web_state/ui/crw_content_view.h',
+ 'public/web_state/ui/crw_generic_content_view.h',
'public/web_state/ui/crw_native_content.h',
'public/web_state/ui/crw_native_content_provider.h',
+ 'public/web_state/ui/crw_web_view_content_view.h',
'public/web_state/url_verification_constants.h',
'public/web_state/web_state.h',
'public/web_state/web_state_observer.h',
@@ -232,6 +235,7 @@
'web_state/ui/crw_context_menu_provider.mm',
'web_state/ui/crw_debug_web_view.h',
'web_state/ui/crw_debug_web_view.mm',
+ 'web_state/ui/crw_generic_content_view.mm',
'web_state/ui/crw_simple_web_view_controller.h',
'web_state/ui/crw_static_file_web_view.h',
'web_state/ui/crw_static_file_web_view.mm',
@@ -247,6 +251,7 @@
'web_state/ui/crw_web_controller.mm',
'web_state/ui/crw_web_controller_container_view.h',
'web_state/ui/crw_web_controller_container_view.mm',
+ 'web_state/ui/crw_web_view_content_view.mm',
'web_state/ui/crw_wk_simple_web_view_controller.h',
'web_state/ui/crw_wk_simple_web_view_controller.mm',
'web_state/ui/crw_wk_web_view_crash_detector.h',
@@ -509,6 +514,8 @@
'public/test/test_web_state.h',
'public/test/test_web_thread.h',
'public/test/test_web_thread_bundle.h',
+ 'public/test/test_web_view_content_view.h',
+ 'public/test/test_web_view_content_view.mm',
'public/test/web_test_util.h',
'test/crw_fake_web_controller_observer.h',
'test/crw_fake_web_controller_observer.mm',
diff --git a/ios/web/public/interstitials/web_interstitial.h b/ios/web/public/interstitials/web_interstitial.h
index 43629c1..8a573c3 100644
--- a/ios/web/public/interstitials/web_interstitial.h
+++ b/ios/web/public/interstitials/web_interstitial.h
@@ -63,9 +63,6 @@ class WebInterstitial {
// the target URL.
// Warning: 'this' has been deleted when this method returns.
virtual void Proceed() = 0;
-
- // Sizes the view showing the actual interstitial page contents.
- virtual void SetSize(const gfx::Size& size) = 0;
};
} // namespace web
diff --git a/ios/web/public/test/test_web_state.h b/ios/web/public/test/test_web_state.h
index 4af4833..17f7a02 100644
--- a/ios/web/public/test/test_web_state.h
+++ b/ios/web/public/test/test_web_state.h
@@ -33,6 +33,7 @@ class TestWebState : public WebState {
const GURL& GetVisibleURL() const override;
const GURL& GetLastCommittedURL() const override;
GURL GetCurrentURL(URLVerificationTrustLevel* trust_level) const override;
+ void ShowTransientContentView(CRWContentView* content_view) override {}
void AddScriptCommandCallback(const ScriptCommandCallback& callback,
const std::string& command_prefix) override {}
void RemoveScriptCommandCallback(const std::string& command_prefix) override {
diff --git a/ios/web/public/test/test_web_view_content_view.h b/ios/web/public/test/test_web_view_content_view.h
new file mode 100644
index 0000000..560b9c7
--- /dev/null
+++ b/ios/web/public/test/test_web_view_content_view.h
@@ -0,0 +1,23 @@
+// Copyright 2015 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_WEB_PUBLIC_TEST_TEST_WEB_VIEW_CONTENT_VIEW_H_
+#define IOS_WEB_PUBLIC_TEST_TEST_WEB_VIEW_CONTENT_VIEW_H_
+
+#import "ios/web/public/web_state/ui/crw_web_view_content_view.h"
+
+// A test version of CRWWebViewContentView.
+@interface TestWebViewContentView : CRWWebViewContentView
+
+// Initializes the CRWTestWebContentView. Since |webView| and |scrollView| may
+// be mock objects, they will not be added as subviews.
+- (instancetype)initWithMockWebView:(id)webView scrollView:(id)scrollView;
+
+// CRWTestWebViewContentViews should be initialized via |-initWithMockWebView:
+// scrollView:|.
+- (instancetype)initWithWebView:(UIView*)webView
+ scrollView:(UIScrollView*)scrollView NS_UNAVAILABLE;
+@end
+
+#endif // IOS_WEB_PUBLIC_TEST_TEST_WEB_VIEW_CONTENT_VIEW_H_
diff --git a/ios/web/public/test/test_web_view_content_view.mm b/ios/web/public/test/test_web_view_content_view.mm
new file mode 100644
index 0000000..afccc98
--- /dev/null
+++ b/ios/web/public/test/test_web_view_content_view.mm
@@ -0,0 +1,40 @@
+// Copyright 2015 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.
+
+#include "ios/web/public/test/test_web_view_content_view.h"
+
+#include "base/logging.h"
+#include "base/mac/scoped_nsobject.h"
+
+@interface TestWebViewContentView () {
+ base::scoped_nsprotocol<id> _mockWebView;
+ base::scoped_nsprotocol<id> _mockScrollView;
+}
+
+@end
+
+@implementation TestWebViewContentView
+
+- (instancetype)initWithMockWebView:(id)webView scrollView:(id)scrollView {
+ self = [super initWithFrame:CGRectZero];
+ if (self) {
+ DCHECK(webView);
+ DCHECK(scrollView);
+ _mockWebView.reset([webView retain]);
+ _mockScrollView.reset([scrollView retain]);
+ }
+ return self;
+}
+
+#pragma mark Accessors
+
+- (UIScrollView*)scrollView {
+ return static_cast<UIScrollView*>(_mockScrollView.get());
+}
+
+- (UIView*)webView {
+ return static_cast<UIView*>(_mockWebView.get());
+}
+
+@end
diff --git a/ios/web/public/web_state/crw_web_view_proxy.h b/ios/web/public/web_state/crw_web_view_proxy.h
index 784df4a..dc89d82 100644
--- a/ios/web/public/web_state/crw_web_view_proxy.h
+++ b/ios/web/public/web_state/crw_web_view_proxy.h
@@ -13,6 +13,7 @@
// Provides an interface for embedders to access the WebState's UIWebView in a
// limited and controlled manner.
+// TODO(kkhorimoto): rename protocol to CRWContentViewProxy.
@protocol CRWWebViewProxy<NSObject>
// The UIWebView's bounding rectangle (relative to its parent).
diff --git a/ios/web/public/web_state/crw_web_view_scroll_view_proxy.h b/ios/web/public/web_state/crw_web_view_scroll_view_proxy.h
index 9f9aadb..d46735e 100644
--- a/ios/web/public/web_state/crw_web_view_scroll_view_proxy.h
+++ b/ios/web/public/web_state/crw_web_view_scroll_view_proxy.h
@@ -20,6 +20,7 @@
// needed.
// The class forwards some of the methods onto the UIScrollView. For more
// information look at the UIScrollView documentation.
+// TODO(kkhorimoto): rename class to CRWContentViewScrollViewProxy.
@interface CRWWebViewScrollViewProxy : NSObject<UIScrollViewDelegate>
@property(nonatomic, assign) CGPoint contentOffset;
@property(nonatomic, assign) UIEdgeInsets contentInset;
diff --git a/ios/web/public/web_state/ui/crw_content_view.h b/ios/web/public/web_state/ui/crw_content_view.h
new file mode 100644
index 0000000..d84ecc2
--- /dev/null
+++ b/ios/web/public/web_state/ui/crw_content_view.h
@@ -0,0 +1,28 @@
+// Copyright 2015 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_WEB_PUBLIC_WEB_STATE_UI_CRW_CONTENT_VIEW_H_
+#define IOS_WEB_PUBLIC_WEB_STATE_UI_CRW_CONTENT_VIEW_H_
+
+#import <UIKit/UIKit.h>
+
+// UIViews conforming to CRWScrollableContent (i.e. CRWContentViews) are used
+// to display content within a WebState.
+@protocol CRWScrollableContent<NSObject>
+
+// The scroll view used to display the content. If |scrollView| is non-nil,
+// it will be used to back the CRWContentViewScrollViewProxy and is expected to
+// be a subview of the CRWContentView.
+@property(nonatomic, retain, readonly) UIScrollView* scrollView;
+
+// Returns YES if content is being displayed in the scroll view.
+// TODO(stuartmorgan): See if this can be removed from the public interface.
+- (BOOL)isViewAlive;
+
+@end
+
+// Convenience type for content views.
+typedef UIView<CRWScrollableContent> CRWContentView;
+
+#endif // IOS_WEB_PUBLIC_WEB_STATE_UI_CRW_CONTENT_VIEW_H_
diff --git a/ios/web/public/web_state/ui/crw_generic_content_view.h b/ios/web/public/web_state/ui/crw_generic_content_view.h
new file mode 100644
index 0000000..985dbb9
--- /dev/null
+++ b/ios/web/public/web_state/ui/crw_generic_content_view.h
@@ -0,0 +1,26 @@
+// Copyright 2015 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_WEB_PUBLIC_WEB_STATE_UI_CRW_GENERIC_CONTENT_VIEW_H_
+#define IOS_WEB_PUBLIC_WEB_STATE_UI_CRW_GENERIC_CONTENT_VIEW_H_
+
+#include "ios/web/public/web_state/ui/crw_content_view.h"
+
+// Wraps an arbitrary native UIView in a CRWContentView.
+@interface CRWGenericContentView : CRWContentView
+
+// The view that was passed to |-initWithContentView:|. This is the view that
+// is displayed in |self.scrollView|.
+@property(nonatomic, retain, readonly) UIView* view;
+
+// Initializes the CRWNativeContentContainerView to display |view|, which
+// will be added to the scroll view.
+- (instancetype)initWithView:(UIView*)view NS_DESIGNATED_INITIALIZER;
+
+// CRWGenericContentViews should be initialized via |-initWithView:|.
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+#endif // IOS_WEB_PUBLIC_WEB_STATE_UI_CRW_GENERIC_CONTENT_VIEW_H_
diff --git a/ios/web/public/web_state/ui/crw_web_view_content_view.h b/ios/web/public/web_state/ui/crw_web_view_content_view.h
new file mode 100644
index 0000000..e2de7bd
--- /dev/null
+++ b/ios/web/public/web_state/ui/crw_web_view_content_view.h
@@ -0,0 +1,27 @@
+// Copyright 2015 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_WEB_PUBLIC_WEB_STATE_UI_CRW_WEB_VIEW_CONTENT_VIEW_H_
+#define IOS_WEB_PUBLIC_WEB_STATE_UI_CRW_WEB_VIEW_CONTENT_VIEW_H_
+
+#import "ios/web/public/web_state/ui/crw_content_view.h"
+
+// Wraps a web vew in a CRWContentView.
+@interface CRWWebViewContentView : CRWContentView
+
+// The webView passed to |-initWithWebView|.
+@property(nonatomic, retain, readonly) UIView* webView;
+
+// Initializes the CRWWebViewContentView to display |webView|.
+- (instancetype)initWithWebView:(UIView*)webView
+ scrollView:(UIScrollView*)scrollView
+ NS_DESIGNATED_INITIALIZER;
+
+// CRWWebViewContentViews should be initialized via |-initWithWebView:
+// scrollView:|.
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+#endif // IOS_WEB_PUBLIC_WEB_STATE_UI_CRW_WEB_VIEW_CONTENT_VIEW_H_
diff --git a/ios/web/public/web_state/web_state.h b/ios/web/public/web_state/web_state.h
index f4cd765..6cdc4b0 100644
--- a/ios/web/public/web_state/web_state.h
+++ b/ios/web/public/web_state/web_state.h
@@ -23,11 +23,14 @@ class SkBitmap;
#if defined(__OBJC__)
@class CRWJSInjectionReceiver;
+@protocol CRWScrollableContent;
@protocol CRWWebViewProxy;
typedef id<CRWWebViewProxy> CRWWebViewProxyType;
@class UIView;
+typedef UIView<CRWScrollableContent> CRWContentView;
#else
class CRWJSInjectionReceiver;
+typedef void CRWContentView;
typedef void* CRWWebViewProxyType;
class UIView;
#endif // defined(__OBJC__)
@@ -137,6 +140,10 @@ class WebState : public base::SupportsUserData {
// See http://crbug.com/457679
virtual GURL GetCurrentURL(URLVerificationTrustLevel* trust_level) const = 0;
+ // Resizes |content_view| to the content area's size and adds it to the
+ // hierarchy. A navigation will remove the view from the hierarchy.
+ virtual void ShowTransientContentView(CRWContentView* content_view) = 0;
+
// Returns true if a WebInterstitial is currently displayed.
virtual bool IsShowingWebInterstitial() const = 0;
diff --git a/ios/web/test/web_test.mm b/ios/web/test/web_test.mm
index c521209..b286b96 100644
--- a/ios/web/test/web_test.mm
+++ b/ios/web/test/web_test.mm
@@ -114,6 +114,7 @@ void WebTestBase::LoadURL(const GURL& url) {
while ([webController_ loadPhase] != PAGE_LOADED)
WaitForBackgroundTasks();
webController_.get().delegate = existingDelegate;
+ [[webController_ view] layoutIfNeeded];
}
void WebTestBase::WaitForBackgroundTasks() {
diff --git a/ios/web/web_state/crw_web_view_proxy_impl.h b/ios/web/web_state/crw_web_view_proxy_impl.h
index 7a8386c..3589106 100644
--- a/ios/web/web_state/crw_web_view_proxy_impl.h
+++ b/ios/web/web_state/crw_web_view_proxy_impl.h
@@ -8,21 +8,24 @@
#import <UIKit/UIKit.h>
#include "ios/web/public/web_state/crw_web_view_proxy.h"
+#include "ios/web/public/web_state/ui/crw_content_view.h"
@class CRWWebController;
+// TODO(kkhorimoto): Rename class to CRWContentViewProxyImpl.
@interface CRWWebViewProxyImpl : NSObject<CRWWebViewProxy>
+// Used by CRWWebController to set the content view being managed.
+// |contentView|'s scroll view property will be managed by the
+// WebViewScrollViewProxy.
+@property(nonatomic, weak) CRWContentView* contentView;
+
// TODO(justincohen): It would be better if we could use something like a
// ScrollPositionController instead of passing in all of web controller.
// crbug.com/227744
// Init with a weak reference of web controller, used for passing thru calls.
- (instancetype)initWithWebController:(CRWWebController*)webController;
-// Used by the CRWWebController to set the web view to be managed.
-// Also sets the UIScrollView to be managed inside the WebViewScrollViewProxy.
-- (void)setWebView:(UIView*)webView scrollView:(UIScrollView*)scrollView;
-
@end
#endif // IOS_WEB_WEB_STATE_CRW_WEB_VIEW_PROXY_IMPL_H_
diff --git a/ios/web/web_state/crw_web_view_proxy_impl.mm b/ios/web/web_state/crw_web_view_proxy_impl.mm
index adb13c8..c8d6142 100644
--- a/ios/web/web_state/crw_web_view_proxy_impl.mm
+++ b/ios/web/web_state/crw_web_view_proxy_impl.mm
@@ -7,6 +7,7 @@
#include "base/ios/weak_nsobject.h"
#include "base/mac/scoped_nsobject.h"
#import "ios/web/public/web_state/crw_web_view_scroll_view_proxy.h"
+#import "ios/web/public/web_state/ui/crw_content_view.h"
#import "ios/web/web_state/ui/crw_web_controller.h"
namespace {
@@ -64,12 +65,12 @@ UIView* GetFirstResponderSubview(UIView* view) {
@end
@implementation CRWWebViewProxyImpl {
- base::WeakNSObject<UIView> _webView;
+ base::WeakNSObject<CRWContentView> _contentView;
base::WeakNSObject<CRWWebController> _webController;
base::scoped_nsobject<NSMutableDictionary> _registeredInsets;
// The WebViewScrollViewProxy is a wrapper around the UIWebView's
// UIScrollView to give components access in a limited and controlled manner.
- base::scoped_nsobject<CRWWebViewScrollViewProxy> _webViewScrollViewProxy;
+ base::scoped_nsobject<CRWWebViewScrollViewProxy> _contentViewScrollViewProxy;
}
- (instancetype)initWithWebController:(CRWWebController*)webController {
@@ -78,21 +79,21 @@ UIView* GetFirstResponderSubview(UIView* view) {
DCHECK(webController);
_registeredInsets.reset([[NSMutableDictionary alloc] init]);
_webController.reset(webController);
- _webViewScrollViewProxy.reset([[CRWWebViewScrollViewProxy alloc] init]);
+ _contentViewScrollViewProxy.reset([[CRWWebViewScrollViewProxy alloc] init]);
}
return self;
}
- (CRWWebViewScrollViewProxy*)scrollViewProxy {
- return _webViewScrollViewProxy.get();
+ return _contentViewScrollViewProxy.get();
}
- (CGRect)bounds {
- return [_webView bounds];
+ return [_contentView bounds];
}
- (NSArray*)gestureRecognizers {
- return [_webView gestureRecognizers];
+ return [_contentView gestureRecognizers];
}
- (web::WebViewType)webViewType {
@@ -115,25 +116,27 @@ UIView* GetFirstResponderSubview(UIView* view) {
[_registeredInsets removeObjectForKey:callerValue];
}
-- (void)setWebView:(UIView*)webView scrollView:(UIScrollView*)scrollView {
- _webView.reset(webView);
- if (webView)
- DCHECK(scrollView);
- [_webViewScrollViewProxy setScrollView:scrollView];
+- (CRWContentView*)contentView {
+ return _contentView.get();
+}
+
+- (void)setContentView:(CRWContentView*)contentView {
+ _contentView.reset(contentView);
+ [_contentViewScrollViewProxy setScrollView:contentView.scrollView];
}
- (void)addSubview:(UIView*)view {
- return [_webView addSubview:view];
+ return [_contentView addSubview:view];
}
- (BOOL)hasSearchableTextContent {
- return _webView != nil && [_webController contentIsHTML];
+ return _contentView != nil && [_webController contentIsHTML];
}
- (UIView*)getKeyboardAccessory {
- if (!_webView)
+ if (!_contentView)
return nil;
- UIView* firstResponder = GetFirstResponderSubview(_webView);
+ UIView* firstResponder = GetFirstResponderSubview(_contentView);
return firstResponder.inputAccessoryView;
}
diff --git a/ios/web/web_state/ui/crw_generic_content_view.mm b/ios/web/web_state/ui/crw_generic_content_view.mm
new file mode 100644
index 0000000..2602313
--- /dev/null
+++ b/ios/web/web_state/ui/crw_generic_content_view.mm
@@ -0,0 +1,74 @@
+// Copyright 2015 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/web/public/web_state/ui/crw_generic_content_view.h"
+
+#include "base/logging.h"
+#include "base/mac/scoped_nsobject.h"
+
+@interface CRWGenericContentView () {
+ // Backing objectect for |self.scrollView|.
+ base::scoped_nsobject<UIScrollView> _scrollView;
+ // Backing object for |self.view|.
+ base::scoped_nsobject<UIView> _view;
+}
+
+@end
+
+@implementation CRWGenericContentView
+
+- (instancetype)initWithView:(UIView*)view {
+ self = [super initWithFrame:CGRectZero];
+ if (self) {
+ DCHECK(view);
+ _view.reset([view retain]);
+ _scrollView.reset([[UIScrollView alloc] initWithFrame:CGRectZero]);
+ [self addSubview:_scrollView];
+ [_scrollView addSubview:_view];
+ [_scrollView setBackgroundColor:[_view backgroundColor]];
+ }
+ return self;
+}
+
+#pragma mark Accessors
+
+- (UIScrollView*)scrollView {
+ if (!_scrollView) {
+ _scrollView.reset([[UIScrollView alloc] initWithFrame:CGRectZero]);
+ }
+ return _scrollView.get();
+}
+
+- (UIView*)view {
+ return _view.get();
+}
+
+#pragma mark Layout
+
+- (void)layoutSubviews {
+ [super layoutSubviews];
+
+ // scrollView layout.
+ self.scrollView.frame = self.bounds;
+
+ // view layout.
+ CGRect contentRect =
+ UIEdgeInsetsInsetRect(self.bounds, self.scrollView.contentInset);
+ CGSize viewSize = [self.view sizeThatFits:contentRect.size];
+ self.view.frame = CGRectMake(0.0, 0.0, viewSize.width, viewSize.height);
+
+ // UIScrollViews only scroll vertically if the content size's height is
+ // creater than that of its content rect.
+ if (viewSize.height <= CGRectGetHeight(contentRect)) {
+ CGFloat singlePixel = 1.0f / [[UIScreen mainScreen] scale];
+ viewSize.height = CGRectGetHeight(contentRect) + singlePixel;
+ }
+ self.scrollView.contentSize = viewSize;
+}
+
+- (BOOL)isViewAlive {
+ return YES;
+}
+
+@end
diff --git a/ios/web/web_state/ui/crw_ui_web_view_web_controller.mm b/ios/web/web_state/ui/crw_ui_web_view_web_controller.mm
index 467607f..465a776 100644
--- a/ios/web/web_state/ui/crw_ui_web_view_web_controller.mm
+++ b/ios/web/web_state/ui/crw_ui_web_view_web_controller.mm
@@ -24,6 +24,7 @@
#include "ios/web/net/request_group_util.h"
#include "ios/web/public/url_scheme_util.h"
#include "ios/web/public/web_client.h"
+#import "ios/web/public/web_state/ui/crw_web_view_content_view.h"
#import "ios/web/ui_web_view_util.h"
#include "ios/web/web_state/frame_info.h"
#import "ios/web/web_state/js/crw_js_invoke_parameter_queue.h"
@@ -439,9 +440,9 @@ const size_t kMaxMessageQueueSize = 262144;
#pragma mark -
#pragma mark Testing-Only Methods
-- (void)injectWebView:(id)webView {
- [super injectWebView:webView];
- [self setWebView:webView];
+- (void)injectWebViewContentView:(CRWWebViewContentView*)webViewContentView {
+ [super injectWebViewContentView:webViewContentView];
+ [self setWebView:static_cast<UIWebView*>(webViewContentView.webView)];
}
#pragma mark CRWJSInjectionEvaluatorMethods
diff --git a/ios/web/web_state/ui/crw_web_controller.h b/ios/web/web_state/ui/crw_web_controller.h
index a6be7b5..2282fe4 100644
--- a/ios/web/web_state/ui/crw_web_controller.h
+++ b/ios/web/web_state/ui/crw_web_controller.h
@@ -52,6 +52,7 @@ extern NSString* const kContainerViewID;
@protocol CRWNativeContentProvider;
@protocol CRWSwipeRecognizerProvider;
@protocol CRWWebControllerObserver;
+@class CRWWebViewContentView;
@protocol CRWWebViewProxy;
class GURL;
@@ -94,10 +95,8 @@ class WebStateImpl;
@property(nonatomic, readonly) web::WebState* webState;
@property(nonatomic, readonly) web::WebStateImpl* webStateImpl;
-// If on a regular webpage, the UIWebView responsible for rendering it. If
-// on an internal page, the native view implementing the functionality. If the
-// view has been purged due to low memory, this will re-create it. It is up
-// to the caller to size the view.
+// The container view used to display content. If the view has been purged due
+// to low memory, this will recreate it.
@property(nonatomic, readonly) UIView* view;
// The web view proxy associated with this controller.
@@ -130,10 +129,12 @@ class WebStateImpl;
// Return an image to use as replacement of a missing snapshot.
+ (UIImage*)defaultSnapshotImage;
-// Adds |interstitialView| to the content view, copying the current scroll
-// offsets to |scrollView|.
-- (void)displayInterstitialView:(UIView*)interstitialView
- withScrollView:(UIScrollView*)scrollView;
+// Replaces the currently displayed content with |contentView|. The content
+// view will be dismissed for the next navigation.
+- (void)showTransientContentView:(CRWContentView*)contentView;
+
+// Clear the transient content view, if one is shown.
+- (void)clearTransientContentView;
// Give the unload listeners a chance to fire. Returns YES if they complete
// and the CRWWebController is in a state it may be closed.
@@ -314,9 +315,10 @@ class WebStateImpl;
@interface CRWWebController (UsedOnlyForTesting) // Testing or internal API.
-// Injects a web view for testing. Takes ownership of the |webView|.
-- (void)injectWebView:(id)webView;
-- (void)resetInjectedWebView;
+// Injects a CRWWebViewContentView for testing. Takes ownership of
+// |webViewContentView|.
+- (void)injectWebViewContentView:(CRWWebViewContentView*)webViewContentView;
+- (void)resetInjectedWebViewContentView;
// Returns the number of observers registered for this CRWWebController.
- (NSUInteger)observerCount;
- (NSString*)windowId;
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 1b630ee..73aa287 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -53,8 +53,10 @@
#import "ios/web/public/web_state/crw_web_view_scroll_view_proxy.h"
#import "ios/web/public/web_state/js/crw_js_injection_manager.h"
#import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
+#import "ios/web/public/web_state/ui/crw_content_view.h"
#import "ios/web/public/web_state/ui/crw_native_content.h"
#import "ios/web/public/web_state/ui/crw_native_content_provider.h"
+#import "ios/web/public/web_state/ui/crw_web_view_content_view.h"
#include "ios/web/public/web_state/url_verification_constants.h"
#include "ios/web/public/web_state/web_state.h"
#include "ios/web/web_state/blocked_popup_info.h"
@@ -259,16 +261,26 @@ void CancelAllTouches(UIScrollView* web_scroll_view) {
base::scoped_nsobject<CRWJSInjectionReceiver> _jsInjectionReceiver;
}
+// The container view. The container view should be accessed through this
+// property rather than |self.view| from within this class, as |self.view|
+// triggers creation while |self.containerView| will return nil if the view
+// hasn't been instantiated.
+@property(nonatomic, retain, readonly)
+ CRWWebControllerContainerView* containerView;
// The current page state of the web view. Writing to this property
// asynchronously applies the passed value to the current web view.
@property(nonatomic, readwrite) web::PageDisplayState pageDisplayState;
+// The currently displayed native controller, if any.
+@property(nonatomic, readwrite) id<CRWNativeContent> nativeController;
+// Removes the container view from the hierarchy and resets the ivar.
+- (void)resetContainerView;
// Resets any state that is associated with a specific document object (e.g.,
// page interaction tracking).
- (void)resetDocumentSpecificState;
// Returns YES if the URL looks like it is one CRWWebController can show.
+ (BOOL)webControllerCanShow:(const GURL&)url;
-// Clear any interstitials being displayed.
-- (void)clearInterstitials;
+// Clears the currently-displayed transient content view.
+- (void)clearTransientContentView;
// Returns a lazily created CRWTouchTrackingRecognizer.
- (CRWTouchTrackingRecognizer*)touchTrackingRecognizer;
// Shows placeholder overlay.
@@ -503,11 +515,6 @@ enum {
WebKitErrorPlugInLoadFailed = 204,
};
-// Tag for the interstitial view so we can find it and dismiss it later.
-enum {
- kInterstitialViewTag = 1000,
-};
-
// URLs that are fed into UIWebView as history push/replace get escaped,
// potentially changing their format. Code that attempts to determine whether a
// URL hasn't changed can be confused by those differences though, so method
@@ -636,24 +643,24 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
return _webStateImpl.get();
}
-// WebStateImpl will delete the interstitial page object, which will in turn
-// remove its view from |_contentView|.
-- (void)clearInterstitials {
- [_webViewProxy setWebView:self.webView scrollView:self.webScrollView];
+- (void)clearTransientContentView {
+ // Early return if there is no transient content view.
+ if (!self.containerView.transientContentView)
+ return;
+
+ // Remove the transient content view from the hierarchy.
+ [self.containerView clearTransientContentView];
+
+ // Notify the WebState so it can perform any required state cleanup.
if (_webStateImpl)
- _webStateImpl->ClearWebInterstitialForNavigation();
+ _webStateImpl->ClearTransientContentView();
}
-// Attaches |interstitialView| to |_contentView|. Note that this class never
-// explicitly removes the interstitial from |_contentView|;
-// web::WebStateImpl::DismissWebInterstitial() takes care of that.
-- (void)displayInterstitialView:(UIView*)interstitialView
- withScrollView:(UIScrollView*)scrollView {
- DCHECK(interstitialView);
- DCHECK(scrollView);
- [_webViewProxy setWebView:interstitialView scrollView:scrollView];
- interstitialView.tag = kInterstitialViewTag;
- [_containerView addSubview:interstitialView];
+- (void)showTransientContentView:(CRWContentView*)contentView {
+ DCHECK(contentView);
+ DCHECK(contentView.scrollView);
+ DCHECK([contentView.scrollView isDescendantOfView:contentView]);
+ [self.containerView displayTransientContent:contentView];
}
- (id<CRWWebDelegate>)delegate {
@@ -662,11 +669,11 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
- (void)setDelegate:(id<CRWWebDelegate>)delegate {
_delegate.reset(delegate);
- if ([_nativeController respondsToSelector:@selector(setDelegate:)]) {
+ if ([self.nativeController respondsToSelector:@selector(setDelegate:)]) {
if ([_delegate respondsToSelector:@selector(webController:titleDidChange:)])
- [_nativeController setDelegate:self];
+ [self.nativeController setDelegate:self];
else
- [_nativeController setDelegate:nil];
+ [self.nativeController setDelegate:nil];
}
}
@@ -694,10 +701,8 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
[self abortLoad];
[self.webView removeFromSuperview];
- [_webViewProxy setWebView:nil scrollView:nil];
+ [self.containerView resetContent];
[self resetWebView];
- // Remove the web toolbars.
- [_containerView removeAllToolbars];
}
- (void)dealloc {
@@ -718,24 +723,24 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
- (void)dismissKeyboard {
[self.webView endEditing:YES];
- if ([_nativeController respondsToSelector:@selector(dismissKeyboard)])
- [_nativeController dismissKeyboard];
+ if ([self.nativeController respondsToSelector:@selector(dismissKeyboard)])
+ [self.nativeController dismissKeyboard];
}
- (id<CRWNativeContent>)nativeController {
- return _nativeController.get();
+ return self.containerView.nativeController;
}
- (void)setNativeController:(id<CRWNativeContent>)nativeController {
// Check for pointer equality.
- if (_nativeController.get() == nativeController)
+ if (self.nativeController == nativeController)
return;
// Unset the delegate on the previous instance.
- if ([_nativeController respondsToSelector:@selector(setDelegate:)])
- [_nativeController setDelegate:nil];
+ if ([self.nativeController respondsToSelector:@selector(setDelegate:)])
+ [self.nativeController setDelegate:nil];
- _nativeController.reset([nativeController retain]);
+ [self.containerView displayNativeContent:nativeController];
[self setNativeControllerWebUsageEnabled:_webUsageEnabled];
}
@@ -746,8 +751,9 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
}
- (void)setNativeControllerWebUsageEnabled:(BOOL)webUsageEnabled {
- if ([_nativeController respondsToSelector:@selector(setWebUsageEnabled:)]) {
- [_nativeController setWebUsageEnabled:webUsageEnabled];
+ if ([self.nativeController
+ respondsToSelector:@selector(setWebUsageEnabled:)]) {
+ [self.nativeController setWebUsageEnabled:webUsageEnabled];
}
}
@@ -764,11 +770,11 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
if (enabled) {
// Don't create the web view; let it be lazy created as needed.
} else {
- [self clearInterstitials];
+ [self clearTransientContentView];
[self removeWebViewAllowingCachedReconstruction:YES];
_touchTrackingRecognizer.get().touchTrackingDelegate = nil;
_touchTrackingRecognizer.reset();
- _containerView.reset();
+ [self resetContainerView];
}
}
}
@@ -777,12 +783,16 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
[self removeWebViewAllowingCachedReconstruction:NO];
}
+- (void)resetContainerView {
+ [self.containerView removeFromSuperview];
+ _containerView.reset();
+}
+
- (void)handleLowMemory {
[self removeWebViewAllowingCachedReconstruction:YES];
- [self setNativeController:nil];
_touchTrackingRecognizer.get().touchTrackingDelegate = nil;
_touchTrackingRecognizer.reset();
- _containerView.reset();
+ [self resetContainerView];
_usePlaceholderOverlay = YES;
}
@@ -796,7 +806,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
_usePlaceholderOverlay = YES;
_touchTrackingRecognizer.get().touchTrackingDelegate = nil;
_touchTrackingRecognizer.reset();
- _containerView.reset();
+ [self resetContainerView];
}
}
}
@@ -806,7 +816,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
}
- (BOOL)isViewAlive {
- return self.webView || [_nativeController isViewAlive];
+ return [self.containerView isViewAlive];
}
- (BOOL)contentIsHTML {
@@ -826,16 +836,16 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
}
- (void)dismissModals {
- if ([_nativeController respondsToSelector:@selector(dismissModals)])
- [_nativeController dismissModals];
+ if ([self.nativeController respondsToSelector:@selector(dismissModals)])
+ [self.nativeController dismissModals];
}
// Caller must reset the delegate before calling.
- (void)close {
self.nativeProvider = nil;
self.swipeRecognizerProvider = nil;
- if ([_nativeController respondsToSelector:@selector(close)])
- [_nativeController close];
+ if ([self.nativeController respondsToSelector:@selector(close)])
+ [self.nativeController close];
base::scoped_nsobject<NSSet> observers([_observers copy]);
for (id it in observers.get()) {
@@ -979,8 +989,8 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
}
// Any non-web URL source is trusted.
*trustLevel = web::URLVerificationTrustLevel::kAbsolute;
- if (_nativeController)
- return [_nativeController url];
+ if (self.nativeController)
+ return [self.nativeController url];
return [self currentNavigationURL];
}
@@ -1159,18 +1169,15 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
[webView addGestureRecognizer:recognizer];
}
- webView.frame = [_containerView bounds];
-
_URLOnStartLoading = _defaultURL;
- // Do final view setup.
- CGPoint initialOffset = CGPointMake(0, 0 - [self headerHeight]);
- [self.webScrollView setContentOffset:initialOffset];
- [_containerView addToolbars:_webViewToolbars];
-
- [_webViewProxy setWebView:self.webView scrollView:self.webScrollView];
+ // Add the web toolbars.
+ [self.containerView addToolbars:_webViewToolbars];
- [_containerView addSubview:webView];
+ base::scoped_nsobject<CRWWebViewContentView> webViewContentView(
+ [[CRWWebViewContentView alloc] initWithWebView:self.webView
+ scrollView:self.webScrollView]);
+ [self.containerView displayWebViewContentView:webViewContentView];
}
- (CRWWebController*)createChildWebControllerWithReferrerURL:
@@ -1184,14 +1191,18 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
}
- (BOOL)canUseViewForGeneratingOverlayPlaceholderView {
- return _containerView != nil;
+ return self.containerView != nil;
}
- (UIView*)view {
// Kick off the process of lazily creating the view and starting the load if
- // necessary; this creates _contentView if it doesn't exist.
+ // necessary; this creates _containerView if it doesn't exist.
[self triggerPendingLoad];
- DCHECK(_containerView);
+ DCHECK(self.containerView);
+ return self.containerView;
+}
+
+- (CRWWebControllerContainerView*)containerView {
return _containerView.get();
}
@@ -1308,9 +1319,6 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
// See crbug.com/228397.
[self registerUserAgent];
- // Freeing the native controller removes its view from the view hierarchy.
- [self setNativeController:nil];
-
// Clear the set of URLs opened in external applications.
_openedApplicationURL.reset([[NSMutableSet alloc] init]);
@@ -1325,7 +1333,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
DCHECK(!targetURL.SchemeIs(url::kJavaScriptScheme));
[self ensureWebViewCreated];
- DCHECK(self.webView && !_nativeController);
+ DCHECK(self.webView && !self.nativeController);
NSMutableURLRequest* request =
[NSMutableURLRequest requestWithURL:net::NSURLWithGURL(targetURL)];
const web::Referrer referrer([self currentSessionEntryReferrer]);
@@ -1393,9 +1401,6 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
}
- (void)loadNativeViewWithSuccess:(BOOL)loadSuccess {
- [_nativeController view].frame = [self visibleFrame];
- [_containerView addSubview:[_nativeController view]];
- [[_nativeController view] setNeedsUpdateConstraints];
const GURL currentURL([self currentURL]);
[self didStartLoadingURL:currentURL updateHistory:loadSuccess];
_loadPhase = web::PAGE_LOADED;
@@ -1405,14 +1410,14 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
// Inform the embedder the title changed.
if ([_delegate respondsToSelector:@selector(webController:titleDidChange:)]) {
- NSString* title = [_nativeController title];
+ NSString* title = [self.nativeController title];
// If a title is present, notify the delegate.
if (title)
[_delegate webController:self titleDidChange:title];
// If the controller handles title change notification, route those to the
// delegate.
- if ([_nativeController respondsToSelector:@selector(setDelegate:)]) {
- [_nativeController setDelegate:self];
+ if ([self.nativeController respondsToSelector:@selector(setDelegate:)]) {
+ [self.nativeController setDelegate:self];
}
}
}
@@ -1518,7 +1523,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
- (void)loadCurrentURL {
// If the content view doesn't exist, the tab has either been evicted, or
// never displayed. Bail, and let the URL be loaded when the tab is shown.
- if (!_containerView)
+ if (!self.containerView)
return;
// Reset current WebUI if one exists.
@@ -1535,8 +1540,8 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
[self abortLoad];
DCHECK(!_isHalted);
- // Remove the interstitial before doing anything else.
- [self clearInterstitials];
+ // Remove the transient content view.
+ [self clearTransientContentView];
const GURL currentURL = [self currentNavigationURL];
// If it's a chrome URL, but not a native one, create the WebUI instance.
@@ -1566,16 +1571,17 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
}
- (void)triggerPendingLoad {
- if (!_containerView) {
+ if (!self.containerView) {
DCHECK(!_isBeingDestroyed);
// Create the top-level parent view, which will contain the content (whether
// native or web). Note, this needs to be created with a non-zero size
// to allow for (native) subviews with autosize constraints to be correctly
// processed.
_containerView.reset([[CRWWebControllerContainerView alloc]
- initWithFrame:[[UIScreen mainScreen] bounds]]);
- [_containerView addGestureRecognizer:[self touchTrackingRecognizer]];
- [_containerView setAccessibilityIdentifier:web::kContainerViewID];
+ initWithContentViewProxy:_webViewProxy]);
+ self.containerView.frame = [[UIScreen mainScreen] bounds];
+ [self.containerView addGestureRecognizer:[self touchTrackingRecognizer]];
+ [self.containerView setAccessibilityIdentifier:web::kContainerViewID];
// Is |currentUrl| a web scheme or native chrome scheme.
BOOL isChromeScheme =
web::GetWebClient()->IsAppSpecificURL([self currentNavigationURL]);
@@ -1622,7 +1628,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
// This ensures state processing and delegate calls are consistent.
[self loadCurrentURL];
} else {
- [_nativeController reload];
+ [self.nativeController reload];
}
}
@@ -1885,7 +1891,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
return;
[_webViewToolbars addObject:toolbarView];
if (self.webView)
- [_containerView addToolbar:toolbarView];
+ [self.containerView addToolbar:toolbarView];
}
- (void)removeToolbarViewFromWebView:(UIView*)toolbarView {
@@ -1893,7 +1899,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
return;
[_webViewToolbars removeObject:toolbarView];
if (self.webView)
- [_containerView removeToolbar:toolbarView];
+ [self.containerView removeToolbar:toolbarView];
}
- (CRWJSInjectionReceiver*)jsInjectionReceiver {
@@ -2567,18 +2573,17 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
#pragma mark -
- (BOOL)wantsKeyboardShield {
- if (_nativeController &&
- [_nativeController respondsToSelector:@selector(wantsKeyboardShield)]) {
- return [_nativeController wantsKeyboardShield];
+ if ([self.nativeController
+ respondsToSelector:@selector(wantsKeyboardShield)]) {
+ return [self.nativeController wantsKeyboardShield];
}
return YES;
}
- (BOOL)wantsLocationBarHintText {
- if (_nativeController &&
- [_nativeController
+ if ([self.nativeController
respondsToSelector:@selector(wantsLocationBarHintText)]) {
- return [_nativeController wantsLocationBarHintText];
+ return [self.nativeController wantsLocationBarHintText];
}
return YES;
}
@@ -2632,18 +2637,16 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
}
- (void)wasShown {
- if (_nativeController &&
- [_nativeController respondsToSelector:@selector(wasShown)]) {
- [_nativeController wasShown];
+ if ([self.nativeController respondsToSelector:@selector(wasShown)]) {
+ [self.nativeController wasShown];
}
}
- (void)wasHidden {
if (_isHalted)
return;
- if (_nativeController &&
- [_nativeController respondsToSelector:@selector(wasHidden)]) {
- [_nativeController wasHidden];
+ if ([self.nativeController respondsToSelector:@selector(wasHidden)]) {
+ [self.nativeController wasHidden];
}
}
@@ -3183,7 +3186,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
setAutoresizingMask:UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight];
[_placeholderOverlayView setContentMode:UIViewContentModeScaleAspectFill];
- [_containerView addSubview:_placeholderOverlayView];
+ [self.containerView addSubview:_placeholderOverlayView];
id callback = ^(UIImage* image) {
[_placeholderOverlayView setImage:image];
@@ -3223,7 +3226,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
// If we were showing the preview, remove it.
if (!_overlayPreviewMode && _placeholderOverlayView) {
- _containerView.reset();
+ [self resetContainerView];
// Reset |_placeholderOverlayView| directly instead of calling
// -removePlaceholderOverlay, which removes |_placeholderOverlayView| in an
// animation.
@@ -3601,7 +3604,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
#pragma mark Fullscreen
- (CGRect)visibleFrame {
- CGRect frame = [_containerView bounds];
+ CGRect frame = self.containerView.bounds;
CGFloat headerHeight = [self headerHeight];
frame.origin.y = headerHeight;
frame.size.height -= headerHeight;
@@ -3725,8 +3728,8 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
}
- (void)loadHTML:(NSString*)html forURL:(const GURL&)url {
- // Remove the interstitial before doing anything else.
- [self clearInterstitials];
+ // Remove the transient content view.
+ [self clearTransientContentView];
DLOG_IF(WARNING, !self.webView)
<< "self.webView null while trying to load HTML";
@@ -3747,7 +3750,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
[self abortLoad];
// If discarding the non-committed entries results in an app-specific URL,
// reload it in its native view.
- if (!_nativeController &&
+ if (!self.nativeController &&
[self shouldLoadURLInNativeView:[self currentNavigationURL]]) {
[self loadCurrentURLInNativeView];
}
@@ -3762,17 +3765,16 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
#pragma mark -
#pragma mark Testing-Only Methods
-- (void)injectWebView:(id)webView {
+- (void)injectWebViewContentView:(id)webViewContentView {
[self removeWebViewAllowingCachedReconstruction:NO];
_lastRegisteredRequestURL = _defaultURL;
- CHECK([webView respondsToSelector:@selector(scrollView)]);
- [_webViewProxy setWebView:webView
- scrollView:[static_cast<id>(webView) scrollView]];
+ [self.containerView displayWebViewContentView:webViewContentView];
}
-- (void)resetInjectedWebView {
+- (void)resetInjectedWebViewContentView {
[self resetWebView];
+ [self resetContainerView];
}
- (void)addObserver:(id<CRWWebControllerObserver>)observer {
diff --git a/ios/web/web_state/ui/crw_web_controller_container_view.h b/ios/web/web_state/ui/crw_web_controller_container_view.h
index 7eb61f1..bac9967 100644
--- a/ios/web/web_state/ui/crw_web_controller_container_view.h
+++ b/ios/web/web_state/ui/crw_web_controller_container_view.h
@@ -7,10 +7,55 @@
#import <UIKit/UIKit.h>
+#include "ios/web/public/web_state/ui/crw_content_view.h"
+
+@class CRWWebViewContentView;
+@class CRWWebViewProxyImpl;
+@protocol CRWNativeContent;
+
// Container view class that manages the display of content within
// CRWWebController.
@interface CRWWebControllerContainerView : UIView
+#pragma mark Content Views
+// The web view content view being displayed.
+@property(nonatomic, retain, readonly)
+ CRWWebViewContentView* webViewContentView;
+// The native controller whose content is being displayed.
+@property(nonatomic, retain, readonly) id<CRWNativeContent> nativeController;
+// The currently displayed transient content view.
+@property(nonatomic, retain, readonly) CRWContentView* transientContentView;
+
+// Designated initializer. |proxy|'s content view will be updated as different
+// content is added to the container.
+- (instancetype)initWithContentViewProxy:(CRWWebViewProxyImpl*)proxy
+ NS_DESIGNATED_INITIALIZER;
+
+// CRWWebControllerContainerView should be initialized via
+// |-initWithContentViewProxy:|.
+- (instancetype)init NS_UNAVAILABLE;
+- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
+
+// Returns YES if the container view is currently displaying content.
+- (BOOL)isViewAlive;
+
+// Removes all subviews and resets state to default.
+- (void)resetContent;
+
+// Replaces the currently displayed content with |webViewContentView|.
+- (void)displayWebViewContentView:(CRWWebViewContentView*)webViewContentView;
+
+// Replaces the currently displayed content with |nativeController|'s view.
+- (void)displayNativeContent:(id<CRWNativeContent>)nativeController;
+
+// Adds |transientContentView| as a subview above previously displayed content.
+- (void)displayTransientContent:(CRWContentView*)transientContentView;
+
+// Removes the transient content view, if one is displayed.
+- (void)clearTransientContentView;
+
+#pragma mark Toolbars
+
// |toolbar| will be resized to the container width, bottom-aligned, and added
// as the topmost subview.
- (void)addToolbar:(UIView*)toolbar;
diff --git a/ios/web/web_state/ui/crw_web_controller_container_view.mm b/ios/web/web_state/ui/crw_web_controller_container_view.mm
index e54e303..f7c4849 100644
--- a/ios/web/web_state/ui/crw_web_controller_container_view.mm
+++ b/ios/web/web_state/ui/crw_web_controller_container_view.mm
@@ -4,8 +4,13 @@
#import "ios/web/web_state/ui/crw_web_controller_container_view.h"
+#include "base/ios/weak_nsobject.h"
#include "base/logging.h"
#include "base/mac/scoped_nsobject.h"
+#import "ios/web/public/web_state/ui/crw_content_view.h"
+#import "ios/web/public/web_state/ui/crw_native_content.h"
+#import "ios/web/public/web_state/ui/crw_web_view_content_view.h"
+#import "ios/web/web_state/crw_web_view_proxy_impl.h"
#pragma mark - CRWToolbarContainerView
@@ -84,10 +89,22 @@
#pragma mark - CRWWebControllerContainerView
@interface CRWWebControllerContainerView () {
- // Backing object for |self.toolbarContainerView|.
+ // The proxy for the content added to the container. It is owned by the web
+ // controller.
+ base::WeakNSObject<CRWWebViewProxyImpl> _webViewProxy;
+ // Backing objects for corresponding properties.
+ base::scoped_nsobject<CRWWebViewContentView> _webViewContentView;
+ base::scoped_nsprotocol<id<CRWNativeContent>> _nativeController;
+ base::scoped_nsobject<CRWContentView> _transientContentView;
base::scoped_nsobject<CRWToolbarContainerView> _toolbarContainerView;
}
+// Redefine properties as readwrite.
+@property(nonatomic, retain, readwrite)
+ CRWWebViewContentView* webViewContentView;
+@property(nonatomic, retain, readwrite) id<CRWNativeContent> nativeController;
+@property(nonatomic, retain, readwrite) CRWContentView* transientContentView;
+
// Container view that displays any added toolbars. It is always the top-most
// subview, and is bottom aligned with the CRWWebControllerContainerView.
@property(nonatomic, retain, readonly)
@@ -97,9 +114,11 @@
@implementation CRWWebControllerContainerView
-- (instancetype)initWithFrame:(CGRect)frame {
- self = [super initWithFrame:frame];
+- (instancetype)initWithContentViewProxy:(CRWWebViewProxyImpl*)proxy {
+ self = [super initWithFrame:CGRectZero];
if (self) {
+ DCHECK(proxy);
+ _webViewProxy.reset(proxy);
self.backgroundColor = [UIColor whiteColor];
self.autoresizingMask =
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
@@ -107,13 +126,57 @@
return self;
}
-- (instancetype)init {
- NOTREACHED();
- return nil;
+- (void)dealloc {
+ [_webViewProxy setContentView:nil];
+ [super dealloc];
}
#pragma mark Accessors
+- (CRWWebViewContentView*)webViewContentView {
+ return _webViewContentView.get();
+}
+
+- (void)setWebViewContentView:(CRWWebViewContentView*)webViewContentView {
+ if (![_webViewContentView isEqual:webViewContentView]) {
+ [_webViewContentView removeFromSuperview];
+ _webViewContentView.reset([webViewContentView retain]);
+ [self addSubview:_webViewContentView];
+ }
+}
+
+- (id<CRWNativeContent>)nativeController {
+ return _nativeController.get();
+}
+
+- (void)setNativeController:(id<CRWNativeContent>)nativeController {
+ if (![_nativeController isEqual:nativeController]) {
+ // TODO(kkhorimoto): This line isn't strictly necessary since all native
+ // controllers currently inherit from NativeContentController, which removes
+ // its view upon deallocation. Consider moving NativeContentController into
+ // web/ so this behavior can be depended upon from within web/ without
+ // making assumptions about chrome/ code.
+ base::WeakNSProtocol<id> oldController(_nativeController);
+ [[_nativeController view] removeFromSuperview];
+ _nativeController.reset([nativeController retain]);
+ [self addSubview:[_nativeController view]];
+ [[_nativeController view] setNeedsUpdateConstraints];
+ DCHECK(!oldController);
+ }
+}
+
+- (CRWContentView*)transientContentView {
+ return _transientContentView.get();
+}
+
+- (void)setTransientContentView:(CRWContentView*)transientContentView {
+ if (![_transientContentView isEqual:transientContentView]) {
+ [_transientContentView removeFromSuperview];
+ _transientContentView.reset([transientContentView retain]);
+ [self addSubview:_transientContentView];
+ }
+}
+
- (void)setToolbarContainerView:(CRWToolbarContainerView*)toolbarContainerView {
if (![_toolbarContainerView isEqual:toolbarContainerView]) {
[_toolbarContainerView removeFromSuperview];
@@ -131,6 +194,12 @@
- (void)layoutSubviews {
[super layoutSubviews];
+ // Resize displayed content to the container's bounds.
+ self.webViewContentView.frame = self.bounds;
+ [self.nativeController view].frame = self.bounds;
+ self.transientContentView.frame = self.bounds;
+
+ // Bottom align the toolbars with the bottom of the container.
if (self.toolbarContainerView) {
[self bringSubviewToFront:self.toolbarContainerView];
CGSize toolbarContainerSize =
@@ -142,6 +211,51 @@
}
}
+- (BOOL)isViewAlive {
+ return self.webViewContentView || self.transientContentView ||
+ [self.nativeController isViewAlive];
+}
+
+#pragma mark Content Setters
+
+- (void)resetContent {
+ self.webViewContentView = nil;
+ self.nativeController = nil;
+ self.transientContentView = nil;
+ [self removeAllToolbars];
+ [_webViewProxy setContentView:nil];
+}
+
+- (void)displayWebViewContentView:(CRWWebViewContentView*)webViewContentView {
+ DCHECK(webViewContentView);
+ self.webViewContentView = webViewContentView;
+ self.nativeController = nil;
+ self.transientContentView = nil;
+ [_webViewProxy setContentView:self.webViewContentView];
+ [self setNeedsLayout];
+}
+
+- (void)displayNativeContent:(id<CRWNativeContent>)nativeController {
+ DCHECK(nativeController);
+ self.webViewContentView = nil;
+ self.nativeController = nativeController;
+ self.transientContentView = nil;
+ [_webViewProxy setContentView:nil];
+ [self setNeedsLayout];
+}
+
+- (void)displayTransientContent:(CRWContentView*)transientContentView {
+ DCHECK(transientContentView);
+ self.transientContentView = transientContentView;
+ [_webViewProxy setContentView:self.transientContentView];
+ [self setNeedsLayout];
+}
+
+- (void)clearTransientContentView {
+ self.transientContentView = nil;
+ [_webViewProxy setContentView:self.webViewContentView];
+}
+
#pragma mark Toolbars
- (void)addToolbar:(UIView*)toolbar {
diff --git a/ios/web/web_state/ui/crw_web_controller_container_view_unittest.mm b/ios/web/web_state/ui/crw_web_controller_container_view_unittest.mm
index 69f49c3..6afb6b16 100644
--- a/ios/web/web_state/ui/crw_web_controller_container_view_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_container_view_unittest.mm
@@ -3,10 +3,13 @@
// found in the LICENSE file.
#import "base/mac/scoped_nsobject.h"
+#import "ios/web/web_state/crw_web_view_proxy_impl.h"
#import "ios/web/web_state/ui/crw_web_controller_container_view.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gtest_mac.h"
#include "testing/platform_test.h"
+#include "third_party/ocmock/gtest_support.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
namespace {
// The frame of CRWWebControllerContainerViewTest's |container_view_|.
@@ -31,10 +34,15 @@ class CRWWebControllerContainerViewTest : public PlatformTest {
protected:
void SetUp() override {
PlatformTest::SetUp();
+ mock_web_view_proxy_.reset(
+ [[OCMockObject niceMockForClass:[CRWWebViewProxyImpl class]] retain]);
container_view_.reset([[CRWWebControllerContainerView alloc]
- initWithFrame:kContainerViewFrame]);
+ initWithContentViewProxy:mock_web_view_proxy_]);
+ [container_view_ setFrame:kContainerViewFrame];
}
+ // The web view proxy object (required for designated initializer).
+ base::scoped_nsobject<id> mock_web_view_proxy_;
// The container view being tested.
base::scoped_nsobject<CRWWebControllerContainerView> container_view_;
};
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index b7b97cf..4e7a4ed 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -18,8 +18,11 @@
#include "ios/web/navigation/navigation_item_impl.h"
#import "ios/web/navigation/navigation_manager_impl.h"
#include "ios/web/public/referrer.h"
+#include "ios/web/public/test/test_web_view_content_view.h"
#include "ios/web/public/test/web_test_util.h"
#import "ios/web/public/web_state/crw_web_controller_observer.h"
+#import "ios/web/public/web_state/ui/crw_content_view.h"
+#import "ios/web/public/web_state/ui/crw_web_view_content_view.h"
#include "ios/web/public/web_state/url_verification_constants.h"
#include "ios/web/test/web_test.h"
#import "ios/web/test/wk_web_view_crash_utils.h"
@@ -27,6 +30,7 @@
#import "ios/web/web_state/js/crw_js_invoke_parameter_queue.h"
#import "ios/web/web_state/ui/crw_ui_web_view_web_controller.h"
#import "ios/web/web_state/ui/crw_web_controller+protected.h"
+#import "ios/web/web_state/ui/crw_web_controller_container_view.h"
#import "ios/web/web_state/web_state_impl.h"
#import "net/base/mac/url_conversions.h"
#include "net/ssl/ssl_info.h"
@@ -46,6 +50,7 @@ using web::NavigationManagerImpl;
@interface CRWWebController (PrivateAPI)
@property(nonatomic, readwrite) web::PageDisplayState pageDisplayState;
+@property(nonatomic, readonly) CRWWebControllerContainerView* containerView;
- (void)setJsMessageQueueThrottled:(BOOL)throttle;
- (void)removeDocumentLoadCommandsFromQueue;
- (GURL)updateURLForHistoryNavigationFromURL:(const GURL&)startURL
@@ -293,7 +298,10 @@ class WebControllerTest : public WebTestT {
mockDelegate_.reset([[MockInteractionLoader alloc]
initWithRepresentedObject:originalMockDelegate]);
[WebTestT::webController_ setDelegate:mockDelegate_];
- [WebTestT::webController_ injectWebView:(UIView*)mockWebView_];
+ base::scoped_nsobject<TestWebViewContentView> webViewContentView(
+ [[TestWebViewContentView alloc] initWithMockWebView:mockWebView_
+ scrollView:mockScrollView_]);
+ [WebTestT::webController_ injectWebViewContentView:webViewContentView];
NavigationManagerImpl& navigationManager =
[WebTestT::webController_ webStateImpl]->GetNavigationManagerImpl();
@@ -315,7 +323,7 @@ class WebControllerTest : public WebTestT {
EXPECT_OCMOCK_VERIFY(mockDelegate_);
EXPECT_OCMOCK_VERIFY(mockChildWebController_.get());
EXPECT_OCMOCK_VERIFY(mockWebView_);
- [WebTestT::webController_ resetInjectedWebView];
+ [WebTestT::webController_ resetInjectedWebViewContentView];
[WebTestT::webController_ setDelegate:nil];
WebTestT::TearDown();
}
@@ -1224,8 +1232,8 @@ TEST_F(WebControllerKeyboardTest, DismissKeyboard) {
@"</body></html>");
// Get the webview.
- UIWebView* webView =
- (UIWebView*)[[[webController_ view] subviews] objectAtIndex:0];
+ UIWebView* webView = static_cast<UIWebView*>(
+ [webController_ containerView].webViewContentView.webView);
EXPECT_TRUE(webView);
// Create the window and add the webview.
@@ -1473,7 +1481,11 @@ class CRWWKWebControllerWebProcessTest : public web::WKWebViewWebTest {
CR_TEST_REQUIRES_WK_WEB_VIEW();
WKWebViewWebTest::SetUp();
webView_.reset(web::CreateTerminatedWKWebView());
- [webController_ injectWebView:webView_];
+ base::scoped_nsobject<TestWebViewContentView> webViewContentView(
+ [[TestWebViewContentView alloc]
+ initWithMockWebView:webView_
+ scrollView:[webView_ scrollView]]);
+ [webController_ injectWebViewContentView:webViewContentView];
}
base::scoped_nsobject<WKWebView> webView_;
};
diff --git a/ios/web/web_state/ui/crw_web_view_content_view.mm b/ios/web/web_state/ui/crw_web_view_content_view.mm
new file mode 100644
index 0000000..e3c085e
--- /dev/null
+++ b/ios/web/web_state/ui/crw_web_view_content_view.mm
@@ -0,0 +1,56 @@
+// Copyright 2015 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/web/public/web_state/ui/crw_web_view_content_view.h"
+
+#include "base/logging.h"
+#include "base/mac/scoped_nsobject.h"
+
+@interface CRWWebViewContentView () {
+ // The web view being shown.
+ base::scoped_nsobject<UIView> _webView;
+ // The web view's scroll view.
+ base::scoped_nsobject<UIScrollView> _scrollView;
+}
+
+@end
+
+@implementation CRWWebViewContentView
+
+- (instancetype)initWithWebView:(UIView*)webView
+ scrollView:(UIScrollView*)scrollView {
+ self = [super initWithFrame:CGRectZero];
+ if (self) {
+ DCHECK(webView);
+ DCHECK(scrollView);
+ DCHECK([scrollView isDescendantOfView:webView]);
+ _webView.reset([webView retain]);
+ _scrollView.reset([scrollView retain]);
+ [self addSubview:_webView];
+ }
+ return self;
+}
+
+#pragma mark Accessors
+
+- (UIScrollView*)scrollView {
+ return _scrollView.get();
+}
+
+- (UIView*)webView {
+ return _webView.get();
+}
+
+#pragma mark Layout
+
+- (void)layoutSubviews {
+ [super layoutSubviews];
+ self.webView.frame = self.bounds;
+}
+
+- (BOOL)isViewAlive {
+ return YES;
+}
+
+@end
diff --git a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
index 87b2713..c77f15b 100644
--- a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
+++ b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
@@ -19,6 +19,7 @@
#include "ios/web/public/web_client.h"
#import "ios/web/public/web_state/js/crw_js_injection_manager.h"
#import "ios/web/public/web_state/ui/crw_native_content_provider.h"
+#import "ios/web/public/web_state/ui/crw_web_view_content_view.h"
#import "ios/web/ui_web_view_util.h"
#include "ios/web/web_state/blocked_popup_info.h"
#include "ios/web/web_state/frame_info.h"
@@ -268,9 +269,9 @@ NSString* const kScriptImmediateName = @"crwebinvokeimmediate";
#pragma mark -
#pragma mark Testing-Only Methods
-- (void)injectWebView:(id)webView {
- [super injectWebView:webView];
- [self setWebView:webView];
+- (void)injectWebViewContentView:(CRWWebViewContentView*)webViewContentView {
+ [super injectWebViewContentView:webViewContentView];
+ [self setWebView:static_cast<WKWebView*>(webViewContentView.webView)];
}
#pragma mark - Protected property implementations
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h
index ba236ce..d5386b2 100644
--- a/ios/web/web_state/web_state_impl.h
+++ b/ios/web/web_state/web_state_impl.h
@@ -222,6 +222,7 @@ class WebStateImpl : public WebState, public NavigationManagerDelegate {
const GURL& GetVisibleURL() const override;
const GURL& GetLastCommittedURL() const override;
GURL GetCurrentURL(URLVerificationTrustLevel* trust_level) const override;
+ void ShowTransientContentView(CRWContentView* content_view) override;
bool IsShowingWebInterstitial() const override;
WebInterstitial* GetWebInterstitial() const override;
void AddScriptCommandCallback(const ScriptCommandCallback& callback,
@@ -234,15 +235,11 @@ class WebStateImpl : public WebState, public NavigationManagerDelegate {
bool bypass_cache,
const ImageDownloadCallback& callback) override;
- // Called before navigation events to clear the currently-displayed
- // WebInterstitials.
- void ClearWebInterstitialForNavigation();
-
// Adds |interstitial|'s view to the web controller's content view.
- void DisplayWebInterstitial(WebInterstitialImpl* interstitial);
+ void ShowWebInterstitial(WebInterstitialImpl* interstitial);
- // Called to dismiss the currently-displayed WebInterstitial.
- void DismissWebInterstitial();
+ // Called to dismiss the currently-displayed transient content view.
+ void ClearTransientContentView();
// NavigationManagerDelegate:
void NavigateToPendingEntry() override;
@@ -294,7 +291,7 @@ class WebStateImpl : public WebState, public NavigationManagerDelegate {
std::string mime_type_;
std::string content_language_header_;
- // Weak pointer to the he interstital page being displayed, if any.
+ // Weak pointer to the interstitial page being displayed, if any.
WebInterstitialImpl* interstitial_;
// Returned by reference.
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index 7450809..fd6aa9a 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -15,8 +15,10 @@
#include "ios/web/public/url_util.h"
#include "ios/web/public/web_client.h"
#include "ios/web/public/web_state/credential.h"
+#include "ios/web/public/web_state/ui/crw_content_view.h"
#include "ios/web/public/web_state/web_state_observer.h"
#import "ios/web/web_state/ui/crw_web_controller.h"
+#import "ios/web/web_state/ui/crw_web_controller_container_view.h"
#include "ios/web/web_state/web_state_facade_delegate.h"
#import "ios/web/webui/web_ui_ios_controller_factory_registry.h"
#import "ios/web/webui/web_ui_ios_impl.h"
@@ -265,6 +267,14 @@ const base::string16& WebStateImpl::GetTitle() const {
return empty_string16_;
}
+void WebStateImpl::ShowTransientContentView(CRWContentView* content_view) {
+ DCHECK(Configured());
+ DCHECK(content_view);
+ DCHECK(content_view.scrollView);
+ DCHECK([content_view.scrollView isDescendantOfView:content_view]);
+ [web_controller_ showTransientContentView:content_view];
+}
+
bool WebStateImpl::IsShowingWebInterstitial() const {
// Technically we could have |interstitial_| set but its view isn't
// being displayed, but there's no code path where that could occur.
@@ -320,16 +330,15 @@ void WebStateImpl::UpdateHttpResponseHeaders(const GURL& url) {
content_language_header_ = content_language;
}
-void WebStateImpl::ClearWebInterstitialForNavigation() {
+void WebStateImpl::ShowWebInterstitial(WebInterstitialImpl* interstitial) {
+ DCHECK(Configured());
+ DCHECK(interstitial);
+ interstitial_ = interstitial;
+ ShowTransientContentView(interstitial_->GetContentView());
+}
+
+void WebStateImpl::ClearTransientContentView() {
if (interstitial_) {
- // DontProceed() dismisses the interstitial page in the same way as if it
- // was closed by user action. Clearing interstitial_ early makes
- // IsShowingWebInterstitial() return false so the code that is triggered in
- // DontProceed knows that the interstitial page is not visible anymore.
- WebInterstitialImpl* interstitial = interstitial_;
- DismissWebInterstitial();
- // In this case, DontProceed() may not remove an unsafe page from the nav
- // history.
CRWSessionController* sessionController =
navigation_manager_.GetSessionController();
web::NavigationItem* currentItem =
@@ -342,27 +351,17 @@ void WebStateImpl::ClearWebInterstitialForNavigation() {
[sessionController goBack];
}
[sessionController discardNonCommittedEntries];
+ // Store the currently displayed interstitial in a local variable and reset
+ // |interstitial_| early. This is to prevent an infinite loop, as
+ // |DontProceed()| internally calls |ClearTransientContentView()|.
+ web::WebInterstitial* interstitial = interstitial_;
+ interstitial_ = nullptr;
interstitial->DontProceed();
- }
-}
-
-void WebStateImpl::DisplayWebInterstitial(WebInterstitialImpl* interstitial) {
- DCHECK(Configured());
- DCHECK(interstitial);
- interstitial_ = interstitial;
- CGSize content_view_size = [web_controller_ view].bounds.size;
- interstitial_->SetSize(
- gfx::Size(content_view_size.width, content_view_size.height));
- [web_controller_ displayInterstitialView:interstitial_->GetView()
- withScrollView:interstitial_->GetScrollView()];
-}
-
-void WebStateImpl::DismissWebInterstitial() {
- if (interstitial_) {
+ // Don't access |interstitial| after calling |DontProceed()|, as it triggers
+ // deletion.
FOR_EACH_OBSERVER(WebStateObserver, observers_, InsterstitialDismissed());
- [interstitial_->GetView() removeFromSuperview];
- interstitial_ = nullptr;
}
+ [web_controller_ clearTransientContentView];
}
WebUIIOS* WebStateImpl::CreateWebUIIOS(const GURL& url) {
@@ -454,7 +453,7 @@ BrowserState* WebStateImpl::GetBrowserState() const {
void WebStateImpl::OpenURL(const WebState::OpenURLParams& params) {
DCHECK(Configured());
- ClearWebInterstitialForNavigation();
+ ClearTransientContentView();
[[web_controller_ delegate] openURLWithParams:params];
}