Roll src/third_party/WebKit a452221:9ff6d11 (svn 202117:202119)
[chromium-blink-merge.git] / mandoline / ui / desktop_ui / browser_window.cc
blobb8ed3f07dcace3aa04dbd986abbecfb99a764599
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/view_manager/public/cpp/scoped_view_ptr.h"
12 #include "components/view_manager/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 "mojo/common/common_type_converters.h"
18 #include "mojo/converters/geometry/geometry_type_converters.h"
19 #include "mojo/services/tracing/public/cpp/switches.h"
20 #include "mojo/services/tracing/public/interfaces/tracing.mojom.h"
21 #include "ui/gfx/canvas.h"
22 #include "ui/views/background.h"
23 #include "ui/views/controls/button/label_button.h"
24 #include "ui/views/widget/widget_delegate.h"
26 namespace mandoline {
28 class ProgressView : public views::View {
29 public:
30 ProgressView() : progress_(0.f), loading_(false) {}
31 ~ProgressView() override {}
33 void SetProgress(double progress) {
34 progress_ = progress;
35 SchedulePaint();
38 void SetIsLoading(bool loading) {
39 if (loading == loading_)
40 return;
42 loading_ = loading;
43 progress_ = 0.f;
44 SchedulePaint();
47 private:
48 void OnPaint(gfx::Canvas* canvas) override {
49 if (loading_) {
50 canvas->FillRect(GetLocalBounds(), SK_ColorGREEN);
51 gfx::Rect progress_rect = GetLocalBounds();
52 progress_rect.set_width(progress_rect.width() * progress_);
53 canvas->FillRect(progress_rect, SK_ColorRED);
54 } else {
55 canvas->FillRect(GetLocalBounds(), SK_ColorGRAY);
59 double progress_;
60 bool loading_;
62 DISALLOW_COPY_AND_ASSIGN(ProgressView);
65 ////////////////////////////////////////////////////////////////////////////////
66 // BrowserWindow, public:
68 BrowserWindow::BrowserWindow(mojo::ApplicationImpl* app,
69 mojo::ViewTreeHostFactory* host_factory,
70 BrowserManager* manager)
71 : app_(app),
72 host_client_binding_(this),
73 manager_(manager),
74 omnibox_launcher_(nullptr),
75 progress_bar_(nullptr),
76 root_(nullptr),
77 content_(nullptr),
78 omnibox_view_(nullptr),
79 web_view_(this) {
80 mojo::ViewTreeHostClientPtr host_client;
81 host_client_binding_.Bind(GetProxy(&host_client));
82 mojo::CreateViewTreeHost(host_factory, host_client.Pass(), this, &host_);
85 void BrowserWindow::LoadURL(const GURL& url) {
86 // Haven't been embedded yet, can't embed.
87 // TODO(beng): remove this.
88 if (!root_) {
89 default_url_ = url;
90 return;
93 if (!url.is_valid()) {
94 ShowOmnibox();
95 return;
98 mojo::URLRequestPtr request(mojo::URLRequest::New());
99 request->url = url.spec();
100 Embed(request.Pass());
103 void BrowserWindow::Close() {
104 if (root_)
105 mojo::ScopedViewPtr::DeleteViewOrViewManager(root_);
106 else
107 delete this;
110 BrowserWindow::~BrowserWindow() {
111 DCHECK(!root_);
112 manager_->BrowserWindowClosed(this);
115 float BrowserWindow::DIPSToPixels(float value) const {
116 return value * root_->viewport_metrics().device_pixel_ratio;
119 ////////////////////////////////////////////////////////////////////////////////
120 // BrowserWindow, mojo::ViewTreeDelegate implementation:
122 void BrowserWindow::OnEmbed(mojo::View* root) {
123 // BrowserWindow does not support being embedded more than once.
124 CHECK(!root_);
126 // Record when the browser window was displayed, used for performance testing.
127 const base::Time display_time = base::Time::Now();
129 root_ = root;
131 host_->SetTitle("Mandoline");
133 content_ = root_->connection()->CreateView();
134 Init(root_);
136 host_->SetSize(mojo::Size::From(gfx::Size(1280, 800)));
138 root_->AddChild(content_);
139 content_->SetVisible(true);
141 web_view_.Init(app_, content_);
143 host_->AddAccelerator(static_cast<uint32_t>(BrowserCommand::CLOSE),
144 mojo::KEYBOARD_CODE_W, mojo::EVENT_FLAGS_CONTROL_DOWN);
145 host_->AddAccelerator(static_cast<uint32_t>(BrowserCommand::FOCUS_OMNIBOX),
146 mojo::KEYBOARD_CODE_L, mojo::EVENT_FLAGS_CONTROL_DOWN);
147 host_->AddAccelerator(static_cast<uint32_t>(BrowserCommand::NEW_WINDOW),
148 mojo::KEYBOARD_CODE_N, mojo::EVENT_FLAGS_CONTROL_DOWN);
150 // Now that we're ready, load the default url.
151 LoadURL(default_url_);
153 // Record the time spent opening initial tabs, used for performance testing.
154 const base::TimeDelta open_tabs_delta = base::Time::Now() - display_time;
156 // Record the browser startup time metrics, used for performance testing.
157 static bool recorded_browser_startup_metrics = false;
158 if (!recorded_browser_startup_metrics &&
159 base::CommandLine::ForCurrentProcess()->HasSwitch(
160 tracing::kEnableStatsCollectionBindings)) {
161 mojo::URLRequestPtr request(mojo::URLRequest::New());
162 request->url = mojo::String::From("mojo:tracing");
163 tracing::StartupPerformanceDataCollectorPtr collector;
164 app_->ConnectToService(request.Pass(), &collector);
165 collector->SetBrowserWindowDisplayTime(display_time.ToInternalValue());
166 collector->SetBrowserOpenTabsTimeDelta(open_tabs_delta.ToInternalValue());
167 collector->SetBrowserMessageLoopStartTime(
168 manager_->startup_time().ToInternalValue());
169 recorded_browser_startup_metrics = true;
173 void BrowserWindow::OnConnectionLost(mojo::ViewTreeConnection* connection) {
174 root_ = nullptr;
175 delete this;
178 ////////////////////////////////////////////////////////////////////////////////
179 // BrowserWindow, mojo::ViewTreeHostClient implementation:
181 void BrowserWindow::OnAccelerator(uint32_t id, mojo::EventPtr event) {
182 switch (static_cast<BrowserCommand>(id)) {
183 case BrowserCommand::CLOSE:
184 Close();
185 break;
186 case BrowserCommand::NEW_WINDOW:
187 manager_->CreateBrowser(GURL());
188 break;
189 case BrowserCommand::FOCUS_OMNIBOX:
190 ShowOmnibox();
191 break;
192 default:
193 NOTREACHED();
194 break;
198 ////////////////////////////////////////////////////////////////////////////////
199 // BrowserWindow, web_view::mojom::WebViewClient implementation:
201 void BrowserWindow::TopLevelNavigate(mojo::URLRequestPtr request) {
202 Embed(request.Pass());
205 void BrowserWindow::LoadingStateChanged(bool is_loading) {
206 progress_bar_->SetIsLoading(is_loading);
209 void BrowserWindow::ProgressChanged(double progress) {
210 progress_bar_->SetProgress(progress);
213 void BrowserWindow::TitleChanged(const mojo::String& title) {
214 base::string16 formatted =
215 title.is_null() ? base::ASCIIToUTF16("Untitled")
216 : title.To<base::string16>() +
217 base::ASCIIToUTF16(" - Mandoline");
218 host_->SetTitle(mojo::String::From(formatted));
221 ////////////////////////////////////////////////////////////////////////////////
222 // BrowserWindow, ViewEmbedder implementation:
224 void BrowserWindow::Embed(mojo::URLRequestPtr request) {
225 const std::string string_url = request->url.To<std::string>();
226 if (string_url == "mojo:omnibox") {
227 EmbedOmnibox();
228 return;
231 GURL gurl(string_url);
232 bool changed = current_url_ != gurl;
233 current_url_ = gurl;
234 if (changed)
235 omnibox_launcher_->SetText(base::UTF8ToUTF16(current_url_.spec()));
237 web_view_.web_view()->LoadRequest(request.Pass());
240 ////////////////////////////////////////////////////////////////////////////////
241 // BrowserWindow, mojo::InterfaceFactory<ViewEmbedder> implementation:
243 void BrowserWindow::Create(mojo::ApplicationConnection* connection,
244 mojo::InterfaceRequest<ViewEmbedder> request) {
245 view_embedder_bindings_.AddBinding(this, request.Pass());
248 ////////////////////////////////////////////////////////////////////////////////
249 // BrowserWindow, views::LayoutManager implementation:
251 gfx::Size BrowserWindow::GetPreferredSize(const views::View* view) const {
252 return gfx::Size();
255 void BrowserWindow::Layout(views::View* host) {
256 // TODO(fsamuel): All bounds should be in physical pixels.
257 gfx::Rect bounds_in_physical_pixels(host->bounds());
258 float inverse_device_pixel_ratio =
259 1.0f / root_->viewport_metrics().device_pixel_ratio;
261 gfx::Rect omnibox_launcher_bounds = gfx::ScaleToEnclosingRect(
262 bounds_in_physical_pixels, inverse_device_pixel_ratio);
263 omnibox_launcher_bounds.Inset(10, 10, 10,
264 omnibox_launcher_bounds.height() - 40);
265 omnibox_launcher_->SetBoundsRect(omnibox_launcher_bounds);
267 gfx::Rect progress_bar_bounds(omnibox_launcher_bounds.x(),
268 omnibox_launcher_bounds.bottom() + 2,
269 omnibox_launcher_bounds.width(),
271 progress_bar_->SetBoundsRect(progress_bar_bounds);
273 // The content view bounds are in physical pixels.
274 mojo::Rect content_bounds_mojo;
275 content_bounds_mojo.x = DIPSToPixels(progress_bar_bounds.x());
276 content_bounds_mojo.y = DIPSToPixels(progress_bar_bounds.bottom()+ 10);
277 content_bounds_mojo.width = DIPSToPixels(progress_bar_bounds.width());
278 content_bounds_mojo.height =
279 host->bounds().height() - content_bounds_mojo.y - DIPSToPixels(10);
280 content_->SetBounds(content_bounds_mojo);
282 // The omnibox view bounds are in physical pixels.
283 omnibox_view_->SetBounds(
284 mojo::TypeConverter<mojo::Rect, gfx::Rect>::Convert(
285 bounds_in_physical_pixels));
289 ////////////////////////////////////////////////////////////////////////////////
290 // BrowserWindow, views::ButtonListener implementation:
292 void BrowserWindow::ButtonPressed(views::Button* sender,
293 const ui::Event& event) {
294 DCHECK_EQ(sender, omnibox_launcher_);
295 ShowOmnibox();
298 ////////////////////////////////////////////////////////////////////////////////
299 // BrowserWindow, private:
301 void BrowserWindow::Init(mojo::View* root) {
302 DCHECK_GT(root->viewport_metrics().device_pixel_ratio, 0);
303 if (!aura_init_)
304 aura_init_.reset(new AuraInit(root, app_->shell()));
306 root_ = root;
307 omnibox_view_ = root_->connection()->CreateView();
308 root_->AddChild(omnibox_view_);
310 views::WidgetDelegateView* widget_delegate = new views::WidgetDelegateView;
311 widget_delegate->GetContentsView()->set_background(
312 views::Background::CreateSolidBackground(0xFFDDDDDD));
313 omnibox_launcher_ =
314 new views::LabelButton(this, base::ASCIIToUTF16("Open Omnibox"));
315 progress_bar_ = new ProgressView;
317 widget_delegate->GetContentsView()->AddChildView(omnibox_launcher_);
318 widget_delegate->GetContentsView()->AddChildView(progress_bar_);
319 widget_delegate->GetContentsView()->SetLayoutManager(this);
321 views::Widget* widget = new views::Widget;
322 views::Widget::InitParams params(
323 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
324 params.native_widget =
325 new NativeWidgetViewManager(widget, app_->shell(), root_);
326 params.delegate = widget_delegate;
327 params.bounds = root_->bounds().To<gfx::Rect>();
328 widget->Init(params);
329 widget->Show();
330 root_->SetFocus();
333 void BrowserWindow::ShowOmnibox() {
334 if (!omnibox_.get()) {
335 mojo::URLRequestPtr request(mojo::URLRequest::New());
336 request->url = mojo::String::From("mojo:omnibox");
337 omnibox_connection_ = app_->ConnectToApplication(request.Pass());
338 omnibox_connection_->AddService<ViewEmbedder>(this);
339 omnibox_connection_->ConnectToService(&omnibox_);
340 omnibox_connection_->SetRemoteServiceProviderConnectionErrorHandler(
341 [this]() {
342 // This will cause the connection to be re-established the next time
343 // we come through this codepath.
344 omnibox_.reset();
347 omnibox_->ShowForURL(mojo::String::From(current_url_.spec()));
350 void BrowserWindow::EmbedOmnibox() {
351 mojo::ViewTreeClientPtr view_tree_client;
352 omnibox_->GetViewTreeClient(GetProxy(&view_tree_client));
353 omnibox_view_->Embed(view_tree_client.Pass());
355 // TODO(beng): This should be handled sufficiently by
356 // OmniboxImpl::ShowWindow() but unfortunately view manager policy
357 // currently prevents the embedded app from changing window z for
358 // its own window.
359 omnibox_view_->MoveToFront();
362 } // namespace mandoline