1 // Copyright 2014 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/display_manager.h"
7 #include "base/numerics/safe_conversions.h"
8 #include "cc/output/compositor_frame.h"
9 #include "cc/output/delegated_frame_data.h"
10 #include "cc/quads/render_pass.h"
11 #include "cc/quads/shared_quad_state.h"
12 #include "cc/quads/surface_draw_quad.h"
13 #include "components/mus/display_manager_factory.h"
14 #include "components/mus/gles2/gpu_state.h"
15 #include "components/mus/public/interfaces/gpu.mojom.h"
16 #include "components/mus/public/interfaces/quads.mojom.h"
17 #include "components/mus/server_view.h"
18 #include "components/mus/surfaces/surfaces_state.h"
19 #include "components/mus/view_coordinate_conversions.h"
20 #include "mojo/application/public/cpp/application_connection.h"
21 #include "mojo/application/public/cpp/application_impl.h"
22 #include "mojo/converters/geometry/geometry_type_converters.h"
23 #include "mojo/converters/input_events/input_events_type_converters.h"
24 #include "mojo/converters/input_events/mojo_extended_key_event_data.h"
25 #include "mojo/converters/surfaces/surfaces_type_converters.h"
26 #include "mojo/converters/surfaces/surfaces_utils.h"
27 #include "mojo/converters/transform/transform_type_converters.h"
28 #include "third_party/skia/include/core/SkXfermode.h"
29 #include "ui/events/event.h"
30 #include "ui/events/event_utils.h"
31 #include "ui/gfx/display.h"
32 #include "ui/platform_window/platform_ime_controller.h"
33 #include "ui/platform_window/platform_window.h"
34 #include "ui/platform_window/stub/stub_window.h"
37 #include "ui/platform_window/win/win_window.h"
38 #elif defined(USE_X11)
39 #include "ui/platform_window/x11/x11_window.h"
40 #elif defined(OS_ANDROID)
41 #include "ui/platform_window/android/platform_window_android.h"
50 // DrawViewTree recursively visits ServerViews, creating a SurfaceDrawQuad for
51 // each that lacks one. For Views that already have CompositorFrames, we can
52 // skip this step and let cc::SurfaceAggregator do the heavy lifting.
53 // |skip_view| indicates whether or not we should generate a SurfaceDrawQuad
54 // for the provided |view|.
55 void DrawViewTree(cc::RenderPass
* pass
,
56 const ServerView
* view
,
57 const gfx::Vector2d
& parent_to_root_origin_offset
,
63 const gfx::Rect absolute_bounds
=
64 view
->bounds() + parent_to_root_origin_offset
;
66 std::vector
<const ServerView
*> children(view
->GetChildren());
67 // TODO(rjkroege, fsamuel): Make sure we're handling alpha correctly.
68 const float combined_opacity
= opacity
* view
->opacity();
69 for (auto it
= children
.rbegin(); it
!= children
.rend(); ++it
) {
70 DrawViewTree(pass
, *it
, absolute_bounds
.OffsetFromOrigin(),
73 !view
->surface_id().is_null() /* skip_view */);
76 if (skip_view
|| view
->surface_id().is_null())
79 gfx::Transform quad_to_target_transform
;
80 quad_to_target_transform
.Translate(absolute_bounds
.x(), absolute_bounds
.y());
81 gfx::Rect
bounds_at_origin(view
->bounds().size());
83 cc::SharedQuadState
* sqs
= pass
->CreateAndAppendSharedQuadState();
84 // TODO(fsamuel): These clipping and visible rects are incorrect. They need
85 // to be populated from CompositorFrame structs.
87 quad_to_target_transform
, bounds_at_origin
.size() /* layer_bounds */,
88 bounds_at_origin
/* visible_layer_bounds */,
89 bounds_at_origin
/* clip_rect */, false /* is_clipped */, view
->opacity(),
90 SkXfermode::kSrc_Mode
, 0 /* sorting-context_id */);
92 auto surface_quad
= pass
->CreateAndAppendDrawQuad
<cc::SurfaceDrawQuad
>();
93 surface_quad
->SetNew(sqs
, bounds_at_origin
/* rect */,
94 bounds_at_origin
/* visible_rect */, view
->surface_id());
100 DisplayManagerFactory
* DisplayManager::factory_
= nullptr;
103 DisplayManager
* DisplayManager::Create(
105 mojo::ApplicationImpl
* app_impl
,
106 const scoped_refptr
<GpuState
>& gpu_state
,
107 const scoped_refptr
<SurfacesState
>& surfaces_state
) {
109 return factory_
->CreateDisplayManager(is_headless
, app_impl
, gpu_state
,
112 return new DefaultDisplayManager(is_headless
, app_impl
, gpu_state
,
116 DefaultDisplayManager::DefaultDisplayManager(
118 mojo::ApplicationImpl
* app_impl
,
119 const scoped_refptr
<GpuState
>& gpu_state
,
120 const scoped_refptr
<SurfacesState
>& surfaces_state
)
121 : is_headless_(is_headless
),
123 gpu_state_(gpu_state
),
124 surfaces_state_(surfaces_state
),
126 draw_timer_(false, false),
127 frame_pending_(false),
128 weak_factory_(this) {
129 metrics_
.size_in_pixels
= mojo::Size::New();
130 metrics_
.size_in_pixels
->width
= 800;
131 metrics_
.size_in_pixels
->height
= 600;
134 void DefaultDisplayManager::Init(DisplayManagerDelegate
* delegate
) {
135 delegate_
= delegate
;
137 gfx::Rect
bounds(metrics_
.size_in_pixels
.To
<gfx::Size
>());
139 platform_window_
.reset(new ui::StubWindow(this));
142 platform_window_
.reset(new ui::WinWindow(this, bounds
));
143 #elif defined(USE_X11)
144 platform_window_
.reset(new ui::X11Window(this));
145 #elif defined(OS_ANDROID)
146 platform_window_
.reset(new ui::PlatformWindowAndroid(this));
148 NOTREACHED() << "Unsupported platform";
151 platform_window_
->SetBounds(bounds
);
152 platform_window_
->Show();
155 DefaultDisplayManager::~DefaultDisplayManager() {
156 // Invalidate WeakPtrs now to avoid callbacks back into the
157 // DefaultDisplayManager during destruction of |top_level_display_client_|.
158 weak_factory_
.InvalidateWeakPtrs();
159 top_level_display_client_
.reset();
160 // Destroy the PlatformWindow early on as it may call us back during
161 // destruction and we want to be in a known state. But destroy the surface
162 // first because it can still be using the platform window.
163 platform_window_
.reset();
166 void DefaultDisplayManager::SchedulePaint(const ServerView
* view
,
167 const gfx::Rect
& bounds
) {
169 if (!view
->IsDrawn())
171 const gfx::Rect root_relative_rect
=
172 ConvertRectBetweenViews(view
, delegate_
->GetRootView(), bounds
);
173 if (root_relative_rect
.IsEmpty())
175 dirty_rect_
.Union(root_relative_rect
);
179 void DefaultDisplayManager::SetViewportSize(const gfx::Size
& size
) {
180 platform_window_
->SetBounds(gfx::Rect(size
));
183 void DefaultDisplayManager::SetTitle(const base::string16
& title
) {
184 platform_window_
->SetTitle(title
);
187 const mojo::ViewportMetrics
& DefaultDisplayManager::GetViewportMetrics() {
191 void DefaultDisplayManager::UpdateTextInputState(
192 const ui::TextInputState
& state
) {
193 ui::PlatformImeController
* ime
= platform_window_
->GetPlatformImeController();
195 ime
->UpdateTextInputState(state
);
198 void DefaultDisplayManager::SetImeVisibility(bool visible
) {
199 ui::PlatformImeController
* ime
= platform_window_
->GetPlatformImeController();
201 ime
->SetImeVisibility(visible
);
204 void DefaultDisplayManager::Draw() {
205 if (!delegate_
->GetRootView()->visible())
208 // TODO(fsamuel): We should add a trace for generating a top level frame.
209 scoped_ptr
<cc::CompositorFrame
> frame(GenerateCompositorFrame());
210 frame_pending_
= true;
211 if (top_level_display_client_
) {
212 top_level_display_client_
->SubmitCompositorFrame(
213 frame
.Pass(), base::Bind(&DefaultDisplayManager::DidDraw
,
214 weak_factory_
.GetWeakPtr()));
216 dirty_rect_
= gfx::Rect();
219 void DefaultDisplayManager::DidDraw() {
220 frame_pending_
= false;
221 if (!dirty_rect_
.IsEmpty())
225 void DefaultDisplayManager::WantToDraw() {
226 if (draw_timer_
.IsRunning() || frame_pending_
)
230 FROM_HERE
, base::TimeDelta(),
231 base::Bind(&DefaultDisplayManager::Draw
, weak_factory_
.GetWeakPtr()));
234 void DefaultDisplayManager::UpdateMetrics(const gfx::Size
& size
,
235 float device_pixel_ratio
) {
236 if (gfx::Display::HasForceDeviceScaleFactor())
237 device_pixel_ratio
= gfx::Display::GetForcedDeviceScaleFactor();
238 if (metrics_
.size_in_pixels
.To
<gfx::Size
>() == size
&&
239 metrics_
.device_pixel_ratio
== device_pixel_ratio
)
241 mojo::ViewportMetrics old_metrics
;
242 old_metrics
.size_in_pixels
= metrics_
.size_in_pixels
.Clone();
243 old_metrics
.device_pixel_ratio
= metrics_
.device_pixel_ratio
;
245 metrics_
.size_in_pixels
= mojo::Size::From(size
);
246 metrics_
.device_pixel_ratio
= device_pixel_ratio
;
248 delegate_
->OnViewportMetricsChanged(old_metrics
, metrics_
);
251 scoped_ptr
<cc::CompositorFrame
>
252 DefaultDisplayManager::GenerateCompositorFrame() {
253 scoped_ptr
<cc::RenderPass
> render_pass
= cc::RenderPass::Create();
254 render_pass
->damage_rect
= dirty_rect_
;
255 render_pass
->output_rect
= gfx::Rect(metrics_
.size_in_pixels
.To
<gfx::Size
>());
257 DrawViewTree(render_pass
.get(),
258 delegate_
->GetRootView(),
259 gfx::Vector2d(), 1.0f
,
260 false /* skip_view */);
262 scoped_ptr
<cc::DelegatedFrameData
> frame_data(new cc::DelegatedFrameData
);
263 frame_data
->device_scale_factor
= metrics_
.device_pixel_ratio
;
264 frame_data
->render_pass_list
.push_back(render_pass
.Pass());
266 scoped_ptr
<cc::CompositorFrame
> frame(new cc::CompositorFrame
);
267 frame
->delegated_frame_data
= frame_data
.Pass();
271 const cc::CompositorFrame
*
272 DefaultDisplayManager::GetLastCompositorFrame() const {
273 if (!top_level_display_client_
)
276 return top_level_display_client_
->GetLastCompositorFrame();
279 void DefaultDisplayManager::OnBoundsChanged(const gfx::Rect
& new_bounds
) {
280 UpdateMetrics(new_bounds
.size(), metrics_
.device_pixel_ratio
);
283 void DefaultDisplayManager::OnDamageRect(const gfx::Rect
& damaged_region
) {
284 dirty_rect_
.Union(damaged_region
);
288 void DefaultDisplayManager::DispatchEvent(ui::Event
* event
) {
289 mojo::EventPtr
mojo_event(mojo::Event::From(*event
));
291 if (event
->IsLocatedEvent() && !!top_level_display_client_
) {
292 ui::LocatedEvent
* located_event
= static_cast<ui::LocatedEvent
*>(event
);
293 gfx::Point transformed_point
;
294 cc::SurfaceId target_surface
=
295 surfaces_state_
->hit_tester()->GetTargetSurfaceAtPoint(
296 top_level_display_client_
->surface_id(),
297 located_event
->location(),
299 id
= ViewIdFromTransportId(
300 cc::SurfaceIdAllocator::NamespaceForId(target_surface
));
302 mojo::LocationData
* location
= nullptr;
303 if (mojo_event
->pointer_data
)
304 location
= mojo_event
->pointer_data
->location
.get();
305 else if (mojo_event
->wheel_data
)
306 location
= mojo_event
->wheel_data
->location
.get();
309 location
->x
= transformed_point
.x();
310 location
->y
= transformed_point
.y();
312 delegate_
->OnEvent(id
, mojo_event
.Pass());
314 switch (event
->type()) {
315 case ui::ET_MOUSE_PRESSED
:
316 case ui::ET_TOUCH_PRESSED
:
317 platform_window_
->SetCapture();
319 case ui::ET_MOUSE_RELEASED
:
320 case ui::ET_TOUCH_RELEASED
:
321 platform_window_
->ReleaseCapture();
328 // We want to emulate the WM_CHAR generation behaviour of Windows.
330 // On Linux, we've previously inserted characters by having
331 // InputMethodAuraLinux take all key down events and send a character event
332 // to the TextInputClient. This causes a mismatch in code that has to be
333 // shared between Windows and Linux, including blink code. Now that we're
334 // trying to have one way of doing things, we need to standardize on and
335 // emulate Windows character events.
337 // This is equivalent to what we're doing in the current Linux port, but
338 // done once instead of done multiple times in different places.
339 if (event
->type() == ui::ET_KEY_PRESSED
) {
340 ui::KeyEvent
* key_press_event
= static_cast<ui::KeyEvent
*>(event
);
341 ui::KeyEvent
char_event(key_press_event
->GetCharacter(),
342 key_press_event
->key_code(),
343 key_press_event
->flags());
345 DCHECK_EQ(key_press_event
->GetCharacter(), char_event
.GetCharacter());
346 DCHECK_EQ(key_press_event
->key_code(), char_event
.key_code());
347 DCHECK_EQ(key_press_event
->flags(), char_event
.flags());
349 char_event
.SetExtendedKeyEventData(
350 make_scoped_ptr(new mojo::MojoExtendedKeyEventData(
351 key_press_event
->GetLocatedWindowsKeyboardCode(),
352 key_press_event
->GetText(), key_press_event
->GetUnmodifiedText())));
354 delegate_
->OnEvent(id
, mojo::Event::From(char_event
));
359 void DefaultDisplayManager::OnCloseRequest() {
360 platform_window_
->Close();
363 void DefaultDisplayManager::OnClosed() {
364 delegate_
->OnDisplayClosed();
367 void DefaultDisplayManager::OnWindowStateChanged(
368 ui::PlatformWindowState new_state
) {}
370 void DefaultDisplayManager::OnLostCapture() {}
372 void DefaultDisplayManager::OnAcceleratedWidgetAvailable(
373 gfx::AcceleratedWidget widget
,
374 float device_pixel_ratio
) {
375 if (widget
!= gfx::kNullAcceleratedWidget
) {
376 top_level_display_client_
.reset(
377 new TopLevelDisplayClient(widget
, gpu_state_
, surfaces_state_
));
379 UpdateMetrics(metrics_
.size_in_pixels
.To
<gfx::Size
>(), device_pixel_ratio
);
382 void DefaultDisplayManager::OnActivationChanged(bool active
) {}