Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ios / web / shell / view_controller.mm
blobc15bf1cdcb415760877763aa8a707433cee44c9e
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "ios/web/shell/view_controller.h"
7 #include "base/mac/objc_property_releaser.h"
8 #import "base/mac/scoped_nsobject.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "ios/net/cookies/cookie_store_ios.h"
12 #import "ios/net/crn_http_protocol_handler.h"
13 #import "ios/net/empty_nsurlcache.h"
14 #import "ios/web/navigation/crw_session_controller.h"
15 #include "ios/web/navigation/web_load_params.h"
16 #import "ios/web/net/crw_url_verifying_protocol_handler.h"
17 #include "ios/web/net/request_tracker_factory_impl.h"
18 #import "ios/web/net/web_http_protocol_handler_delegate.h"
19 #include "ios/web/public/referrer.h"
20 #import "ios/web/public/web_controller_factory.h"
21 #include "ios/web/public/web_state/web_state.h"
22 #include "ios/web/public/web_view_creation_util.h"
23 #include "ios/web/shell/shell_browser_state.h"
24 #include "ios/web/web_state/ui/crw_web_controller.h"
25 #include "ios/web/web_state/web_state_impl.h"
26 #include "ui/base/page_transition_types.h"
28 namespace {
29 // Returns true if WKWebView should be used instead of UIWebView.
30 // TODO(stuartmorgan): Decide on a better way to control this.
31 bool UseWKWebView() {
32 #if defined(FORCE_ENABLE_WKWEBVIEW)
33   return web::IsWKWebViewSupported();
34 #else
35   return false;
36 #endif
40 @interface ViewController () {
41   web::BrowserState* _browserState;
42   base::scoped_nsobject<CRWWebController> _webController;
43   scoped_ptr<web::RequestTrackerFactoryImpl> _requestTrackerFactory;
44   scoped_ptr<web::WebHTTPProtocolHandlerDelegate> _httpProtocolDelegate;
46   base::mac::ObjCPropertyReleaser _propertyReleaser_ViewController;
48 @property(nonatomic, readwrite, retain) UITextField* field;
49 @end
51 @implementation ViewController
53 @synthesize field = _field;
54 @synthesize containerView = _containerView;
55 @synthesize toolbarView = _toolbarView;
57 - (instancetype)initWithBrowserState:(web::BrowserState*)browserState {
58   self = [super initWithNibName:@"MainView" bundle:nil];
59   if (self) {
60     _propertyReleaser_ViewController.Init(self, [ViewController class]);
61     _browserState = browserState;
62   }
63   return self;
66 - (void)dealloc {
67   net::HTTPProtocolHandlerDelegate::SetInstance(nullptr);
68   net::RequestTracker::SetRequestTrackerFactory(nullptr);
69   [super dealloc];
72 - (void)viewDidLoad {
73   [super viewDidLoad];
75   // Set up the toolbar buttons.
76   UIButton* back = [UIButton buttonWithType:UIButtonTypeCustom];
77   [back setImage:[UIImage imageNamed:@"toolbar_back"]
78         forState:UIControlStateNormal];
79   [back setFrame:CGRectMake(0, 0, 44, 44)];
80   [back setImageEdgeInsets:UIEdgeInsetsMake(5, 5, 4, 4)];
81   [back setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin];
82   [back addTarget:self
83                 action:@selector(back)
84       forControlEvents:UIControlEventTouchUpInside];
86   UIButton* forward = [UIButton buttonWithType:UIButtonTypeCustom];
87   [forward setImage:[UIImage imageNamed:@"toolbar_forward"]
88            forState:UIControlStateNormal];
89   [forward setFrame:CGRectMake(44, 0, 44, 44)];
90   [forward setImageEdgeInsets:UIEdgeInsetsMake(5, 5, 4, 4)];
91   [forward setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin];
92   [forward addTarget:self
93                 action:@selector(forward)
94       forControlEvents:UIControlEventTouchUpInside];
96   base::scoped_nsobject<UITextField> field([[UITextField alloc]
97       initWithFrame:CGRectMake(88, 6, CGRectGetWidth([_toolbarView frame]) - 98,
98                                31)]);
99   [field setDelegate:self];
100   [field setBackground:[[UIImage imageNamed:@"textfield_background"]
101                            resizableImageWithCapInsets:UIEdgeInsetsMake(
102                                                            12, 12, 12, 12)]];
103   [field setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
104   [field setKeyboardType:UIKeyboardTypeWebSearch];
105   [field setAutocorrectionType:UITextAutocorrectionTypeNo];
106   [field setClearButtonMode:UITextFieldViewModeWhileEditing];
107   self.field = field;
109   [_toolbarView addSubview:back];
110   [_toolbarView addSubview:forward];
111   [_toolbarView addSubview:field];
113   // Set up the network stack before creating the WebState.
114   [self setUpNetworkStack];
116   scoped_ptr<web::WebStateImpl> webState(new web::WebStateImpl(_browserState));
117   webState->GetNavigationManagerImpl().InitializeSession(nil, nil, NO, 0);
118   web::WebViewType webViewType =
119       UseWKWebView() ? web::WK_WEB_VIEW_TYPE : web::UI_WEB_VIEW_TYPE;
120   _webController.reset(web::CreateWebController(webViewType, webState.Pass()));
121   [_webController setDelegate:self];
122   [_webController setWebUsageEnabled:YES];
124   [[_webController view] setFrame:[_containerView bounds]];
125   [_containerView addSubview:[_webController view]];
127   web::WebLoadParams params(GURL("https://dev.chromium.org/"));
128   params.transition_type = ui::PAGE_TRANSITION_TYPED;
129   [_webController loadWithParams:params];
132 - (void)setUpNetworkStack {
133   // Disable the default cache.
134   [NSURLCache setSharedURLCache:[EmptyNSURLCache emptyNSURLCache]];
136   _httpProtocolDelegate.reset(new web::WebHTTPProtocolHandlerDelegate(
137       _browserState->GetRequestContext()));
138   net::HTTPProtocolHandlerDelegate::SetInstance(_httpProtocolDelegate.get());
139   BOOL success = [NSURLProtocol registerClass:[CRNHTTPProtocolHandler class]];
140   DCHECK(success);
141   // The CRWURLVerifyingProtocolHandler is used to verify URL in the
142   // CRWWebController. It must be registered after the HttpProtocolHandler
143   // because handlers are called in the reverse order of declaration.
144   success =
145       [NSURLProtocol registerClass:[CRWURLVerifyingProtocolHandler class]];
146   DCHECK(success);
147   _requestTrackerFactory.reset(
148       new web::RequestTrackerFactoryImpl(std::string()));
149   net::RequestTracker::SetRequestTrackerFactory(_requestTrackerFactory.get());
150   net::CookieStoreIOS::SetCookiePolicy(net::CookieStoreIOS::ALLOW);
153 - (void)didReceiveMemoryWarning {
154   [super didReceiveMemoryWarning];
157 - (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar {
158   if (bar == _toolbarView) {
159     return UIBarPositionTopAttached;
160   }
161   return UIBarPositionAny;
164 - (void)back {
165   if ([_webController canGoBack]) {
166     [_webController goBack];
167   }
170 - (void)forward {
171   if ([_webController canGoForward]) {
172     [_webController goForward];
173   }
176 - (BOOL)textFieldShouldReturn:(UITextField*)field {
177   GURL url = GURL(base::SysNSStringToUTF8([field text]));
179   // Do not try to load invalid URLs.
180   if (url.is_valid()) {
181     web::WebLoadParams params(url);
182     params.transition_type = ui::PAGE_TRANSITION_TYPED;
183     [_webController loadWithParams:params];
184   }
186   [field resignFirstResponder];
187   [self updateToolbar];
188   return YES;
191 - (void)updateToolbar {
192   // Do not update the URL if the text field is currently being edited.
193   if ([_field isFirstResponder]) {
194     return;
195   }
197   const GURL& url = [_webController webStateImpl]->GetVisibleURL();
198   [_field setText:base::SysUTF8ToNSString(url.spec())];
201 // -----------------------------------------------------------------------
202 #pragma mark Bikeshedding Implementation
204 // Overridden to allow this view controller to receive motion events by being
205 // first responder when no other views are.
206 - (BOOL)canBecomeFirstResponder {
207   return YES;
210 - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent*)event {
211   if (event.subtype == UIEventSubtypeMotionShake) {
212     [self updateToolbarColor];
213   }
216 - (void)updateToolbarColor {
217   // Cycle through the following set of colors:
218   NSArray* colors = @[
219     // Vanilla Blue.
220     [UIColor colorWithRed:0.337 green:0.467 blue:0.988 alpha:1.0],
221     // Vanilla Red.
222     [UIColor colorWithRed:0.898 green:0.110 blue:0.137 alpha:1.0],
223     // Blue Grey.
224     [UIColor colorWithRed:0.376 green:0.490 blue:0.545 alpha:1.0],
225     // Brown.
226     [UIColor colorWithRed:0.475 green:0.333 blue:0.282 alpha:1.0],
227     // Purple.
228     [UIColor colorWithRed:0.612 green:0.153 blue:0.690 alpha:1.0],
229     // Teal.
230     [UIColor colorWithRed:0.000 green:0.737 blue:0.831 alpha:1.0],
231     // Deep Orange.
232     [UIColor colorWithRed:1.000 green:0.341 blue:0.133 alpha:1.0],
233     // Indigo.
234     [UIColor colorWithRed:0.247 green:0.318 blue:0.710 alpha:1.0],
235     // Vanilla Green.
236     [UIColor colorWithRed:0.145 green:0.608 blue:0.141 alpha:1.0],
237     // Pinkerton.
238     [UIColor colorWithRed:0.914 green:0.118 blue:0.388 alpha:1.0],
239   ];
241   NSUInteger currentIndex = [colors indexOfObject:_toolbarView.barTintColor];
242   if (currentIndex == NSNotFound) {
243     currentIndex = 0;
244   }
245   NSUInteger newIndex = currentIndex + 1;
246   if (newIndex >= [colors count]) {
247     // TODO(rohitrao): Out of colors!  Consider prompting the user to pick their
248     // own color here.  Also consider allowing the user to choose the entire set
249     // of colors or allowing the user to choose color randomization.
250     newIndex = 0;
251   }
252   _toolbarView.barTintColor = [colors objectAtIndex:newIndex];
255 // -----------------------------------------------------------------------
256 // WebDelegate implementation.
258 - (void)webWillAddPendingURL:(const GURL&)url
259                   transition:(ui::PageTransition)transition {
261 - (void)webDidAddPendingURL {
262   [self updateToolbar];
264 - (void)webCancelStartLoadingRequest {
266 - (void)webDidStartLoadingURL:(const GURL&)currentUrl
267           shouldUpdateHistory:(BOOL)updateHistory {
268   [self updateToolbar];
270 - (void)webDidFinishWithURL:(const GURL&)url loadSuccess:(BOOL)loadSuccess {
271   [self updateToolbar];
274 - (CRWWebController*)webPageOrderedOpen:(const GURL&)url
275                                referrer:(const web::Referrer&)referrer
276                              windowName:(NSString*)windowName
277                            inBackground:(BOOL)inBackground {
278   return nil;
281 - (CRWWebController*)webPageOrderedOpenBlankWithReferrer:
282                          (const web::Referrer&)referrer
283                                             inBackground:(BOOL)inBackground {
284   return nil;
287 - (void)webPageOrderedClose {
289 - (void)goDelta:(int)delta {
291 - (void)openURLWithParams:(const web::WebState::OpenURLParams&)params {
293 - (BOOL)openExternalURL:(const GURL&)url {
294   return NO;
296 - (void)presentSSLError:(const net::SSLInfo&)info
297            forSSLStatus:(const web::SSLStatus&)status
298             recoverable:(BOOL)recoverable
299                callback:(SSLErrorCallback)shouldContinue {
301 - (void)presentSpoofingError {
303 - (void)webLoadCancelled:(const GURL&)url {
305 - (void)webDidUpdateHistoryStateWithPageURL:(const GURL&)pageUrl {
307 - (void)webController:(CRWWebController*)webController
308     retrievePlaceholderOverlayImage:(void (^)(UIImage*))block {
310 - (void)webController:(CRWWebController*)webController
311     onFormResubmissionForRequest:(NSURLRequest*)request
312                    continueBlock:(ProceduralBlock)continueBlock
313                      cancelBlock:(ProceduralBlock)cancelBlock {
315 - (void)webWillReload {
317 - (void)webWillInitiateLoadWithParams:(web::WebLoadParams&)params {
319 - (void)webDidUpdateSessionForLoadWithParams:(const web::WebLoadParams&)params
320                         wasInitialNavigation:(BOOL)initialNavigation {
322 - (void)webWillFinishHistoryNavigationFromEntry:(CRWSessionEntry*)fromEntry {
324 - (void)webWillGoDelta:(int)delta {
326 - (void)webDidPrepareForGoBack {
328 - (int)downloadImageAtUrl:(const GURL&)url
329             maxBitmapSize:(uint32_t)maxBitmapSize
330                  callback:
331                      (const web::WebState::ImageDownloadCallback&)callback {
332   return -1;
335 @end