Chromium Code Reviews| Index: content/renderer/android/synchronous_compositor_filter.cc |
| diff --git a/content/renderer/android/synchronous_compositor_filter.cc b/content/renderer/android/synchronous_compositor_filter.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ae292f84596c62f1dbf014be3cd443be1dc731d8 |
| --- /dev/null |
| +++ b/content/renderer/android/synchronous_compositor_filter.cc |
| @@ -0,0 +1,234 @@ |
| +// 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 "base/callback.h" |
| +#include "base/thread_task_runner_handle.h" |
| +#include "content/common/android/sync_compositor_messages.h" |
| +#include "content/renderer/android/synchronous_compositor_proxy.h" |
| + |
| +namespace content { |
| + |
| +SynchronousCompositorFilter::SynchronousCompositorFilter( |
| + const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner) |
| + : compositor_task_runner_(compositor_task_runner) { |
| + DCHECK(compositor_task_runner_.get()); |
| +} |
| + |
| +SynchronousCompositorFilter::~SynchronousCompositorFilter() {} |
| + |
| +void SynchronousCompositorFilter::OnFilterAdded(IPC::Sender* sender) { |
| + io_task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
| + sender_ = sender; |
| +} |
| + |
| +void SynchronousCompositorFilter::OnFilterRemoved() { |
| + sender_ = nullptr; |
| +} |
| + |
| +void SynchronousCompositorFilter::OnChannelClosing() { |
| + sender_ = nullptr; |
| +} |
| + |
| +bool SynchronousCompositorFilter::OnMessageReceived( |
| + const IPC::Message& message) { |
| + if (IPC_MESSAGE_ID_CLASS(message.type()) != SyncCompositorMsgStart) { |
| + return false; |
| + } |
| + |
| + 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; |
| +} |
| + |
| +void SynchronousCompositorFilter::OnMessageReceivedOnCompositorThread( |
| + const IPC::Message& message) { |
| + DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| + |
| + auto itr = sync_compositor_map_.find(message.routing_id()); |
| + if (itr != sync_compositor_map_.end()) { |
| + itr->second->OnMessageReceived(message); |
| + 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(io_task_runner_.get()); // TODO(boliu): Not really thread safe. |
| + if (!io_task_runner_->PostTask( |
| + FROM_HERE, base::Bind(&SynchronousCompositorFilter::SendOnIOThread, |
| + this, base::Unretained(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_) { // TODO(boliu): just in case..? |
| + delete message; |
| + return; |
| + } |
| + bool result = sender_->Send(message); |
| + if (!result) |
| + DLOG(WARNING) << "Failed to send message"; |
| +} |
| + |
| +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; |
| + CheckIsReady(routing_id); |
| +} |
| + |
| +void SynchronousCompositorFilter::UnregisterOutputSurface( |
| + int routing_id, |
| + SynchronousCompositorOutputSurface* output_surface) { |
| + DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| + DCHECK(output_surface); |
| + DCHECK(entry_map_.find(routing_id) != entry_map_.end()); |
|
dcheng
2015/10/27 21:06:58
You could use ContainsKey.
boliu
2015/10/28 02:07:06
Done
|
| + Entry& entry = entry_map_[routing_id]; |
| + DCHECK_EQ(output_surface, entry.output_surface); |
| + |
| + if (entry.IsReady()) |
| + UnregisterObjects(routing_id); |
| + entry.output_surface = nullptr; |
| + RemoveEntryIfNeeded(routing_id); |
| +} |
| + |
| +void SynchronousCompositorFilter::RegisterBeginFrameSource( |
| + int routing_id, |
| + SynchronousCompositorExternalBeginFrameSource* begin_frame_source) { |
| + DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| + DCHECK(begin_frame_source); |
| + Entry& entry = entry_map_[routing_id]; |
| + DCHECK(!entry.begin_frame_source); |
| + entry.begin_frame_source = begin_frame_source; |
| + CheckIsReady(routing_id); |
| +} |
| + |
| +void SynchronousCompositorFilter::UnregisterBeginFrameSource( |
| + int routing_id, |
| + SynchronousCompositorExternalBeginFrameSource* begin_frame_source) { |
| + DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| + DCHECK(begin_frame_source); |
| + DCHECK(entry_map_.find(routing_id) != entry_map_.end()); |
| + Entry& entry = entry_map_[routing_id]; |
| + DCHECK_EQ(begin_frame_source, entry.begin_frame_source); |
| + |
| + if (entry.IsReady()) |
| + UnregisterObjects(routing_id); |
| + entry.begin_frame_source = nullptr; |
| + RemoveEntryIfNeeded(routing_id); |
| +} |
| + |
| +void SynchronousCompositorFilter::CheckIsReady(int routing_id) { |
| + DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| + DCHECK(entry_map_.find(routing_id) != entry_map_.end()); |
| + Entry& entry = entry_map_[routing_id]; |
| + if (entry.IsReady()) { |
| + DCHECK(!sync_compositor_map_.contains(routing_id)); |
| + sync_compositor_map_.add( |
| + routing_id, |
| + make_scoped_ptr(new SynchronousCompositorProxy( |
| + routing_id, this, entry.output_surface, entry.begin_frame_source, |
| + entry.synchronous_input_handler_proxy, &input_handler_))); |
| + } |
| +} |
| + |
| +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(entry_map_.find(routing_id) != entry_map_.end()); |
| + Entry& entry = entry_map_[routing_id]; |
| + if (!entry.begin_frame_source && !entry.output_surface && |
| + !entry.synchronous_input_handler_proxy) { |
| + entry_map_.erase(routing_id); |
| + } |
| +} |
| + |
| +// TODO(boliu): implement |
| +void SynchronousCompositorFilter::SetBoundHandler(const Handler& handler) { |
| + compositor_task_runner_->PostTask( |
| + FROM_HERE, |
| + base::Bind( |
| + &SynchronousCompositorFilter::SetBoundHandlerOnCompositorThread, this, |
| + handler)); |
| +} |
| + |
| +void SynchronousCompositorFilter::SetBoundHandlerOnCompositorThread( |
| + const Handler& handler) { |
| + DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| + input_handler_ = handler; |
| +} |
| + |
| +void SynchronousCompositorFilter::DidAddInputHandler( |
| + int routing_id, |
| + 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::DidRemoveInputHandler(int routing_id) { |
| + DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| + DCHECK(entry_map_.find(routing_id) != entry_map_.end()); |
| + Entry& entry = entry_map_[routing_id]; |
| + |
| + if (entry.IsReady()) |
| + UnregisterObjects(routing_id); |
| + entry.synchronous_input_handler_proxy = nullptr; |
| + RemoveEntryIfNeeded(routing_id); |
| +} |
| + |
| +void SynchronousCompositorFilter::DidOverscroll( |
| + int routing_id, |
| + const DidOverscrollParams& params) { |
| + DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| + // TODO(boliu): Implement |
| +} |
| + |
| +void SynchronousCompositorFilter::DidStopFlinging(int routing_id) { |
| + DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| + // TODO(boliu): Implement |
| +} |
| + |
| +SynchronousCompositorFilter::Entry::Entry() |
| + : begin_frame_source(nullptr), |
| + output_surface(nullptr), |
| + synchronous_input_handler_proxy(nullptr) {} |
| + |
| +bool SynchronousCompositorFilter::Entry::IsReady() { |
| + return begin_frame_source && output_surface && |
| + synchronous_input_handler_proxy; |
| +} |
| + |
| +} // namespace content |