Unverified Commit a9e27811 authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Do not do semantics for detached objects (#15320)

parent 35c43ecc
......@@ -2222,8 +2222,10 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
/// any way to update the semantics tree.
void markNeedsSemanticsUpdate() {
assert(!attached || !owner._debugDoingSemantics);
if (attached && owner._semanticsOwner == null)
if (!attached || owner._semanticsOwner == null) {
_cachedSemanticsConfiguration = null;
return;
}
// Dirty the semantics tree starting at `this` until we have reached a
// RenderObject that is a semantics boundary. All semantics past this
......
......@@ -723,24 +723,42 @@ class _GestureSemantics extends SingleChildRenderObjectWidget {
@override
RenderSemanticsGestureHandler createRenderObject(BuildContext context) {
final RenderSemanticsGestureHandler renderObject = new RenderSemanticsGestureHandler();
_updateHandlers(renderObject);
return renderObject;
return new RenderSemanticsGestureHandler(
onTap: _onTapHandler,
onLongPress: _onLongPressHandler,
onHorizontalDragUpdate: _onHorizontalDragUpdateHandler,
onVerticalDragUpdate: _onVerticalDragUpdateHandler,
);
}
void _updateHandlers(RenderSemanticsGestureHandler renderObject) {
final Map<Type, GestureRecognizer> recognizers = owner._recognizers;
renderObject
..onTap = recognizers.containsKey(TapGestureRecognizer) ? owner._handleSemanticsTap : null
..onLongPress = recognizers.containsKey(LongPressGestureRecognizer) ? owner._handleSemanticsLongPress : null
..onHorizontalDragUpdate = recognizers.containsKey(HorizontalDragGestureRecognizer) ||
recognizers.containsKey(PanGestureRecognizer) ? owner._handleSemanticsHorizontalDragUpdate : null
..onVerticalDragUpdate = recognizers.containsKey(VerticalDragGestureRecognizer) ||
recognizers.containsKey(PanGestureRecognizer) ? owner._handleSemanticsVerticalDragUpdate : null;
..onTap = _onTapHandler
..onLongPress = _onLongPressHandler
..onHorizontalDragUpdate = _onHorizontalDragUpdateHandler
..onVerticalDragUpdate = _onVerticalDragUpdateHandler;
}
@override
void updateRenderObject(BuildContext context, RenderSemanticsGestureHandler renderObject) {
_updateHandlers(renderObject);
}
GestureTapCallback get _onTapHandler {
return owner._recognizers.containsKey(TapGestureRecognizer) ? owner._handleSemanticsTap : null;
}
GestureTapCallback get _onLongPressHandler {
return owner._recognizers.containsKey(LongPressGestureRecognizer) ? owner._handleSemanticsLongPress : null;
}
GestureDragUpdateCallback get _onHorizontalDragUpdateHandler {
return owner._recognizers.containsKey(HorizontalDragGestureRecognizer) ||
owner._recognizers.containsKey(PanGestureRecognizer) ? owner._handleSemanticsHorizontalDragUpdate : null;
}
GestureDragUpdateCallback get _onVerticalDragUpdateHandler {
return owner._recognizers.containsKey(VerticalDragGestureRecognizer) ||
owner._recognizers.containsKey(PanGestureRecognizer) ? owner._handleSemanticsVerticalDragUpdate : null;
}
}
......@@ -21,6 +21,15 @@ void main() {
renderObject.markNeedsSemanticsUpdate();
expect(onNeedVisualUpdateCallCount, 2);
});
test('detached RenderObject does not do semantics', () {
final TestRenderObject renderObject = new TestRenderObject();
expect(renderObject.attached, isFalse);
expect(renderObject.describeSemanticsConfigurationCallCount, 0);
renderObject.markNeedsSemanticsUpdate();
expect(renderObject.describeSemanticsConfigurationCallCount, 0);
});
}
class TestRenderObject extends RenderObject {
......@@ -39,10 +48,13 @@ class TestRenderObject extends RenderObject {
@override
Rect get semanticBounds => new Rect.fromLTWH(0.0, 0.0, 10.0, 20.0);
int describeSemanticsConfigurationCallCount = 0;
@override
void describeSemanticsConfiguration(SemanticsConfiguration config) {
super.describeSemanticsConfiguration(config);
config.isSemanticBoundary = true;
describeSemanticsConfigurationCallCount++;
}
}
......@@ -12,6 +12,10 @@ import 'semantics_tester.dart';
void main() {
SemanticsTester semantics;
setUp(() {
debugResetSemanticsIdCounter();
});
tearDown(() {
semantics?.dispose();
semantics = null;
......@@ -327,13 +331,35 @@ void main() {
children: new List<Widget>.generate(40, (int i) {
return new Container(
child: new Text('item $i'),
height: 40.0,
height: 400.0,
);
}),
),
),
);
final TestSemantics expectedSemantics = new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
children: <TestSemantics>[
new TestSemantics(
actions: <SemanticsAction>[SemanticsAction.scrollUp],
children: <TestSemantics>[
new TestSemantics(
label: r'item 0',
textDirection: TextDirection.ltr,
),
new TestSemantics(
label: r'item 1',
textDirection: TextDirection.ltr,
),
],
),
],
),
],
);
// Start with semantics off.
expect(tester.binding.pipelineOwner.semanticsOwner, isNull);
......@@ -341,6 +367,7 @@ void main() {
semantics = new SemanticsTester(tester);
await tester.pumpAndSettle();
expect(tester.binding.pipelineOwner.semanticsOwner, isNotNull);
expect(semantics, hasSemantics(expectedSemantics, ignoreId: true, ignoreRect: true, ignoreTransform: true));
// Semantics off
semantics.dispose();
......@@ -351,6 +378,7 @@ void main() {
semantics = new SemanticsTester(tester);
await tester.pumpAndSettle();
expect(tester.binding.pipelineOwner.semanticsOwner, isNotNull);
expect(semantics, hasSemantics(expectedSemantics, ignoreId: true, ignoreRect: true, ignoreTransform: true));
});
}
......
......@@ -265,9 +265,9 @@ class TestSemantics {
return fail('expected node id $id to have hint "$hint" but found hint "${nodeData.hint}".');
if (textDirection != null && textDirection != nodeData.textDirection)
return fail('expected node id $id to have textDirection "$textDirection" but found "${nodeData.textDirection}".');
if (nextNodeId != null && nextNodeId != nodeData.nextNodeId)
if (!ignoreId && nextNodeId != null && nextNodeId != nodeData.nextNodeId)
return fail('expected node id $id to have nextNodeId "$nextNodeId" but found "${nodeData.nextNodeId}".');
if (previousNodeId != null && previousNodeId != nodeData.previousNodeId)
if (!ignoreId && previousNodeId != null && previousNodeId != nodeData.previousNodeId)
return fail('expected node id $id to have previousNodeId "$previousNodeId" but found "${nodeData.previousNodeId}".');
if ((nodeData.label != '' || nodeData.value != '' || nodeData.hint != '' || node.increasedValue != '' || node.decreasedValue != '') && nodeData.textDirection == null)
return fail('expected node id $id, which has a label, value, or hint, to have a textDirection, but it did not.');
......
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