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 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: 35 NativeViewportImpl(shell::Context* context) 36 : context_(context), 37 widget_(gfx::kNullAcceleratedWidget), 38 waiting_for_event_ack_(false), 39 weak_factory_(this) {} 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 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 54 virtual void Show() OVERRIDE { 55 native_viewport_->Show(); 56 } 57 58 virtual void Hide() OVERRIDE { 59 native_viewport_->Hide(); 60 } 61 62 virtual void Close() OVERRIDE { 63 command_buffer_.reset(); 64 DCHECK(native_viewport_); 65 native_viewport_->Close(); 66 } 67 68 virtual void SetBounds(RectPtr bounds) OVERRIDE { 69 native_viewport_->SetBounds(bounds.To<gfx::Rect>()); 70 } 71 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 82 void AckEvent() { 83 waiting_for_event_ack_ = false; 84 } 85 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 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 126 virtual void OnAcceleratedWidgetAvailable( 127 gfx::AcceleratedWidget widget) OVERRIDE { 128 widget_ = widget; 129 CreateCommandBufferIfNeeded(); 130 } 131 132 virtual void OnBoundsChanged(const gfx::Rect& bounds) OVERRIDE { 133 CreateCommandBufferIfNeeded(); 134 client()->OnBoundsChanged(Rect::From(bounds)); 135 } 136 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* 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