1// Copyright 2014 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 "ppapi/proxy/compositor_resource.h"
6
7#include "base/logging.h"
8#include "ppapi/proxy/ppapi_messages.h"
9#include "ppapi/thunk/enter.h"
10
11namespace ppapi {
12namespace proxy {
13
14CompositorResource::CompositorResource(Connection connection,
15                                       PP_Instance instance)
16    : PluginResource(connection, instance),
17      layer_reset_(true),
18      last_resource_id_(0) {
19  SendCreate(RENDERER, PpapiHostMsg_Compositor_Create());
20}
21
22bool CompositorResource::IsInProgress() const {
23  ProxyLock::AssertAcquiredDebugOnly();
24  return TrackedCallback::IsPending(commit_callback_);
25}
26
27int32_t CompositorResource::GenerateResourceId() const {
28  ProxyLock::AssertAcquiredDebugOnly();
29  return ++last_resource_id_;
30}
31
32CompositorResource::~CompositorResource() {
33  ResetLayersInternal(true);
34
35  // Abort all release callbacks.
36  for (ReleaseCallbackMap::iterator it = release_callback_map_.begin();
37       it != release_callback_map_.end(); ++it) {
38    if (!it->second.is_null())
39      it->second.Run(PP_ERROR_ABORTED, 0, false);
40  }
41}
42
43thunk::PPB_Compositor_API* CompositorResource::AsPPB_Compositor_API() {
44  return this;
45}
46
47void CompositorResource::OnReplyReceived(
48    const ResourceMessageReplyParams& params,
49    const IPC::Message& msg) {
50   PPAPI_BEGIN_MESSAGE_MAP(CompositorResource, msg)
51     PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
52         PpapiPluginMsg_Compositor_ReleaseResource,
53         OnPluginMsgReleaseResource)
54     PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(
55          PluginResource::OnReplyReceived(params, msg))
56   PPAPI_END_MESSAGE_MAP()
57}
58
59PP_Resource CompositorResource::AddLayer() {
60  scoped_refptr<CompositorLayerResource> resource(new CompositorLayerResource(
61      connection(), pp_instance(), this));
62  layers_.push_back(resource);
63  return resource->GetReference();
64}
65
66int32_t CompositorResource::CommitLayers(
67    const scoped_refptr<ppapi::TrackedCallback>& callback) {
68  if (IsInProgress())
69    return PP_ERROR_INPROGRESS;
70
71  std::vector<CompositorLayerData> layers;
72  layers.reserve(layers_.size());
73
74  for (LayerList::const_iterator it = layers_.begin();
75       it != layers_.end(); ++it) {
76    if ((*it)->data().is_null())
77      return PP_ERROR_FAILED;
78    layers.push_back((*it)->data());
79  }
80
81  commit_callback_ = callback;
82  Call<PpapiPluginMsg_Compositor_CommitLayersReply>(
83      RENDERER,
84      PpapiHostMsg_Compositor_CommitLayers(layers, layer_reset_),
85      base::Bind(&CompositorResource::OnPluginMsgCommitLayersReply,
86                 base::Unretained(this)),
87      callback);
88
89  return PP_OK_COMPLETIONPENDING;
90}
91
92int32_t CompositorResource::ResetLayers() {
93  if (IsInProgress())
94    return PP_ERROR_INPROGRESS;
95
96  ResetLayersInternal(false);
97  return PP_OK;
98}
99
100void CompositorResource::OnPluginMsgCommitLayersReply(
101    const ResourceMessageReplyParams& params) {
102  if (!TrackedCallback::IsPending(commit_callback_))
103    return;
104
105  // On success, we put layers' release_callbacks into a map,
106  // otherwise we will do nothing. So plugin may change layers and
107  // call CommitLayers() again.
108  if (params.result() == PP_OK) {
109    layer_reset_ = false;
110    for (LayerList::iterator it = layers_.begin();
111         it != layers_.end(); ++it) {
112      ReleaseCallback release_callback = (*it)->release_callback();
113      if (!release_callback.is_null()) {
114        release_callback_map_.insert(ReleaseCallbackMap::value_type(
115            (*it)->data().common.resource_id, release_callback));
116        (*it)->ResetReleaseCallback();
117      }
118    }
119  }
120
121  scoped_refptr<TrackedCallback> callback;
122  callback.swap(commit_callback_);
123  callback->Run(params.result());
124}
125
126void CompositorResource::OnPluginMsgReleaseResource(
127    const ResourceMessageReplyParams& params,
128    int32_t id,
129    uint32_t sync_point,
130    bool is_lost) {
131  ReleaseCallbackMap::iterator it = release_callback_map_.find(id);
132  DCHECK(it != release_callback_map_.end()) <<
133      "Can not found release_callback_ by id(" << id << ")!";
134  it->second.Run(PP_OK, sync_point, is_lost);
135  release_callback_map_.erase(it);
136}
137
138void CompositorResource::ResetLayersInternal(bool is_aborted) {
139  for (LayerList::iterator it = layers_.begin();
140       it != layers_.end(); ++it) {
141    ReleaseCallback release_callback = (*it)->release_callback();
142    if (!release_callback.is_null()) {
143      release_callback.Run(is_aborted ? PP_ERROR_ABORTED : PP_OK, 0, false);
144      (*it)->ResetReleaseCallback();
145    }
146    (*it)->Invalidate();
147  }
148
149  layers_.clear();
150  layer_reset_ = true;
151}
152
153}  // namespace proxy
154}  // namespace ppapi
155