blob: 886c4dcb4b9cabaae14c67e22624ecbd171142c5 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "mojo/services/native_viewport/native_viewport_service.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/time/time.h"
#include "mojo/public/interfaces/service_provider/service_provider.mojom.h"
#include "mojo/services/gles2/command_buffer_impl.h"
#include "mojo/services/native_viewport/native_viewport.h"
#include "mojo/services/public/cpp/geometry/geometry_type_converters.h"
#include "mojo/services/public/cpp/input_events/input_events_type_converters.h"
#include "mojo/services/public/interfaces/native_viewport/native_viewport.mojom.h"
#include "ui/events/event.h"
namespace mojo {
namespace services {
namespace {
bool IsRateLimitedEventType(ui::Event* event) {
return event->type() == ui::ET_MOUSE_MOVED ||
event->type() == ui::ET_MOUSE_DRAGGED ||
event->type() == ui::ET_TOUCH_MOVED;
}
}
class NativeViewportImpl
: public InterfaceImpl<mojo::NativeViewport>,
public NativeViewportDelegate {
public:
NativeViewportImpl(shell::Context* context)
: context_(context),
widget_(gfx::kNullAcceleratedWidget),
waiting_for_event_ack_(false),
weak_factory_(this) {}
virtual ~NativeViewportImpl() {
// Destroy the NativeViewport early on as it may call us back during
// destruction and we want to be in a known state.
native_viewport_.reset();
}
virtual void Create(RectPtr bounds) OVERRIDE {
native_viewport_ =
services::NativeViewport::Create(context_, this);
native_viewport_->Init(bounds.To<gfx::Rect>());
client()->OnCreated();
OnBoundsChanged(bounds.To<gfx::Rect>());
}
virtual void Show() OVERRIDE {
native_viewport_->Show();
}
virtual void Hide() OVERRIDE {
native_viewport_->Hide();
}
virtual void Close() OVERRIDE {
command_buffer_.reset();
DCHECK(native_viewport_);
native_viewport_->Close();
}
virtual void SetBounds(RectPtr bounds) OVERRIDE {
native_viewport_->SetBounds(bounds.To<gfx::Rect>());
}
virtual void CreateGLES2Context(
InterfaceRequest<CommandBuffer> command_buffer_request) OVERRIDE {
if (command_buffer_.get() || command_buffer_request_.is_pending()) {
LOG(ERROR) << "Can't create multiple contexts on a NativeViewport";
return;
}
command_buffer_request_ = command_buffer_request.Pass();
CreateCommandBufferIfNeeded();
}
void AckEvent() {
waiting_for_event_ack_ = false;
}
void CreateCommandBufferIfNeeded() {
if (!command_buffer_request_.is_pending())
return;
DCHECK(!command_buffer_.get());
if (widget_ == gfx::kNullAcceleratedWidget)
return;
gfx::Size size = native_viewport_->GetSize();
if (size.IsEmpty())
return;
command_buffer_.reset(
new CommandBufferImpl(widget_, native_viewport_->GetSize()));
BindToRequest(command_buffer_.get(), &command_buffer_request_);
}
virtual bool OnEvent(ui::Event* ui_event) OVERRIDE {
// Must not return early before updating capture.
switch (ui_event->type()) {
case ui::ET_MOUSE_PRESSED:
case ui::ET_TOUCH_PRESSED:
native_viewport_->SetCapture();
break;
case ui::ET_MOUSE_RELEASED:
case ui::ET_TOUCH_RELEASED:
native_viewport_->ReleaseCapture();
break;
default:
break;
}
if (waiting_for_event_ack_ && IsRateLimitedEventType(ui_event))
return false;
client()->OnEvent(
TypeConverter<EventPtr, ui::Event>::ConvertFrom(*ui_event),
base::Bind(&NativeViewportImpl::AckEvent,
weak_factory_.GetWeakPtr()));
waiting_for_event_ack_ = true;
return false;
}
virtual void OnAcceleratedWidgetAvailable(
gfx::AcceleratedWidget widget) OVERRIDE {
widget_ = widget;
CreateCommandBufferIfNeeded();
}
virtual void OnBoundsChanged(const gfx::Rect& bounds) OVERRIDE {
CreateCommandBufferIfNeeded();
client()->OnBoundsChanged(Rect::From(bounds));
}
virtual void OnDestroyed() OVERRIDE {
command_buffer_.reset();
client()->OnDestroyed();
base::MessageLoop::current()->Quit();
}
private:
shell::Context* context_;
gfx::AcceleratedWidget widget_;
scoped_ptr<services::NativeViewport> native_viewport_;
InterfaceRequest<CommandBuffer> command_buffer_request_;
scoped_ptr<CommandBufferImpl> command_buffer_;
bool waiting_for_event_ack_;
base::WeakPtrFactory<NativeViewportImpl> weak_factory_;
};
} // namespace services
} // namespace mojo
MOJO_NATIVE_VIEWPORT_EXPORT mojo::Application*
CreateNativeViewportService(
mojo::shell::Context* context,
mojo::ScopedMessagePipeHandle service_provider_handle) {
mojo::Application* app = new mojo::Application(
service_provider_handle.Pass());
app->AddService<mojo::services::NativeViewportImpl>(context);
return app;
}