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..7f731b95ad3b80bad8a1fecc2da466324c3326bc |
--- /dev/null |
+++ b/services/gfx/compositor/graph/node_def.cc |
@@ -0,0 +1,366 @@ |
+// 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 <sstream> |
+ |
+#include "base/logging.h" |
+#include "mojo/services/gfx/composition/cpp/logging.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 { |
+ |
+// TODO(jeffbrown): Move these conversion functions somewhere more useful. |
abarth
2016/01/10 22:55:36
There's a converters directory in mojo/common. Ma
jeffbrown
2016/01/16 03:28:32
Yeah... but maybe later. :)
|
+ |
+static SkRect ToSkRect(const mojo::Rect& rect) { |
abarth
2016/01/10 22:55:36
The mojo types have template magic to make these s
|
+ return SkRect::MakeXYWH(rect.x, rect.y, rect.width, rect.height); |
+} |
+ |
+static SkRRect ToSkRRect(const mojo::RRect& rrect) { |
+ SkVector radii[4] = { |
+ {rrect.top_left_radius_x, rrect.top_left_radius_y}, |
+ {rrect.top_right_radius_x, rrect.top_right_radius_y}, |
+ {rrect.bottom_left_radius_x, rrect.bottom_left_radius_y}, |
+ {rrect.bottom_right_radius_x, rrect.bottom_right_radius_y}}; |
+ SkRRect result; |
+ result.setRectRadii( |
+ SkRect::MakeXYWH(rrect.x, rrect.y, rrect.width, rrect.height), radii); |
abarth
2016/01/10 22:55:35
Note that this routine is more expensive that setR
jeffbrown
2016/01/16 03:28:32
Yes, but we don't know whether we're in the fast c
|
+ return result; |
+} |
+ |
+static SkMatrix ToSkMatrix(const mojo::Transform& transform) { |
+ // TODO(jeffbrown): What to do with the Z components? |
+ // Perhaps we need a simpler 2D transform matrix mojom. |
abarth
2016/01/10 22:55:36
This is the same thing we do in Flutter. We can t
jeffbrown
2016/01/16 03:28:32
Acknowledged.
|
+ SkMatrix result; |
+ result.setAll(transform.matrix[0], transform.matrix[1], transform.matrix[3], |
+ transform.matrix[4], transform.matrix[5], transform.matrix[7], |
+ transform.matrix[12], transform.matrix[13], |
+ transform.matrix[15]); |
+ return result; |
+} |
+ |
+static SkColor ToSkColor(const mojo::gfx::composition::Color& color) { |
+ return SkColorSetARGBInline(color.alpha, color.red, color.green, color.blue); |
+} |
+ |
+static SkPath ToSkPath(const mojo::gfx::composition::Clip& clip) { |
+ SkPath result; |
+ if (clip.is_rect()) { |
+ result.addRect(ToSkRect(*clip.get_rect())); |
abarth
2016/01/10 22:55:36
Woah there. I haven't seen where you're using thi
jeffbrown
2016/01/16 03:28:32
Dropping RRect clips for now.
|
+ } else if (clip.is_rect()) { |
+ result.addRRect(ToSkRRect(*clip.get_rrect())); |
+ } else { |
+ DCHECK(false); // was checked during validation |
+ } |
+ return result; |
+} |
+ |
+static SkPaint ToSkPaint(const mojo::gfx::composition::Blend& blend) { |
+ SkPaint result; |
+ result.setAlpha(blend.alpha); |
+ return result; |
+} |
+ |
+NodeDef::NodeDef(uint32_t node_id, |
+ mojo::TransformPtr content_transform, |
+ mojo::gfx::composition::ClipPtr 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) { |
+ if (content_clip_) { |
+ if (!content_clip_->is_rect() && !content_clip_->is_rrect()) { |
+ err << "Node contains unsupported content clip type: " |
+ << FormattedLabel(scene); |
+ return false; |
+ } |
+ } |
+ |
+ 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_, |
+ content_transform_ ? ToSkMatrix(*content_transform_) : SkMatrix::I(), |
+ content_clip_ ? ToSkPath(*content_clip_) : SkPath()); |
+ |
+ 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 |
+ } |
+ } |
+} |
+ |
+std::string NodeDef::FormattedLabel(SceneDef* scene) { |
+ std::ostringstream s; |
+ s << scene->FormattedLabel() << "[" << node_id_ << "]"; |
+ return s.str(); |
abarth
2016/01/10 22:55:35
base::StringPrintf
jeffbrown
2016/01/16 03:28:32
Done.
|
+} |
+ |
+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(ToSkColor(color_)); |
+ layer_builder->DrawRect(ToSkRect(content_rect_), 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(), ToSkRect(content_rect_), |
+ image_rect_ ? ToSkRect(*image_rect_) |
+ : SkRect::MakeWH(image_resource_->image()->width(), |
+ image_resource_->image()->height()), |
+ blend_ ? ToSkPaint(*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_ ? ToSkPaint(*blend_) : SkPaint()); |
+ return true; |
+} |
+ |
+} // namespace compositor |