Commit d65cda23 authored by Adam Barth's avatar Adam Barth Committed by GitHub

Switch the model for SemanticsNode to use dart:ui types (#6234)

This will make it easier to switch to SemanticsUpdateBuilder.
parent 41a91a7a
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:math' as math; import 'dart:math' as math;
import 'dart:ui' show Rect; import 'dart:ui' show Rect, SemanticsAction, SemanticsFlags;
import 'package:flutter_services/semantics.dart' as mojom; import 'package:flutter_services/semantics.dart' as mojom;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
...@@ -13,55 +13,7 @@ import 'package:vector_math/vector_math_64.dart'; ...@@ -13,55 +13,7 @@ import 'package:vector_math/vector_math_64.dart';
import 'node.dart'; import 'node.dart';
/// The possible actions that can be conveyed from the operating system export 'dart:ui' show SemanticsAction;
/// accessibility APIs to a [SemanticsNode] object.
enum SemanticsAction {
/// The equivalent of a user briefly tapping the screen with the finger
/// without moving it.
tap,
/// The equivalent of a user pressing and holding the screen with the finger
/// for a few seconds without moving it.
longPress,
/// The equivalent of a user moving their finger across the screen from right
/// to left.
///
/// This action should be recognized by controls that are horizontally
/// scrollable.
scrollLeft,
/// The equivalent of a user moving their finger across the screen from left
/// to right.
///
/// This action should be recognized by controls that are horizontally
/// scrollable.
scrollRight,
/// The equivalent of a user moving their finger across the screen from
/// bottom to top.
///
/// This action should be recognized by controls that are vertically
/// scrollable.
scrollUp,
/// The equivalent of a user moving their finger across the screen from top
/// to bottom.
///
/// This action should be recognized by controls that are vertically
/// scrollable.
scrollDown,
/// A request to increase the value represented by the [SemanticsNode].
///
/// For example, this action might be recognized by a slider control.
increase,
/// A request to decrease the value represented by the [SemanticsNode].
///
/// For example, this action might be recognized by a slider control.
decrease,
}
/// Interface for [RenderObject]s to implement when they want to support /// Interface for [RenderObject]s to implement when they want to support
/// being tapped, etc. /// being tapped, etc.
...@@ -89,13 +41,6 @@ abstract class SemanticsActionHandler { // ignore: one_member_abstracts ...@@ -89,13 +41,6 @@ abstract class SemanticsActionHandler { // ignore: one_member_abstracts
/// contract that semantic annotators must follow. /// contract that semantic annotators must follow.
typedef void SemanticsAnnotator(SemanticsNode semantics); typedef void SemanticsAnnotator(SemanticsNode semantics);
enum _SemanticsFlags {
mergeAllDescendantsIntoThisNode,
inheritedMergeAllDescendantsIntoThisNode, // whether an ancestor had mergeAllDescendantsIntoThisNode set
hasCheckedState,
isChecked,
}
/// Signature for a function that is called for each [SemanticsNode]. /// Signature for a function that is called for each [SemanticsNode].
/// ///
/// Return false to stop visiting nodes. /// Return false to stop visiting nodes.
...@@ -173,7 +118,7 @@ class SemanticsNode extends AbstractNode { ...@@ -173,7 +118,7 @@ class SemanticsNode extends AbstractNode {
// FLAGS AND LABELS // FLAGS AND LABELS
// These are supposed to be set by SemanticsAnnotator obtained from getSemanticsAnnotators // These are supposed to be set by SemanticsAnnotator obtained from getSemanticsAnnotators
final Set<SemanticsAction> _actions = new Set<SemanticsAction>(); int _actions = 0;
/// Adds the given action to the set of semantic actions. /// Adds the given action to the set of semantic actions.
/// ///
...@@ -181,8 +126,11 @@ class SemanticsNode extends AbstractNode { ...@@ -181,8 +126,11 @@ class SemanticsNode extends AbstractNode {
/// [SemanticsActionHandler.performAction] will be called with the chosen /// [SemanticsActionHandler.performAction] will be called with the chosen
/// action. /// action.
void addAction(SemanticsAction action) { void addAction(SemanticsAction action) {
if (_actions.add(action)) final int index = action.index;
if ((_actions & index) == 0) {
_actions |= index;
_markDirty(); _markDirty();
}
} }
/// Adds the [SemanticsAction.scrollLeft] and [SemanticsAction.scrollRight] actions. /// Adds the [SemanticsAction.scrollLeft] and [SemanticsAction.scrollRight] actions.
...@@ -204,36 +152,55 @@ class SemanticsNode extends AbstractNode { ...@@ -204,36 +152,55 @@ class SemanticsNode extends AbstractNode {
} }
bool _hasAction(SemanticsAction action) { bool _hasAction(SemanticsAction action) {
return _actionHandler != null && _actions.contains(action); return _actionHandler != null && (_actions & action.index) != 0;
} }
BitField<_SemanticsFlags> _flags = new BitField<_SemanticsFlags>.filled(_SemanticsFlags.values.length, false); /// Whether all this node and all of its descendants should be treated as one logical entity.
bool get mergeAllDescendantsIntoThisNode => _mergeAllDescendantsIntoThisNode;
void _setFlag(_SemanticsFlags flag, bool value, { bool needsHandler: false }) { bool _mergeAllDescendantsIntoThisNode = false;
set mergeAllDescendantsIntoThisNode(bool value) {
assert(value != null); assert(value != null);
assert((!needsHandler) || (_actionHandler != null) || (value == false)); if (_mergeAllDescendantsIntoThisNode == value)
if (_flags[flag] != value) { return;
_flags[flag] = value; _mergeAllDescendantsIntoThisNode = value;
_markDirty(); _markDirty();
}
} }
/// Whether all this node and all of its descendants should be treated as one logical entity. bool get _inheritedMergeAllDescendantsIntoThisNode => _inheritedMergeAllDescendantsIntoThisNodeValue;
bool get mergeAllDescendantsIntoThisNode => _flags[_SemanticsFlags.mergeAllDescendantsIntoThisNode]; bool _inheritedMergeAllDescendantsIntoThisNodeValue = false;
set mergeAllDescendantsIntoThisNode(bool value) => _setFlag(_SemanticsFlags.mergeAllDescendantsIntoThisNode, value); set _inheritedMergeAllDescendantsIntoThisNode(bool value) {
assert(value != null);
bool get _inheritedMergeAllDescendantsIntoThisNode => _flags[_SemanticsFlags.inheritedMergeAllDescendantsIntoThisNode]; if (_inheritedMergeAllDescendantsIntoThisNodeValue == value)
set _inheritedMergeAllDescendantsIntoThisNode(bool value) => _setFlag(_SemanticsFlags.inheritedMergeAllDescendantsIntoThisNode, value); return;
_inheritedMergeAllDescendantsIntoThisNodeValue = value;
_markDirty();
}
bool get _shouldMergeAllDescendantsIntoThisNode => mergeAllDescendantsIntoThisNode || _inheritedMergeAllDescendantsIntoThisNode; bool get _shouldMergeAllDescendantsIntoThisNode => mergeAllDescendantsIntoThisNode || _inheritedMergeAllDescendantsIntoThisNode;
int _flags = 0;
void _setFlag(SemanticsFlags flag, bool value) {
final int index = flag.index;
if (value) {
if ((_flags & index) == 0) {
_flags |= index;
_markDirty();
}
} else {
if ((_flags & index) != 0) {
_flags &= ~index;
_markDirty();
}
}
}
/// Whether this node has Boolean state that can be controlled by the user. /// Whether this node has Boolean state that can be controlled by the user.
bool get hasCheckedState => _flags[_SemanticsFlags.hasCheckedState]; bool get hasCheckedState => (_flags & SemanticsFlags.hasCheckedState.index) != 0;
set hasCheckedState(bool value) => _setFlag(_SemanticsFlags.hasCheckedState, value); set hasCheckedState(bool value) => _setFlag(SemanticsFlags.hasCheckedState, value);
/// If this node has Boolean state that can be controlled by the user, whether that state is on or off, cooresponding to `true` and `false`, respectively. /// If this node has Boolean state that can be controlled by the user, whether that state is on or off, cooresponding to `true` and `false`, respectively.
bool get isChecked => _flags[_SemanticsFlags.isChecked]; bool get isChecked => (_flags & SemanticsFlags.isChecked.index) != 0;
set isChecked(bool value) => _setFlag(_SemanticsFlags.isChecked, value); set isChecked(bool value) => _setFlag(SemanticsFlags.isChecked, value);
/// A textual description of this node. /// A textual description of this node.
String get label => _label; String get label => _label;
...@@ -249,10 +216,10 @@ class SemanticsNode extends AbstractNode { ...@@ -249,10 +216,10 @@ class SemanticsNode extends AbstractNode {
/// Restore this node to its default state. /// Restore this node to its default state.
void reset() { void reset() {
bool hadInheritedMergeAllDescendantsIntoThisNode = _inheritedMergeAllDescendantsIntoThisNode; bool hadInheritedMergeAllDescendantsIntoThisNode = _inheritedMergeAllDescendantsIntoThisNode;
_actions.clear(); _actions = 0;
_flags.reset(); _flags = 0;
if (hadInheritedMergeAllDescendantsIntoThisNode) if (hadInheritedMergeAllDescendantsIntoThisNode)
_inheritedMergeAllDescendantsIntoThisNode = true; _inheritedMergeAllDescendantsIntoThisNodeValue = true;
_label = ''; _label = '';
_markDirty(); _markDirty();
} }
...@@ -430,11 +397,10 @@ class SemanticsNode extends AbstractNode { ...@@ -430,11 +397,10 @@ class SemanticsNode extends AbstractNode {
result.strings = new mojom.SemanticStrings(); result.strings = new mojom.SemanticStrings();
result.strings.label = label; result.strings.label = label;
List<mojom.SemanticsNode> children = <mojom.SemanticsNode>[]; List<mojom.SemanticsNode> children = <mojom.SemanticsNode>[];
Set<SemanticsAction> mergedActions = new Set<SemanticsAction>(); int mergedActions = _actions;
mergedActions.addAll(_actions);
if (_shouldMergeAllDescendantsIntoThisNode) { if (_shouldMergeAllDescendantsIntoThisNode) {
_visitDescendants((SemanticsNode node) { _visitDescendants((SemanticsNode node) {
mergedActions.addAll(node._actions); mergedActions |= node._actions;
result.flags.hasCheckedState = result.flags.hasCheckedState || node.hasCheckedState; result.flags.hasCheckedState = result.flags.hasCheckedState || node.hasCheckedState;
result.flags.isChecked = result.flags.isChecked || node.isChecked; result.flags.isChecked = result.flags.isChecked || node.isChecked;
if (node.label != '') if (node.label != '')
...@@ -451,8 +417,11 @@ class SemanticsNode extends AbstractNode { ...@@ -451,8 +417,11 @@ class SemanticsNode extends AbstractNode {
} }
result.children = children; result.children = children;
result.actions = <int>[]; result.actions = <int>[];
for (SemanticsAction action in mergedActions) for (mojom.SemanticAction action in mojom.SemanticAction.values) {
result.actions.add(action.index); int bit = 1 << action.mojoEnumValue;
if ((mergedActions & bit) != 0)
result.actions.add(action.mojoEnumValue);
}
_dirty = false; _dirty = false;
} }
return result; return result;
...@@ -469,8 +438,9 @@ class SemanticsNode extends AbstractNode { ...@@ -469,8 +438,9 @@ class SemanticsNode extends AbstractNode {
buffer.write('; $rect'); buffer.write('; $rect');
if (wasAffectedByClip) if (wasAffectedByClip)
buffer.write(' (clipped)'); buffer.write(' (clipped)');
for (SemanticsAction action in _actions) { for (SemanticsAction action in SemanticsAction.values.values) {
buffer.write('; $action'); if ((_actions & action.index) != 0)
buffer.write('; $action');
} }
if (hasCheckedState) { if (hasCheckedState) {
if (isChecked) if (isChecked)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment