Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upRangeError in RenderParagraph.assembleSemanticsNode #69787
Comments
|
Looks like |
|
/cc @chunhtai |
|
I am also trying to reduce the customer:money test case since they don't seem to be using ExcludeSemantics. |
|
@mehmetf The following code reproduces it without import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.ltr,
child: Center(
child: Container(
color: Colors.green,
child: RichText(
text: TextSpan(
children: [
TextSpan(
text: 'Start\n',
recognizer: TapGestureRecognizer()..onTap = () { },
),
WidgetSpan(
child: Icon(
Icons.edit,
size: 16,
),
),
WidgetSpan(
child: Icon(
Icons.edit,
size: 16,
semanticLabel: 'foo',
),
),
TextSpan(text: 'End'),
],
),
),
),
),
);
}
} |
|
This turns out to be a harder problem than I think. There is no way to tell whether a render child of renderparagrah has a semantics node or not. same thing for semantics node to know which render object creates it. It may requires some structure change. I will see if i can come up with something. |
|
As a work-around in an app you can wrap the child of the widgetspan that's causing the problem (that's the widget span that doesn't produce any semantics information) in an empty semantics container: import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.ltr,
child: Center(
child: Container(
color: Colors.green,
child: RichText(
text: TextSpan(
children: [
TextSpan(
text: 'Start\n',
recognizer: TapGestureRecognizer()..onTap = () { },
),
WidgetSpan(
child: Semantics( // HERE
container: true, // and HERE
child: Icon(
Icons.edit,
size: 16,
),
),
),
WidgetSpan(
child: Icon(
Icons.edit,
size: 16,
semanticLabel: 'foo',
),
),
TextSpan(text: 'End'),
],
),
),
),
),
);
}
} |
|
The workaround will hit another corner case. We have another issue that we only apply textscalefactor to the top most semantics node of the children. it should recursively apply the scaling down it children. |
|
@goderbauer I see. Yes, they do have a few widget spans that do not provide semantics. The odd thing is that the issue reproduces only in specific configurations. For instance: I am able to reproduce it via:
however not when I reduce the number of widgets:
If
|
|
This is my approximation of what they are doing but it fails to reproduce the problem: https://gist.github.com/mehmetf/42d11f9bb4d709e7dc699106659af66b I can see they extend |
|
@mehmetf The fact that the number of HtmlViews is relevant for whether the issue is triggered or not is very strange. I don't have an explanation for that... The gist you provided crashes for me with a different crash ("RenderBox did not set its size during layout"). Do you think it's related to this problem? It looks like something else to me. To trigger the bug described in the issue here in your gist, try adding a TextSpan child with a |
@chunhtai Can you file a separate bug for that issue? |
|
filed #69835 |
|
@goderbauer @chunhtai I know range check is the wrong fix here. However, since we are unsure how to fix it properly, do we consider it a safe bandaid? or could it generate accessibility nodes that do not map to the UI? |
|
Great! Let me know when the PR is ready so I can patch in google3 and try it on the internal repro I have. |
|
I have reduced the internal case into something manageable. It is still quite complex but I am hoping it will give you enough of a playground to figure out whether the issue is related. main.dart: https://gist.github.com/mehmetf/7001d39f3ddc674f5f54e9763f6199cc Several (huh?) moments:
|
I found this very puzzling, BUT I think I have an explanation for it! I think the reason for you needing multiple HtmlWidgets is clipping. Each of your HtmlWidgets on their own are fine. Every WidgetSpan in the HtmlWidget produces semantics, so they shouldn't crash by themselves. However, the HtmlWidget that is at the edge of the SingleScrollView viewport will get some of its content clipped (the part that's outside of the viewport). For the clipped part, we do not calculate any semantics nodes as an optimization (after all, they will not be visible) - and suddenly because of that you now have WidgetSpans that seem to not contribute any semantics (because we proactively didn't calculate the semantics for them). RenderParagraph.assembleSemantics expects semantics for each and every WidgetSpan (as we have established before) and crashes if it doesn't get them. I think the fix @chunhtai and I have in mind will also fix this particular situation where semantic information are missing due to clipping (@chunhtai we should add a test for this scenario as well). Here's a more minimal repo for the clipping case: import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ClipRect( // If you remove the clip, the crash goes away
child: Container(
color: Colors.green,
height: 100,
width: 100,
child: OverflowBox(
alignment: Alignment.topLeft,
maxWidth: double.infinity,
child: RichText(
text: TextSpan(
children: [
WidgetSpan(
child: Icon(
Icons.edit,
size: 16,
semanticLabel: 'not clipped',
),
),
TextSpan(
text: 'next WS is clipped',
recognizer: TapGestureRecognizer()..onTap = () { },
),
WidgetSpan(
child: Icon(
Icons.edit,
size: 16,
semanticLabel: 'clipped',
),
),
],
),
),
)
),
)
),
);
}
}Notice how the RichText by itself is totally fine (every WidgetSpan contributes semantics) and if you remove the This is likely also going to be the reason why the work-around proposed in #69787 (comment) will not work (sorry about that). Even if we wrap the WidgetSpans in extra Semantics containers, they can still be clipped off triggering the bug again. |
See also: b/172290978
Produces the following error: