blob: b8051bdc81e15abd5712fb8306f28c91aaab6348 [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 "services/gfx/compositor/graph/snapshot.h"
#include "base/logging.h"
#include "mojo/services/gfx/composition/cpp/formatting.h"
#include "mojo/skia/type_converters.h"
#include "services/gfx/compositor/graph/scene_content.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/utils/SkMatrix44.h"
namespace compositor {
Snapshot::Snapshot() {}
Snapshot::~Snapshot() {}
bool Snapshot::HasDependency(
const mojo::gfx::composition::SceneToken& scene_token) const {
return dependencies_.find(scene_token.value) != dependencies_.end();
}
scoped_refptr<RenderFrame> Snapshot::Paint(
const RenderFrame::Metadata& metadata,
const mojo::Rect& viewport) const {
DCHECK(!is_blocked());
DCHECK(root_scene_content_);
SkIRect sk_viewport = viewport.To<SkIRect>();
SkPictureRecorder recorder;
recorder.beginRecording(SkRect::Make(sk_viewport));
root_scene_content_->Paint(this, recorder.getRecordingCanvas());
return new RenderFrame(metadata, sk_viewport,
skia::AdoptRef(recorder.endRecordingAsPicture()));
}
void Snapshot::HitTest(const mojo::PointF& point,
mojo::gfx::composition::HitTestResult* result) const {
DCHECK(result);
DCHECK(!is_blocked());
DCHECK(root_scene_content_);
root_scene_content_->HitTest(this, point.To<SkPoint>(), SkMatrix44::I(),
&result->root);
}
bool Snapshot::IsNodeBlocked(const Node* node) const {
DCHECK(!is_blocked());
auto it = node_dispositions_.find(node);
DCHECK(it != node_dispositions_.end());
DCHECK(it->second == Disposition::kSuccess ||
it->second == Disposition::kBlocked);
return it->second == Disposition::kBlocked;
}
const SceneContent* Snapshot::GetResolvedSceneContent(
const SceneNode* scene_node) const {
DCHECK(!is_blocked());
auto it = resolved_scene_contents_.find(scene_node);
DCHECK(it != resolved_scene_contents_.end());
return it->second.get();
}
SnapshotBuilder::SnapshotBuilder(std::ostream* block_log)
: snapshot_(new Snapshot()), block_log_(block_log) {}
SnapshotBuilder::~SnapshotBuilder() {}
Snapshot::Disposition SnapshotBuilder::SnapshotNode(
const Node* node,
const SceneContent* content) {
DCHECK(snapshot_);
DCHECK(node);
DCHECK(content);
auto it = snapshot_->node_dispositions_.find(node);
if (it != snapshot_->node_dispositions_.end())
return it->second;
Snapshot::Disposition disposition = node->RecordSnapshot(content, this);
snapshot_->node_dispositions_[node] = disposition;
return disposition;
}
Snapshot::Disposition SnapshotBuilder::SnapshotReferencedScene(
const SceneNode* referrer_node,
const SceneContent* referrer_content) {
DCHECK(snapshot_);
DCHECK(referrer_node);
DCHECK(referrer_content);
// This function should only ever be called once when snapshotting the
// referring |SceneNode| at which point the result will be memoized
// by |SnapshotNode| as usual so reentrance should not occur.
DCHECK(snapshot_->resolved_scene_contents_.find(referrer_node) ==
snapshot_->resolved_scene_contents_.end());
auto scene_resource =
static_cast<const SceneResource*>(referrer_content->GetResource(
referrer_node->scene_resource_id(), Resource::Type::kScene));
DCHECK(scene_resource);
scoped_refptr<const SceneContent> content;
Snapshot::Disposition disposition = AddDependencyResolveAndSnapshotScene(
scene_resource->scene_token(), referrer_node->scene_version(), &content);
if (disposition == Snapshot::Disposition::kSuccess) {
snapshot_->resolved_scene_contents_[referrer_node] = content;
} else if (disposition == Snapshot::Disposition::kBlocked) {
if (block_log_) {
*block_log_ << "Scene node's referenced scene is blocked: "
<< referrer_node->FormattedLabel(referrer_content)
<< ", referenced scene " << scene_resource->scene_token()
<< ", version " << referrer_node->scene_version()
<< std::endl;
}
}
return disposition;
}
Snapshot::Disposition SnapshotBuilder::SnapshotSceneContent(
const SceneContent* content) {
DCHECK(snapshot_);
DCHECK(content);
const Node* root = content->GetRootNodeIfExists();
if (!root) {
if (block_log_) {
*block_log_ << "Scene has no root node: " << content->FormattedLabel()
<< std::endl;
}
return Snapshot::Disposition::kBlocked;
}
return SnapshotNode(root, content);
}
Snapshot::Disposition SnapshotBuilder::AddDependencyResolveAndSnapshotScene(
const mojo::gfx::composition::SceneToken& scene_token,
uint32_t version,
scoped_refptr<const SceneContent>* out_content) {
DCHECK(out_content);
snapshot_->dependencies_.insert(scene_token.value);
return ResolveAndSnapshotScene(scene_token, version, out_content);
}
scoped_refptr<const Snapshot> SnapshotBuilder::Build(
const mojo::gfx::composition::SceneToken& scene_token,
uint32_t version) {
DCHECK(snapshot_);
DCHECK(!snapshot_->root_scene_content_);
scoped_refptr<const SceneContent> content;
snapshot_->disposition_ =
AddDependencyResolveAndSnapshotScene(scene_token, version, &content);
if (!snapshot_->is_blocked()) {
snapshot_->root_scene_content_ = content;
} else {
snapshot_->resolved_scene_contents_.clear();
snapshot_->node_dispositions_.clear();
}
return std::move(snapshot_);
}
} // namespace compositor