Index: services/gfx/compositor/graph/node_def.cc |
diff --git a/services/gfx/compositor/graph/node_def.cc b/services/gfx/compositor/graph/node_def.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3287301495fe45e24ea286fbbe55a21ca2ddb9fa |
--- /dev/null |
+++ b/services/gfx/compositor/graph/node_def.cc |
@@ -0,0 +1,328 @@ |
+// 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/node_def.h" |
+ |
+#include "base/logging.h" |
+#include "base/strings/stringprintf.h" |
+#include "mojo/services/gfx/composition/cpp/formatting.h" |
+#include "mojo/skia/type_converters.h" |
+#include "services/gfx/compositor/graph/scene_def.h" |
+#include "services/gfx/compositor/graph/snapshot.h" |
+#include "services/gfx/compositor/render/render_image.h" |
+#include "services/gfx/compositor/render/render_layer.h" |
+ |
+namespace compositor { |
+namespace { |
+SkColor MakeSkColor(const mojo::gfx::composition::Color& color) { |
+ return SkColorSetARGBInline(color.alpha, color.red, color.green, color.blue); |
+} |
+ |
+SkPaint MakePaintForBlend(const mojo::gfx::composition::Blend& blend) { |
+ SkPaint result; |
+ result.setAlpha(blend.alpha); |
+ return result; |
+} |
+} // namespace |
+ |
+NodeDef::NodeDef(uint32_t node_id, |
+ mojo::TransformPtr content_transform, |
+ mojo::RectPtr content_clip, |
+ uint32_t hit_id, |
+ Combinator combinator, |
+ const std::vector<uint32_t>& child_node_ids, |
+ NodeOp* op) |
+ : node_id_(node_id), |
+ content_transform_(content_transform.Pass()), |
+ content_clip_(content_clip.Pass()), |
+ hit_id_(hit_id), |
+ combinator_(combinator), |
+ child_node_ids_(child_node_ids), |
+ op_(op) {} |
+ |
+NodeDef::~NodeDef() {} |
+ |
+bool NodeDef::Validate(SceneDef* scene, std::ostream& err) { |
+ child_nodes_.clear(); |
+ for (uint32_t child_node_id : child_node_ids_) { |
+ NodeDef* child_node = scene->FindNode(child_node_id); |
+ if (!child_node) { |
+ err << "Node refers to unknown child: " << FormattedLabel(scene) |
+ << ", child_node_id=" << child_node_id; |
+ return false; |
+ } |
+ child_nodes_.push_back(child_node); |
+ } |
+ |
+ return !op_ || op_->Validate(scene, this, err); |
+} |
+ |
+bool NodeDef::Snapshot(SnapshotBuilder* snapshot_builder, |
+ RenderLayerBuilder* layer_builder, |
+ SceneDef* scene) { |
+ DCHECK(snapshot_builder); |
+ DCHECK(layer_builder); |
+ DCHECK(scene); |
+ |
+ // Detect cycles. |
+ if (visited_) { |
+ if (snapshot_builder->block_log()) { |
+ *snapshot_builder->block_log() |
+ << "Node blocked due to recursive cycle: " << FormattedLabel(scene) |
+ << std::endl; |
+ } |
+ return false; |
+ } |
+ |
+ // Snapshot the contents of the node. |
+ visited_ = true; |
+ bool success = SnapshotInner(snapshot_builder, layer_builder, scene); |
+ visited_ = false; |
+ return success; |
+} |
+ |
+bool NodeDef::SnapshotInner(SnapshotBuilder* snapshot_builder, |
+ RenderLayerBuilder* layer_builder, |
+ SceneDef* scene) { |
+ // TODO(jeffbrown): Frequently referenced and reused nodes, especially |
+ // layer nodes, may benefit from caching. |
+ layer_builder->PushNode(node_id_, hit_id_); |
+ if (content_transform_) |
+ layer_builder->ApplyTransform(content_transform_.To<SkMatrix>()); |
+ if (content_clip_) |
+ layer_builder->ApplyClip(content_clip_->To<SkRect>()); |
+ |
+ bool success = |
+ op_ ? op_->Snapshot(snapshot_builder, layer_builder, scene, this) |
+ : SnapshotChildren(snapshot_builder, layer_builder, scene); |
+ if (!success) |
+ return false; |
+ |
+ layer_builder->PopNode(); |
+ return true; |
+} |
+ |
+bool NodeDef::SnapshotChildren(SnapshotBuilder* snapshot_builder, |
+ RenderLayerBuilder* layer_builder, |
+ SceneDef* scene) { |
+ DCHECK(snapshot_builder); |
+ DCHECK(layer_builder); |
+ DCHECK(scene); |
+ |
+ switch (combinator_) { |
+ // MERGE: All or nothing. |
+ case Combinator::MERGE: { |
+ for (NodeDef* child_node : child_nodes_) { |
+ if (!child_node->Snapshot(snapshot_builder, layer_builder, scene)) { |
+ if (snapshot_builder->block_log()) { |
+ *snapshot_builder->block_log() |
+ << "Node with MERGE combinator blocked since " |
+ "one of its children is blocked: " |
+ << FormattedLabel(scene) << ", blocked child " |
+ << child_node->FormattedLabel(scene) << std::endl; |
+ } |
+ return false; // blocked |
+ } |
+ } |
+ return true; |
+ } |
+ |
+ // PRUNE: Silently discard blocked children. |
+ case Combinator::PRUNE: { |
+ for (NodeDef* child_node : child_nodes_) { |
+ RenderLayerBuilder child_layer_builder; |
+ if (child_node->Snapshot(snapshot_builder, &child_layer_builder, |
+ scene)) { |
+ layer_builder->DrawLayer(child_layer_builder.Build()); |
+ } |
+ } |
+ return true; |
+ } |
+ |
+ // FALLBACK: Keep only the first unblocked child. |
+ case Combinator::FALLBACK: { |
+ if (child_nodes_.empty()) |
+ return true; |
+ for (NodeDef* child_node : child_nodes_) { |
+ RenderLayerBuilder child_layer_builder; |
+ if (child_node->Snapshot(snapshot_builder, &child_layer_builder, |
+ scene)) { |
+ layer_builder->DrawLayer(child_layer_builder.Build()); |
+ return true; |
+ } |
+ } |
+ if (snapshot_builder->block_log()) { |
+ *snapshot_builder->block_log() |
+ << "Node with FALLBACK combinator blocked since " |
+ "all of its children are blocked: " |
+ << FormattedLabel(scene) << std::endl; |
+ } |
+ return false; // blocked |
+ } |
+ |
+ default: { |
+ if (snapshot_builder->block_log()) { |
+ *snapshot_builder->block_log() |
+ << "Unrecognized combinator: " << FormattedLabel(scene) |
+ << std::endl; |
+ } |
+ return false; |
+ } |
+ } |
+} |
+ |
+std::string NodeDef::FormattedLabel(SceneDef* scene) { |
+ return base::StringPrintf("%s[%d]", scene->FormattedLabel().c_str(), |
+ node_id_); |
+} |
+ |
+bool NodeOp::Validate(SceneDef* scene, NodeDef* node, std::ostream& err) { |
+ return true; |
+} |
+ |
+RectNodeOp::RectNodeOp(const mojo::Rect& content_rect, |
+ const mojo::gfx::composition::Color& color) |
+ : content_rect_(content_rect), color_(color) {} |
+ |
+RectNodeOp::~RectNodeOp() {} |
+ |
+bool RectNodeOp::Snapshot(SnapshotBuilder* snapshot_builder, |
+ RenderLayerBuilder* layer_builder, |
+ SceneDef* scene, |
+ NodeDef* node) { |
+ if (!node->SnapshotChildren(snapshot_builder, layer_builder, scene)) |
+ return false; |
+ |
+ SkPaint paint; |
+ paint.setColor(MakeSkColor(color_)); |
+ layer_builder->DrawRect(content_rect_.To<SkRect>(), paint); |
+ return true; |
+} |
+ |
+ImageNodeOp::ImageNodeOp(const mojo::Rect& content_rect, |
+ mojo::RectPtr image_rect, |
+ uint32 image_resource_id, |
+ mojo::gfx::composition::BlendPtr blend) |
+ : content_rect_(content_rect), |
+ image_rect_(image_rect.Pass()), |
+ image_resource_id_(image_resource_id), |
+ blend_(blend.Pass()) {} |
+ |
+ImageNodeOp::~ImageNodeOp() {} |
+ |
+bool ImageNodeOp::Validate(SceneDef* scene, NodeDef* node, std::ostream& err) { |
+ image_resource_ = scene->FindImageResource(image_resource_id_); |
+ if (!image_resource_) { |
+ err << "Node refers to unknown or invalid image resource: " |
+ << node->FormattedLabel(scene) |
+ << ", image_resource_id=" << image_resource_id_; |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+bool ImageNodeOp::Snapshot(SnapshotBuilder* snapshot_builder, |
+ RenderLayerBuilder* layer_builder, |
+ SceneDef* scene, |
+ NodeDef* node) { |
+ DCHECK(image_resource_); |
+ |
+ if (!image_resource_->image()) { |
+ if (snapshot_builder->block_log()) { |
+ *snapshot_builder->block_log() |
+ << "Node blocked due to its referenced image " |
+ "resource being unavailable: " |
+ << node->FormattedLabel(scene) << std::endl; |
+ } |
+ return false; |
+ } |
+ |
+ if (!node->SnapshotChildren(snapshot_builder, layer_builder, scene)) |
+ return false; |
+ |
+ layer_builder->DrawImage( |
+ image_resource_->image(), content_rect_.To<SkRect>(), |
+ image_rect_ ? image_rect_->To<SkRect>() |
+ : SkRect::MakeWH(image_resource_->image()->width(), |
+ image_resource_->image()->height()), |
+ blend_ ? MakePaintForBlend(*blend_) : SkPaint()); |
+ return true; |
+} |
+ |
+SceneNodeOp::SceneNodeOp(uint32_t scene_resource_id, uint32_t scene_version) |
+ : scene_resource_id_(scene_resource_id), scene_version_(scene_version) {} |
+ |
+SceneNodeOp::~SceneNodeOp() {} |
+ |
+bool SceneNodeOp::Validate(SceneDef* scene, NodeDef* node, std::ostream& err) { |
+ scene_resource_ = scene->FindSceneResource(scene_resource_id_); |
+ if (!scene_resource_) { |
+ err << "Node refers to unknown or invalid scene resource: " |
+ << node->FormattedLabel(scene) |
+ << ", scene_resource_id=" << scene_resource_id_; |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+bool SceneNodeOp::Snapshot(SnapshotBuilder* snapshot_builder, |
+ RenderLayerBuilder* layer_builder, |
+ SceneDef* scene, |
+ NodeDef* node) { |
+ DCHECK(scene_resource_); |
+ |
+ SceneDef* referenced_scene = scene_resource_->referenced_scene(); |
+ if (!referenced_scene) { |
+ if (snapshot_builder->block_log()) { |
+ *snapshot_builder->block_log() |
+ << "Node blocked due to its referenced scene " |
+ "resource being unavailable: " |
+ << node->FormattedLabel(scene) << std::endl; |
+ } |
+ return false; |
+ } |
+ |
+ uint32_t actual_version = referenced_scene->version(); |
+ if (scene_version_ != mojo::gfx::composition::kSceneVersionNone && |
+ actual_version != mojo::gfx::composition::kSceneVersionNone && |
+ scene_version_ != actual_version) { |
+ if (snapshot_builder->block_log()) { |
+ *snapshot_builder->block_log() |
+ << "Node blocked due to its referenced scene " |
+ "resource not having the desired version: " |
+ << node->FormattedLabel(scene) |
+ << ", requested_version=" << scene_version_ |
+ << ", actual_version=" << actual_version << std::endl; |
+ } |
+ return false; |
+ } |
+ |
+ if (!node->SnapshotChildren(snapshot_builder, layer_builder, scene)) |
+ return false; |
+ |
+ return referenced_scene->Snapshot(snapshot_builder, layer_builder); |
+} |
+ |
+LayerNodeOp::LayerNodeOp(const mojo::Size& size, |
+ mojo::gfx::composition::BlendPtr blend) |
+ : size_(size), blend_(blend.Pass()) {} |
+ |
+LayerNodeOp::~LayerNodeOp() {} |
+ |
+bool LayerNodeOp::Snapshot(SnapshotBuilder* snapshot_builder, |
+ RenderLayerBuilder* layer_builder, |
+ SceneDef* scene, |
+ NodeDef* node) { |
+ SkRect content_rect = SkRect::MakeWH(size_.width, size_.height); |
+ RenderLayerBuilder children_layer_builder(&content_rect); |
+ if (!node->SnapshotChildren(snapshot_builder, &children_layer_builder, scene)) |
+ return false; |
+ |
+ layer_builder->DrawSavedLayer( |
+ children_layer_builder.Build(), content_rect, |
+ blend_ ? MakePaintForBlend(*blend_) : SkPaint()); |
+ return true; |
+} |
+ |
+} // namespace compositor |