blob: a73fde1af966e580368bcc594f3db94330381614 [file] [log] [blame]
// Copyright 2015 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 "content/renderer/android/synchronous_compositor_filter.h"
#include <utility>
#include "base/callback.h"
#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/common/android/sync_compositor_messages.h"
#include "content/common/input_messages.h"
#include "content/renderer/android/synchronous_compositor_proxy.h"
#include "ui/events/blink/synchronous_input_handler_proxy.h"
namespace content {
SynchronousCompositorFilter::SynchronousCompositorFilter(
const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner)
: compositor_task_runner_(compositor_task_runner), filter_ready_(false) {
DCHECK(compositor_task_runner_);
}
SynchronousCompositorFilter::~SynchronousCompositorFilter() {}
void SynchronousCompositorFilter::OnFilterAdded(IPC::Sender* sender) {
io_task_runner_ = base::ThreadTaskRunnerHandle::Get();
sender_ = sender;
compositor_task_runner_->PostTask(
FROM_HERE,
base::Bind(&SynchronousCompositorFilter::FilterReadyyOnCompositorThread,
this));
}
void SynchronousCompositorFilter::OnFilterRemoved() {
sender_ = nullptr;
}
void SynchronousCompositorFilter::OnChannelClosing() {
sender_ = nullptr;
}
bool SynchronousCompositorFilter::OnMessageReceived(
const IPC::Message& message) {
DCHECK_EQ(SyncCompositorMsgStart, IPC_MESSAGE_ID_CLASS(message.type()));
bool result = compositor_task_runner_->PostTask(
FROM_HERE,
base::Bind(
&SynchronousCompositorFilter::OnMessageReceivedOnCompositorThread,
this, message));
if (!result && message.is_sync()) {
IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message);
reply->set_reply_error();
SendOnIOThread(reply);
}
return result;
}
SynchronousCompositorProxy* SynchronousCompositorFilter::FindProxy(
int routing_id) {
auto itr = sync_compositor_map_.find(routing_id);
if (itr == sync_compositor_map_.end()) {
return nullptr;
}
return itr->second;
}
bool SynchronousCompositorFilter::GetSupportedMessageClasses(
std::vector<uint32_t>* supported_message_classes) const {
supported_message_classes->push_back(SyncCompositorMsgStart);
return true;
}
void SynchronousCompositorFilter::OnMessageReceivedOnCompositorThread(
const IPC::Message& message) {
DCHECK(compositor_task_runner_->BelongsToCurrentThread());
SynchronousCompositorProxy* proxy = FindProxy(message.routing_id());
if (proxy) {
proxy->OnMessageReceived(message);
return;
}
if (!message.is_sync())
return;
IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message);
reply->set_reply_error();
Send(reply);
}
bool SynchronousCompositorFilter::Send(IPC::Message* message) {
DCHECK(compositor_task_runner_->BelongsToCurrentThread());
DCHECK(filter_ready_);
if (!io_task_runner_->PostTask(
FROM_HERE, base::Bind(&SynchronousCompositorFilter::SendOnIOThread,
this, message))) {
delete message;
DLOG(WARNING) << "IO PostTask failed";
return false;
}
return true;
}
void SynchronousCompositorFilter::SendOnIOThread(IPC::Message* message) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
DCHECK(sender_);
if (!sender_) {
delete message;
return;
}
bool result = sender_->Send(message);
if (!result)
DLOG(WARNING) << "Failed to send message";
}
void SynchronousCompositorFilter::FilterReadyyOnCompositorThread() {
DCHECK(!filter_ready_);
filter_ready_ = true;
for (const auto& entry_pair : entry_map_) {
CheckIsReady(entry_pair.first);
}
}
void SynchronousCompositorFilter::RegisterOutputSurface(
int routing_id,
SynchronousCompositorOutputSurface* output_surface) {
DCHECK(compositor_task_runner_->BelongsToCurrentThread());
DCHECK(output_surface);
Entry& entry = entry_map_[routing_id];
DCHECK(!entry.output_surface);
entry.output_surface = output_surface;
SynchronousCompositorProxy* proxy = FindProxy(routing_id);
if (proxy) {
proxy->SetOutputSurface(output_surface);
}
}
void SynchronousCompositorFilter::UnregisterOutputSurface(
int routing_id,
SynchronousCompositorOutputSurface* output_surface) {
DCHECK(compositor_task_runner_->BelongsToCurrentThread());
DCHECK(output_surface);
DCHECK(ContainsKey(entry_map_, routing_id));
Entry& entry = entry_map_[routing_id];
DCHECK_EQ(output_surface, entry.output_surface);
SynchronousCompositorProxy* proxy = FindProxy(routing_id);
if (proxy) {
proxy->SetOutputSurface(nullptr);
}
entry.output_surface = nullptr;
RemoveEntryIfNeeded(routing_id);
}
void SynchronousCompositorFilter::CheckIsReady(int routing_id) {
DCHECK(compositor_task_runner_->BelongsToCurrentThread());
DCHECK(ContainsKey(entry_map_, routing_id));
Entry& entry = entry_map_[routing_id];
if (filter_ready_ && entry.IsReady()) {
DCHECK(!sync_compositor_map_.contains(routing_id));
std::unique_ptr<SynchronousCompositorProxy> proxy(
new SynchronousCompositorProxy(routing_id, this,
entry.synchronous_input_handler_proxy));
if (entry.output_surface)
proxy->SetOutputSurface(entry.output_surface);
sync_compositor_map_.add(routing_id, std::move(proxy));
}
}
void SynchronousCompositorFilter::UnregisterObjects(int routing_id) {
DCHECK(compositor_task_runner_->BelongsToCurrentThread());
DCHECK(sync_compositor_map_.contains(routing_id));
sync_compositor_map_.erase(routing_id);
}
void SynchronousCompositorFilter::RemoveEntryIfNeeded(int routing_id) {
DCHECK(compositor_task_runner_->BelongsToCurrentThread());
DCHECK(ContainsKey(entry_map_, routing_id));
Entry& entry = entry_map_[routing_id];
if (!entry.output_surface && !entry.synchronous_input_handler_proxy) {
entry_map_.erase(routing_id);
}
}
void SynchronousCompositorFilter::DidAddSynchronousHandlerProxy(
int routing_id,
ui::SynchronousInputHandlerProxy* synchronous_input_handler_proxy) {
DCHECK(compositor_task_runner_->BelongsToCurrentThread());
DCHECK(synchronous_input_handler_proxy);
Entry& entry = entry_map_[routing_id];
DCHECK(!entry.synchronous_input_handler_proxy);
entry.synchronous_input_handler_proxy = synchronous_input_handler_proxy;
CheckIsReady(routing_id);
}
void SynchronousCompositorFilter::DidRemoveSynchronousHandlerProxy(
int routing_id) {
DCHECK(compositor_task_runner_->BelongsToCurrentThread());
DCHECK(ContainsKey(entry_map_, routing_id));
Entry& entry = entry_map_[routing_id];
if (entry.IsReady())
UnregisterObjects(routing_id);
entry.synchronous_input_handler_proxy = nullptr;
RemoveEntryIfNeeded(routing_id);
}
SynchronousCompositorFilter::Entry::Entry()
: output_surface(nullptr),
synchronous_input_handler_proxy(nullptr) {}
// TODO(boliu): refactor this
bool SynchronousCompositorFilter::Entry::IsReady() {
return synchronous_input_handler_proxy;
}
} // namespace content