Home | History | Annotate | Download | only in native_viewport
      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