| // 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 |