OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #import "ios/web/webui/crw_web_ui_manager.h" | |
6 | |
7 #include "base/mac/bind_objc_block.h" | |
8 #include "base/mac/scoped_nsobject.h" | |
9 #include "base/memory/scoped_vector.h" | |
10 #import "base/strings/sys_string_conversions.h" | |
11 #include "base/values.h" | |
12 #import "ios/web/net/request_group_util.h" | |
13 #include "ios/web/public/browser_state.h" | |
14 #import "ios/web/public/web_state/web_state_observer_bridge.h" | |
15 #include "ios/web/public/web_client.h" | |
16 #include "ios/web/web_state/web_state_impl.h" | |
17 #import "ios/web/webui/crw_web_ui_page_builder.h" | |
18 #include "ios/web/webui/url_fetcher_block_adapter.h" | |
19 #import "net/base/mac/url_conversions.h" | |
20 | |
21 namespace { | |
22 // Prefix for history.requestFavicon JavaScript message. | |
23 const char kScriptCommandPrefix[] = "webui"; | |
24 } | |
25 | |
26 @interface CRWWebUIManager () <CRWWebUIPageBuilderDelegate> | |
27 | |
28 // Current web state. | |
29 @property(nonatomic, readonly) web::WebStateImpl* webState; | |
30 | |
31 // Composes WebUI page for webUIURL and invokes completionHandler with the | |
32 // result. | |
33 - (void)loadWebUIPageForURL:(const GURL&)webUIURL | |
34 completionHandler:(void (^)(NSString*))completionHandler; | |
35 | |
36 // Retrieves resource for URL and invokes completionHandler with the result. | |
37 - (void)fetchResourceWithURL:(const GURL&)URL | |
38 completionHandler:(void (^)(NSData*))completionHandler; | |
39 | |
40 // Handles JavaScript message from the WebUI page. | |
41 - (BOOL)handleWebUIJSMessage:(const base::DictionaryValue&)message; | |
42 | |
43 // Removes favicon callback from web state. | |
44 - (void)resetWebState; | |
45 | |
46 // Removes fetcher from vector of active fetchers. | |
47 - (void)removeFetcher:(web::URLFetcherBlockAdapter*)fetcher; | |
48 | |
49 @end | |
50 | |
51 @implementation CRWWebUIManager { | |
52 // Set of live WebUI fetchers for retrieving data. | |
53 ScopedVector<web::URLFetcherBlockAdapter> _fetchers; | |
54 // Bridge to observe the web state from Objective-C. | |
55 scoped_ptr<web::WebStateObserverBridge> _webStateObserverBridge; | |
56 // Weak WebStateImpl this CRWWebUIManager is associated with. | |
57 web::WebStateImpl* _webState; | |
58 } | |
59 | |
60 - (instancetype)init { | |
61 NOTREACHED(); | |
62 return self; | |
63 } | |
64 | |
65 - (instancetype)initWithWebState:(web::WebStateImpl*)webState { | |
66 if (self = [super init]) { | |
67 _webState = webState; | |
68 _webStateObserverBridge.reset( | |
69 new web::WebStateObserverBridge(webState, self)); | |
70 base::WeakNSObject<CRWWebUIManager> weakSelf(self); | |
71 _webState->AddScriptCommandCallback( | |
72 base::BindBlock( | |
73 ^bool(const base::DictionaryValue& message, const GURL&, bool) { | |
74 return [weakSelf handleWebUIJSMessage:message]; | |
75 }), | |
76 kScriptCommandPrefix); | |
77 } | |
78 return self; | |
79 } | |
80 | |
81 - (void)dealloc { | |
82 [self resetWebState]; | |
83 [super dealloc]; | |
84 } | |
85 | |
86 #pragma mark - CRWWebStateObserver Methods | |
87 | |
88 - (void)webState:(web::WebState*)webState | |
89 didStartProvisionalNavigationForURL:(const GURL&)URL { | |
90 DCHECK(webState == _webState); | |
91 GURL navigationURL(URL); | |
92 // Add request group ID to the URL, if not present. Request group ID may | |
93 // already be added if restoring state to a WebUI page. | |
94 GURL requestURL = | |
95 web::ExtractRequestGroupIDFromURL(net::NSURLWithGURL(URL)) | |
96 ? URL | |
97 : net::GURLWithNSURL(web::AddRequestGroupIDToURL( | |
98 net::NSURLWithGURL(URL), _webState->GetRequestGroupID())); | |
99 base::WeakNSObject<CRWWebUIManager> weakSelf(self); | |
100 [self loadWebUIPageForURL:requestURL | |
101 completionHandler:^(NSString* HTML) { | |
102 scoped_ptr<web::WebState> webState([weakSelf webState]); | |
Eugene But (OOO till 7-30)
2015/05/12 18:26:36
web::WebState* webState = [weakSelf webState];
Wr
Jackie Quinn
2015/05/13 21:05:29
Done!
| |
103 if (webState) { | |
104 webState->LoadWebUIHtml(base::SysNSStringToUTF16(HTML), | |
105 navigationURL); | |
106 } | |
107 }]; | |
108 } | |
109 | |
110 - (void)webStateDestroyed:(web::WebState*)webState { | |
111 [self resetWebState]; | |
112 } | |
113 | |
114 #pragma mark - CRWWebUIPageBuilderDelegate Methods | |
115 | |
116 - (void)webUIPageBuilder:(CRWWebUIPageBuilder*)webUIPageBuilder | |
117 fetchResourceWithURL:(const GURL&)resourceURL | |
118 completionHandler:(web::WebUIDelegateCompletion)completionHandler { | |
119 GURL URL(resourceURL); | |
120 [self fetchResourceWithURL:URL | |
121 completionHandler:^(NSData* data) { | |
122 base::scoped_nsobject<NSString> resource( | |
123 [[NSString alloc] initWithData:data | |
124 encoding:NSUTF8StringEncoding]); | |
125 completionHandler(resource, URL); | |
126 }]; | |
127 } | |
128 | |
129 #pragma mark - Private Methods | |
130 | |
131 - (void)loadWebUIPageForURL:(const GURL&)webUIURL | |
132 completionHandler:(void (^)(NSString*))handler { | |
133 base::scoped_nsobject<CRWWebUIPageBuilder> pageBuilder( | |
134 [[CRWWebUIPageBuilder alloc] initWithDelegate:self]); | |
135 [pageBuilder buildWebUIPageForURL:webUIURL completionHandler:handler]; | |
136 } | |
137 | |
138 - (void)fetchResourceWithURL:(const GURL&)URL | |
139 completionHandler:(void (^)(NSData*))completionHandler { | |
140 base::WeakNSObject<CRWWebUIManager> weakSelf(self); | |
141 web::URLFetcherBlockAdapterCompletion fetcherCompletion = | |
142 ^(NSData* data, web::URLFetcherBlockAdapter* fetcher) { | |
143 completionHandler(data); | |
144 [weakSelf removeFetcher:fetcher]; | |
145 }; | |
146 | |
147 _fetchers.push_back( | |
148 [self fetcherForURL:URL completionHandler:fetcherCompletion].Pass()); | |
149 _fetchers.back()->Start(); | |
150 } | |
151 | |
152 - (BOOL)handleWebUIJSMessage:(const base::DictionaryValue&)message { | |
153 std::string command; | |
154 if (!message.GetString("message", &command) || command != "requestFavicon") { | |
155 DLOG(WARNING) << "Unexpected message received" << command; | |
156 return NO; | |
157 } | |
158 const base::ListValue* arguments = nullptr; | |
159 if (!message.GetList("arguments", &arguments)) { | |
160 DLOG(WARNING) << "JS message parameter not found: arguments"; | |
161 return NO; | |
162 } | |
163 std::string favicon; | |
164 if (!arguments->GetString(0, &favicon)) { | |
165 DLOG(WARNING) << "JS message parameter not found: Favicon URL"; | |
166 return NO; | |
167 } | |
168 GURL faviconURL(favicon); | |
169 DCHECK(faviconURL.is_valid()); | |
170 // Retrieve favicon resource and set favicon background image via JavaScript. | |
171 base::WeakNSObject<CRWWebUIManager> weakSelf(self); | |
172 void (^faviconHandler)(NSData*) = ^void(NSData* data) { | |
173 NSString* base64EncodedResource = [data base64EncodedStringWithOptions:0]; | |
174 NSString* dataURLString = [NSString | |
175 stringWithFormat:@"data:image/png;base64,%@", base64EncodedResource]; | |
176 NSString* faviconURLString = base::SysUTF8ToNSString(faviconURL.spec()); | |
177 NSString* script = | |
178 [NSString stringWithFormat:@"chrome.setFaviconBackground('%@', '%@');", | |
179 faviconURLString, dataURLString]; | |
180 [weakSelf webState]->ExecuteJavaScriptAsync( | |
181 base::SysNSStringToUTF16(script)); | |
182 }; | |
183 [self fetchResourceWithURL:faviconURL completionHandler:faviconHandler]; | |
184 return YES; | |
185 } | |
186 | |
187 - (void)resetWebState { | |
188 if (_webState) { | |
189 _webState->RemoveScriptCommandCallback(kScriptCommandPrefix); | |
190 } | |
191 _webState = nullptr; | |
192 } | |
193 | |
194 - (web::WebStateImpl*)webState { | |
195 return _webState; | |
196 } | |
197 | |
198 - (void)removeFetcher:(web::URLFetcherBlockAdapter*)fetcher { | |
199 _fetchers.erase(std::find(_fetchers.begin(), _fetchers.end(), fetcher)); | |
200 } | |
201 | |
202 #pragma mark - Testing-Only Methods | |
203 | |
204 - (scoped_ptr<web::URLFetcherBlockAdapter>) | |
205 fetcherForURL:(const GURL&)URL | |
206 completionHandler:(web::URLFetcherBlockAdapterCompletion)handler { | |
207 return scoped_ptr<web::URLFetcherBlockAdapter>( | |
208 new web::URLFetcherBlockAdapter( | |
209 URL, _webState->GetBrowserState()->GetRequestContext(), handler)); | |
210 } | |
211 | |
212 @end | |
OLD | NEW |