Unverified Commit bc4cacac authored by Tomasz Gucio's avatar Tomasz Gucio Committed by GitHub

Take paint offset into account for inline children hit test in Editable (#131675)

parent 545ecd29
......@@ -1916,9 +1916,9 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
@override
@protected
bool hitTestChildren(BoxHitTestResult result, { required Offset position }) {
final Offset effectivePosition = position - _paintOffset;
final InlineSpan? textSpan = _textPainter.text;
if (textSpan != null) {
final Offset effectivePosition = position - _paintOffset;
final TextPosition textPosition = _textPainter.getPositionForOffset(effectivePosition);
final Object? span = textSpan.getSpanForPosition(textPosition);
if (span is HitTestTarget) {
......@@ -1926,7 +1926,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
return true;
}
}
return hitTestInlineChildren(result, position);
return hitTestInlineChildren(result, effectivePosition);
}
late TapGestureRecognizer _tap;
......
......@@ -1721,6 +1721,89 @@ void main() {
editable.hitTest(result, position: const Offset(5.0, 15.0));
expect(result.path, hasLength(0));
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/61020
test('hits correct WidgetSpan when scrolled', () {
final String text = '${"\n" * 10}test';
final TextSelectionDelegate delegate = _FakeEditableTextState()
..textEditingValue = TextEditingValue(
text: text,
selection: const TextSelection.collapsed(offset: 13),
);
final List<RenderBox> renderBoxes = <RenderBox>[
RenderParagraph(const TextSpan(text: 'a'), textDirection: TextDirection.ltr),
RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr),
RenderParagraph(const TextSpan(text: 'c'), textDirection: TextDirection.ltr),
];
final RenderEditable editable = RenderEditable(
maxLines: null,
text: TextSpan(
style: const TextStyle(height: 1.0, fontSize: 10.0),
children: <InlineSpan>[
TextSpan(text: text),
const WidgetSpan(child: Text('a')),
const TextSpan(children: <InlineSpan>[
WidgetSpan(child: Text('b')),
WidgetSpan(child: Text('c')),
],
),
],
),
startHandleLayerLink: LayerLink(),
endHandleLayerLink: LayerLink(),
textDirection: TextDirection.ltr,
offset: ViewportOffset.fixed(100.0), // equal to the height of the 10 empty lines
textSelectionDelegate: delegate,
selection: const TextSelection.collapsed(
offset: 0,
),
children: renderBoxes,
);
_applyParentData(renderBoxes, editable.text!);
layout(editable, constraints: BoxConstraints.loose(const Size(500.0, 500.0)));
// Prepare for painting after layout.
pumpFrame(phase: EnginePhase.compositingBits);
BoxHitTestResult result = BoxHitTestResult();
editable.hitTest(result, position: Offset.zero);
// We expect two hit test entries in the path because the RenderEditable
// will add itself as well.
expect(result.path, hasLength(2));
HitTestTarget target = result.path.first.target;
expect(target, isA<TextSpan>());
expect((target as TextSpan).text, text);
// Only testing the RenderEditable entry here once, not anymore below.
expect(result.path.last.target, isA<RenderEditable>());
result = BoxHitTestResult();
editable.hitTest(result, position: const Offset(15.0, 0.0));
expect(result.path, hasLength(2));
target = result.path.first.target;
expect(target, isA<TextSpan>());
expect((target as TextSpan).text, text);
result = BoxHitTestResult();
editable.hitTest(result, position: const Offset(41.0, 0.0));
expect(result.path, hasLength(3));
target = result.path.first.target;
expect(target, isA<TextSpan>());
expect((target as TextSpan).text, 'a');
result = BoxHitTestResult();
editable.hitTest(result, position: const Offset(55.0, 0.0));
expect(result.path, hasLength(3));
target = result.path.first.target;
expect(target, isA<TextSpan>());
expect((target as TextSpan).text, 'b');
result = BoxHitTestResult();
editable.hitTest(result, position: const Offset(69.0, 5.0));
expect(result.path, hasLength(3));
target = result.path.first.target;
expect(target, isA<TextSpan>());
expect((target as TextSpan).text, 'c');
result = BoxHitTestResult();
editable.hitTest(result, position: const Offset(5.0, 15.0));
expect(result.path, hasLength(2));
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/61020
});
test('does not skip TextPainter.layout because of invalid cache', () {
......
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