forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 1
/
image.dart
90 lines (80 loc) · 3.06 KB
/
image.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import '../dom.dart';
import 'semantics.dart';
/// Represents semantic objects that deliver information in a visual manner.
///
/// Uses aria img role to convey this semantic information to the element.
///
/// Screen-readers takes advantage of "aria-label" to describe the visual.
class ImageRoleManager extends PrimaryRoleManager {
ImageRoleManager(SemanticsObject semanticsObject)
: super.blank(PrimaryRole.image, semanticsObject) {
// The following secondary roles can coexist with images. `LabelAndValue` is
// not used because this role manager uses special auxiliary elements to
// supply ARIA labels.
// TODO(yjbanov): reevaluate usage of aux elements, https://github.com/flutter/flutter/issues/129317
addFocusManagement();
addLiveRegion();
addRouteName();
addTappable();
}
/// The element with role="img" and aria-label could block access to all
/// children elements, therefore create an auxiliary element and describe the
/// image in that if the semantic object have child nodes.
DomElement? _auxiliaryImageElement;
@override
void update() {
super.update();
if (semanticsObject.isVisualOnly && semanticsObject.hasChildren) {
if (_auxiliaryImageElement == null) {
_auxiliaryImageElement = domDocument.createElement('flt-semantics-img');
// Absolute positioning and sizing of leaf text elements confuses
// VoiceOver. So we let the browser size the value node. The node will
// still have a bigger tap area. However, if the node is a parent to
// other nodes, then VoiceOver behaves as expected with absolute
// positioning and sizing.
if (semanticsObject.hasChildren) {
_auxiliaryImageElement!.style
..position = 'absolute'
..top = '0'
..left = '0'
..width = '${semanticsObject.rect!.width}px'
..height = '${semanticsObject.rect!.height}px';
}
_auxiliaryImageElement!.style.fontSize = '6px';
semanticsObject.element.append(_auxiliaryImageElement!);
}
_auxiliaryImageElement!.setAttribute('role', 'img');
_setLabel(_auxiliaryImageElement);
} else if (semanticsObject.isVisualOnly) {
semanticsObject.setAriaRole('img');
_setLabel(semanticsObject.element);
_cleanUpAuxiliaryElement();
} else {
_cleanUpAuxiliaryElement();
_cleanupElement();
}
}
void _setLabel(DomElement? element) {
if (semanticsObject.hasLabel) {
element!.setAttribute('aria-label', semanticsObject.label!);
}
}
void _cleanUpAuxiliaryElement() {
if (_auxiliaryImageElement != null) {
_auxiliaryImageElement!.remove();
_auxiliaryImageElement = null;
}
}
void _cleanupElement() {
semanticsObject.element.removeAttribute('aria-label');
}
@override
void dispose() {
super.dispose();
_cleanUpAuxiliaryElement();
_cleanupElement();
}
}