1 // Copyright 2013 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 "mojo/services/native_viewport/native_viewport_service.h"
7 #include "base/macros.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/time/time.h"
10 #include "mojo/public/cpp/bindings/allocation_scope.h"
11 #include "mojo/public/interfaces/shell/shell.mojom.h"
12 #include "mojo/services/gles2/command_buffer_impl.h"
13 #include "mojo/services/native_viewport/geometry_conversions.h"
14 #include "mojo/services/native_viewport/native_viewport.h"
15 #include "mojo/services/native_viewport/native_viewport.mojom.h"
16 #include "ui/events/event.h"
22 bool IsRateLimitedEventType(ui::Event* event) {
23 return event->type() == ui::ET_MOUSE_MOVED ||
24 event->type() == ui::ET_MOUSE_DRAGGED ||
25 event->type() == ui::ET_TOUCH_MOVED;
30 class NativeViewportImpl
31 : public ServiceConnection<mojo::NativeViewport,
34 public NativeViewportDelegate {
38 widget_(gfx::kNullAcceleratedWidget),
39 waiting_for_event_ack_(false) {}
40 virtual ~NativeViewportImpl() {
41 // Destroy the NativeViewport early on as it may call us back during
42 // destruction and we want to be in a known state.
43 native_viewport_.reset();
46 virtual void SetClient(NativeViewportClient* client) OVERRIDE {
50 virtual void Create(const Rect& bounds) OVERRIDE {
52 services::NativeViewport::Create(context(), this);
53 native_viewport_->Init(bounds);
55 OnBoundsChanged(bounds);
58 virtual void Show() OVERRIDE {
59 native_viewport_->Show();
62 virtual void Hide() OVERRIDE {
63 native_viewport_->Hide();
66 virtual void Close() OVERRIDE {
67 command_buffer_.reset();
68 DCHECK(native_viewport_);
69 native_viewport_->Close();
72 virtual void SetBounds(const Rect& bounds) OVERRIDE {
73 gfx::Rect gfx_bounds(bounds.position().x(), bounds.position().y(),
74 bounds.size().width(), bounds.size().height());
75 native_viewport_->SetBounds(gfx_bounds);
78 virtual void CreateGLES2Context(ScopedMessagePipeHandle client_handle)
80 if (command_buffer_.get() || command_buffer_handle_.is_valid()) {
81 LOG(ERROR) << "Can't create multiple contexts on a NativeViewport";
85 // TODO(darin): CreateGLES2Context should accept a |CommandBufferPtr*|.
86 command_buffer_handle_ = client_handle.Pass();
88 CreateCommandBufferIfNeeded();
92 waiting_for_event_ack_ = false;
95 void CreateCommandBufferIfNeeded() {
96 if (!command_buffer_handle_.is_valid())
98 DCHECK(!command_buffer_.get());
99 if (widget_ == gfx::kNullAcceleratedWidget)
101 gfx::Size size = native_viewport_->GetSize();
104 command_buffer_.reset(
105 BindToPipe(new CommandBufferImpl(widget_, native_viewport_->GetSize()),
106 command_buffer_handle_.Pass()));
109 virtual bool OnEvent(ui::Event* ui_event) OVERRIDE {
110 // Must not return early before updating capture.
111 switch (ui_event->type()) {
112 case ui::ET_MOUSE_PRESSED:
113 case ui::ET_TOUCH_PRESSED:
114 native_viewport_->SetCapture();
116 case ui::ET_MOUSE_RELEASED:
117 case ui::ET_TOUCH_RELEASED:
118 native_viewport_->ReleaseCapture();
124 if (waiting_for_event_ack_ && IsRateLimitedEventType(ui_event))
127 AllocationScope scope;
129 Event::Builder event;
130 event.set_action(ui_event->type());
131 event.set_flags(ui_event->flags());
132 event.set_time_stamp(ui_event->time_stamp().ToInternalValue());
134 if (ui_event->IsMouseEvent() || ui_event->IsTouchEvent()) {
135 ui::LocatedEvent* located_event =
136 static_cast<ui::LocatedEvent*>(ui_event);
137 Point::Builder location;
138 location.set_x(located_event->location().x());
139 location.set_y(located_event->location().y());
140 event.set_location(location.Finish());
143 if (ui_event->IsTouchEvent()) {
144 ui::TouchEvent* touch_event = static_cast<ui::TouchEvent*>(ui_event);
145 TouchData::Builder touch_data;
146 touch_data.set_pointer_id(touch_event->touch_id());
147 event.set_touch_data(touch_data.Finish());
148 } else if (ui_event->IsKeyEvent()) {
149 ui::KeyEvent* key_event = static_cast<ui::KeyEvent*>(ui_event);
150 KeyData::Builder key_data;
151 key_data.set_key_code(key_event->key_code());
152 key_data.set_is_char(key_event->is_char());
153 event.set_key_data(key_data.Finish());
156 client_->OnEvent(event.Finish(),
157 base::Bind(&NativeViewportImpl::AckEvent,
158 base::Unretained(this)));
159 waiting_for_event_ack_ = true;
163 virtual void OnAcceleratedWidgetAvailable(
164 gfx::AcceleratedWidget widget) OVERRIDE {
166 CreateCommandBufferIfNeeded();
169 virtual void OnBoundsChanged(const gfx::Rect& bounds) OVERRIDE {
170 CreateCommandBufferIfNeeded();
171 AllocationScope scope;
172 client_->OnBoundsChanged(bounds);
175 virtual void OnDestroyed() OVERRIDE {
176 command_buffer_.reset();
177 client_->OnDestroyed();
178 base::MessageLoop::current()->Quit();
182 NativeViewportClient* client_;
183 gfx::AcceleratedWidget widget_;
184 scoped_ptr<services::NativeViewport> native_viewport_;
185 ScopedMessagePipeHandle command_buffer_handle_;
186 scoped_ptr<CommandBufferImpl> command_buffer_;
187 bool waiting_for_event_ack_;
190 } // namespace services
194 MOJO_NATIVE_VIEWPORT_EXPORT mojo::Application*
195 CreateNativeViewportService(mojo::shell::Context* context,
196 mojo::ScopedMessagePipeHandle shell_handle) {
197 mojo::Application* app = new mojo::Application(shell_handle.Pass());
198 app->AddServiceConnector(
199 new mojo::ServiceConnector<mojo::services::NativeViewportImpl,
200 mojo::shell::Context>(context));