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/view_manager/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/view_manager/display_manager_factory.h"
14 #include "components/view_manager/gles2/gpu_state.h"
15 #include "components/view_manager/public/interfaces/gpu.mojom.h"
16 #include "components/view_manager/public/interfaces/quads.mojom.h"
17 #include "components/view_manager/public/interfaces/surfaces.mojom.h"
18 #include "components/view_manager/server_view.h"
19 #include "components/view_manager/surfaces/surfaces_state.h"
20 #include "components/view_manager/view_coordinate_conversions.h"
21 #include "mojo/application/public/cpp/application_connection.h"
22 #include "mojo/application/public/cpp/application_impl.h"
23 #include "mojo/converters/geometry/geometry_type_converters.h"
24 #include "mojo/converters/input_events/input_events_type_converters.h"
25 #include "mojo/converters/input_events/mojo_extended_key_event_data.h"
26 #include "mojo/converters/surfaces/surfaces_type_converters.h"
27 #include "mojo/converters/surfaces/surfaces_utils.h"
28 #include "mojo/converters/transform/transform_type_converters.h"
29 #include "third_party/skia/include/core/SkXfermode.h"
30 #include "ui/events/event.h"
31 #include "ui/events/event_utils.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"
47 namespace view_manager
{
50 void DrawViewTree(cc::RenderPass
* pass
,
51 const ServerView
* view
,
52 const gfx::Vector2d
& parent_to_root_origin_offset
,
57 const gfx::Rect absolute_bounds
=
58 view
->bounds() + parent_to_root_origin_offset
;
59 std::vector
<const ServerView
*> children(view
->GetChildren());
60 const float combined_opacity
= opacity
* view
->opacity();
61 for (std::vector
<const ServerView
*>::reverse_iterator it
= children
.rbegin();
62 it
!= children
.rend();
64 DrawViewTree(pass
, *it
, absolute_bounds
.OffsetFromOrigin(),
68 gfx::Transform quad_to_target_transform
;
69 quad_to_target_transform
.Translate(absolute_bounds
.x(), absolute_bounds
.y());
70 const gfx::Rect
bounds_at_origin(view
->bounds().size());
71 cc::SharedQuadState
* sqs
= pass
->CreateAndAppendSharedQuadState();
72 // TODO(fsamuel): These clipping and visible rects are incorrect. They need
73 // to be populated from CompositorFrame structs.
74 sqs
->SetAll(quad_to_target_transform
,
75 bounds_at_origin
.size() /* layer_bounds */,
76 bounds_at_origin
/* visible_layer_bounds */,
77 bounds_at_origin
/* clip_rect */,
78 false /* is_clipped */,
80 SkXfermode::kSrc_Mode
,
81 0 /* sorting-context_id */);
84 pass
->CreateAndAppendDrawQuad
<cc::SurfaceDrawQuad
>();
85 surface_quad
->SetNew(sqs
,
86 bounds_at_origin
/* rect */,
87 bounds_at_origin
/* visible_rect */,
91 float ConvertUIWheelValueToMojoValue(int offset
) {
92 // Mojo's event type takes a value between -1 and 1. Normalize by allowing
93 // up to 20 of ui's offset. This is a bit arbitrary.
95 -1.0f
, std::min(1.0f
, static_cast<float>(offset
) /
96 (20 * static_cast<float>(
97 ui::MouseWheelEvent::kWheelDelta
))));
103 DisplayManagerFactory
* DisplayManager::factory_
= nullptr;
106 DisplayManager
* DisplayManager::Create(
108 mojo::ApplicationImpl
* app_impl
,
109 const scoped_refptr
<gles2::GpuState
>& gpu_state
,
110 const scoped_refptr
<surfaces::SurfacesState
>& surfaces_state
) {
112 return factory_
->CreateDisplayManager(is_headless
, app_impl
, gpu_state
,
115 return new DefaultDisplayManager(is_headless
, app_impl
, gpu_state
,
119 DefaultDisplayManager::DefaultDisplayManager(
121 mojo::ApplicationImpl
* app_impl
,
122 const scoped_refptr
<gles2::GpuState
>& gpu_state
,
123 const scoped_refptr
<surfaces::SurfacesState
>& surfaces_state
)
124 : is_headless_(is_headless
),
126 gpu_state_(gpu_state
),
127 surfaces_state_(surfaces_state
),
129 draw_timer_(false, false),
130 frame_pending_(false) {
131 metrics_
.size_in_pixels
= mojo::Size::New();
132 metrics_
.size_in_pixels
->width
= 800;
133 metrics_
.size_in_pixels
->height
= 600;
136 void DefaultDisplayManager::Init(DisplayManagerDelegate
* delegate
) {
137 delegate_
= delegate
;
139 gfx::Rect
bounds(metrics_
.size_in_pixels
.To
<gfx::Size
>());
141 platform_window_
.reset(new ui::StubWindow(this));
144 platform_window_
.reset(new ui::WinWindow(this, bounds
));
145 #elif defined(USE_X11)
146 platform_window_
.reset(new ui::X11Window(this));
147 #elif defined(OS_ANDROID)
148 platform_window_
.reset(new ui::PlatformWindowAndroid(this));
150 NOTREACHED() << "Unsupported platform";
153 platform_window_
->SetBounds(bounds
);
154 platform_window_
->Show();
157 DefaultDisplayManager::~DefaultDisplayManager() {
158 // Destroy the PlatformWindow early on as it may call us back during
159 // destruction and we want to be in a known state.
160 platform_window_
.reset();
163 void DefaultDisplayManager::SchedulePaint(const ServerView
* view
,
164 const gfx::Rect
& bounds
) {
166 if (!view
->IsDrawn())
168 const gfx::Rect root_relative_rect
=
169 ConvertRectBetweenViews(view
, delegate_
->GetRootView(), bounds
);
170 if (root_relative_rect
.IsEmpty())
172 dirty_rect_
.Union(root_relative_rect
);
176 void DefaultDisplayManager::SetViewportSize(const gfx::Size
& size
) {
177 platform_window_
->SetBounds(gfx::Rect(size
));
180 const mojo::ViewportMetrics
& DefaultDisplayManager::GetViewportMetrics() {
184 void DefaultDisplayManager::UpdateTextInputState(
185 const ui::TextInputState
& state
) {
186 ui::PlatformImeController
* ime
= platform_window_
->GetPlatformImeController();
188 ime
->UpdateTextInputState(state
);
191 void DefaultDisplayManager::SetImeVisibility(bool visible
) {
192 ui::PlatformImeController
* ime
= platform_window_
->GetPlatformImeController();
194 ime
->SetImeVisibility(visible
);
197 void DefaultDisplayManager::Draw() {
198 if (!delegate_
->GetRootView()->visible())
201 scoped_ptr
<cc::RenderPass
> render_pass
= cc::RenderPass::Create();
202 render_pass
->damage_rect
= dirty_rect_
;
203 render_pass
->output_rect
= gfx::Rect(metrics_
.size_in_pixels
.To
<gfx::Size
>());
205 DrawViewTree(render_pass
.get(),
206 delegate_
->GetRootView(),
207 gfx::Vector2d(), 1.0f
);
209 scoped_ptr
<cc::DelegatedFrameData
> frame_data(new cc::DelegatedFrameData
);
210 frame_data
->device_scale_factor
= 1.f
;
211 frame_data
->render_pass_list
.push_back(render_pass
.Pass());
213 scoped_ptr
<cc::CompositorFrame
> frame(new cc::CompositorFrame
);
214 frame
->delegated_frame_data
= frame_data
.Pass();
215 frame_pending_
= true;
216 if (top_level_display_client_
) {
217 top_level_display_client_
->SubmitFrame(
219 base::Bind(&DefaultDisplayManager::DidDraw
, base::Unretained(this)));
221 dirty_rect_
= gfx::Rect();
224 void DefaultDisplayManager::DidDraw() {
225 frame_pending_
= false;
226 if (!dirty_rect_
.IsEmpty())
230 void DefaultDisplayManager::WantToDraw() {
231 if (draw_timer_
.IsRunning() || frame_pending_
)
235 FROM_HERE
, base::TimeDelta(),
236 base::Bind(&DefaultDisplayManager::Draw
, base::Unretained(this)));
239 void DefaultDisplayManager::UpdateMetrics(const gfx::Size
& size
,
240 float device_pixel_ratio
) {
241 if (metrics_
.size_in_pixels
.To
<gfx::Size
>() == size
&&
242 metrics_
.device_pixel_ratio
== device_pixel_ratio
)
244 mojo::ViewportMetrics old_metrics
;
245 old_metrics
.size_in_pixels
= metrics_
.size_in_pixels
.Clone();
246 old_metrics
.device_pixel_ratio
= metrics_
.device_pixel_ratio
;
248 metrics_
.size_in_pixels
= mojo::Size::From(size
);
249 metrics_
.device_pixel_ratio
= device_pixel_ratio
;
251 delegate_
->OnViewportMetricsChanged(old_metrics
, metrics_
);
254 void DefaultDisplayManager::OnBoundsChanged(const gfx::Rect
& new_bounds
) {
255 UpdateMetrics(new_bounds
.size(), metrics_
.device_pixel_ratio
);
258 void DefaultDisplayManager::OnDamageRect(const gfx::Rect
& damaged_region
) {
261 void DefaultDisplayManager::DispatchEvent(ui::Event
* event
) {
262 mojo::EventPtr
mojo_event(mojo::Event::From(*event
));
263 if (event
->IsMouseWheelEvent()) {
264 // Mojo's event type has a different meaning for wheel events. Convert
266 ui::MouseWheelEvent
* wheel_event
=
267 static_cast<ui::MouseWheelEvent
*>(event
);
268 DCHECK(mojo_event
->pointer_data
);
269 mojo_event
->pointer_data
->horizontal_wheel
=
270 ConvertUIWheelValueToMojoValue(wheel_event
->x_offset());
271 mojo_event
->pointer_data
->horizontal_wheel
=
272 ConvertUIWheelValueToMojoValue(wheel_event
->y_offset());
274 delegate_
->OnEvent(mojo_event
.Pass());
276 switch (event
->type()) {
277 case ui::ET_MOUSE_PRESSED
:
278 case ui::ET_TOUCH_PRESSED
:
279 platform_window_
->SetCapture();
281 case ui::ET_MOUSE_RELEASED
:
282 case ui::ET_TOUCH_RELEASED
:
283 platform_window_
->ReleaseCapture();
290 // We want to emulate the WM_CHAR generation behaviour of Windows.
292 // On Linux, we've previously inserted characters by having
293 // InputMethodAuraLinux take all key down events and send a character event
294 // to the TextInputClient. This causes a mismatch in code that has to be
295 // shared between Windows and Linux, including blink code. Now that we're
296 // trying to have one way of doing things, we need to standardize on and
297 // emulate Windows character events.
299 // This is equivalent to what we're doing in the current Linux port, but
300 // done once instead of done multiple times in different places.
301 if (event
->type() == ui::ET_KEY_PRESSED
) {
302 ui::KeyEvent
* key_press_event
= static_cast<ui::KeyEvent
*>(event
);
303 ui::KeyEvent
char_event(key_press_event
->GetCharacter(),
304 key_press_event
->key_code(),
305 key_press_event
->flags());
307 DCHECK_EQ(key_press_event
->GetCharacter(), char_event
.GetCharacter());
308 DCHECK_EQ(key_press_event
->key_code(), char_event
.key_code());
309 DCHECK_EQ(key_press_event
->flags(), char_event
.flags());
311 char_event
.SetExtendedKeyEventData(
312 make_scoped_ptr(new mojo::MojoExtendedKeyEventData(
313 key_press_event
->GetLocatedWindowsKeyboardCode(),
314 key_press_event
->GetText(),
315 key_press_event
->GetUnmodifiedText())));
316 char_event
.set_platform_keycode(key_press_event
->platform_keycode());
318 delegate_
->OnEvent(mojo::Event::From(char_event
));
323 void DefaultDisplayManager::OnCloseRequest() {
324 platform_window_
->Close();
327 void DefaultDisplayManager::OnClosed() {
328 delegate_
->OnDisplayClosed();
331 void DefaultDisplayManager::OnWindowStateChanged(
332 ui::PlatformWindowState new_state
) {
335 void DefaultDisplayManager::OnLostCapture() {
338 void DefaultDisplayManager::OnAcceleratedWidgetAvailable(
339 gfx::AcceleratedWidget widget
,
340 float device_pixel_ratio
) {
341 if (widget
!= gfx::kNullAcceleratedWidget
) {
342 top_level_display_client_
.reset(new surfaces::TopLevelDisplayClient(
343 widget
, gpu_state_
, surfaces_state_
));
345 UpdateMetrics(metrics_
.size_in_pixels
.To
<gfx::Size
>(), device_pixel_ratio
);
348 void DefaultDisplayManager::OnActivationChanged(bool active
) {
351 } // namespace view_manager