This reverts commit f477c8b184d2364fcef0a15cee6ab5c909188229.
This commit is contained in:
parent
041c3af532
commit
41b50c22b0
@ -331,79 +331,61 @@ class MinimumTextContrastGuideline extends AccessibilityGuideline {
|
||||
if (shouldSkipNode(data)) {
|
||||
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.
|
||||
late bool isBold;
|
||||
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 paintBoundsWithOffset;
|
||||
|
||||
final RenderObject? renderBox = element.renderObject;
|
||||
if (renderBox is! RenderBox) {
|
||||
throw StateError('Unexpected renderObject type: $renderBox');
|
||||
}
|
||||
if (elements.length == 1) {
|
||||
final Element element = elements.single;
|
||||
final RenderObject? renderBox = element.renderObject;
|
||||
if (renderBox is! RenderBox) {
|
||||
throw StateError('Unexpected renderObject type: $renderBox');
|
||||
}
|
||||
|
||||
const Offset offset = Offset(4.0, 4.0);
|
||||
paintBoundsWithOffset = Rect.fromPoints(
|
||||
renderBox.localToGlobal(renderBox.paintBounds.topLeft - offset),
|
||||
renderBox.localToGlobal(renderBox.paintBounds.bottomRight + offset),
|
||||
);
|
||||
|
||||
paintBounds = Rect.fromPoints(
|
||||
renderBox.localToGlobal(renderBox.paintBounds.topLeft),
|
||||
renderBox.localToGlobal(renderBox.paintBounds.bottomRight),
|
||||
);
|
||||
|
||||
final Offset? nodeOffset = node.transform != null ? MatrixUtils.getAsTranslation(node.transform!) : null;
|
||||
|
||||
final Rect nodeBounds = node.rect.shift(nodeOffset ?? Offset.zero);
|
||||
final Rect intersection = nodeBounds.intersect(paintBounds);
|
||||
if (intersection.width <= 0 || intersection.height <= 0) {
|
||||
// Skip this element since it doesn't correspond to the given semantic
|
||||
// node.
|
||||
return const Evaluation.pass();
|
||||
}
|
||||
|
||||
final Widget widget = element.widget;
|
||||
final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(element);
|
||||
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;
|
||||
const Offset offset = Offset(4.0, 4.0);
|
||||
paintBounds = Rect.fromPoints(
|
||||
renderBox.localToGlobal(renderBox.paintBounds.topLeft - offset),
|
||||
renderBox.localToGlobal(renderBox.paintBounds.bottomRight + offset),
|
||||
);
|
||||
final Widget widget = element.widget;
|
||||
final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(element);
|
||||
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 {
|
||||
throw StateError('Unexpected widget type: ${widget.runtimeType}');
|
||||
}
|
||||
} else if (elements.length > 1) {
|
||||
return Evaluation.fail(
|
||||
'Multiple nodes with the same label: ${data.label}\n',
|
||||
);
|
||||
} 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)) {
|
||||
return const Evaluation.pass();
|
||||
if (isNodeOffScreen(paintBounds, tester.binding.window)) {
|
||||
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.
|
||||
if (colorHistogram.isEmpty) {
|
||||
return const Evaluation.pass();
|
||||
return result;
|
||||
}
|
||||
|
||||
final _ContrastReport report = _ContrastReport(colorHistogram);
|
||||
@ -412,18 +394,19 @@ class MinimumTextContrastGuideline extends AccessibilityGuideline {
|
||||
final double targetContrastRatio = this.targetContrastRatio(fontSize, bold: isBold);
|
||||
|
||||
if (contrastRatio - targetContrastRatio >= _tolerance) {
|
||||
return const Evaluation.pass();
|
||||
return result + const Evaluation.pass();
|
||||
}
|
||||
return Evaluation.fail(
|
||||
'$node:\n'
|
||||
'Expected contrast ratio of at least $targetContrastRatio '
|
||||
'but found ${contrastRatio.toStringAsFixed(2)} '
|
||||
'for a font size of $fontSize.\n'
|
||||
'The computed colors was:\n'
|
||||
'light - ${report.lightColor}, dark - ${report.darkColor}\n'
|
||||
'See also: '
|
||||
'https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html',
|
||||
);
|
||||
return result +
|
||||
Evaluation.fail(
|
||||
'$node:\n'
|
||||
'Expected contrast ratio of at least $targetContrastRatio '
|
||||
'but found ${contrastRatio.toStringAsFixed(2)} '
|
||||
'for a font size of $fontSize.\n'
|
||||
'The computed colors was:\n'
|
||||
'light - ${report.lightColor}, dark - ${report.darkColor}\n'
|
||||
'See also: '
|
||||
'https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html',
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns whether node should be skipped.
|
||||
|
@ -23,61 +23,6 @@ void main() {
|
||||
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',
|
||||
(WidgetTester tester) async {
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
|
Loading…
x
Reference in New Issue
Block a user