Revert "Update accessibility contrast test coverage (#109784)" (#110436)

This reverts commit f477c8b184d2364fcef0a15cee6ab5c909188229.
This commit is contained in:
Casey Hillers 2022-08-28 10:30:01 -07:00 committed by GitHub
parent 041c3af532
commit 41b50c22b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 51 additions and 123 deletions

View File

@ -331,79 +331,61 @@ class MinimumTextContrastGuideline extends AccessibilityGuideline {
if (shouldSkipNode(data)) { if (shouldSkipNode(data)) {
return result; return result;
} }
final String text = data.label.isEmpty ? data.value : data.label;
final Iterable<Element> elements = find.text(text).hitTestable().evaluate();
for (final Element element in elements) {
result += await _evaluateElement(node, element, tester, image, byteData);
}
return result;
}
Future<Evaluation> _evaluateElement(
SemanticsNode node,
Element element,
WidgetTester tester,
ui.Image image,
ByteData byteData,
) async {
// Look up inherited text properties to determine text size and weight. // Look up inherited text properties to determine text size and weight.
late bool isBold; late bool isBold;
double? fontSize; double? fontSize;
final String text = data.label.isEmpty ? data.value : data.label;
final List<Element> elements = find.text(text).hitTestable().evaluate().toList();
late final Rect paintBounds; late final Rect paintBounds;
late final Rect paintBoundsWithOffset;
final RenderObject? renderBox = element.renderObject; if (elements.length == 1) {
if (renderBox is! RenderBox) { final Element element = elements.single;
throw StateError('Unexpected renderObject type: $renderBox'); final RenderObject? renderBox = element.renderObject;
} if (renderBox is! RenderBox) {
throw StateError('Unexpected renderObject type: $renderBox');
}
const Offset offset = Offset(4.0, 4.0); const Offset offset = Offset(4.0, 4.0);
paintBoundsWithOffset = Rect.fromPoints( paintBounds = Rect.fromPoints(
renderBox.localToGlobal(renderBox.paintBounds.topLeft - offset), renderBox.localToGlobal(renderBox.paintBounds.topLeft - offset),
renderBox.localToGlobal(renderBox.paintBounds.bottomRight + offset), renderBox.localToGlobal(renderBox.paintBounds.bottomRight + offset),
); );
final Widget widget = element.widget;
paintBounds = Rect.fromPoints( final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(element);
renderBox.localToGlobal(renderBox.paintBounds.topLeft), if (widget is Text) {
renderBox.localToGlobal(renderBox.paintBounds.bottomRight), final TextStyle? style = widget.style;
); final TextStyle effectiveTextStyle = style == null || style.inherit
? defaultTextStyle.style.merge(widget.style)
final Offset? nodeOffset = node.transform != null ? MatrixUtils.getAsTranslation(node.transform!) : null; : style;
isBold = effectiveTextStyle.fontWeight == FontWeight.bold;
final Rect nodeBounds = node.rect.shift(nodeOffset ?? Offset.zero); fontSize = effectiveTextStyle.fontSize;
final Rect intersection = nodeBounds.intersect(paintBounds); } else if (widget is EditableText) {
if (intersection.width <= 0 || intersection.height <= 0) { isBold = widget.style.fontWeight == FontWeight.bold;
// Skip this element since it doesn't correspond to the given semantic fontSize = widget.style.fontSize;
// node. } else {
return const Evaluation.pass(); throw StateError('Unexpected widget type: ${widget.runtimeType}');
} }
} else if (elements.length > 1) {
final Widget widget = element.widget; return Evaluation.fail(
final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(element); 'Multiple nodes with the same label: ${data.label}\n',
if (widget is Text) { );
final TextStyle? style = widget.style;
final TextStyle effectiveTextStyle = style == null || style.inherit
? defaultTextStyle.style.merge(widget.style)
: style;
isBold = effectiveTextStyle.fontWeight == FontWeight.bold;
fontSize = effectiveTextStyle.fontSize;
} else if (widget is EditableText) {
isBold = widget.style.fontWeight == FontWeight.bold;
fontSize = widget.style.fontSize;
} else { } else {
throw StateError('Unexpected widget type: ${widget.runtimeType}'); // If we can't find the text node then assume the label does not
// correspond to actual text.
return result;
} }
if (isNodeOffScreen(paintBoundsWithOffset, tester.binding.window)) { if (isNodeOffScreen(paintBounds, tester.binding.window)) {
return const Evaluation.pass(); return result;
} }
final Map<Color, int> colorHistogram = _colorsWithinRect(byteData, paintBoundsWithOffset, image.width, image.height); final Map<Color, int> colorHistogram = _colorsWithinRect(byteData, paintBounds, image.width, image.height);
// Node was too far off screen. // Node was too far off screen.
if (colorHistogram.isEmpty) { if (colorHistogram.isEmpty) {
return const Evaluation.pass(); return result;
} }
final _ContrastReport report = _ContrastReport(colorHistogram); final _ContrastReport report = _ContrastReport(colorHistogram);
@ -412,18 +394,19 @@ class MinimumTextContrastGuideline extends AccessibilityGuideline {
final double targetContrastRatio = this.targetContrastRatio(fontSize, bold: isBold); final double targetContrastRatio = this.targetContrastRatio(fontSize, bold: isBold);
if (contrastRatio - targetContrastRatio >= _tolerance) { if (contrastRatio - targetContrastRatio >= _tolerance) {
return const Evaluation.pass(); return result + const Evaluation.pass();
} }
return Evaluation.fail( return result +
'$node:\n' Evaluation.fail(
'Expected contrast ratio of at least $targetContrastRatio ' '$node:\n'
'but found ${contrastRatio.toStringAsFixed(2)} ' 'Expected contrast ratio of at least $targetContrastRatio '
'for a font size of $fontSize.\n' 'but found ${contrastRatio.toStringAsFixed(2)} '
'The computed colors was:\n' 'for a font size of $fontSize.\n'
'light - ${report.lightColor}, dark - ${report.darkColor}\n' 'The computed colors was:\n'
'See also: ' 'light - ${report.lightColor}, dark - ${report.darkColor}\n'
'https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html', 'See also: '
); 'https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html',
);
} }
/// Returns whether node should be skipped. /// Returns whether node should be skipped.

View File

@ -23,61 +23,6 @@ void main() {
handle.dispose(); handle.dispose();
}); });
testWidgets('Multiple text with same label', (WidgetTester tester) async {
final SemanticsHandle handle = tester.ensureSemantics();
await tester.pumpWidget(
_boilerplate(
Column(
children: const <Widget>[
Text(
'this is a test',
style: TextStyle(fontSize: 14.0, color: Colors.black),
),
Text(
'this is a test',
style: TextStyle(fontSize: 14.0, color: Colors.black),
),
],
),
),
);
await expectLater(tester, meetsGuideline(textContrastGuideline));
handle.dispose();
});
testWidgets(
'Multiple text with same label but Nodes excluded from '
'semantic tree have failing contrast should pass a11y guideline ',
(WidgetTester tester) async {
final SemanticsHandle handle = tester.ensureSemantics();
await tester.pumpWidget(
_boilerplate(
Column(
children: const <Widget>[
Text(
'this is a test',
style: TextStyle(fontSize: 14.0, color: Colors.black),
),
SizedBox(height: 50),
Text(
'this is a test',
style: TextStyle(fontSize: 14.0, color: Colors.black),
),
SizedBox(height: 50),
ExcludeSemantics(
child: Text(
'this is a test',
style: TextStyle(fontSize: 14.0, color: Colors.white),
),
),
],
),
),
);
await expectLater(tester, meetsGuideline(textContrastGuideline));
handle.dispose();
});
testWidgets('white text on black background - Text Widget - direct style', testWidgets('white text on black background - Text Widget - direct style',
(WidgetTester tester) async { (WidgetTester tester) async {
final SemanticsHandle handle = tester.ensureSemantics(); final SemanticsHandle handle = tester.ensureSemantics();