Commit 4c5084cb authored by Adam Barth's avatar Adam Barth Committed by GitHub

Update clip geometry during hitTest if needed (#6091)

The code previously assumed that paint would be called before hitTest, but that
assumption isn't valid because RenderOpacity hit tests its children without
painting them.

Fixes #6089
parent 7238d93e
......@@ -1269,6 +1269,13 @@ abstract class RenderBox extends RenderObject {
/// The caller is responsible for transforming [position] into the local
/// coordinate space of the callee. The callee is responsible for checking
/// whether the given position is within its bounds.
///
/// Hit testing requires layout to be up-to-date but does not require painting
/// to be up-to-date. That means a render object can rely upon [performLayout]
/// having been called in [hitTest] but cannot rely upon [paint] having been
/// called. For example, a render object might be a child of a [RenderOpacity]
/// object, which calls [hitTest] on its children when its opacity is zero
/// even through it does not [paint] its children.
bool hitTest(HitTestResult result, { @required Point position }) {
assert(() {
if (needsLayout) {
......
......@@ -941,6 +941,7 @@ class RenderClipRect extends _RenderCustomClip<Rect> {
@override
bool hitTest(HitTestResult result, { Point position }) {
if (_clipper != null) {
_updateClip();
assert(_clip != null);
if (!_clip.contains(position))
return false;
......@@ -1033,6 +1034,7 @@ class RenderClipOval extends _RenderCustomClip<Rect> {
@override
bool hitTest(HitTestResult result, { Point position }) {
_updateClip();
assert(_clip != null);
Point center = _clip.center;
// convert the position to an offset from the center of the unit circle
......@@ -1082,6 +1084,7 @@ class RenderClipPath extends _RenderCustomClip<Path> {
@override
bool hitTest(HitTestResult result, { Point position }) {
if (_clipper != null) {
_updateClip();
assert(_clip != null);
if (!_clip.contains(position))
return false;
......
......@@ -78,6 +78,29 @@ void main() {
log.clear();
});
testWidgets('Transparent ClipOval hit test', (WidgetTester tester) async {
await tester.pumpWidget(
new Opacity(
opacity: 0.0,
child: new ClipOval(
child: new GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () { log.add('tap'); },
)
)
)
);
expect(log, equals(<String>[]));
await tester.tapAt(new Point(10.0, 10.0));
expect(log, equals(<String>[]));
log.clear();
await tester.tapAt(new Point(400.0, 300.0));
expect(log, equals(<String>['tap']));
log.clear();
});
testWidgets('ClipRect', (WidgetTester tester) async {
await tester.pumpWidget(
new Align(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment