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