Upstream version 7.36.149.0
[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/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"
17
18 namespace mojo {
19 namespace services {
20 namespace {
21
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;
26 }
27
28 }
29
30 class NativeViewportImpl
31     : public ServiceConnection<mojo::NativeViewport,
32                                NativeViewportImpl,
33                                shell::Context>,
34       public NativeViewportDelegate {
35  public:
36   NativeViewportImpl()
37       : client_(NULL),
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();
44   }
45
46   virtual void SetClient(NativeViewportClient* client) OVERRIDE {
47     client_ = client;
48   }
49
50   virtual void Create(const Rect& bounds) OVERRIDE {
51     native_viewport_ =
52         services::NativeViewport::Create(context(), this);
53     native_viewport_->Init(bounds);
54     client_->OnCreated();
55     OnBoundsChanged(bounds);
56   }
57
58   virtual void Show() OVERRIDE {
59     native_viewport_->Show();
60   }
61
62   virtual void Hide() OVERRIDE {
63     native_viewport_->Hide();
64   }
65
66   virtual void Close() OVERRIDE {
67     command_buffer_.reset();
68     DCHECK(native_viewport_);
69     native_viewport_->Close();
70   }
71
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);
76   }
77
78   virtual void CreateGLES2Context(ScopedMessagePipeHandle client_handle)
79       OVERRIDE {
80     if (command_buffer_.get() || command_buffer_handle_.is_valid()) {
81       LOG(ERROR) << "Can't create multiple contexts on a NativeViewport";
82       return;
83     }
84
85     // TODO(darin): CreateGLES2Context should accept a |CommandBufferPtr*|.
86     command_buffer_handle_ = client_handle.Pass();
87
88     CreateCommandBufferIfNeeded();
89   }
90
91   void AckEvent() {
92     waiting_for_event_ack_ = false;
93   }
94
95   void CreateCommandBufferIfNeeded() {
96     if (!command_buffer_handle_.is_valid())
97       return;
98     DCHECK(!command_buffer_.get());
99     if (widget_ == gfx::kNullAcceleratedWidget)
100       return;
101     gfx::Size size = native_viewport_->GetSize();
102     if (size.IsEmpty())
103       return;
104     command_buffer_.reset(
105         BindToPipe(new CommandBufferImpl(widget_, native_viewport_->GetSize()),
106                    command_buffer_handle_.Pass()));
107   }
108
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();
115       break;
116     case ui::ET_MOUSE_RELEASED:
117     case ui::ET_TOUCH_RELEASED:
118       native_viewport_->ReleaseCapture();
119       break;
120     default:
121       break;
122     }
123
124     if (waiting_for_event_ack_ && IsRateLimitedEventType(ui_event))
125       return false;
126
127     AllocationScope scope;
128
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());
133
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());
141     }
142
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());
154     }
155
156     client_->OnEvent(event.Finish(),
157                      base::Bind(&NativeViewportImpl::AckEvent,
158                                 base::Unretained(this)));
159     waiting_for_event_ack_ = true;
160     return false;
161   }
162
163   virtual void OnAcceleratedWidgetAvailable(
164       gfx::AcceleratedWidget widget) OVERRIDE {
165     widget_ = widget;
166     CreateCommandBufferIfNeeded();
167   }
168
169   virtual void OnBoundsChanged(const gfx::Rect& bounds) OVERRIDE {
170     CreateCommandBufferIfNeeded();
171     AllocationScope scope;
172     client_->OnBoundsChanged(bounds);
173   }
174
175   virtual void OnDestroyed() OVERRIDE {
176     command_buffer_.reset();
177     client_->OnDestroyed();
178     base::MessageLoop::current()->Quit();
179   }
180
181  private:
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_;
188 };
189
190 }  // namespace services
191 }  // namespace mojo
192
193
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));
201   return app;
202 }
203