Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / mandoline / ui / desktop_ui / browser_window.cc
blob069fa7d9ecc936aacb1f53031eb862a114aaf653
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.
5 #include "mandoline/ui/desktop_ui/browser_window.h"
7 #include "base/command_line.h"
8 #include "base/strings/string16.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/time/time.h"
11 #include "components/mus/public/cpp/scoped_view_ptr.h"
12 #include "components/mus/public/cpp/view_tree_host_factory.h"
13 #include "mandoline/ui/aura/native_widget_view_manager.h"
14 #include "mandoline/ui/desktop_ui/browser_commands.h"
15 #include "mandoline/ui/desktop_ui/browser_manager.h"
16 #include "mandoline/ui/desktop_ui/public/interfaces/omnibox.mojom.h"
17 #include "mandoline/ui/desktop_ui/toolbar_view.h"
18 #include "mojo/common/common_type_converters.h"
19 #include "mojo/converters/geometry/geometry_type_converters.h"
20 #include "mojo/services/tracing/public/cpp/switches.h"
21 #include "mojo/services/tracing/public/interfaces/tracing.mojom.h"
22 #include "ui/gfx/canvas.h"
23 #include "ui/views/background.h"
24 #include "ui/views/controls/button/label_button.h"
25 #include "ui/views/widget/widget_delegate.h"
27 namespace mandoline {
29 class ProgressView : public views::View {
30 public:
31 ProgressView() : progress_(0.f), loading_(false) {}
32 ~ProgressView() override {}
34 void SetProgress(double progress) {
35 progress_ = progress;
36 SchedulePaint();
39 void SetIsLoading(bool loading) {
40 if (loading == loading_)
41 return;
43 loading_ = loading;
44 progress_ = 0.f;
45 SchedulePaint();
48 private:
49 void OnPaint(gfx::Canvas* canvas) override {
50 if (loading_) {
51 canvas->FillRect(GetLocalBounds(), SK_ColorGREEN);
52 gfx::Rect progress_rect = GetLocalBounds();
53 progress_rect.set_width(progress_rect.width() * progress_);
54 canvas->FillRect(progress_rect, SK_ColorRED);
55 } else {
56 canvas->FillRect(GetLocalBounds(), SK_ColorGRAY);
60 double progress_;
61 bool loading_;
63 DISALLOW_COPY_AND_ASSIGN(ProgressView);
66 ////////////////////////////////////////////////////////////////////////////////
67 // BrowserWindow, public:
69 BrowserWindow::BrowserWindow(mojo::ApplicationImpl* app,
70 mojo::ViewTreeHostFactory* host_factory,
71 BrowserManager* manager)
72 : app_(app),
73 host_client_binding_(this),
74 manager_(manager),
75 toolbar_view_(nullptr),
76 progress_bar_(nullptr),
77 root_(nullptr),
78 content_(nullptr),
79 omnibox_view_(nullptr),
80 web_view_(this) {
81 mojo::ViewTreeHostClientPtr host_client;
82 host_client_binding_.Bind(GetProxy(&host_client));
83 mus::CreateViewTreeHost(host_factory, host_client.Pass(), this, &host_);
86 void BrowserWindow::LoadURL(const GURL& url) {
87 // Haven't been embedded yet, can't embed.
88 // TODO(beng): remove this.
89 if (!root_) {
90 default_url_ = url;
91 return;
94 if (!url.is_valid()) {
95 ShowOmnibox();
96 return;
99 mojo::URLRequestPtr request(mojo::URLRequest::New());
100 request->url = url.spec();
101 Embed(request.Pass());
104 void BrowserWindow::Close() {
105 if (root_)
106 mus::ScopedViewPtr::DeleteViewOrViewManager(root_);
107 else
108 delete this;
111 void BrowserWindow::ShowOmnibox() {
112 if (!omnibox_.get()) {
113 mojo::URLRequestPtr request(mojo::URLRequest::New());
114 request->url = mojo::String::From("mojo:omnibox");
115 omnibox_connection_ = app_->ConnectToApplication(request.Pass());
116 omnibox_connection_->AddService<ViewEmbedder>(this);
117 omnibox_connection_->ConnectToService(&omnibox_);
118 omnibox_connection_->SetRemoteServiceProviderConnectionErrorHandler(
119 [this]() {
120 // This will cause the connection to be re-established the next time
121 // we come through this codepath.
122 omnibox_.reset();
125 omnibox_->ShowForURL(mojo::String::From(current_url_.spec()));
128 void BrowserWindow::GoBack() {
129 web_view_.web_view()->GoBack();
132 void BrowserWindow::GoForward() {
133 web_view_.web_view()->GoForward();
136 BrowserWindow::~BrowserWindow() {
137 DCHECK(!root_);
138 manager_->BrowserWindowClosed(this);
141 float BrowserWindow::DIPSToPixels(float value) const {
142 return value * root_->viewport_metrics().device_pixel_ratio;
145 ////////////////////////////////////////////////////////////////////////////////
146 // BrowserWindow, mus::ViewTreeDelegate implementation:
148 void BrowserWindow::OnEmbed(mus::View* root) {
149 // BrowserWindow does not support being embedded more than once.
150 CHECK(!root_);
152 // Record when the browser window was displayed, used for performance testing.
153 const base::Time display_time = base::Time::Now();
155 root_ = root;
157 host_->SetTitle("Mandoline");
159 content_ = root_->connection()->CreateView();
160 Init(root_);
162 host_->SetSize(mojo::Size::From(gfx::Size(1280, 800)));
164 root_->AddChild(content_);
165 content_->SetVisible(true);
167 web_view_.Init(app_, content_);
169 host_->AddAccelerator(static_cast<uint32_t>(BrowserCommand::CLOSE),
170 mojo::KEYBOARD_CODE_W, mojo::EVENT_FLAGS_CONTROL_DOWN);
171 host_->AddAccelerator(static_cast<uint32_t>(BrowserCommand::FOCUS_OMNIBOX),
172 mojo::KEYBOARD_CODE_L, mojo::EVENT_FLAGS_CONTROL_DOWN);
173 host_->AddAccelerator(static_cast<uint32_t>(BrowserCommand::NEW_WINDOW),
174 mojo::KEYBOARD_CODE_N, mojo::EVENT_FLAGS_CONTROL_DOWN);
175 host_->AddAccelerator(static_cast<uint32_t>(BrowserCommand::GO_BACK),
176 mojo::KEYBOARD_CODE_LEFT, mojo::EVENT_FLAGS_ALT_DOWN);
177 host_->AddAccelerator(static_cast<uint32_t>(BrowserCommand::GO_FORWARD),
178 mojo::KEYBOARD_CODE_RIGHT, mojo::EVENT_FLAGS_ALT_DOWN);
180 // Now that we're ready, load the default url.
181 LoadURL(default_url_);
183 // Record the time spent opening initial tabs, used for performance testing.
184 const base::TimeDelta open_tabs_delta = base::Time::Now() - display_time;
186 // Record the browser startup time metrics, used for performance testing.
187 static bool recorded_browser_startup_metrics = false;
188 if (!recorded_browser_startup_metrics &&
189 base::CommandLine::ForCurrentProcess()->HasSwitch(
190 tracing::kEnableStatsCollectionBindings)) {
191 mojo::URLRequestPtr request(mojo::URLRequest::New());
192 request->url = mojo::String::From("mojo:tracing");
193 tracing::StartupPerformanceDataCollectorPtr collector;
194 app_->ConnectToService(request.Pass(), &collector);
195 collector->SetBrowserWindowDisplayTime(display_time.ToInternalValue());
196 collector->SetBrowserOpenTabsTimeDelta(open_tabs_delta.ToInternalValue());
197 collector->SetBrowserMessageLoopStartTime(
198 manager_->startup_time().ToInternalValue());
199 recorded_browser_startup_metrics = true;
203 void BrowserWindow::OnConnectionLost(mus::ViewTreeConnection* connection) {
204 root_ = nullptr;
205 delete this;
208 ////////////////////////////////////////////////////////////////////////////////
209 // BrowserWindow, mus::ViewTreeHostClient implementation:
211 void BrowserWindow::OnAccelerator(uint32_t id, mojo::EventPtr event) {
212 switch (static_cast<BrowserCommand>(id)) {
213 case BrowserCommand::CLOSE:
214 Close();
215 break;
216 case BrowserCommand::NEW_WINDOW:
217 manager_->CreateBrowser(GURL());
218 break;
219 case BrowserCommand::FOCUS_OMNIBOX:
220 ShowOmnibox();
221 break;
222 case BrowserCommand::GO_BACK:
223 GoBack();
224 break;
225 case BrowserCommand::GO_FORWARD:
226 GoForward();
227 break;
228 default:
229 NOTREACHED();
230 break;
234 ////////////////////////////////////////////////////////////////////////////////
235 // BrowserWindow, web_view::mojom::WebViewClient implementation:
237 void BrowserWindow::TopLevelNavigate(mojo::URLRequestPtr request) {
238 Embed(request.Pass());
241 void BrowserWindow::LoadingStateChanged(bool is_loading, double progress) {
242 progress_bar_->SetIsLoading(is_loading);
243 progress_bar_->SetProgress(progress);
246 void BrowserWindow::BackForwardChanged(
247 web_view::mojom::ButtonState back_button,
248 web_view::mojom::ButtonState forward_button) {
249 toolbar_view_->SetBackForwardEnabled(
250 back_button == web_view::mojom::ButtonState::BUTTON_STATE_ENABLED,
251 forward_button == web_view::mojom::ButtonState::BUTTON_STATE_ENABLED);
254 void BrowserWindow::TitleChanged(const mojo::String& title) {
255 base::string16 formatted =
256 title.is_null() ? base::ASCIIToUTF16("Untitled")
257 : title.To<base::string16>() +
258 base::ASCIIToUTF16(" - Mandoline");
259 host_->SetTitle(mojo::String::From(formatted));
262 ////////////////////////////////////////////////////////////////////////////////
263 // BrowserWindow, ViewEmbedder implementation:
265 void BrowserWindow::Embed(mojo::URLRequestPtr request) {
266 const std::string string_url = request->url.To<std::string>();
267 if (string_url == "mojo:omnibox") {
268 EmbedOmnibox();
269 return;
272 GURL gurl(string_url);
273 bool changed = current_url_ != gurl;
274 current_url_ = gurl;
275 if (changed)
276 toolbar_view_->SetOmniboxText(base::UTF8ToUTF16(current_url_.spec()));
278 web_view_.web_view()->LoadRequest(request.Pass());
281 ////////////////////////////////////////////////////////////////////////////////
282 // BrowserWindow, mojo::InterfaceFactory<ViewEmbedder> implementation:
284 void BrowserWindow::Create(mojo::ApplicationConnection* connection,
285 mojo::InterfaceRequest<ViewEmbedder> request) {
286 view_embedder_bindings_.AddBinding(this, request.Pass());
289 ////////////////////////////////////////////////////////////////////////////////
290 // BrowserWindow, views::LayoutManager implementation:
292 gfx::Size BrowserWindow::GetPreferredSize(const views::View* view) const {
293 return gfx::Size();
296 void BrowserWindow::Layout(views::View* host) {
297 // TODO(fsamuel): All bounds should be in physical pixels.
298 gfx::Rect bounds_in_physical_pixels(host->bounds());
299 float inverse_device_pixel_ratio =
300 1.0f / root_->viewport_metrics().device_pixel_ratio;
302 gfx::Rect toolbar_bounds = gfx::ScaleToEnclosingRect(
303 bounds_in_physical_pixels, inverse_device_pixel_ratio);
304 toolbar_bounds.Inset(10, 10, 10, toolbar_bounds.height() - 40);
305 toolbar_view_->SetBoundsRect(toolbar_bounds);
307 gfx::Rect progress_bar_bounds(toolbar_bounds.x(), toolbar_bounds.bottom() + 2,
308 toolbar_bounds.width(), 5);
310 // The content view bounds are in physical pixels.
311 mojo::Rect content_bounds_mojo;
312 content_bounds_mojo.x = DIPSToPixels(progress_bar_bounds.x());
313 content_bounds_mojo.y = DIPSToPixels(progress_bar_bounds.bottom()+ 10);
314 content_bounds_mojo.width = DIPSToPixels(progress_bar_bounds.width());
315 content_bounds_mojo.height =
316 host->bounds().height() - content_bounds_mojo.y - DIPSToPixels(10);
317 content_->SetBounds(content_bounds_mojo);
319 // The omnibox view bounds are in physical pixels.
320 omnibox_view_->SetBounds(
321 mojo::TypeConverter<mojo::Rect, gfx::Rect>::Convert(
322 bounds_in_physical_pixels));
325 ////////////////////////////////////////////////////////////////////////////////
326 // BrowserWindow, private:
328 void BrowserWindow::Init(mus::View* root) {
329 DCHECK_GT(root->viewport_metrics().device_pixel_ratio, 0);
330 if (!aura_init_)
331 aura_init_.reset(new AuraInit(root, app_->shell()));
333 root_ = root;
334 omnibox_view_ = root_->connection()->CreateView();
335 root_->AddChild(omnibox_view_);
337 views::WidgetDelegateView* widget_delegate = new views::WidgetDelegateView;
338 widget_delegate->GetContentsView()->set_background(
339 views::Background::CreateSolidBackground(0xFFDDDDDD));
340 toolbar_view_ = new ToolbarView(this);
341 progress_bar_ = new ProgressView;
342 widget_delegate->GetContentsView()->AddChildView(toolbar_view_);
343 widget_delegate->GetContentsView()->AddChildView(progress_bar_);
344 widget_delegate->GetContentsView()->SetLayoutManager(this);
346 views::Widget* widget = new views::Widget;
347 views::Widget::InitParams params(
348 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
349 params.native_widget =
350 new NativeWidgetViewManager(widget, app_->shell(), root_);
351 params.delegate = widget_delegate;
352 params.bounds = root_->bounds().To<gfx::Rect>();
353 widget->Init(params);
354 widget->Show();
355 root_->SetFocus();
358 void BrowserWindow::EmbedOmnibox() {
359 mojo::ViewTreeClientPtr view_tree_client;
360 omnibox_->GetViewTreeClient(GetProxy(&view_tree_client));
361 omnibox_view_->Embed(view_tree_client.Pass());
363 // TODO(beng): This should be handled sufficiently by
364 // OmniboxImpl::ShowWindow() but unfortunately view manager policy
365 // currently prevents the embedded app from changing window z for
366 // its own window.
367 omnibox_view_->MoveToFront();
370 } // namespace mandoline