This reverts commit f477c8b184d2364fcef0a15cee6ab5c909188229.
This commit is contained in:
parent
041c3af532
commit
41b50c22b0
@ -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.
|
||||||
|
@ -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();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user