Upstreaming browser/ui/uikit_ui_util from iOS.
[chromium-blink-merge.git] / mandoline / ui / browser / browser.cc
blob82d5191ca3bcd4cbc4cd198cbcb9653ea0bbb3b9
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/browser/browser.h"
7 #include "base/command_line.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "components/view_manager/public/cpp/view.h"
10 #include "components/view_manager/public/cpp/view_manager_init.h"
11 #include "mandoline/tab/frame.h"
12 #include "mandoline/tab/frame_connection.h"
13 #include "mandoline/tab/frame_tree.h"
14 #include "mandoline/ui/browser/browser_delegate.h"
15 #include "mandoline/ui/browser/browser_ui.h"
16 #include "mojo/application/public/cpp/application_runner.h"
17 #include "mojo/common/common_type_converters.h"
18 #include "mojo/converters/geometry/geometry_type_converters.h"
19 #include "third_party/mojo/src/mojo/public/c/system/main.h"
20 #include "ui/gfx/geometry/size.h"
22 namespace mandoline {
23 namespace {
25 gfx::Size GetInitialViewportSize() {
26 #if defined(OS_ANDROID)
27 // Resize to match the Nexus 5 aspect ratio:
28 return gfx::Size(320, 640);
29 #else
30 return gfx::Size(1280, 800);
31 #endif
34 } // namespace
36 Browser::Browser(mojo::ApplicationImpl* app,
37 BrowserDelegate* delegate,
38 const GURL& default_url)
39 : view_manager_init_(app, this, this),
40 root_(nullptr),
41 content_(nullptr),
42 omnibox_(nullptr),
43 default_url_(default_url),
44 navigator_host_(this),
45 app_(app),
46 delegate_(delegate) {
47 ui_.reset(BrowserUI::Create(this, app));
50 Browser::~Browser() {
51 // Destruct ui_ manually while |this| is alive and reset the pointer first.
52 // This is to avoid a double delete when OnViewManagerDestroyed gets
53 // called.
54 ui_.reset();
57 void Browser::ReplaceContentWithRequest(mojo::URLRequestPtr request) {
58 Embed(request.Pass());
61 mojo::ApplicationConnection* Browser::GetViewManagerConnectionForTesting() {
62 return view_manager_init_.connection();
65 void Browser::OnEmbed(mojo::View* root) {
66 // Browser does not support being embedded more than once.
67 CHECK(!root_);
69 // Make it so we get OnWillEmbed() for any Embed()s done by other apps we
70 // Embed().
71 root->view_manager()->SetEmbedRoot();
73 // TODO(beng): still unhappy with the fact that both this class & the UI class
74 // know so much about these views. Figure out how to shift more to
75 // the UI class.
76 root_ = root;
78 delegate_->InitUIIfNecessary(this, root_);
80 content_ = root_->view_manager()->CreateView();
81 ui_->Init(root_);
83 view_manager_init_.view_manager_root()->SetViewportSize(
84 mojo::Size::From(GetInitialViewportSize()));
86 root_->AddChild(content_);
87 content_->SetVisible(true);
89 view_manager_init_.view_manager_root()->AddAccelerator(
90 mojo::KEYBOARD_CODE_BROWSER_BACK, mojo::EVENT_FLAGS_NONE);
92 // Now that we're ready, either load a pending url or the default url.
93 if (pending_request_) {
94 Embed(pending_request_.Pass());
95 } else if (default_url_.is_valid()) {
96 mojo::URLRequestPtr request(mojo::URLRequest::New());
97 request->url = mojo::String::From(default_url_.spec());
98 Embed(request.Pass());
102 void Browser::OnEmbedForDescendant(mojo::View* view,
103 mojo::URLRequestPtr request,
104 mojo::ViewManagerClientPtr* client) {
105 // TODO(sky): move this to Frame/FrameTree.
106 Frame* frame = Frame::FindFirstFrameAncestor(view);
107 if (!frame || !frame->HasAncestor(frame_tree_->root())) {
108 // TODO(sky): add requestor url so that we can return false if it's not
109 // an app we expect.
110 mojo::ApplicationConnection* connection =
111 app_->ConnectToApplication(request.Pass());
112 connection->ConnectToService(client);
113 return;
116 scoped_ptr<FrameConnection> frame_connection(new FrameConnection);
117 frame_connection->Init(app_, request.Pass(), client);
118 FrameTreeClient* frame_tree_client = frame_connection->frame_tree_client();
119 frame_tree_->CreateOrReplaceFrame(frame, view, frame_tree_client,
120 frame_connection.Pass());
123 void Browser::OnViewManagerDestroyed(mojo::ViewManager* view_manager) {
124 ui_.reset();
125 root_ = nullptr;
126 delegate_->BrowserClosed(this);
129 void Browser::OnAccelerator(mojo::EventPtr event) {
130 DCHECK_EQ(mojo::KEYBOARD_CODE_BROWSER_BACK,
131 event->key_data->windows_key_code);
132 navigator_host_.RequestNavigateHistory(-1);
135 void Browser::OpenURL(const mojo::String& url) {
136 omnibox_->SetVisible(false);
137 mojo::URLRequestPtr request(mojo::URLRequest::New());
138 request->url = mojo::String::From(url);
139 ReplaceContentWithRequest(request.Pass());
142 void Browser::Embed(mojo::URLRequestPtr request) {
143 const std::string string_url = request->url.To<std::string>();
144 if (string_url == "mojo:omnibox") {
145 ShowOmnibox(request.Pass());
146 return;
149 // We can get Embed calls before we've actually been
150 // embedded into the root view and content_ is created.
151 // Just save the last url, we'll embed it when we're ready.
152 if (!content_) {
153 pending_request_ = request.Pass();
154 return;
157 GURL gurl(string_url);
158 bool changed = current_url_ != gurl;
159 current_url_ = gurl;
160 if (changed)
161 ui_->OnURLChanged();
163 scoped_ptr<FrameConnection> frame_connection(new FrameConnection);
164 mojo::ViewManagerClientPtr view_manager_client;
165 frame_connection->Init(app_, request.Pass(), &view_manager_client);
166 frame_connection->application_connection()->AddService<mojo::NavigatorHost>(
167 this);
168 FrameTreeClient* frame_tree_client = frame_connection->frame_tree_client();
169 frame_tree_.reset(new FrameTree(content_, this, frame_tree_client,
170 frame_connection.Pass()));
171 content_->Embed(view_manager_client.Pass());
172 LoadingStateChanged(true);
174 navigator_host_.RecordNavigation(gurl.spec());
177 bool Browser::CanPostMessageEventToFrame(const Frame* source,
178 const Frame* target,
179 MessageEvent* event) {
180 return true;
183 void Browser::LoadingStateChanged(bool loading) {
184 ui_->LoadingStateChanged(loading);
187 void Browser::ProgressChanged(double progress) {
188 ui_->ProgressChanged(progress);
191 void Browser::Create(mojo::ApplicationConnection* connection,
192 mojo::InterfaceRequest<mojo::NavigatorHost> request) {
193 navigator_host_.Bind(request.Pass());
196 void Browser::Create(mojo::ApplicationConnection* connection,
197 mojo::InterfaceRequest<ViewEmbedder> request) {
198 view_embedder_bindings_.AddBinding(this, request.Pass());
201 void Browser::ShowOmnibox(mojo::URLRequestPtr request) {
202 if (!omnibox_) {
203 omnibox_ = root_->view_manager()->CreateView();
204 root_->AddChild(omnibox_);
205 omnibox_->SetBounds(root_->bounds());
207 mojo::ViewManagerClientPtr view_manager_client;
208 mojo::ApplicationConnection* connection =
209 app_->ConnectToApplication(request.Pass());
210 connection->AddService<ViewEmbedder>(this);
211 connection->ConnectToService(&view_manager_client);
212 omnibox_->Embed(view_manager_client.Pass());
213 omnibox_->SetVisible(true);
216 void Browser::RequestNavigate(Frame* source,
217 NavigationTarget target,
218 mojo::URLRequestPtr request) {
219 // TODO(sky): we shouldn't always do a top level navigation here.
220 ReplaceContentWithRequest(request.Pass());
223 } // namespace mandoline