3d42382c4e5c7df617d096c2fd800dbbecf9df4c
[platform/framework/web/crosswalk.git] / src / mojo / services / native_viewport / native_viewport_service.cc
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.
4
5 #include "mojo/services/native_viewport/native_viewport_service.h"
6
7 #include "base/message_loop/message_loop.h"
8 #include "base/time/time.h"
9 #include "mojo/services/gles2/gles2_impl.h"
10 #include "mojo/services/native_viewport/geometry_conversions.h"
11 #include "mojo/services/native_viewport/native_viewport.h"
12 #include "mojom/native_viewport.h"
13 #include "ui/events/event.h"
14
15 namespace mojo {
16 namespace services {
17 namespace {
18
19 bool IsRateLimitedEventType(ui::Event* event) {
20   return event->type() == ui::ET_MOUSE_MOVED ||
21          event->type() == ui::ET_MOUSE_DRAGGED ||
22          event->type() == ui::ET_TOUCH_MOVED;
23 }
24
25 }
26
27 class NativeViewportService::NativeViewportImpl
28     : public mojo::NativeViewport,
29       public NativeViewportDelegate {
30  public:
31   NativeViewportImpl(NativeViewportService* service,
32                      ScopedMessagePipeHandle client_handle)
33       : service_(service),
34         widget_(gfx::kNullAcceleratedWidget),
35         waiting_for_event_ack_(false),
36         pending_event_timestamp_(0),
37         created_context_(false),
38         client_(client_handle.Pass(), this) {
39   }
40   virtual ~NativeViewportImpl() {}
41
42   virtual void Create(const Rect& bounds) MOJO_OVERRIDE {
43     native_viewport_ =
44         services::NativeViewport::Create(service_->context_, this);
45     native_viewport_->Init(bounds);
46     client_->OnCreated();
47   }
48
49   virtual void Show() MOJO_OVERRIDE {
50     native_viewport_->Show();
51   }
52
53   virtual void Close() MOJO_OVERRIDE {
54     gles2_.reset();
55     DCHECK(native_viewport_);
56     native_viewport_->Close();
57   }
58
59   virtual void SetBounds(const Rect& bounds) MOJO_OVERRIDE {
60     gfx::Rect gfx_bounds(bounds.position().x(), bounds.position().y(),
61                          bounds.size().width(), bounds.size().height());
62     native_viewport_->SetBounds(gfx_bounds);
63   }
64
65   virtual void CreateGLES2Context(ScopedMessagePipeHandle client_handle)
66       MOJO_OVERRIDE {
67     gles2_.reset(new GLES2Impl(client_handle.Pass()));
68     CreateGLES2ContextIfNeeded();
69   }
70
71   virtual void AckEvent(const Event& event) MOJO_OVERRIDE {
72     DCHECK_EQ(event.time_stamp(), pending_event_timestamp_);
73     waiting_for_event_ack_ = false;
74   }
75
76   void CreateGLES2ContextIfNeeded() {
77     if (created_context_)
78       return;
79     if (widget_ == gfx::kNullAcceleratedWidget || !gles2_)
80       return;
81     gfx::Size size = native_viewport_->GetSize();
82     if (size.width() == 0 || size.height() == 0)
83       return;
84     gles2_->CreateContext(widget_, size);
85     created_context_ = true;
86   }
87
88   virtual bool OnEvent(ui::Event* ui_event) MOJO_OVERRIDE {
89     // Must not return early before updating capture.
90     switch (ui_event->type()) {
91     case ui::ET_MOUSE_PRESSED:
92     case ui::ET_TOUCH_PRESSED:
93       native_viewport_->SetCapture();
94       break;
95     case ui::ET_MOUSE_RELEASED:
96     case ui::ET_TOUCH_RELEASED:
97       native_viewport_->ReleaseCapture();
98       break;
99     default:
100       break;
101     }
102
103     if (waiting_for_event_ack_ && IsRateLimitedEventType(ui_event))
104       return false;
105
106     pending_event_timestamp_ = ui_event->time_stamp().ToInternalValue();
107     AllocationScope scope;
108
109     Event::Builder event;
110     event.set_action(ui_event->type());
111     event.set_flags(ui_event->flags());
112     event.set_time_stamp(pending_event_timestamp_);
113
114     if (ui_event->IsMouseEvent() || ui_event->IsTouchEvent()) {
115       ui::LocatedEvent* located_event =
116           static_cast<ui::LocatedEvent*>(ui_event);
117       Point::Builder location;
118       location.set_x(located_event->location().x());
119       location.set_y(located_event->location().y());
120       event.set_location(location.Finish());
121     }
122
123     if (ui_event->IsTouchEvent()) {
124       ui::TouchEvent* touch_event = static_cast<ui::TouchEvent*>(ui_event);
125       TouchData::Builder touch_data;
126       touch_data.set_pointer_id(touch_event->touch_id());
127       event.set_touch_data(touch_data.Finish());
128     } else if (ui_event->IsKeyEvent()) {
129       ui::KeyEvent* key_event = static_cast<ui::KeyEvent*>(ui_event);
130       KeyData::Builder key_data;
131       key_data.set_key_code(key_event->key_code());
132       key_data.set_is_char(key_event->is_char());
133       event.set_key_data(key_data.Finish());
134     }
135
136     client_->OnEvent(event.Finish());
137     waiting_for_event_ack_ = true;
138     return false;
139   }
140
141   virtual void OnAcceleratedWidgetAvailable(
142       gfx::AcceleratedWidget widget) MOJO_OVERRIDE {
143     widget_ = widget;
144     CreateGLES2ContextIfNeeded();
145   }
146
147   virtual void OnBoundsChanged(const gfx::Rect& bounds) MOJO_OVERRIDE {
148     CreateGLES2ContextIfNeeded();
149     client_->OnBoundsChanged(bounds);
150   }
151
152   virtual void OnDestroyed() MOJO_OVERRIDE {
153     // TODO(beng):
154     // Destroying |gles2_| on the shell thread here hits thread checker
155     // asserts. All code must stop touching the AcceleratedWidget at this
156     // point as it is dead after this call stack. jamesr said we probably
157     // should make our own GLSurface and simply tell it to stop touching the
158     // AcceleratedWidget via Destroy() but we have no good way of doing that
159     // right now given our current threading model so james' recommendation
160     // was just to wait until after we move the gl service out of process.
161     // gles2_.reset();
162     client_->OnDestroyed();
163     base::MessageLoop::current()->Quit();
164   }
165
166  private:
167   NativeViewportService* service_;
168   gfx::AcceleratedWidget widget_;
169   scoped_ptr<services::NativeViewport> native_viewport_;
170   scoped_ptr<GLES2Impl> gles2_;
171   bool waiting_for_event_ack_;
172   int64 pending_event_timestamp_;
173   bool created_context_;
174
175   RemotePtr<NativeViewportClient> client_;
176 };
177
178 NativeViewportService::NativeViewportService(
179     ScopedMessagePipeHandle shell_handle)
180     : shell_(shell_handle.Pass(), this),
181       context_(NULL) {
182 }
183
184 NativeViewportService::~NativeViewportService() {}
185
186 void NativeViewportService::AcceptConnection(
187     ScopedMessagePipeHandle client_handle) {
188   // TODO(davemoore): We need a mechanism to determine when connectors
189   // go away, so we can remove viewports correctly.
190   viewports_.push_back(new NativeViewportImpl(this, client_handle.Pass()));
191 }
192
193 }  // namespace services
194 }  // namespace mojo
195
196 #if defined(OS_ANDROID)
197
198 // Android will call this.
199 mojo::services::NativeViewportService*
200     CreateNativeViewportService(mojo::ScopedMessagePipeHandle shell_handle) {
201   return new mojo::services::NativeViewportService(shell_handle.Pass());
202 }
203
204 #else
205
206 extern "C" MOJO_NATIVE_VIEWPORT_EXPORT MojoResult MojoMain(
207     const MojoHandle shell_handle) {
208   base::MessageLoopForUI loop;
209   mojo::services::NativeViewportService app(
210       mojo::MakeScopedHandle(mojo::MessagePipeHandle(shell_handle)).Pass());
211   base::MessageLoop::current()->Run();
212   return MOJO_RESULT_OK;
213 }
214
215 #endif // !OS_ANDROID