普通文本  |  155行  |  4.6 KB

// Copyright 2014 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 "ppapi/proxy/compositor_resource.h"

#include "base/logging.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/thunk/enter.h"

namespace ppapi {
namespace proxy {

CompositorResource::CompositorResource(Connection connection,
                                       PP_Instance instance)
    : PluginResource(connection, instance),
      layer_reset_(true),
      last_resource_id_(0) {
  SendCreate(RENDERER, PpapiHostMsg_Compositor_Create());
}

bool CompositorResource::IsInProgress() const {
  ProxyLock::AssertAcquiredDebugOnly();
  return TrackedCallback::IsPending(commit_callback_);
}

int32_t CompositorResource::GenerateResourceId() const {
  ProxyLock::AssertAcquiredDebugOnly();
  return ++last_resource_id_;
}

CompositorResource::~CompositorResource() {
  ResetLayersInternal(true);

  // Abort all release callbacks.
  for (ReleaseCallbackMap::iterator it = release_callback_map_.begin();
       it != release_callback_map_.end(); ++it) {
    if (!it->second.is_null())
      it->second.Run(PP_ERROR_ABORTED, 0, false);
  }
}

thunk::PPB_Compositor_API* CompositorResource::AsPPB_Compositor_API() {
  return this;
}

void CompositorResource::OnReplyReceived(
    const ResourceMessageReplyParams& params,
    const IPC::Message& msg) {
   PPAPI_BEGIN_MESSAGE_MAP(CompositorResource, msg)
     PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(
         PpapiPluginMsg_Compositor_ReleaseResource,
         OnPluginMsgReleaseResource)
     PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(
          PluginResource::OnReplyReceived(params, msg))
   PPAPI_END_MESSAGE_MAP()
}

PP_Resource CompositorResource::AddLayer() {
  scoped_refptr<CompositorLayerResource> resource(new CompositorLayerResource(
      connection(), pp_instance(), this));
  layers_.push_back(resource);
  return resource->GetReference();
}

int32_t CompositorResource::CommitLayers(
    const scoped_refptr<ppapi::TrackedCallback>& callback) {
  if (IsInProgress())
    return PP_ERROR_INPROGRESS;

  std::vector<CompositorLayerData> layers;
  layers.reserve(layers_.size());

  for (LayerList::const_iterator it = layers_.begin();
       it != layers_.end(); ++it) {
    if ((*it)->data().is_null())
      return PP_ERROR_FAILED;
    layers.push_back((*it)->data());
  }

  commit_callback_ = callback;
  Call<PpapiPluginMsg_Compositor_CommitLayersReply>(
      RENDERER,
      PpapiHostMsg_Compositor_CommitLayers(layers, layer_reset_),
      base::Bind(&CompositorResource::OnPluginMsgCommitLayersReply,
                 base::Unretained(this)),
      callback);

  return PP_OK_COMPLETIONPENDING;
}

int32_t CompositorResource::ResetLayers() {
  if (IsInProgress())
    return PP_ERROR_INPROGRESS;

  ResetLayersInternal(false);
  return PP_OK;
}

void CompositorResource::OnPluginMsgCommitLayersReply(
    const ResourceMessageReplyParams& params) {
  if (!TrackedCallback::IsPending(commit_callback_))
    return;

  // On success, we put layers' release_callbacks into a map,
  // otherwise we will do nothing. So plugin may change layers and
  // call CommitLayers() again.
  if (params.result() == PP_OK) {
    layer_reset_ = false;
    for (LayerList::iterator it = layers_.begin();
         it != layers_.end(); ++it) {
      ReleaseCallback release_callback = (*it)->release_callback();
      if (!release_callback.is_null()) {
        release_callback_map_.insert(ReleaseCallbackMap::value_type(
            (*it)->data().common.resource_id, release_callback));
        (*it)->ResetReleaseCallback();
      }
    }
  }

  scoped_refptr<TrackedCallback> callback;
  callback.swap(commit_callback_);
  callback->Run(params.result());
}

void CompositorResource::OnPluginMsgReleaseResource(
    const ResourceMessageReplyParams& params,
    int32_t id,
    uint32_t sync_point,
    bool is_lost) {
  ReleaseCallbackMap::iterator it = release_callback_map_.find(id);
  DCHECK(it != release_callback_map_.end()) <<
      "Can not found release_callback_ by id(" << id << ")!";
  it->second.Run(PP_OK, sync_point, is_lost);
  release_callback_map_.erase(it);
}

void CompositorResource::ResetLayersInternal(bool is_aborted) {
  for (LayerList::iterator it = layers_.begin();
       it != layers_.end(); ++it) {
    ReleaseCallback release_callback = (*it)->release_callback();
    if (!release_callback.is_null()) {
      release_callback.Run(is_aborted ? PP_ERROR_ABORTED : PP_OK, 0, false);
      (*it)->ResetReleaseCallback();
    }
    (*it)->Invalidate();
  }

  layers_.clear();
  layer_reset_ = true;
}

}  // namespace proxy
}  // namespace ppapi