OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "services/gfx/compositor/graph/node_def.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "base/strings/stringprintf.h" |
| 9 #include "mojo/services/gfx/composition/cpp/formatting.h" |
| 10 #include "mojo/skia/type_converters.h" |
| 11 #include "services/gfx/compositor/graph/scene_def.h" |
| 12 #include "services/gfx/compositor/graph/snapshot.h" |
| 13 #include "services/gfx/compositor/render/render_image.h" |
| 14 #include "services/gfx/compositor/render/render_layer.h" |
| 15 |
| 16 namespace compositor { |
| 17 namespace { |
| 18 SkColor MakeSkColor(const mojo::gfx::composition::Color& color) { |
| 19 return SkColorSetARGBInline(color.alpha, color.red, color.green, color.blue); |
| 20 } |
| 21 |
| 22 SkPaint MakePaintForBlend(const mojo::gfx::composition::Blend& blend) { |
| 23 SkPaint result; |
| 24 result.setAlpha(blend.alpha); |
| 25 return result; |
| 26 } |
| 27 } // namespace |
| 28 |
| 29 NodeDef::NodeDef(uint32_t node_id, |
| 30 mojo::TransformPtr content_transform, |
| 31 mojo::RectPtr content_clip, |
| 32 uint32_t hit_id, |
| 33 Combinator combinator, |
| 34 const std::vector<uint32_t>& child_node_ids, |
| 35 NodeOp* op) |
| 36 : node_id_(node_id), |
| 37 content_transform_(content_transform.Pass()), |
| 38 content_clip_(content_clip.Pass()), |
| 39 hit_id_(hit_id), |
| 40 combinator_(combinator), |
| 41 child_node_ids_(child_node_ids), |
| 42 op_(op) {} |
| 43 |
| 44 NodeDef::~NodeDef() {} |
| 45 |
| 46 bool NodeDef::Validate(SceneDef* scene, std::ostream& err) { |
| 47 child_nodes_.clear(); |
| 48 for (uint32_t child_node_id : child_node_ids_) { |
| 49 NodeDef* child_node = scene->FindNode(child_node_id); |
| 50 if (!child_node) { |
| 51 err << "Node refers to unknown child: " << FormattedLabel(scene) |
| 52 << ", child_node_id=" << child_node_id; |
| 53 return false; |
| 54 } |
| 55 child_nodes_.push_back(child_node); |
| 56 } |
| 57 |
| 58 return !op_ || op_->Validate(scene, this, err); |
| 59 } |
| 60 |
| 61 bool NodeDef::Snapshot(SnapshotBuilder* snapshot_builder, |
| 62 RenderLayerBuilder* layer_builder, |
| 63 SceneDef* scene) { |
| 64 DCHECK(snapshot_builder); |
| 65 DCHECK(layer_builder); |
| 66 DCHECK(scene); |
| 67 |
| 68 // Detect cycles. |
| 69 if (visited_) { |
| 70 if (snapshot_builder->block_log()) { |
| 71 *snapshot_builder->block_log() |
| 72 << "Node blocked due to recursive cycle: " << FormattedLabel(scene) |
| 73 << std::endl; |
| 74 } |
| 75 return false; |
| 76 } |
| 77 |
| 78 // Snapshot the contents of the node. |
| 79 visited_ = true; |
| 80 bool success = SnapshotInner(snapshot_builder, layer_builder, scene); |
| 81 visited_ = false; |
| 82 return success; |
| 83 } |
| 84 |
| 85 bool NodeDef::SnapshotInner(SnapshotBuilder* snapshot_builder, |
| 86 RenderLayerBuilder* layer_builder, |
| 87 SceneDef* scene) { |
| 88 // TODO(jeffbrown): Frequently referenced and reused nodes, especially |
| 89 // layer nodes, may benefit from caching. |
| 90 layer_builder->PushNode(node_id_, hit_id_); |
| 91 if (content_transform_) |
| 92 layer_builder->ApplyTransform(content_transform_.To<SkMatrix>()); |
| 93 if (content_clip_) |
| 94 layer_builder->ApplyClip(content_clip_->To<SkRect>()); |
| 95 |
| 96 bool success = |
| 97 op_ ? op_->Snapshot(snapshot_builder, layer_builder, scene, this) |
| 98 : SnapshotChildren(snapshot_builder, layer_builder, scene); |
| 99 if (!success) |
| 100 return false; |
| 101 |
| 102 layer_builder->PopNode(); |
| 103 return true; |
| 104 } |
| 105 |
| 106 bool NodeDef::SnapshotChildren(SnapshotBuilder* snapshot_builder, |
| 107 RenderLayerBuilder* layer_builder, |
| 108 SceneDef* scene) { |
| 109 DCHECK(snapshot_builder); |
| 110 DCHECK(layer_builder); |
| 111 DCHECK(scene); |
| 112 |
| 113 switch (combinator_) { |
| 114 // MERGE: All or nothing. |
| 115 case Combinator::MERGE: { |
| 116 for (NodeDef* child_node : child_nodes_) { |
| 117 if (!child_node->Snapshot(snapshot_builder, layer_builder, scene)) { |
| 118 if (snapshot_builder->block_log()) { |
| 119 *snapshot_builder->block_log() |
| 120 << "Node with MERGE combinator blocked since " |
| 121 "one of its children is blocked: " |
| 122 << FormattedLabel(scene) << ", blocked child " |
| 123 << child_node->FormattedLabel(scene) << std::endl; |
| 124 } |
| 125 return false; // blocked |
| 126 } |
| 127 } |
| 128 return true; |
| 129 } |
| 130 |
| 131 // PRUNE: Silently discard blocked children. |
| 132 case Combinator::PRUNE: { |
| 133 for (NodeDef* child_node : child_nodes_) { |
| 134 RenderLayerBuilder child_layer_builder; |
| 135 if (child_node->Snapshot(snapshot_builder, &child_layer_builder, |
| 136 scene)) { |
| 137 layer_builder->DrawLayer(child_layer_builder.Build()); |
| 138 } |
| 139 } |
| 140 return true; |
| 141 } |
| 142 |
| 143 // FALLBACK: Keep only the first unblocked child. |
| 144 case Combinator::FALLBACK: { |
| 145 if (child_nodes_.empty()) |
| 146 return true; |
| 147 for (NodeDef* child_node : child_nodes_) { |
| 148 RenderLayerBuilder child_layer_builder; |
| 149 if (child_node->Snapshot(snapshot_builder, &child_layer_builder, |
| 150 scene)) { |
| 151 layer_builder->DrawLayer(child_layer_builder.Build()); |
| 152 return true; |
| 153 } |
| 154 } |
| 155 if (snapshot_builder->block_log()) { |
| 156 *snapshot_builder->block_log() |
| 157 << "Node with FALLBACK combinator blocked since " |
| 158 "all of its children are blocked: " |
| 159 << FormattedLabel(scene) << std::endl; |
| 160 } |
| 161 return false; // blocked |
| 162 } |
| 163 |
| 164 default: { |
| 165 if (snapshot_builder->block_log()) { |
| 166 *snapshot_builder->block_log() |
| 167 << "Unrecognized combinator: " << FormattedLabel(scene) |
| 168 << std::endl; |
| 169 } |
| 170 return false; |
| 171 } |
| 172 } |
| 173 } |
| 174 |
| 175 std::string NodeDef::FormattedLabel(SceneDef* scene) { |
| 176 return base::StringPrintf("%s[%d]", scene->FormattedLabel().c_str(), |
| 177 node_id_); |
| 178 } |
| 179 |
| 180 bool NodeOp::Validate(SceneDef* scene, NodeDef* node, std::ostream& err) { |
| 181 return true; |
| 182 } |
| 183 |
| 184 RectNodeOp::RectNodeOp(const mojo::Rect& content_rect, |
| 185 const mojo::gfx::composition::Color& color) |
| 186 : content_rect_(content_rect), color_(color) {} |
| 187 |
| 188 RectNodeOp::~RectNodeOp() {} |
| 189 |
| 190 bool RectNodeOp::Snapshot(SnapshotBuilder* snapshot_builder, |
| 191 RenderLayerBuilder* layer_builder, |
| 192 SceneDef* scene, |
| 193 NodeDef* node) { |
| 194 if (!node->SnapshotChildren(snapshot_builder, layer_builder, scene)) |
| 195 return false; |
| 196 |
| 197 SkPaint paint; |
| 198 paint.setColor(MakeSkColor(color_)); |
| 199 layer_builder->DrawRect(content_rect_.To<SkRect>(), paint); |
| 200 return true; |
| 201 } |
| 202 |
| 203 ImageNodeOp::ImageNodeOp(const mojo::Rect& content_rect, |
| 204 mojo::RectPtr image_rect, |
| 205 uint32 image_resource_id, |
| 206 mojo::gfx::composition::BlendPtr blend) |
| 207 : content_rect_(content_rect), |
| 208 image_rect_(image_rect.Pass()), |
| 209 image_resource_id_(image_resource_id), |
| 210 blend_(blend.Pass()) {} |
| 211 |
| 212 ImageNodeOp::~ImageNodeOp() {} |
| 213 |
| 214 bool ImageNodeOp::Validate(SceneDef* scene, NodeDef* node, std::ostream& err) { |
| 215 image_resource_ = scene->FindImageResource(image_resource_id_); |
| 216 if (!image_resource_) { |
| 217 err << "Node refers to unknown or invalid image resource: " |
| 218 << node->FormattedLabel(scene) |
| 219 << ", image_resource_id=" << image_resource_id_; |
| 220 return false; |
| 221 } |
| 222 return true; |
| 223 } |
| 224 |
| 225 bool ImageNodeOp::Snapshot(SnapshotBuilder* snapshot_builder, |
| 226 RenderLayerBuilder* layer_builder, |
| 227 SceneDef* scene, |
| 228 NodeDef* node) { |
| 229 DCHECK(image_resource_); |
| 230 |
| 231 if (!image_resource_->image()) { |
| 232 if (snapshot_builder->block_log()) { |
| 233 *snapshot_builder->block_log() |
| 234 << "Node blocked due to its referenced image " |
| 235 "resource being unavailable: " |
| 236 << node->FormattedLabel(scene) << std::endl; |
| 237 } |
| 238 return false; |
| 239 } |
| 240 |
| 241 if (!node->SnapshotChildren(snapshot_builder, layer_builder, scene)) |
| 242 return false; |
| 243 |
| 244 layer_builder->DrawImage( |
| 245 image_resource_->image(), content_rect_.To<SkRect>(), |
| 246 image_rect_ ? image_rect_->To<SkRect>() |
| 247 : SkRect::MakeWH(image_resource_->image()->width(), |
| 248 image_resource_->image()->height()), |
| 249 blend_ ? MakePaintForBlend(*blend_) : SkPaint()); |
| 250 return true; |
| 251 } |
| 252 |
| 253 SceneNodeOp::SceneNodeOp(uint32_t scene_resource_id, uint32_t scene_version) |
| 254 : scene_resource_id_(scene_resource_id), scene_version_(scene_version) {} |
| 255 |
| 256 SceneNodeOp::~SceneNodeOp() {} |
| 257 |
| 258 bool SceneNodeOp::Validate(SceneDef* scene, NodeDef* node, std::ostream& err) { |
| 259 scene_resource_ = scene->FindSceneResource(scene_resource_id_); |
| 260 if (!scene_resource_) { |
| 261 err << "Node refers to unknown or invalid scene resource: " |
| 262 << node->FormattedLabel(scene) |
| 263 << ", scene_resource_id=" << scene_resource_id_; |
| 264 return false; |
| 265 } |
| 266 return true; |
| 267 } |
| 268 |
| 269 bool SceneNodeOp::Snapshot(SnapshotBuilder* snapshot_builder, |
| 270 RenderLayerBuilder* layer_builder, |
| 271 SceneDef* scene, |
| 272 NodeDef* node) { |
| 273 DCHECK(scene_resource_); |
| 274 |
| 275 SceneDef* referenced_scene = scene_resource_->referenced_scene(); |
| 276 if (!referenced_scene) { |
| 277 if (snapshot_builder->block_log()) { |
| 278 *snapshot_builder->block_log() |
| 279 << "Node blocked due to its referenced scene " |
| 280 "resource being unavailable: " |
| 281 << node->FormattedLabel(scene) << std::endl; |
| 282 } |
| 283 return false; |
| 284 } |
| 285 |
| 286 uint32_t actual_version = referenced_scene->version(); |
| 287 if (scene_version_ != mojo::gfx::composition::kSceneVersionNone && |
| 288 actual_version != mojo::gfx::composition::kSceneVersionNone && |
| 289 scene_version_ != actual_version) { |
| 290 if (snapshot_builder->block_log()) { |
| 291 *snapshot_builder->block_log() |
| 292 << "Node blocked due to its referenced scene " |
| 293 "resource not having the desired version: " |
| 294 << node->FormattedLabel(scene) |
| 295 << ", requested_version=" << scene_version_ |
| 296 << ", actual_version=" << actual_version << std::endl; |
| 297 } |
| 298 return false; |
| 299 } |
| 300 |
| 301 if (!node->SnapshotChildren(snapshot_builder, layer_builder, scene)) |
| 302 return false; |
| 303 |
| 304 return referenced_scene->Snapshot(snapshot_builder, layer_builder); |
| 305 } |
| 306 |
| 307 LayerNodeOp::LayerNodeOp(const mojo::Size& size, |
| 308 mojo::gfx::composition::BlendPtr blend) |
| 309 : size_(size), blend_(blend.Pass()) {} |
| 310 |
| 311 LayerNodeOp::~LayerNodeOp() {} |
| 312 |
| 313 bool LayerNodeOp::Snapshot(SnapshotBuilder* snapshot_builder, |
| 314 RenderLayerBuilder* layer_builder, |
| 315 SceneDef* scene, |
| 316 NodeDef* node) { |
| 317 SkRect content_rect = SkRect::MakeWH(size_.width, size_.height); |
| 318 RenderLayerBuilder children_layer_builder(&content_rect); |
| 319 if (!node->SnapshotChildren(snapshot_builder, &children_layer_builder, scene)) |
| 320 return false; |
| 321 |
| 322 layer_builder->DrawSavedLayer( |
| 323 children_layer_builder.Build(), content_rect, |
| 324 blend_ ? MakePaintForBlend(*blend_) : SkPaint()); |
| 325 return true; |
| 326 } |
| 327 |
| 328 } // namespace compositor |
OLD | NEW |