| 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 <ostream> | |
| 8 | |
| 9 #include "base/logging.h" | |
| 10 #include "mojo/services/gfx/composition/cpp/formatting.h" | |
| 11 #include "mojo/skia/type_converters.h" | |
| 12 #include "services/gfx/compositor/graph/scene_content.h" | |
| 13 #include "services/gfx/compositor/graph/scene_def.h" | |
| 14 #include "services/gfx/compositor/graph/snapshot.h" | |
| 15 #include "services/gfx/compositor/graph/transform_pair.h" | |
| 16 #include "services/gfx/compositor/render/render_image.h" | |
| 17 #include "third_party/skia/include/core/SkCanvas.h" | |
| 18 #include "third_party/skia/include/core/SkColor.h" | |
| 19 #include "third_party/skia/include/core/SkMatrix.h" | |
| 20 #include "third_party/skia/include/core/SkPaint.h" | |
| 21 #include "third_party/skia/include/core/SkPoint.h" | |
| 22 #include "third_party/skia/include/core/SkRect.h" | |
| 23 #include "third_party/skia/include/utils/SkMatrix44.h" | |
| 24 | |
| 25 namespace compositor { | |
| 26 namespace { | |
| 27 SkColor MakeSkColor(const mojo::gfx::composition::Color& color) { | |
| 28 return SkColorSetARGBInline(color.alpha, color.red, color.green, color.blue); | |
| 29 } | |
| 30 | |
| 31 void SetPaintForBlend(SkPaint* paint, mojo::gfx::composition::Blend* blend) { | |
| 32 DCHECK(paint); | |
| 33 if (blend) | |
| 34 paint->setAlpha(blend->alpha); | |
| 35 } | |
| 36 | |
| 37 bool Contains(const SkRect& bounds, const SkPoint& point) { | |
| 38 return point.x() >= bounds.left() && point.x() < bounds.right() && | |
| 39 point.y() >= bounds.top() && point.y() < bounds.bottom(); | |
| 40 } | |
| 41 } // namespace | |
| 42 | |
| 43 NodeDef::NodeDef(uint32_t node_id, | |
| 44 std::unique_ptr<TransformPair> content_transform, | |
| 45 mojo::RectFPtr content_clip, | |
| 46 mojo::gfx::composition::HitTestBehaviorPtr hit_test_behavior, | |
| 47 Combinator combinator, | |
| 48 const std::vector<uint32_t>& child_node_ids) | |
| 49 : node_id_(node_id), | |
| 50 content_transform_(std::move(content_transform)), | |
| 51 content_clip_(content_clip.Pass()), | |
| 52 hit_test_behavior_(hit_test_behavior.Pass()), | |
| 53 combinator_(combinator), | |
| 54 child_node_ids_(child_node_ids) {} | |
| 55 | |
| 56 NodeDef::~NodeDef() {} | |
| 57 | |
| 58 std::string NodeDef::FormattedLabel(const SceneContent* content) const { | |
| 59 return content->FormattedLabelForNode(node_id_); | |
| 60 } | |
| 61 | |
| 62 bool NodeDef::RecordContent(SceneContentBuilder* builder) const { | |
| 63 DCHECK(builder); | |
| 64 | |
| 65 for (const auto& child_node_id : child_node_ids_) { | |
| 66 if (!builder->RequireNode(child_node_id, node_id_)) | |
| 67 return false; | |
| 68 } | |
| 69 return true; | |
| 70 } | |
| 71 | |
| 72 Snapshot::Disposition NodeDef::RecordSnapshot(const SceneContent* content, | |
| 73 SnapshotBuilder* builder) const { | |
| 74 DCHECK(content); | |
| 75 DCHECK(builder); | |
| 76 | |
| 77 switch (combinator_) { | |
| 78 // MERGE: All or nothing. | |
| 79 case Combinator::MERGE: { | |
| 80 for (uint32_t child_node_id : child_node_ids_) { | |
| 81 const NodeDef* child_node = content->GetNode(child_node_id); | |
| 82 DCHECK(child_node); | |
| 83 Snapshot::Disposition disposition = | |
| 84 builder->SnapshotNode(child_node, content); | |
| 85 if (disposition == Snapshot::Disposition::kCycle) | |
| 86 return disposition; | |
| 87 if (disposition == Snapshot::Disposition::kBlocked) { | |
| 88 if (builder->block_log()) { | |
| 89 *builder->block_log() | |
| 90 << "Node with MERGE combinator blocked since " | |
| 91 "one of its children is blocked: " | |
| 92 << FormattedLabel(content) << ", blocked child " | |
| 93 << child_node->FormattedLabel(content) << std::endl; | |
| 94 } | |
| 95 return disposition; | |
| 96 } | |
| 97 } | |
| 98 return Snapshot::Disposition::kSuccess; | |
| 99 } | |
| 100 | |
| 101 // PRUNE: Silently discard blocked children. | |
| 102 case Combinator::PRUNE: { | |
| 103 for (uint32_t child_node_id : child_node_ids_) { | |
| 104 const NodeDef* child_node = content->GetNode(child_node_id); | |
| 105 DCHECK(child_node); | |
| 106 Snapshot::Disposition disposition = | |
| 107 builder->SnapshotNode(child_node, content); | |
| 108 if (disposition == Snapshot::Disposition::kCycle) | |
| 109 return disposition; | |
| 110 } | |
| 111 return Snapshot::Disposition::kSuccess; | |
| 112 } | |
| 113 | |
| 114 // FALLBACK: Keep only the first unblocked child. | |
| 115 case Combinator::FALLBACK: { | |
| 116 if (child_node_ids_.empty()) | |
| 117 return Snapshot::Disposition::kSuccess; | |
| 118 for (uint32_t child_node_id : child_node_ids_) { | |
| 119 const NodeDef* child_node = content->GetNode(child_node_id); | |
| 120 DCHECK(child_node); | |
| 121 Snapshot::Disposition disposition = | |
| 122 builder->SnapshotNode(child_node, content); | |
| 123 if (disposition != Snapshot::Disposition::kBlocked) | |
| 124 return disposition; | |
| 125 } | |
| 126 if (builder->block_log()) { | |
| 127 *builder->block_log() << "Node with FALLBACK combinator blocked since " | |
| 128 "all of its children are blocked: " | |
| 129 << FormattedLabel(content) << std::endl; | |
| 130 } | |
| 131 return Snapshot::Disposition::kBlocked; | |
| 132 } | |
| 133 | |
| 134 default: { | |
| 135 if (builder->block_log()) { | |
| 136 *builder->block_log() | |
| 137 << "Unrecognized combinator: " << FormattedLabel(content) | |
| 138 << std::endl; | |
| 139 } | |
| 140 return Snapshot::Disposition::kBlocked; | |
| 141 } | |
| 142 } | |
| 143 } | |
| 144 | |
| 145 template <typename Func> | |
| 146 void NodeDef::TraverseSnapshottedChildren(const SceneContent* content, | |
| 147 const Snapshot* snapshot, | |
| 148 const Func& func) const { | |
| 149 DCHECK(content); | |
| 150 DCHECK(snapshot); | |
| 151 | |
| 152 switch (combinator_) { | |
| 153 // MERGE: All or nothing. | |
| 154 case Combinator::MERGE: { | |
| 155 for (uint32_t child_node_id : child_node_ids_) { | |
| 156 const NodeDef* child_node = content->GetNode(child_node_id); | |
| 157 DCHECK(child_node); | |
| 158 DCHECK(!snapshot->IsNodeBlocked(child_node)); | |
| 159 if (!func(child_node)) | |
| 160 return; | |
| 161 } | |
| 162 return; | |
| 163 } | |
| 164 | |
| 165 // PRUNE: Silently discard blocked children. | |
| 166 case Combinator::PRUNE: { | |
| 167 for (uint32_t child_node_id : child_node_ids_) { | |
| 168 const NodeDef* child_node = content->GetNode(child_node_id); | |
| 169 DCHECK(child_node); | |
| 170 if (!snapshot->IsNodeBlocked(child_node) && !func(child_node)) | |
| 171 return; | |
| 172 } | |
| 173 return; | |
| 174 } | |
| 175 | |
| 176 // FALLBACK: Keep only the first unblocked child. | |
| 177 case Combinator::FALLBACK: { | |
| 178 if (child_node_ids_.empty()) | |
| 179 return; | |
| 180 for (uint32_t child_node_id : child_node_ids_) { | |
| 181 const NodeDef* child_node = content->GetNode(child_node_id); | |
| 182 DCHECK(child_node); | |
| 183 if (!snapshot->IsNodeBlocked(child_node)) { | |
| 184 func(child_node); // don't care about the result because we | |
| 185 return; // always stop after the first one | |
| 186 } | |
| 187 } | |
| 188 NOTREACHED(); | |
| 189 return; | |
| 190 } | |
| 191 | |
| 192 default: { | |
| 193 NOTREACHED(); | |
| 194 return; | |
| 195 } | |
| 196 } | |
| 197 } | |
| 198 | |
| 199 void NodeDef::RecordPicture(const SceneContent* content, | |
| 200 const Snapshot* snapshot, | |
| 201 SkCanvas* canvas) const { | |
| 202 DCHECK(content); | |
| 203 DCHECK(snapshot); | |
| 204 DCHECK(canvas); | |
| 205 | |
| 206 const bool must_save = content_transform_ || content_clip_; | |
| 207 if (must_save) { | |
| 208 canvas->save(); | |
| 209 if (content_transform_) | |
| 210 canvas->concat(content_transform_->forward()); | |
| 211 if (content_clip_) | |
| 212 canvas->clipRect(content_clip_->To<SkRect>()); | |
| 213 } | |
| 214 | |
| 215 RecordPictureInner(content, snapshot, canvas); | |
| 216 | |
| 217 if (must_save) | |
| 218 canvas->restore(); | |
| 219 } | |
| 220 | |
| 221 void NodeDef::RecordPictureInner(const SceneContent* content, | |
| 222 const Snapshot* snapshot, | |
| 223 SkCanvas* canvas) const { | |
| 224 DCHECK(content); | |
| 225 DCHECK(snapshot); | |
| 226 DCHECK(canvas); | |
| 227 | |
| 228 TraverseSnapshottedChildren( | |
| 229 content, snapshot, | |
| 230 [this, content, snapshot, canvas](const NodeDef* child_node) -> bool { | |
| 231 child_node->RecordPicture(content, snapshot, canvas); | |
| 232 return true; | |
| 233 }); | |
| 234 } | |
| 235 | |
| 236 bool NodeDef::HitTest(const SceneContent* content, | |
| 237 const Snapshot* snapshot, | |
| 238 const SkPoint& parent_point, | |
| 239 const SkMatrix44& global_to_parent_transform, | |
| 240 mojo::Array<mojo::gfx::composition::HitPtr>* hits) const { | |
| 241 DCHECK(content); | |
| 242 DCHECK(snapshot); | |
| 243 DCHECK(hits); | |
| 244 | |
| 245 // TODO(jeffbrown): These calculations should probably be happening using | |
| 246 // a 4x4 matrix instead. | |
| 247 SkPoint local_point(parent_point); | |
| 248 SkMatrix global_to_local_transform(global_to_parent_transform); | |
| 249 if (content_transform_) { | |
| 250 // TODO(jeffbrown): Defer matrix multiplications using a matrix stack. | |
| 251 local_point = content_transform_->InverseMapPoint(parent_point); | |
| 252 global_to_local_transform.preConcat(content_transform_->GetInverse()); | |
| 253 } | |
| 254 | |
| 255 if (content_clip_ && !Contains(content_clip_->To<SkRect>(), local_point)) | |
| 256 return false; | |
| 257 | |
| 258 bool opaque_children = false; | |
| 259 if (!hit_test_behavior_ || !hit_test_behavior_->prune) { | |
| 260 opaque_children = HitTestInner(content, snapshot, local_point, | |
| 261 global_to_local_transform, hits); | |
| 262 } | |
| 263 | |
| 264 return HitTestSelf(content, snapshot, local_point, global_to_local_transform, | |
| 265 hits) || | |
| 266 opaque_children; | |
| 267 } | |
| 268 | |
| 269 bool NodeDef::HitTestInner( | |
| 270 const SceneContent* content, | |
| 271 const Snapshot* snapshot, | |
| 272 const SkPoint& local_point, | |
| 273 const SkMatrix44& global_to_local_transform, | |
| 274 mojo::Array<mojo::gfx::composition::HitPtr>* hits) const { | |
| 275 DCHECK(content); | |
| 276 DCHECK(snapshot); | |
| 277 DCHECK(hits); | |
| 278 | |
| 279 // TODO(jeffbrown): Implement a more efficient way to traverse children in | |
| 280 // reverse order. | |
| 281 std::vector<const NodeDef*> children; | |
| 282 TraverseSnapshottedChildren( | |
| 283 content, snapshot, [this, &children](const NodeDef* child_node) -> bool { | |
| 284 children.push_back(child_node); | |
| 285 return true; | |
| 286 }); | |
| 287 | |
| 288 for (auto it = children.crbegin(); it != children.crend(); ++it) { | |
| 289 if ((*it)->HitTest(content, snapshot, local_point, | |
| 290 global_to_local_transform, hits)) | |
| 291 return true; // opaque child covering siblings | |
| 292 } | |
| 293 return false; | |
| 294 } | |
| 295 | |
| 296 bool NodeDef::HitTestSelf( | |
| 297 const SceneContent* content, | |
| 298 const Snapshot* snapshot, | |
| 299 const SkPoint& local_point, | |
| 300 const SkMatrix44& global_to_local_transform, | |
| 301 mojo::Array<mojo::gfx::composition::HitPtr>* hits) const { | |
| 302 DCHECK(content); | |
| 303 DCHECK(snapshot); | |
| 304 DCHECK(hits); | |
| 305 | |
| 306 if (!hit_test_behavior_ || | |
| 307 hit_test_behavior_->visibility == | |
| 308 mojo::gfx::composition::HitTestBehavior::Visibility::INVISIBLE) | |
| 309 return false; | |
| 310 | |
| 311 if (hit_test_behavior_->hit_rect && | |
| 312 !Contains(hit_test_behavior_->hit_rect->To<SkRect>(), local_point)) | |
| 313 return false; | |
| 314 | |
| 315 auto hit = mojo::gfx::composition::Hit::New(); | |
| 316 hit->set_node(mojo::gfx::composition::NodeHit::New()); | |
| 317 hit->get_node()->node_id = node_id_; | |
| 318 hit->get_node()->transform = | |
| 319 mojo::ConvertTo<mojo::TransformPtr>(global_to_local_transform); | |
| 320 hits->push_back(hit.Pass()); | |
| 321 return hit_test_behavior_->visibility == | |
| 322 mojo::gfx::composition::HitTestBehavior::Visibility::OPAQUE; | |
| 323 } | |
| 324 | |
| 325 RectNodeDef::RectNodeDef( | |
| 326 uint32_t node_id, | |
| 327 std::unique_ptr<TransformPair> content_transform, | |
| 328 mojo::RectFPtr content_clip, | |
| 329 mojo::gfx::composition::HitTestBehaviorPtr hit_test_behavior, | |
| 330 Combinator combinator, | |
| 331 const std::vector<uint32_t>& child_node_ids, | |
| 332 const mojo::RectF& content_rect, | |
| 333 const mojo::gfx::composition::Color& color) | |
| 334 : NodeDef(node_id, | |
| 335 std::move(content_transform), | |
| 336 content_clip.Pass(), | |
| 337 hit_test_behavior.Pass(), | |
| 338 combinator, | |
| 339 child_node_ids), | |
| 340 content_rect_(content_rect), | |
| 341 color_(color) {} | |
| 342 | |
| 343 RectNodeDef::~RectNodeDef() {} | |
| 344 | |
| 345 void RectNodeDef::RecordPictureInner(const SceneContent* content, | |
| 346 const Snapshot* snapshot, | |
| 347 SkCanvas* canvas) const { | |
| 348 DCHECK(content); | |
| 349 DCHECK(snapshot); | |
| 350 DCHECK(canvas); | |
| 351 | |
| 352 SkPaint paint; | |
| 353 paint.setColor(MakeSkColor(color_)); | |
| 354 canvas->drawRect(content_rect_.To<SkRect>(), paint); | |
| 355 | |
| 356 NodeDef::RecordPictureInner(content, snapshot, canvas); | |
| 357 } | |
| 358 | |
| 359 ImageNodeDef::ImageNodeDef( | |
| 360 uint32_t node_id, | |
| 361 std::unique_ptr<TransformPair> content_transform, | |
| 362 mojo::RectFPtr content_clip, | |
| 363 mojo::gfx::composition::HitTestBehaviorPtr hit_test_behavior, | |
| 364 Combinator combinator, | |
| 365 const std::vector<uint32_t>& child_node_ids, | |
| 366 const mojo::RectF& content_rect, | |
| 367 mojo::RectFPtr image_rect, | |
| 368 uint32 image_resource_id, | |
| 369 mojo::gfx::composition::BlendPtr blend) | |
| 370 : NodeDef(node_id, | |
| 371 std::move(content_transform), | |
| 372 content_clip.Pass(), | |
| 373 hit_test_behavior.Pass(), | |
| 374 combinator, | |
| 375 child_node_ids), | |
| 376 content_rect_(content_rect), | |
| 377 image_rect_(image_rect.Pass()), | |
| 378 image_resource_id_(image_resource_id), | |
| 379 blend_(blend.Pass()) {} | |
| 380 | |
| 381 ImageNodeDef::~ImageNodeDef() {} | |
| 382 | |
| 383 bool ImageNodeDef::RecordContent(SceneContentBuilder* builder) const { | |
| 384 DCHECK(builder); | |
| 385 | |
| 386 return NodeDef::RecordContent(builder) && | |
| 387 builder->RequireResource(image_resource_id_, ResourceDef::Type::kImage, | |
| 388 node_id()); | |
| 389 } | |
| 390 | |
| 391 void ImageNodeDef::RecordPictureInner(const SceneContent* content, | |
| 392 const Snapshot* snapshot, | |
| 393 SkCanvas* canvas) const { | |
| 394 DCHECK(content); | |
| 395 DCHECK(snapshot); | |
| 396 DCHECK(canvas); | |
| 397 | |
| 398 auto image_resource = static_cast<const ImageResourceDef*>( | |
| 399 content->GetResource(image_resource_id_, ResourceDef::Type::kImage)); | |
| 400 DCHECK(image_resource); | |
| 401 | |
| 402 SkPaint paint; | |
| 403 SetPaintForBlend(&paint, blend_.get()); | |
| 404 | |
| 405 canvas->drawImageRect(image_resource->image()->image().get(), | |
| 406 image_rect_ | |
| 407 ? image_rect_->To<SkRect>() | |
| 408 : SkRect::MakeWH(image_resource->image()->width(), | |
| 409 image_resource->image()->height()), | |
| 410 content_rect_.To<SkRect>(), &paint); | |
| 411 | |
| 412 NodeDef::RecordPictureInner(content, snapshot, canvas); | |
| 413 } | |
| 414 | |
| 415 SceneNodeDef::SceneNodeDef( | |
| 416 uint32_t node_id, | |
| 417 std::unique_ptr<TransformPair> content_transform, | |
| 418 mojo::RectFPtr content_clip, | |
| 419 mojo::gfx::composition::HitTestBehaviorPtr hit_test_behavior, | |
| 420 Combinator combinator, | |
| 421 const std::vector<uint32_t>& child_node_ids, | |
| 422 uint32_t scene_resource_id, | |
| 423 uint32_t scene_version) | |
| 424 : NodeDef(node_id, | |
| 425 std::move(content_transform), | |
| 426 content_clip.Pass(), | |
| 427 hit_test_behavior.Pass(), | |
| 428 combinator, | |
| 429 child_node_ids), | |
| 430 scene_resource_id_(scene_resource_id), | |
| 431 scene_version_(scene_version) {} | |
| 432 | |
| 433 SceneNodeDef::~SceneNodeDef() {} | |
| 434 | |
| 435 bool SceneNodeDef::RecordContent(SceneContentBuilder* builder) const { | |
| 436 DCHECK(builder); | |
| 437 | |
| 438 return NodeDef::RecordContent(builder) && | |
| 439 builder->RequireResource(scene_resource_id_, ResourceDef::Type::kScene, | |
| 440 node_id()); | |
| 441 } | |
| 442 | |
| 443 Snapshot::Disposition SceneNodeDef::RecordSnapshot( | |
| 444 const SceneContent* content, | |
| 445 SnapshotBuilder* builder) const { | |
| 446 DCHECK(content); | |
| 447 DCHECK(builder); | |
| 448 | |
| 449 auto scene_resource = static_cast<const SceneResourceDef*>( | |
| 450 content->GetResource(scene_resource_id_, ResourceDef::Type::kScene)); | |
| 451 DCHECK(scene_resource); | |
| 452 | |
| 453 SceneDef* referenced_scene = scene_resource->referenced_scene().get(); | |
| 454 if (!referenced_scene) { | |
| 455 if (builder->block_log()) { | |
| 456 *builder->block_log() | |
| 457 << "Scene node blocked because its referenced scene is unavailable: " | |
| 458 << FormattedLabel(content) << std::endl; | |
| 459 } | |
| 460 return Snapshot::Disposition::kBlocked; | |
| 461 } | |
| 462 | |
| 463 Snapshot::Disposition disposition = | |
| 464 builder->SnapshotScene(referenced_scene, scene_version_, this, content); | |
| 465 if (disposition != Snapshot::Disposition::kSuccess) | |
| 466 return disposition; | |
| 467 return NodeDef::RecordSnapshot(content, builder); | |
| 468 } | |
| 469 | |
| 470 void SceneNodeDef::RecordPictureInner(const SceneContent* content, | |
| 471 const Snapshot* snapshot, | |
| 472 SkCanvas* canvas) const { | |
| 473 DCHECK(content); | |
| 474 DCHECK(snapshot); | |
| 475 DCHECK(canvas); | |
| 476 | |
| 477 const SceneContent* resolved_content = | |
| 478 snapshot->GetResolvedSceneContent(this); | |
| 479 DCHECK(resolved_content); | |
| 480 resolved_content->RecordPicture(snapshot, canvas); | |
| 481 | |
| 482 NodeDef::RecordPictureInner(content, snapshot, canvas); | |
| 483 } | |
| 484 | |
| 485 bool SceneNodeDef::HitTestInner( | |
| 486 const SceneContent* content, | |
| 487 const Snapshot* snapshot, | |
| 488 const SkPoint& local_point, | |
| 489 const SkMatrix44& global_to_local_transform, | |
| 490 mojo::Array<mojo::gfx::composition::HitPtr>* hits) const { | |
| 491 DCHECK(content); | |
| 492 DCHECK(snapshot); | |
| 493 DCHECK(hits); | |
| 494 | |
| 495 if (NodeDef::HitTestInner(content, snapshot, local_point, | |
| 496 global_to_local_transform, hits)) | |
| 497 return true; // opaque child covering referenced scene | |
| 498 | |
| 499 const SceneContent* resolved_content = | |
| 500 snapshot->GetResolvedSceneContent(this); | |
| 501 DCHECK(resolved_content); | |
| 502 | |
| 503 mojo::gfx::composition::SceneHitPtr scene_hit; | |
| 504 bool opaque = resolved_content->HitTest( | |
| 505 snapshot, local_point, global_to_local_transform, &scene_hit); | |
| 506 if (scene_hit) { | |
| 507 auto hit = mojo::gfx::composition::Hit::New(); | |
| 508 hit->set_scene(scene_hit.Pass()); | |
| 509 hits->push_back(hit.Pass()); | |
| 510 } | |
| 511 return opaque; | |
| 512 } | |
| 513 | |
| 514 LayerNodeDef::LayerNodeDef( | |
| 515 uint32_t node_id, | |
| 516 std::unique_ptr<TransformPair> content_transform, | |
| 517 mojo::RectFPtr content_clip, | |
| 518 mojo::gfx::composition::HitTestBehaviorPtr hit_test_behavior, | |
| 519 Combinator combinator, | |
| 520 const std::vector<uint32_t>& child_node_ids, | |
| 521 const mojo::RectF& layer_rect, | |
| 522 mojo::gfx::composition::BlendPtr blend) | |
| 523 : NodeDef(node_id, | |
| 524 std::move(content_transform), | |
| 525 content_clip.Pass(), | |
| 526 hit_test_behavior.Pass(), | |
| 527 combinator, | |
| 528 child_node_ids), | |
| 529 layer_rect_(layer_rect), | |
| 530 blend_(blend.Pass()) {} | |
| 531 | |
| 532 LayerNodeDef::~LayerNodeDef() {} | |
| 533 | |
| 534 void LayerNodeDef::RecordPictureInner(const SceneContent* content, | |
| 535 const Snapshot* snapshot, | |
| 536 SkCanvas* canvas) const { | |
| 537 DCHECK(content); | |
| 538 DCHECK(snapshot); | |
| 539 DCHECK(canvas); | |
| 540 | |
| 541 SkPaint paint; | |
| 542 SetPaintForBlend(&paint, blend_.get()); | |
| 543 | |
| 544 canvas->saveLayer(layer_rect_.To<SkRect>(), &paint); | |
| 545 NodeDef::RecordPictureInner(content, snapshot, canvas); | |
| 546 canvas->restore(); | |
| 547 } | |
| 548 | |
| 549 } // namespace compositor | |
| OLD | NEW |