OLD | NEW |
| (Empty) |
1 // Copyright 2016 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 #include "services/navigation/view_impl.h" | |
6 | |
7 #include "base/memory/ptr_util.h" | |
8 #include "base/strings/utf_string_conversions.h" | |
9 #include "content/public/browser/browser_context.h" | |
10 #include "content/public/browser/interstitial_page.h" | |
11 #include "content/public/browser/interstitial_page_delegate.h" | |
12 #include "content/public/browser/navigation_controller.h" | |
13 #include "content/public/browser/navigation_details.h" | |
14 #include "content/public/browser/navigation_entry.h" | |
15 #include "content/public/browser/notification_details.h" | |
16 #include "content/public/browser/notification_source.h" | |
17 #include "content/public/browser/notification_types.h" | |
18 #include "content/public/browser/web_contents.h" | |
19 #include "services/service_manager/public/cpp/connector.h" | |
20 #include "ui/aura/mus/window_tree_client.h" | |
21 #include "ui/aura/mus/window_tree_host_mus.h" | |
22 #include "ui/views/controls/webview/webview.h" | |
23 #include "ui/views/widget/widget.h" | |
24 #include "url/gurl.h" | |
25 | |
26 namespace navigation { | |
27 namespace { | |
28 | |
29 class InterstitialPageDelegate : public content::InterstitialPageDelegate { | |
30 public: | |
31 explicit InterstitialPageDelegate(const std::string& html) : html_(html) {} | |
32 ~InterstitialPageDelegate() override {} | |
33 InterstitialPageDelegate(const InterstitialPageDelegate&) = delete; | |
34 void operator=(const InterstitialPageDelegate&) = delete; | |
35 | |
36 private: | |
37 | |
38 // content::InterstitialPageDelegate: | |
39 std::string GetHTMLContents() override { | |
40 return html_; | |
41 } | |
42 | |
43 const std::string html_; | |
44 }; | |
45 | |
46 // TODO(beng): Explicitly not writing a TypeConverter for this, and not doing a | |
47 // typemap just yet since I'm still figuring out what these | |
48 // interfaces should take as parameters. | |
49 mojom::NavigationEntryPtr EntryPtrFromNavEntry( | |
50 const content::NavigationEntry& entry) { | |
51 mojom::NavigationEntryPtr entry_ptr(mojom::NavigationEntry::New()); | |
52 entry_ptr->id = entry.GetUniqueID(); | |
53 entry_ptr->url = entry.GetURL(); | |
54 entry_ptr->title = base::UTF16ToUTF8(entry.GetTitle()); | |
55 entry_ptr->redirect_chain = entry.GetRedirectChain(); | |
56 return entry_ptr; | |
57 } | |
58 | |
59 } // namespace | |
60 | |
61 ViewImpl::ViewImpl(std::unique_ptr<service_manager::Connector> connector, | |
62 const std::string& client_user_id, | |
63 mojom::ViewClientPtr client, | |
64 std::unique_ptr<service_manager::ServiceContextRef> ref) | |
65 : connector_(std::move(connector)), | |
66 client_(std::move(client)), | |
67 ref_(std::move(ref)), | |
68 web_view_(new views::WebView( | |
69 content::BrowserContext::GetBrowserContextForServiceUserId( | |
70 client_user_id))) { | |
71 web_view_->GetWebContents()->SetDelegate(this); | |
72 const content::NavigationController* controller = | |
73 &web_view_->GetWebContents()->GetController(); | |
74 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING, | |
75 content::Source<content::NavigationController>(controller)); | |
76 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | |
77 content::Source<content::NavigationController>(controller)); | |
78 registrar_.Add(this, content::NOTIFICATION_NAV_LIST_PRUNED, | |
79 content::Source<content::NavigationController>(controller)); | |
80 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_CHANGED, | |
81 content::Source<content::NavigationController>(controller)); | |
82 } | |
83 | |
84 ViewImpl::~ViewImpl() { | |
85 DeleteTreeAndWidget(); | |
86 } | |
87 | |
88 void ViewImpl::DeleteTreeAndWidget() { | |
89 widget_.reset(); | |
90 window_tree_host_.reset(); | |
91 window_tree_client_.reset(); | |
92 } | |
93 | |
94 void ViewImpl::NavigateTo(const GURL& url) { | |
95 web_view_->GetWebContents()->GetController().LoadURL( | |
96 url, content::Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); | |
97 } | |
98 | |
99 void ViewImpl::GoBack() { | |
100 web_view_->GetWebContents()->GetController().GoBack(); | |
101 } | |
102 | |
103 void ViewImpl::GoForward() { | |
104 web_view_->GetWebContents()->GetController().GoForward(); | |
105 } | |
106 | |
107 void ViewImpl::NavigateToOffset(int offset) { | |
108 web_view_->GetWebContents()->GetController().GoToOffset(offset); | |
109 } | |
110 | |
111 void ViewImpl::Reload(bool bypass_cache) { | |
112 web_view_->GetWebContents()->GetController().Reload( | |
113 bypass_cache ? content::ReloadType::BYPASSING_CACHE | |
114 : content::ReloadType::NORMAL, | |
115 true); | |
116 } | |
117 | |
118 void ViewImpl::Stop() { | |
119 web_view_->GetWebContents()->Stop(); | |
120 } | |
121 | |
122 void ViewImpl::GetWindowTreeClient(ui::mojom::WindowTreeClientRequest request) { | |
123 window_tree_client_ = base::MakeUnique<aura::WindowTreeClient>( | |
124 connector_.get(), this, nullptr, std::move(request)); | |
125 } | |
126 | |
127 void ViewImpl::ShowInterstitial(const std::string& html) { | |
128 content::InterstitialPage* interstitial = | |
129 content::InterstitialPage::Create(web_view_->GetWebContents(), | |
130 false, | |
131 GURL(), | |
132 new InterstitialPageDelegate(html)); | |
133 interstitial->Show(); | |
134 } | |
135 | |
136 void ViewImpl::HideInterstitial() { | |
137 // TODO(beng): this is not quite right. | |
138 if (web_view_->GetWebContents()->ShowingInterstitialPage()) | |
139 web_view_->GetWebContents()->GetInterstitialPage()->Proceed(); | |
140 } | |
141 | |
142 void ViewImpl::AddNewContents(content::WebContents* source, | |
143 content::WebContents* new_contents, | |
144 WindowOpenDisposition disposition, | |
145 const gfx::Rect& initial_rect, | |
146 bool user_gesture, | |
147 bool* was_blocked) { | |
148 mojom::ViewClientPtr client; | |
149 mojom::ViewPtr view; | |
150 auto view_request = mojo::MakeRequest(&view); | |
151 client_->ViewCreated(std::move(view), MakeRequest(&client), | |
152 disposition == WindowOpenDisposition::NEW_POPUP, | |
153 initial_rect, user_gesture); | |
154 | |
155 const std::string new_user_id = | |
156 content::BrowserContext::GetServiceUserIdFor( | |
157 new_contents->GetBrowserContext()); | |
158 auto impl = base::MakeUnique<ViewImpl>(connector_->Clone(), new_user_id, | |
159 std::move(client), ref_->Clone()); | |
160 | |
161 // TODO(beng): This is a bit crappy. should be able to create the ViewImpl | |
162 // with |new_contents| instead. | |
163 impl->web_view_->SetWebContents(new_contents); | |
164 impl->web_view_->GetWebContents()->SetDelegate(impl.get()); | |
165 | |
166 // TODO(beng): this reply is currently synchronous, figure out a fix. | |
167 if (was_blocked) | |
168 *was_blocked = false; | |
169 | |
170 mojo::MakeStrongBinding(std::move(impl), std::move(view_request)); | |
171 } | |
172 | |
173 void ViewImpl::CloseContents(content::WebContents* source) { | |
174 client_->Close(); | |
175 } | |
176 | |
177 content::WebContents* ViewImpl::OpenURLFromTab( | |
178 content::WebContents* source, | |
179 const content::OpenURLParams& params) { | |
180 mojom::OpenURLParamsPtr params_ptr = mojom::OpenURLParams::New(); | |
181 params_ptr->url = params.url; | |
182 params_ptr->disposition = | |
183 static_cast<mojom::WindowOpenDisposition>(params.disposition); | |
184 client_->OpenURL(std::move(params_ptr)); | |
185 // TODO(beng): Obviously this is the wrong thing to return for dispositions | |
186 // that would lead to the creation of a new View, i.e. NEW_TAB, NEW_POPUP etc. | |
187 // However it seems the callers of this function that we've seen so far | |
188 // disregard the return value. Rather than returning |source| I'm returning | |
189 // nullptr to locate (via crash) any sites that depend on a valid result. | |
190 // If we actually had to do this then we'd have to create the new WebContents | |
191 // here, store it with a cookie, and pass the cookie through to the client to | |
192 // pass back with their call to CreateView(), so it would get bound to the | |
193 // WebContents. | |
194 return nullptr; | |
195 } | |
196 | |
197 void ViewImpl::LoadingStateChanged(content::WebContents* source, | |
198 bool to_different_document) { | |
199 client_->LoadingStateChanged(source->IsLoading()); | |
200 } | |
201 | |
202 void ViewImpl::NavigationStateChanged(content::WebContents* source, | |
203 content::InvalidateTypes changed_flags) { | |
204 client_->NavigationStateChanged(source->GetVisibleURL(), | |
205 base::UTF16ToUTF8(source->GetTitle()), | |
206 source->GetController().CanGoBack(), | |
207 source->GetController().CanGoForward()); | |
208 } | |
209 | |
210 void ViewImpl::LoadProgressChanged(content::WebContents* source, | |
211 double progress) { | |
212 client_->LoadProgressChanged(progress); | |
213 } | |
214 | |
215 void ViewImpl::UpdateTargetURL(content::WebContents* source, const GURL& url) { | |
216 client_->UpdateHoverURL(url); | |
217 } | |
218 | |
219 void ViewImpl::Observe(int type, | |
220 const content::NotificationSource& source, | |
221 const content::NotificationDetails& details) { | |
222 if (content::Source<content::NavigationController>(source).ptr() != | |
223 &web_view_->GetWebContents()->GetController()) { | |
224 return; | |
225 } | |
226 | |
227 switch (type) { | |
228 case content::NOTIFICATION_NAV_ENTRY_PENDING: { | |
229 const content::NavigationEntry* entry = | |
230 content::Details<content::NavigationEntry>(details).ptr(); | |
231 client_->NavigationPending(EntryPtrFromNavEntry(*entry)); | |
232 break; | |
233 } | |
234 case content::NOTIFICATION_NAV_ENTRY_COMMITTED: { | |
235 const content::LoadCommittedDetails* lcd = | |
236 content::Details<content::LoadCommittedDetails>(details).ptr(); | |
237 mojom::NavigationCommittedDetailsPtr details_ptr( | |
238 mojom::NavigationCommittedDetails::New()); | |
239 details_ptr->entry = lcd->entry->GetUniqueID(); | |
240 details_ptr->type = static_cast<mojom::NavigationType>(lcd->type); | |
241 details_ptr->previous_entry_index = lcd->previous_entry_index; | |
242 details_ptr->previous_url = lcd->previous_url; | |
243 details_ptr->is_in_page = lcd->is_same_document; | |
244 details_ptr->is_main_frame = lcd->is_main_frame; | |
245 details_ptr->http_status_code = lcd->http_status_code; | |
246 client_->NavigationCommitted( | |
247 std::move(details_ptr), | |
248 web_view_->GetWebContents()->GetController().GetCurrentEntryIndex()); | |
249 break; | |
250 } | |
251 case content::NOTIFICATION_NAV_ENTRY_CHANGED: { | |
252 const content::EntryChangedDetails* ecd = | |
253 content::Details<content::EntryChangedDetails>(details).ptr(); | |
254 client_->NavigationEntryChanged(EntryPtrFromNavEntry(*ecd->changed_entry), | |
255 ecd->index); | |
256 break; | |
257 } | |
258 case content::NOTIFICATION_NAV_LIST_PRUNED: { | |
259 const content::PrunedDetails* pd = | |
260 content::Details<content::PrunedDetails>(details).ptr(); | |
261 client_->NavigationListPruned(pd->from_front, pd->count); | |
262 break; | |
263 } | |
264 default: | |
265 NOTREACHED(); | |
266 break; | |
267 } | |
268 } | |
269 | |
270 void ViewImpl::OnEmbed( | |
271 std::unique_ptr<aura::WindowTreeHostMus> window_tree_host) { | |
272 // TODO: Supplying a WindowTreeHostMus isn't particularly ideal in this case. | |
273 // In particular it would be nice if the WindowTreeClientDelegate could create | |
274 // its own WindowTreeHostMus, that way this code could directly create a | |
275 // DesktopWindowTreeTreeHostMus. | |
276 window_tree_host_ = std::move(window_tree_host); | |
277 DCHECK(!widget_.get()); | |
278 // TODO: fix this. The following won't work if multiple WindowTreeClients | |
279 // are used at the same time. The best fix is to have the ability to specify | |
280 // a WindowTreeClient when DesktopNativeWidgetAura is created so that it can | |
281 // create WindowPortMus with the correct client. | |
282 widget_.reset(new views::Widget); | |
283 views::Widget::InitParams params( | |
284 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); | |
285 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
286 params.delegate = this; | |
287 widget_->Init(params); | |
288 widget_->Show(); | |
289 } | |
290 | |
291 void ViewImpl::OnEmbedRootDestroyed(aura::WindowTreeHostMus* window_tree_host) { | |
292 DCHECK_EQ(window_tree_host, window_tree_host_.get()); | |
293 DeleteTreeAndWidget(); | |
294 } | |
295 | |
296 void ViewImpl::OnLostConnection(aura::WindowTreeClient* client) { | |
297 DeleteTreeAndWidget(); | |
298 } | |
299 | |
300 void ViewImpl::OnPointerEventObserved(const ui::PointerEvent& event, | |
301 aura::Window* target) {} | |
302 | |
303 aura::PropertyConverter* ViewImpl::GetPropertyConverter() { | |
304 // TODO: wire this up. | |
305 return nullptr; | |
306 } | |
307 | |
308 views::View* ViewImpl::GetContentsView() { | |
309 return web_view_; | |
310 } | |
311 | |
312 views::Widget* ViewImpl::GetWidget() { | |
313 return web_view_->GetWidget(); | |
314 } | |
315 | |
316 const views::Widget* ViewImpl::GetWidget() const { | |
317 return web_view_->GetWidget(); | |
318 } | |
319 | |
320 } // navigation | |
OLD | NEW |