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/memory/weak_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/time/time.h"
11 #include "mojo/public/interfaces/service_provider/service_provider.mojom.h"
12 #include "mojo/services/gles2/command_buffer_impl.h"
13 #include "mojo/services/native_viewport/native_viewport.h"
14 #include "mojo/services/public/cpp/geometry/geometry_type_converters.h"
15 #include "mojo/services/public/cpp/input_events/input_events_type_converters.h"
16 #include "mojo/services/public/interfaces/native_viewport/native_viewport.mojom.h"
17 #include "ui/events/event.h"
18
19 namespace mojo {
20 namespace services {
21 namespace {
22
IsRateLimitedEventType(ui::Event * event)23 bool IsRateLimitedEventType(ui::Event* event) {
24 return event->type() == ui::ET_MOUSE_MOVED ||
25 event->type() == ui::ET_MOUSE_DRAGGED ||
26 event->type() == ui::ET_TOUCH_MOVED;
27 }
28
29 }
30
31 class NativeViewportImpl
32 : public InterfaceImpl<mojo::NativeViewport>,
33 public NativeViewportDelegate {
34 public:
NativeViewportImpl(shell::Context * context)35 NativeViewportImpl(shell::Context* context)
36 : context_(context),
37 widget_(gfx::kNullAcceleratedWidget),
38 waiting_for_event_ack_(false),
39 weak_factory_(this) {}
~NativeViewportImpl()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
Create(RectPtr bounds)46 virtual void Create(RectPtr bounds) OVERRIDE {
47 native_viewport_ =
48 services::NativeViewport::Create(context_, this);
49 native_viewport_->Init(bounds.To<gfx::Rect>());
50 client()->OnCreated();
51 OnBoundsChanged(bounds.To<gfx::Rect>());
52 }
53
Show()54 virtual void Show() OVERRIDE {
55 native_viewport_->Show();
56 }
57
Hide()58 virtual void Hide() OVERRIDE {
59 native_viewport_->Hide();
60 }
61
Close()62 virtual void Close() OVERRIDE {
63 command_buffer_.reset();
64 DCHECK(native_viewport_);
65 native_viewport_->Close();
66 }
67
SetBounds(RectPtr bounds)68 virtual void SetBounds(RectPtr bounds) OVERRIDE {
69 native_viewport_->SetBounds(bounds.To<gfx::Rect>());
70 }
71
CreateGLES2Context(InterfaceRequest<CommandBuffer> command_buffer_request)72 virtual void CreateGLES2Context(
73 InterfaceRequest<CommandBuffer> command_buffer_request) OVERRIDE {
74 if (command_buffer_.get() || command_buffer_request_.is_pending()) {
75 LOG(ERROR) << "Can't create multiple contexts on a NativeViewport";
76 return;
77 }
78 command_buffer_request_ = command_buffer_request.Pass();
79 CreateCommandBufferIfNeeded();
80 }
81
AckEvent()82 void AckEvent() {
83 waiting_for_event_ack_ = false;
84 }
85
CreateCommandBufferIfNeeded()86 void CreateCommandBufferIfNeeded() {
87 if (!command_buffer_request_.is_pending())
88 return;
89 DCHECK(!command_buffer_.get());
90 if (widget_ == gfx::kNullAcceleratedWidget)
91 return;
92 gfx::Size size = native_viewport_->GetSize();
93 if (size.IsEmpty())
94 return;
95 command_buffer_.reset(
96 new CommandBufferImpl(widget_, native_viewport_->GetSize()));
97 BindToRequest(command_buffer_.get(), &command_buffer_request_);
98 }
99
OnEvent(ui::Event * ui_event)100 virtual bool OnEvent(ui::Event* ui_event) OVERRIDE {
101 // Must not return early before updating capture.
102 switch (ui_event->type()) {
103 case ui::ET_MOUSE_PRESSED:
104 case ui::ET_TOUCH_PRESSED:
105 native_viewport_->SetCapture();
106 break;
107 case ui::ET_MOUSE_RELEASED:
108 case ui::ET_TOUCH_RELEASED:
109 native_viewport_->ReleaseCapture();
110 break;
111 default:
112 break;
113 }
114
115 if (waiting_for_event_ack_ && IsRateLimitedEventType(ui_event))
116 return false;
117
118 client()->OnEvent(
119 TypeConverter<EventPtr, ui::Event>::ConvertFrom(*ui_event),
120 base::Bind(&NativeViewportImpl::AckEvent,
121 weak_factory_.GetWeakPtr()));
122 waiting_for_event_ack_ = true;
123 return false;
124 }
125
OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget)126 virtual void OnAcceleratedWidgetAvailable(
127 gfx::AcceleratedWidget widget) OVERRIDE {
128 widget_ = widget;
129 CreateCommandBufferIfNeeded();
130 }
131
OnBoundsChanged(const gfx::Rect & bounds)132 virtual void OnBoundsChanged(const gfx::Rect& bounds) OVERRIDE {
133 CreateCommandBufferIfNeeded();
134 client()->OnBoundsChanged(Rect::From(bounds));
135 }
136
OnDestroyed()137 virtual void OnDestroyed() OVERRIDE {
138 command_buffer_.reset();
139 client()->OnDestroyed();
140 base::MessageLoop::current()->Quit();
141 }
142
143 private:
144 shell::Context* context_;
145 gfx::AcceleratedWidget widget_;
146 scoped_ptr<services::NativeViewport> native_viewport_;
147 InterfaceRequest<CommandBuffer> command_buffer_request_;
148 scoped_ptr<CommandBufferImpl> command_buffer_;
149 bool waiting_for_event_ack_;
150 base::WeakPtrFactory<NativeViewportImpl> weak_factory_;
151 };
152
153 } // namespace services
154 } // namespace mojo
155
156
157 MOJO_NATIVE_VIEWPORT_EXPORT mojo::Application*
CreateNativeViewportService(mojo::shell::Context * context,mojo::ScopedMessagePipeHandle service_provider_handle)158 CreateNativeViewportService(
159 mojo::shell::Context* context,
160 mojo::ScopedMessagePipeHandle service_provider_handle) {
161 mojo::Application* app = new mojo::Application(
162 service_provider_handle.Pass());
163 app->AddService<mojo::services::NativeViewportImpl>(context);
164 return app;
165 }
166