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 |
index 6a1dfc9a974083244d8bf59ee8bcbe6a2a86f066..6092bab1c79677760dafc30201125752b4960b90 100644 |
--- a/services/gfx/compositor/graph/node_def.cc |
+++ b/services/gfx/compositor/graph/node_def.cc |
@@ -15,7 +15,9 @@ |
#include "services/gfx/compositor/render/render_image.h" |
#include "third_party/skia/include/core/SkCanvas.h" |
#include "third_party/skia/include/core/SkColor.h" |
+#include "third_party/skia/include/core/SkMatrix.h" |
#include "third_party/skia/include/core/SkPaint.h" |
+#include "third_party/skia/include/core/SkPoint.h" |
#include "third_party/skia/include/core/SkRect.h" |
namespace compositor { |
@@ -29,16 +31,23 @@ void SetPaintForBlend(SkPaint* paint, mojo::gfx::composition::Blend* blend) { |
if (blend) |
paint->setAlpha(blend->alpha); |
} |
+ |
+bool Contains(const SkRect& bounds, const SkPoint& point) { |
+ return point.x() >= bounds.left() && point.x() < bounds.right() && |
+ point.y() >= bounds.top() && point.y() < bounds.bottom(); |
+} |
} // namespace |
NodeDef::NodeDef(uint32_t node_id, |
mojo::TransformPtr content_transform, |
mojo::RectPtr content_clip, |
+ mojo::gfx::composition::HitTestBehaviorPtr hit_test_behavior, |
Combinator combinator, |
const std::vector<uint32_t>& child_node_ids) |
: node_id_(node_id), |
content_transform_(content_transform.Pass()), |
content_clip_(content_clip.Pass()), |
+ hit_test_behavior_(hit_test_behavior.Pass()), |
combinator_(combinator), |
child_node_ids_(child_node_ids) {} |
@@ -222,16 +231,105 @@ void NodeDef::RecordPictureInner(const SceneContent* content, |
}); |
} |
-RectNodeDef::RectNodeDef(uint32_t node_id, |
- mojo::TransformPtr content_transform, |
- mojo::RectPtr content_clip, |
- Combinator combinator, |
- const std::vector<uint32_t>& child_node_ids, |
- const mojo::Rect& content_rect, |
- const mojo::gfx::composition::Color& color) |
+void NodeDef::HitTest(const SceneContent* content, |
+ const Snapshot* snapshot, |
+ const SkPoint& global_point, |
+ const SkMatrix& parent_transform, |
+ bool* opaque, |
+ mojo::Array<mojo::gfx::composition::HitPtr>* hits) const { |
+ DCHECK(content); |
+ DCHECK(snapshot); |
+ DCHECK(opaque); |
+ DCHECK(hits); |
+ |
+ SkMatrix node_transform = parent_transform; |
+ if (content_transform_) |
+ node_transform.postConcat(content_transform_.To<SkMatrix>()); |
abarth
2016/03/09 04:02:48
I think you want to do this work in 4x4 matrices.
jeffbrown
2016/03/09 20:32:11
You're probably right. Noted for later since this
|
+ if (content_clip_) { |
+ SkRect global_clip_rect; |
+ node_transform.mapRect(&global_clip_rect, content_clip_->To<SkRect>()); |
abarth
2016/03/09 04:02:48
This isn't very efficient because you're doing a m
jeffbrown
2016/03/09 20:32:11
I previously wrote the code that way. The trade-o
|
+ if (!Contains(global_clip_rect, global_point)) |
+ return; |
+ } |
+ |
+ if (!hit_test_behavior_ || !hit_test_behavior_->prune) |
+ HitTestInner(content, snapshot, global_point, node_transform, opaque, hits); |
+ |
+ if (!hit_test_behavior_ || |
+ hit_test_behavior_->visibility == |
+ mojo::gfx::composition::HitTestBehavior::Visibility::INVISIBLE) |
+ return; |
+ |
+ if (hit_test_behavior_->hit_rect) { |
+ SkRect global_hit_rect; |
+ node_transform.mapRect(&global_hit_rect, |
+ hit_test_behavior_->hit_rect->To<SkRect>()); |
+ if (!Contains(global_hit_rect, global_point)) |
+ return; |
+ } |
+ |
+ if (hit_test_behavior_->visibility == |
+ mojo::gfx::composition::HitTestBehavior::Visibility::OPAQUE) |
+ *opaque = true; |
+ |
+ SkMatrix inverse_node_transform; |
+ if (!node_transform.invert(&inverse_node_transform)) { |
+ // Matrix is singular! |
+ // Return [0,0,0][0,0,0][0,0,1] (all zeroes except last component). |
+ // This causes all points to be mapped to (0,0) when transformed. |
+ inverse_node_transform.setScale(0.f, 0.f); |
+ } |
+ |
+ auto hit = mojo::gfx::composition::Hit::New(); |
+ hit->set_node(mojo::gfx::composition::NodeHit::New()); |
+ hit->get_node()->node_id = node_id_; |
+ hit->get_node()->transform = |
+ mojo::ConvertTo<mojo::TransformPtr>(inverse_node_transform); |
+ hits->push_back(hit.Pass()); |
+} |
+ |
+void NodeDef::HitTestInner( |
abarth
2016/03/09 04:02:48
s/HitTestInner/HitTestChildren/ ?
jeffbrown
2016/03/09 20:32:11
Strictly speaking it's not just children since ref
|
+ const SceneContent* content, |
+ const Snapshot* snapshot, |
+ const SkPoint& global_point, |
+ const SkMatrix& node_transform, |
+ bool* opaque, |
+ mojo::Array<mojo::gfx::composition::HitPtr>* hits) const { |
+ DCHECK(content); |
+ DCHECK(snapshot); |
+ DCHECK(opaque); |
+ DCHECK(hits); |
+ |
+ // TODO(jeffbrown): Implement a more efficient way to traverse children in |
+ // reverse order. |
+ std::vector<const NodeDef*> children; |
+ TraverseSnapshottedChildren( |
+ content, snapshot, [this, &children](const NodeDef* child_node) -> bool { |
+ children.push_back(child_node); |
+ return true; |
+ }); |
+ |
+ for (auto it = children.crbegin(); it != children.crend(); ++it) { |
+ (*it)->HitTest(content, snapshot, global_point, node_transform, opaque, |
+ hits); |
+ if (*opaque) |
abarth
2016/03/09 04:02:48
In other systems, we've passed this value through
jeffbrown
2016/03/09 20:32:11
SceneContent::HitTest returns a SceneHitPtr as its
|
+ break; |
+ } |
+} |
+ |
+RectNodeDef::RectNodeDef( |
+ uint32_t node_id, |
+ mojo::TransformPtr content_transform, |
+ mojo::RectPtr content_clip, |
+ mojo::gfx::composition::HitTestBehaviorPtr hit_test_behavior, |
+ Combinator combinator, |
+ const std::vector<uint32_t>& child_node_ids, |
+ const mojo::Rect& content_rect, |
+ const mojo::gfx::composition::Color& color) |
: NodeDef(node_id, |
content_transform.Pass(), |
content_clip.Pass(), |
+ hit_test_behavior.Pass(), |
combinator, |
child_node_ids), |
content_rect_(content_rect), |
@@ -253,18 +351,21 @@ void RectNodeDef::RecordPictureInner(const SceneContent* content, |
NodeDef::RecordPictureInner(content, snapshot, canvas); |
} |
-ImageNodeDef::ImageNodeDef(uint32_t node_id, |
- mojo::TransformPtr content_transform, |
- mojo::RectPtr content_clip, |
- Combinator combinator, |
- const std::vector<uint32_t>& child_node_ids, |
- const mojo::Rect& content_rect, |
- mojo::RectPtr image_rect, |
- uint32 image_resource_id, |
- mojo::gfx::composition::BlendPtr blend) |
+ImageNodeDef::ImageNodeDef( |
+ uint32_t node_id, |
+ mojo::TransformPtr content_transform, |
+ mojo::RectPtr content_clip, |
+ mojo::gfx::composition::HitTestBehaviorPtr hit_test_behavior, |
+ Combinator combinator, |
+ const std::vector<uint32_t>& child_node_ids, |
+ const mojo::Rect& content_rect, |
+ mojo::RectPtr image_rect, |
+ uint32 image_resource_id, |
+ mojo::gfx::composition::BlendPtr blend) |
: NodeDef(node_id, |
content_transform.Pass(), |
content_clip.Pass(), |
+ hit_test_behavior.Pass(), |
combinator, |
child_node_ids), |
content_rect_(content_rect), |
@@ -306,16 +407,19 @@ void ImageNodeDef::RecordPictureInner(const SceneContent* content, |
NodeDef::RecordPictureInner(content, snapshot, canvas); |
} |
-SceneNodeDef::SceneNodeDef(uint32_t node_id, |
- mojo::TransformPtr content_transform, |
- mojo::RectPtr content_clip, |
- Combinator combinator, |
- const std::vector<uint32_t>& child_node_ids, |
- uint32_t scene_resource_id, |
- uint32_t scene_version) |
+SceneNodeDef::SceneNodeDef( |
+ uint32_t node_id, |
+ mojo::TransformPtr content_transform, |
+ mojo::RectPtr content_clip, |
+ mojo::gfx::composition::HitTestBehaviorPtr hit_test_behavior, |
+ Combinator combinator, |
+ const std::vector<uint32_t>& child_node_ids, |
+ uint32_t scene_resource_id, |
+ uint32_t scene_version) |
: NodeDef(node_id, |
content_transform.Pass(), |
content_clip.Pass(), |
+ hit_test_behavior.Pass(), |
combinator, |
child_node_ids), |
scene_resource_id_(scene_resource_id), |
@@ -368,24 +472,51 @@ void SceneNodeDef::RecordPictureInner(const SceneContent* content, |
const SceneContent* resolved_content = |
snapshot->GetResolvedSceneContent(this); |
DCHECK(resolved_content); |
- |
- const NodeDef* root_node = resolved_content->GetRootNodeIfExists(); |
- DCHECK(root_node); // must have a root otherwise would have been blocked |
- root_node->RecordPicture(resolved_content, snapshot, canvas); |
+ resolved_content->RecordPicture(snapshot, canvas); |
NodeDef::RecordPictureInner(content, snapshot, canvas); |
} |
-LayerNodeDef::LayerNodeDef(uint32_t node_id, |
- mojo::TransformPtr content_transform, |
- mojo::RectPtr content_clip, |
- Combinator combinator, |
- const std::vector<uint32_t>& child_node_ids, |
- const mojo::Size& size, |
- mojo::gfx::composition::BlendPtr blend) |
+void SceneNodeDef::HitTestInner( |
+ const SceneContent* content, |
+ const Snapshot* snapshot, |
+ const SkPoint& global_point, |
+ const SkMatrix& node_transform, |
+ bool* opaque, |
+ mojo::Array<mojo::gfx::composition::HitPtr>* hits) const { |
+ DCHECK(content); |
+ DCHECK(snapshot); |
+ DCHECK(opaque); |
+ DCHECK(hits); |
+ |
+ NodeDef::HitTestInner(content, snapshot, global_point, node_transform, opaque, |
+ hits); |
abarth
2016/03/09 04:02:48
Do we need to test opaque after calling this funct
jeffbrown
2016/03/09 20:32:11
Initially I didn't think so since I was imagining
|
+ |
+ const SceneContent* resolved_content = |
+ snapshot->GetResolvedSceneContent(this); |
+ DCHECK(resolved_content); |
+ mojo::gfx::composition::SceneHitPtr scene_hit = |
+ resolved_content->HitTest(snapshot, global_point, node_transform, opaque); |
+ if (scene_hit) { |
+ auto hit = mojo::gfx::composition::Hit::New(); |
+ hit->set_scene(scene_hit.Pass()); |
+ hits->push_back(hit.Pass()); |
+ } |
+} |
+ |
+LayerNodeDef::LayerNodeDef( |
+ uint32_t node_id, |
+ mojo::TransformPtr content_transform, |
+ mojo::RectPtr content_clip, |
+ mojo::gfx::composition::HitTestBehaviorPtr hit_test_behavior, |
+ Combinator combinator, |
+ const std::vector<uint32_t>& child_node_ids, |
+ const mojo::Size& size, |
+ mojo::gfx::composition::BlendPtr blend) |
: NodeDef(node_id, |
content_transform.Pass(), |
content_clip.Pass(), |
+ hit_test_behavior.Pass(), |
combinator, |
child_node_ids), |
size_(size), |