Add 'did_proceed' and 'repeat_visit' to ClientMalwareReportRequest to track CTR.
[chromium-blink-merge.git] / components / mus / view_tree_host_impl.cc
blob32fcfe2cebf0b099dbc4f50279712425abd62f6a
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 "components/mus/view_tree_host_impl.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "components/mus/connection_manager.h"
9 #include "components/mus/display_manager.h"
10 #include "components/mus/focus_controller.h"
11 #include "components/mus/public/cpp/types.h"
12 #include "components/mus/view_tree_host_delegate.h"
13 #include "components/mus/view_tree_impl.h"
14 #include "mojo/common/common_type_converters.h"
15 #include "mojo/converters/geometry/geometry_type_converters.h"
17 namespace mus {
19 ViewTreeHostImpl::ViewTreeHostImpl(
20 mojo::ViewTreeHostClientPtr client,
21 ConnectionManager* connection_manager,
22 bool is_headless,
23 mojo::ApplicationImpl* app_impl,
24 const scoped_refptr<GpuState>& gpu_state,
25 const scoped_refptr<SurfacesState>& surfaces_state)
26 : delegate_(nullptr),
27 connection_manager_(connection_manager),
28 client_(client.Pass()),
29 event_dispatcher_(this),
30 display_manager_(DisplayManager::Create(is_headless,
31 app_impl,
32 gpu_state,
33 surfaces_state)),
34 focus_controller_(new FocusController(this)) {
35 display_manager_->Init(this);
36 if (client_) {
37 client_.set_connection_error_handler(
38 base::Bind(&ViewTreeHostImpl::OnClientClosed, base::Unretained(this)));
42 ViewTreeHostImpl::~ViewTreeHostImpl() {}
44 void ViewTreeHostImpl::Init(ViewTreeHostDelegate* delegate) {
45 delegate_ = delegate;
46 if (delegate_ && root_)
47 delegate_->OnDisplayInitialized();
50 ViewTreeImpl* ViewTreeHostImpl::GetViewTree() {
51 return delegate_ ? delegate_->GetViewTree() : nullptr;
54 bool ViewTreeHostImpl::IsViewAttachedToRoot(const ServerView* view) const {
55 return root_->Contains(view) && view != root_.get();
58 bool ViewTreeHostImpl::SchedulePaintIfInViewport(const ServerView* view,
59 const gfx::Rect& bounds) {
60 if (root_->Contains(view)) {
61 display_manager_->SchedulePaint(view, bounds);
62 return true;
64 return false;
67 const mojo::ViewportMetrics& ViewTreeHostImpl::GetViewportMetrics() const {
68 return display_manager_->GetViewportMetrics();
71 void ViewTreeHostImpl::SetFocusedView(ServerView* new_focused_view) {
72 ServerView* old_focused_view = focus_controller_->GetFocusedView();
73 if (old_focused_view == new_focused_view)
74 return;
75 DCHECK(root_view()->Contains(new_focused_view));
76 focus_controller_->SetFocusedView(new_focused_view);
77 // TODO(beng): have the FocusController notify us via FocusControllerDelegate.
78 OnFocusChanged(old_focused_view, new_focused_view);
81 ServerView* ViewTreeHostImpl::GetFocusedView() {
82 return focus_controller_->GetFocusedView();
85 void ViewTreeHostImpl::DestroyFocusController() {
86 focus_controller_.reset();
89 void ViewTreeHostImpl::UpdateTextInputState(ServerView* view,
90 const ui::TextInputState& state) {
91 // Do not need to update text input for unfocused views.
92 if (!display_manager_ || focus_controller_->GetFocusedView() != view)
93 return;
94 display_manager_->UpdateTextInputState(state);
97 void ViewTreeHostImpl::SetImeVisibility(ServerView* view, bool visible) {
98 // Do not need to show or hide IME for unfocused view.
99 if (focus_controller_->GetFocusedView() != view)
100 return;
101 display_manager_->SetImeVisibility(visible);
104 void ViewTreeHostImpl::OnAccelerator(uint32_t accelerator_id,
105 mojo::EventPtr event) {
106 client()->OnAccelerator(accelerator_id, event.Pass());
109 void ViewTreeHostImpl::DispatchInputEventToView(const ServerView* target,
110 mojo::EventPtr event) {
111 // If the view is an embed root, forward to the embedded view, not the owner.
112 ViewTreeImpl* connection =
113 connection_manager_->GetConnectionWithRoot(target->id());
114 if (!connection)
115 connection = connection_manager_->GetConnection(target->id().connection_id);
116 connection->client()->OnViewInputEvent(ViewIdToTransportId(target->id()),
117 event.Pass(),
118 base::Bind(&base::DoNothing));
121 void ViewTreeHostImpl::SetSize(mojo::SizePtr size) {
122 display_manager_->SetViewportSize(size.To<gfx::Size>());
125 void ViewTreeHostImpl::SetTitle(const mojo::String& title) {
126 display_manager_->SetTitle(title.To<base::string16>());
129 void ViewTreeHostImpl::AddAccelerator(uint32_t id,
130 mojo::KeyboardCode keyboard_code,
131 mojo::EventFlags flags) {
132 event_dispatcher_.AddAccelerator(id, keyboard_code, flags);
135 void ViewTreeHostImpl::RemoveAccelerator(uint32_t id) {
136 event_dispatcher_.RemoveAccelerator(id);
139 void ViewTreeHostImpl::OnClientClosed() {
140 // |display_manager_.reset()| destroys the display-manager first, and then
141 // sets |display_manager_| to nullptr. However, destroying |display_manager_|
142 // can destroy the corresponding ViewTreeHostConnection, and |this|. So
143 // setting it to nullptr afterwards in reset() ends up writing on free'd
144 // memory. So transfer over to a local scoped_ptr<> before destroying it.
145 scoped_ptr<DisplayManager> temp = display_manager_.Pass();
148 ServerView* ViewTreeHostImpl::GetRootView() {
149 return root_.get();
152 void ViewTreeHostImpl::OnEvent(ViewId id, mojo::EventPtr event) {
153 ServerView* view = connection_manager_->GetView(id);
154 // TODO(fsamuel): This should be a DCHECK but currently we use stale
155 // information to decide where to route input events. This should be fixed
156 // once we implement a UI scheduler.
157 if (view) {
158 DispatchInputEventToView(view, event.Pass());
159 return;
161 event_dispatcher_.OnEvent(event.Pass());
164 void ViewTreeHostImpl::OnDisplayClosed() {
165 if (delegate_)
166 delegate_->OnDisplayClosed();
169 void ViewTreeHostImpl::OnViewportMetricsChanged(
170 const mojo::ViewportMetrics& old_metrics,
171 const mojo::ViewportMetrics& new_metrics) {
172 if (!root_) {
173 root_.reset(connection_manager_->CreateServerView(
174 RootViewId(connection_manager_->GetAndAdvanceNextHostId())));
175 root_->SetBounds(gfx::Rect(new_metrics.size_in_pixels.To<gfx::Size>()));
176 root_->SetVisible(true);
177 if (delegate_)
178 delegate_->OnDisplayInitialized();
179 } else {
180 root_->SetBounds(gfx::Rect(new_metrics.size_in_pixels.To<gfx::Size>()));
182 // TODO(fsamuel): We shouldn't broadcast this to all connections but only
183 // those within a window root.
184 connection_manager_->ProcessViewportMetricsChanged(old_metrics, new_metrics);
187 void ViewTreeHostImpl::OnFocusChanged(ServerView* old_focused_view,
188 ServerView* new_focused_view) {
189 // There are up to four connections that need to be notified:
190 // . the connection containing |old_focused_view|.
191 // . the connection with |old_focused_view| as its root.
192 // . the connection containing |new_focused_view|.
193 // . the connection with |new_focused_view| as its root.
194 // Some of these connections may be the same. The following takes care to
195 // notify each only once.
196 ViewTreeImpl* owning_connection_old = nullptr;
197 ViewTreeImpl* embedded_connection_old = nullptr;
199 if (old_focused_view) {
200 owning_connection_old = connection_manager_->GetConnection(
201 old_focused_view->id().connection_id);
202 if (owning_connection_old) {
203 owning_connection_old->ProcessFocusChanged(old_focused_view,
204 new_focused_view);
206 embedded_connection_old =
207 connection_manager_->GetConnectionWithRoot(old_focused_view->id());
208 if (embedded_connection_old) {
209 DCHECK_NE(owning_connection_old, embedded_connection_old);
210 embedded_connection_old->ProcessFocusChanged(old_focused_view,
211 new_focused_view);
214 ViewTreeImpl* owning_connection_new = nullptr;
215 ViewTreeImpl* embedded_connection_new = nullptr;
216 if (new_focused_view) {
217 owning_connection_new = connection_manager_->GetConnection(
218 new_focused_view->id().connection_id);
219 if (owning_connection_new &&
220 owning_connection_new != owning_connection_old &&
221 owning_connection_new != embedded_connection_old) {
222 owning_connection_new->ProcessFocusChanged(old_focused_view,
223 new_focused_view);
225 embedded_connection_new =
226 connection_manager_->GetConnectionWithRoot(new_focused_view->id());
227 if (embedded_connection_new &&
228 embedded_connection_new != owning_connection_old &&
229 embedded_connection_new != embedded_connection_old) {
230 DCHECK_NE(owning_connection_new, embedded_connection_new);
231 embedded_connection_new->ProcessFocusChanged(old_focused_view,
232 new_focused_view);
236 // Ensure that we always notify the root connection of a focus change.
237 ViewTreeImpl* root_tree = GetViewTree();
238 if (root_tree != owning_connection_old &&
239 root_tree != embedded_connection_old &&
240 root_tree != owning_connection_new &&
241 root_tree != embedded_connection_new) {
242 root_tree->ProcessFocusChanged(old_focused_view, new_focused_view);
245 UpdateTextInputState(new_focused_view, new_focused_view->text_input_state());
248 } // namespace mus