| 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 |