From a341b2693b6e23241e8a116523bbfc16924dc3a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Sun, 23 Apr 2023 18:16:04 +0200 Subject: [PATCH 01/38] Add support for setting the heading level for web semantics (#97894) --- lib/ui/fixtures/ui_test.dart | 3 ++- lib/ui/semantics.dart | 8 ++++-- lib/ui/semantics/semantics_node.h | 1 + lib/ui/semantics/semantics_update_builder.cc | 5 +++- lib/ui/semantics/semantics_update_builder.h | 3 ++- lib/web_ui/lib/semantics.dart | 2 ++ .../src/engine/semantics/label_and_value.dart | 4 +++ .../lib/src/engine/semantics/semantics.dart | 27 +++++++++++++++++++ .../test/engine/semantics/semantics_test.dart | 25 +++++++++++++++++ .../engine/semantics/semantics_tester.dart | 2 ++ shell/platform/embedder/fixtures/main.dart | 4 +++ 11 files changed, 79 insertions(+), 5 deletions(-) diff --git a/lib/ui/fixtures/ui_test.dart b/lib/ui/fixtures/ui_test.dart index 36f09bf397811..5a495225614fc 100644 --- a/lib/ui/fixtures/ui_test.dart +++ b/lib/ui/fixtures/ui_test.dart @@ -226,7 +226,8 @@ void sendSemanticsUpdate() { transform: transform, childrenInTraversalOrder: childrenInTraversalOrder, childrenInHitTestOrder: childrenInHitTestOrder, - additionalActions: additionalActions); + additionalActions: additionalActions, + headingLevel: -1); _semanticsUpdate(builder.build()); } diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index bab51799b1306..90a5d28a018f5 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -798,6 +798,7 @@ class SemanticsUpdateBuilder extends NativeFieldWrapperClass1 { required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, + required int headingLevel, }) { assert(_matrix4IsValid(transform)); _updateNode( @@ -836,6 +837,7 @@ class SemanticsUpdateBuilder extends NativeFieldWrapperClass1 { childrenInTraversalOrder, childrenInHitTestOrder, additionalActions, + headingLevel, ); } @Native< @@ -875,7 +877,8 @@ class SemanticsUpdateBuilder extends NativeFieldWrapperClass1 { Handle, Handle, Handle, - Handle)>(symbol: 'SemanticsUpdateBuilder::updateNode') + Handle, + Int32)>(symbol: 'SemanticsUpdateBuilder::updateNode') external void _updateNode( int id, int flags, @@ -911,7 +914,8 @@ class SemanticsUpdateBuilder extends NativeFieldWrapperClass1 { Float64List transform, Int32List childrenInTraversalOrder, Int32List childrenInHitTestOrder, - Int32List additionalActions); + Int32List additionalAction, + int headingLevel); /// Update the custom semantics action associated with the given `id`. /// diff --git a/lib/ui/semantics/semantics_node.h b/lib/ui/semantics/semantics_node.h index 3fad29b844bbd..e710bbc7b6b37 100644 --- a/lib/ui/semantics/semantics_node.h +++ b/lib/ui/semantics/semantics_node.h @@ -139,6 +139,7 @@ struct SemanticsNode { std::vector childrenInTraversalOrder; std::vector childrenInHitTestOrder; std::vector customAccessibilityActions; + int32_t headingLevel = -1; }; // Contains semantic nodes that need to be updated. diff --git a/lib/ui/semantics/semantics_update_builder.cc b/lib/ui/semantics/semantics_update_builder.cc index 2382a901e9aa6..987b472be8759 100644 --- a/lib/ui/semantics/semantics_update_builder.cc +++ b/lib/ui/semantics/semantics_update_builder.cc @@ -65,7 +65,8 @@ void SemanticsUpdateBuilder::updateNode( const tonic::Float64List& transform, const tonic::Int32List& childrenInTraversalOrder, const tonic::Int32List& childrenInHitTestOrder, - const tonic::Int32List& localContextActions) { + const tonic::Int32List& localContextActions, + int headingLevel) { FML_CHECK(scrollChildren == 0 || (scrollChildren > 0 && childrenInHitTestOrder.data())) << "Semantics update contained scrollChildren but did not have " @@ -116,6 +117,8 @@ void SemanticsUpdateBuilder::updateNode( localContextActions.data(), localContextActions.data() + localContextActions.num_elements()); nodes_[id] = node; + + node.headingLevel = headingLevel; } void SemanticsUpdateBuilder::updateCustomAction(int id, diff --git a/lib/ui/semantics/semantics_update_builder.h b/lib/ui/semantics/semantics_update_builder.h index 37d45d9f746be..491176102aea4 100644 --- a/lib/ui/semantics/semantics_update_builder.h +++ b/lib/ui/semantics/semantics_update_builder.h @@ -64,7 +64,8 @@ class SemanticsUpdateBuilder const tonic::Float64List& transform, const tonic::Int32List& childrenInTraversalOrder, const tonic::Int32List& childrenInHitTestOrder, - const tonic::Int32List& customAccessibilityActions); + const tonic::Int32List& customAccessibilityActions, + int headingLevel); void updateCustomAction(int id, std::string label, diff --git a/lib/web_ui/lib/semantics.dart b/lib/web_ui/lib/semantics.dart index 01a46bfad289c..131f4834a303c 100644 --- a/lib/web_ui/lib/semantics.dart +++ b/lib/web_ui/lib/semantics.dart @@ -276,6 +276,7 @@ class SemanticsUpdateBuilder { required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, + required int headingLevel, }) { if (transform.length != 16) { throw ArgumentError('transform argument must have 16 entries.'); @@ -313,6 +314,7 @@ class SemanticsUpdateBuilder { childrenInHitTestOrder: childrenInHitTestOrder, additionalActions: additionalActions, platformViewId: platformViewId, + headingLevel: headingLevel, )); } diff --git a/lib/web_ui/lib/src/engine/semantics/label_and_value.dart b/lib/web_ui/lib/src/engine/semantics/label_and_value.dart index 748ec58f08759..78c4b81e068b7 100644 --- a/lib/web_ui/lib/src/engine/semantics/label_and_value.dart +++ b/lib/web_ui/lib/src/engine/semantics/label_and_value.dart @@ -90,6 +90,9 @@ class LabelAndValue extends RoleManager { semanticsObject.setAriaRole('group', true); } else if (semanticsObject.hasFlag(ui.SemanticsFlag.isHeader)) { semanticsObject.setAriaRole('heading', true); + if (semanticsObject.headingLevel != -1) { + semanticsObject.setAriaLevel(semanticsObject.headingLevel); + } } else { semanticsObject.setAriaRole('text', true); } @@ -98,6 +101,7 @@ class LabelAndValue extends RoleManager { void _cleanUpDom() { semanticsObject.element.removeAttribute('aria-label'); semanticsObject.clearAriaRole(); + semanticsObject.clearAriaLevel(); } @override diff --git a/lib/web_ui/lib/src/engine/semantics/semantics.dart b/lib/web_ui/lib/src/engine/semantics/semantics.dart index 62f89313f30ca..dbbb5ca47791f 100644 --- a/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -224,6 +224,7 @@ class SemanticsNodeUpdate { required this.childrenInTraversalOrder, required this.childrenInHitTestOrder, required this.additionalActions, + required this.headingLevel, }); /// See [ui.SemanticsUpdateBuilder.updateNode]. @@ -321,6 +322,9 @@ class SemanticsNodeUpdate { /// See [ui.SemanticsUpdateBuilder.updateNode]. final double thickness; + + /// See [ui.SemanticsUpdateBuilder.updateNode]. + final int headingLevel; } /// Identifies one of the roles a [SemanticsObject] plays. @@ -758,6 +762,15 @@ class SemanticsObject { _dirtyFields |= _platformViewIdIndex; } + /// See [ui.SemanticsUpdateBuilder.updateNode]. + int get headingLevel => _headingLevel; + int _headingLevel = -1; + + static const int _headingLevelIndex = 1 << 24; + void _markHeadingLevelDirty() { + _dirtyFields |= _headingLevelIndex; + } + /// A unique permanent identifier of the semantics node in the tree. final int id; @@ -978,6 +991,11 @@ class SemanticsObject { _markTooltipDirty(); } + if (_headingLevel != update.headingLevel) { + _headingLevel = update.headingLevel; + _markHeadingLevelDirty(); + } + if (_textDirection != update.textDirection) { _textDirection = update.textDirection; _markTextDirectionDirty(); @@ -1224,6 +1242,15 @@ class SemanticsObject { element.removeAttribute('role'); } + void setAriaLevel(int ariaLevel) { + element.setAttribute('aria-level', ariaLevel); + } + + /// Removes the `aria-level` HTML attribue, if any. + void clearAriaLevel() { + element.removeAttribute('aria-level'); + } + /// Role managers. /// /// The [_roleManagers] map needs to have a stable order for easier debugging diff --git a/lib/web_ui/test/engine/semantics/semantics_test.dart b/lib/web_ui/test/engine/semantics/semantics_test.dart index e4da65ad22d69..9d6f8927f1c35 100644 --- a/lib/web_ui/test/engine/semantics/semantics_test.dart +++ b/lib/web_ui/test/engine/semantics/semantics_test.dart @@ -518,6 +518,29 @@ void _testHeader() { semantics().updateSemantics(builder.build()); expectSemanticsTree(''' +'''); + + semantics().semanticsEnabled = false; + }); + + test('renders aria-level tag for headers with heading level', () { + semantics() + ..debugOverrideTimestampFunction(() => _testTime) + ..semanticsEnabled = true; + + final ui.SemanticsUpdateBuilder builder = ui.SemanticsUpdateBuilder(); + updateNode( + builder, + flags: 0 | ui.SemanticsFlag.isHeader.index, + headingLevel: 1, + label: 'Header of the page', + transform: Matrix4.identity().toFloat64(), + rect: const ui.Rect.fromLTRB(0, 0, 100, 50), + ); + + semantics().updateSemantics(builder.build()); + expectSemanticsTree(''' + '''); semantics().semanticsEnabled = false; @@ -2125,6 +2148,7 @@ void updateNode( Int32List? childrenInTraversalOrder, Int32List? childrenInHitTestOrder, Int32List? additionalActions, + int headingLevel = -1, }) { transform ??= Float64List.fromList(Matrix4.identity().storage); childrenInTraversalOrder ??= Int32List(0); @@ -2163,6 +2187,7 @@ void updateNode( childrenInTraversalOrder: childrenInTraversalOrder, childrenInHitTestOrder: childrenInHitTestOrder, additionalActions: additionalActions, + headingLevel: headingLevel, ); } diff --git a/lib/web_ui/test/engine/semantics/semantics_tester.dart b/lib/web_ui/test/engine/semantics/semantics_tester.dart index bd2ebed3f5229..1beb5bcc3d5c7 100644 --- a/lib/web_ui/test/engine/semantics/semantics_tester.dart +++ b/lib/web_ui/test/engine/semantics/semantics_tester.dart @@ -126,6 +126,7 @@ class SemanticsTester { Float64List? transform, Int32List? additionalActions, List? children, + int? headingLevel, }) { // Flags if (hasCheckedState ?? false) { @@ -325,6 +326,7 @@ class SemanticsTester { childrenInTraversalOrder: childIds, childrenInHitTestOrder: childIds, additionalActions: additionalActions ?? Int32List(0), + headingLevel: headingLevel ?? -1, ); _nodeUpdates.add(update); return update; diff --git a/shell/platform/embedder/fixtures/main.dart b/shell/platform/embedder/fixtures/main.dart index c0611f3ef059b..30886ef82e8c3 100644 --- a/shell/platform/embedder/fixtures/main.dart +++ b/shell/platform/embedder/fixtures/main.dart @@ -174,6 +174,7 @@ void a11y_main() async { decreasedValueAttributes: [], tooltip: 'tooltip', additionalActions: Int32List(0), + headingLevel: -1 ) ..updateNode( id: 84, @@ -207,6 +208,7 @@ void a11y_main() async { additionalActions: Int32List(0), childrenInHitTestOrder: Int32List(0), childrenInTraversalOrder: Int32List(0), + headingLevel: -1 ) ..updateNode( id: 96, @@ -240,6 +242,7 @@ void a11y_main() async { decreasedValueAttributes: [], tooltip: 'tooltip', additionalActions: Int32List(0), + headingLevel: -1 ) ..updateNode( id: 128, @@ -273,6 +276,7 @@ void a11y_main() async { tooltip: 'tooltip', childrenInHitTestOrder: Int32List(0), childrenInTraversalOrder: Int32List(0), + headingLevel: -1 ) ..updateCustomAction( id: 21, From eff0206672a033123a08223a90a2fbcc8348ba04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Mon, 24 Apr 2023 19:25:36 +0200 Subject: [PATCH 02/38] Add support for setting the heading level for web semantics (#97894) --- testing/scenario_app/lib/src/locale_initialization.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/testing/scenario_app/lib/src/locale_initialization.dart b/testing/scenario_app/lib/src/locale_initialization.dart index 1185d9b8efe09..bb4b6cbe19193 100644 --- a/testing/scenario_app/lib/src/locale_initialization.dart +++ b/testing/scenario_app/lib/src/locale_initialization.dart @@ -77,6 +77,7 @@ class LocaleInitialization extends Scenario { childrenInTraversalOrder: Int32List(0), childrenInHitTestOrder: Int32List(0), additionalActions: Int32List(0), + headingLevel: -1, ); final SemanticsUpdate semanticsUpdate = semanticsUpdateBuilder.build(); From 9029d63ac59161050b334680a00a30af7fdc74cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Mon, 24 Apr 2023 19:44:33 +0200 Subject: [PATCH 03/38] Add support for setting the heading level for web semantics (#97894) --- testing/scenario_app/lib/src/locale_initialization.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/testing/scenario_app/lib/src/locale_initialization.dart b/testing/scenario_app/lib/src/locale_initialization.dart index bb4b6cbe19193..abd24af882a5e 100644 --- a/testing/scenario_app/lib/src/locale_initialization.dart +++ b/testing/scenario_app/lib/src/locale_initialization.dart @@ -136,6 +136,7 @@ class LocaleInitialization extends Scenario { childrenInTraversalOrder: Int32List(0), childrenInHitTestOrder: Int32List(0), additionalActions: Int32List(0), + headingLevel: -1, ); final SemanticsUpdate semanticsUpdate = semanticsUpdateBuilder.build(); From 260d4bd7aaa8d7f0bfcd4b071cb710a65c062b13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Sun, 30 Apr 2023 15:35:37 +0200 Subject: [PATCH 04/38] Add support for setting the heading level for web semantics (#97894) --- lib/ui/semantics.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index 90a5d28a018f5..14debc8660b79 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -798,7 +798,7 @@ class SemanticsUpdateBuilder extends NativeFieldWrapperClass1 { required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, - required int headingLevel, + int? headingLevel, }) { assert(_matrix4IsValid(transform)); _updateNode( @@ -837,7 +837,7 @@ class SemanticsUpdateBuilder extends NativeFieldWrapperClass1 { childrenInTraversalOrder, childrenInHitTestOrder, additionalActions, - headingLevel, + headingLevel ?? -1, ); } @Native< From 90de9fc92314d7031da38caf9c17e9558f52282b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Sun, 10 Sep 2023 00:33:54 +0200 Subject: [PATCH 05/38] Remove trailing spaces --- lib/web_ui/lib/src/engine/semantics/heading.dart | 3 +-- lib/web_ui/lib/src/engine/semantics/semantics.dart | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/web_ui/lib/src/engine/semantics/heading.dart b/lib/web_ui/lib/src/engine/semantics/heading.dart index cc7fb99cfe03c..2e6b246fa6b28 100644 --- a/lib/web_ui/lib/src/engine/semantics/heading.dart +++ b/lib/web_ui/lib/src/engine/semantics/heading.dart @@ -7,7 +7,7 @@ import 'package:ui/ui.dart' as ui; import '../dom.dart'; import 'semantics.dart'; -/// Renders semantics objects as headings with the corresponding +/// Renders semantics objects as headings with the corresponding /// level (h1 ... h6). class Heading extends PrimaryRoleManager { Heading(SemanticsObject semanticsObject) @@ -22,5 +22,4 @@ class Heading extends PrimaryRoleManager { semanticsObject.element.setAttribute('aria-level', semanticsObject.headingLevel); } } - } diff --git a/lib/web_ui/lib/src/engine/semantics/semantics.dart b/lib/web_ui/lib/src/engine/semantics/semantics.dart index 7d9440441584b..607146e1d115d 100644 --- a/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -353,7 +353,7 @@ enum PrimaryRole { /// A control that has a checked state, such as a check box or a radio button. checkable, - /// Adds the "heading" ARIA role to the node. The attribute "aria-level" is + /// Adds the "heading" ARIA role to the node. The attribute "aria-level" is /// also assigned. heading, @@ -1498,7 +1498,7 @@ class SemanticsObject { if (isPlatformView) { return PrimaryRole.platformView; } else if (isHeading) { - return PrimaryRole.heading; + return PrimaryRole.heading; } else if (isTextField) { return PrimaryRole.textField; } else if (isIncrementable) { From c8ccd3101f343047d30e3d7b8e341773b94bedf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Sun, 10 Sep 2023 01:48:00 +0200 Subject: [PATCH 06/38] Add export for new Heading role --- lib/web_ui/lib/src/engine/semantics.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/web_ui/lib/src/engine/semantics.dart b/lib/web_ui/lib/src/engine/semantics.dart index d1d58ce4a688e..718a4c81598dd 100644 --- a/lib/web_ui/lib/src/engine/semantics.dart +++ b/lib/web_ui/lib/src/engine/semantics.dart @@ -5,6 +5,7 @@ export 'semantics/accessibility.dart'; export 'semantics/checkable.dart'; export 'semantics/focusable.dart'; +export 'semantics/heading.dart'; export 'semantics/image.dart'; export 'semantics/incrementable.dart'; export 'semantics/label_and_value.dart'; From 0241f070c7e05fb373ed8318ad9a7990cd5be1ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Sun, 10 Sep 2023 02:08:54 +0200 Subject: [PATCH 07/38] Fix references for new Heading role --- ci/licenses_golden/licenses_flutter | 2 ++ lib/web_ui/lib/src/engine.dart | 1 + lib/web_ui/lib/src/engine/semantics/semantics.dart | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 679275c98a8c0..151573b11e797 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -2066,6 +2066,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/accessibility.dart ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/checkable.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/dialog.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/focusable.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/heading.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/image.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/incrementable.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/semantics/label_and_value.dart + ../../../flutter/LICENSE @@ -4817,6 +4818,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/accessibility.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/checkable.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/dialog.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/focusable.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/heading.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/image.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/incrementable.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics/label_and_value.dart diff --git a/lib/web_ui/lib/src/engine.dart b/lib/web_ui/lib/src/engine.dart index 016117334272e..32d36770d9fe8 100644 --- a/lib/web_ui/lib/src/engine.dart +++ b/lib/web_ui/lib/src/engine.dart @@ -138,6 +138,7 @@ export 'engine/semantics/accessibility.dart'; export 'engine/semantics/checkable.dart'; export 'engine/semantics/dialog.dart'; export 'engine/semantics/focusable.dart'; +export 'engine/semantics/heading.dart'; export 'engine/semantics/image.dart'; export 'engine/semantics/incrementable.dart'; export 'engine/semantics/label_and_value.dart'; diff --git a/lib/web_ui/lib/src/engine/semantics/semantics.dart b/lib/web_ui/lib/src/engine/semantics/semantics.dart index 607146e1d115d..3aaec08c29853 100644 --- a/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -6,7 +6,6 @@ import 'dart:math' as math; import 'dart:typed_data'; import 'package:meta/meta.dart'; -import 'package:ui/src/engine/semantics/heading.dart'; import 'package:ui/ui.dart' as ui; import 'package:ui/ui_web/src/ui_web.dart' as ui_web; @@ -22,6 +21,7 @@ import '../vector_math.dart'; import 'checkable.dart'; import 'dialog.dart'; import 'focusable.dart'; +import 'heading.dart'; import 'image.dart'; import 'incrementable.dart'; import 'label_and_value.dart'; From 6298a5fe956558f62eaddcc7971749ea11ab227c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Sun, 10 Sep 2023 02:21:08 +0200 Subject: [PATCH 08/38] Remove unused import --- lib/web_ui/lib/src/engine/semantics/heading.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/web_ui/lib/src/engine/semantics/heading.dart b/lib/web_ui/lib/src/engine/semantics/heading.dart index 2e6b246fa6b28..f94fef6b068b1 100644 --- a/lib/web_ui/lib/src/engine/semantics/heading.dart +++ b/lib/web_ui/lib/src/engine/semantics/heading.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:ui/ui.dart' as ui; - import '../dom.dart'; import 'semantics.dart'; From 36c5fd6211b899e17fb5d0e4fe1a448ed345b743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Wed, 20 Sep 2023 01:15:24 +0200 Subject: [PATCH 09/38] Fix PR comments (41435) --- lib/ui/semantics.dart | 5 ++ lib/web_ui/lib/semantics.dart | 2 +- .../lib/src/engine/semantics/heading.dart | 21 ++++++-- .../lib/src/engine/semantics/semantics.dart | 8 ++-- .../test/engine/semantics/semantics_test.dart | 48 +++++++++++++------ 5 files changed, 60 insertions(+), 24 deletions(-) diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index 5e15496154121..1c8593ad1fa2c 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -786,6 +786,11 @@ abstract class SemanticsUpdateBuilder { /// z-direction starting at `elevation`. Basically, in the z-direction the /// node starts at `elevation` above the parent and ends at `elevation` + /// `thickness` above the parent. + /// + /// The `headingLevel` describes that this node is a heading, additionally + /// indicates the hierarchy level this node represents as a heading. A value + /// of -1 indicates that this node is not a heading. A value of 1 or greater + /// indicates that this node is a heading at the specified level. void updateNode({ required int id, required int flags, diff --git a/lib/web_ui/lib/semantics.dart b/lib/web_ui/lib/semantics.dart index 276c28d676e96..9f19697c5c1f4 100644 --- a/lib/web_ui/lib/semantics.dart +++ b/lib/web_ui/lib/semantics.dart @@ -282,7 +282,7 @@ class SemanticsUpdateBuilder { required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, - required int headingLevel, + int? headingLevel, }) { if (transform.length != 16) { throw ArgumentError('transform argument must have 16 entries.'); diff --git a/lib/web_ui/lib/src/engine/semantics/heading.dart b/lib/web_ui/lib/src/engine/semantics/heading.dart index f94fef6b068b1..dae76b71e33ce 100644 --- a/lib/web_ui/lib/src/engine/semantics/heading.dart +++ b/lib/web_ui/lib/src/engine/semantics/heading.dart @@ -9,15 +9,26 @@ import 'semantics.dart'; /// level (h1 ... h6). class Heading extends PrimaryRoleManager { Heading(SemanticsObject semanticsObject) - : super.withBasics(PrimaryRole.heading, semanticsObject); + : super.withBasics(PrimaryRole.heading, semanticsObject) { + addHeadingRole(); + } @override void update() { super.update(); - if (semanticsObject.headingLevel != -1) { - semanticsObject.setAriaRole('heading'); - semanticsObject.element.setAttribute('aria-level', semanticsObject.headingLevel); - } + if (semanticsObject.headingLevel != -1) { + addHeadingLevel(semanticsObject.headingLevel); + } else { + addHeadingLevel(1); + } + } + + void addHeadingRole() { + semanticsObject.setAriaRole('heading'); + } + + void addHeadingLevel(int headingLevel) { + semanticsObject.element.setAttribute('aria-level', headingLevel); } } diff --git a/lib/web_ui/lib/src/engine/semantics/semantics.dart b/lib/web_ui/lib/src/engine/semantics/semantics.dart index 3aaec08c29853..3c47a1fec395b 100644 --- a/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -230,7 +230,7 @@ class SemanticsNodeUpdate { required this.childrenInTraversalOrder, required this.childrenInHitTestOrder, required this.additionalActions, - required this.headingLevel, + this.headingLevel, }); /// See [ui.SemanticsUpdateBuilder.updateNode]. @@ -330,7 +330,7 @@ class SemanticsNodeUpdate { final double thickness; /// See [ui.SemanticsUpdateBuilder.updateNode]. - final int headingLevel; + final int? headingLevel; } /// Identifies [PrimaryRoleManager] implementations. @@ -1097,7 +1097,7 @@ class SemanticsObject { /// Whether this object represents an editable text field. bool get isTextField => hasFlag(ui.SemanticsFlag.isTextField); - /// Whether this object represents a heading element + /// Whether this object represents a heading element. bool get isHeading => headingLevel != -1; /// Whether this object needs screen readers attention right away. @@ -1528,8 +1528,8 @@ class SemanticsObject { PrimaryRole.dialog => Dialog(this), PrimaryRole.image => ImageRoleManager(this), PrimaryRole.platformView => PlatformViewRoleManager(this), - PrimaryRole.generic => GenericRole(this), PrimaryRole.heading => Heading(this), + PrimaryRole.generic => GenericRole(this), }; } diff --git a/lib/web_ui/test/engine/semantics/semantics_test.dart b/lib/web_ui/test/engine/semantics/semantics_test.dart index 1668b06cb8088..7f5ef5c0143fc 100644 --- a/lib/web_ui/test/engine/semantics/semantics_test.dart +++ b/lib/web_ui/test/engine/semantics/semantics_test.dart @@ -670,25 +670,45 @@ void _testHeader() { semantics().semanticsEnabled = false; }); - test('renders aria-level tag for headers with heading level', () { + test('renders aria-level tag for headings with heading level', () { semantics() ..debugOverrideTimestampFunction(() => _testTime) ..semanticsEnabled = true; - final ui.SemanticsUpdateBuilder builder = ui.SemanticsUpdateBuilder(); - updateNode( - builder, - flags: 0 | ui.SemanticsFlag.isHeader.index, - headingLevel: 1, - label: 'Header of the page', - transform: Matrix4.identity().toFloat64(), - rect: const ui.Rect.fromLTRB(0, 0, 100, 50), - ); + // State 1: render element with an initial headingLevel. + { + final ui.SemanticsUpdateBuilder builder = ui.SemanticsUpdateBuilder(); + updateNode( + builder, + headingLevel: 2, + label: 'Heading of the page', + transform: Matrix4.identity().toFloat64(), + rect: const ui.Rect.fromLTRB(0, 0, 100, 50), + ); - semantics().updateSemantics(builder.build()); - expectSemanticsTree(''' - -'''); + semantics().updateSemantics(builder.build()); + expectSemanticsTree(''' + + '''); + } + + // State 2: when the new state "clears" the headingLevel, a default value + // of 1 is assigned, as the aria-level is a required attribute for the + // heading role. + { + final ui.SemanticsUpdateBuilder builder = ui.SemanticsUpdateBuilder(); + updateNode( + builder, + label: 'Heading of the page', + transform: Matrix4.identity().toFloat64(), + rect: const ui.Rect.fromLTRB(0, 0, 100, 50), + ); + + semantics().updateSemantics(builder.build()); + expectSemanticsTree(''' + + '''); + } semantics().semanticsEnabled = false; }); From 30153e0ba8a3f4b6f23665b2c124d619b51a9213 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Wed, 20 Sep 2023 01:18:19 +0200 Subject: [PATCH 10/38] Remove trailing whitespace --- lib/ui/semantics.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index 1c8593ad1fa2c..928e7a4a92377 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -786,7 +786,7 @@ abstract class SemanticsUpdateBuilder { /// z-direction starting at `elevation`. Basically, in the z-direction the /// node starts at `elevation` above the parent and ends at `elevation` + /// `thickness` above the parent. - /// + /// /// The `headingLevel` describes that this node is a heading, additionally /// indicates the hierarchy level this node represents as a heading. A value /// of -1 indicates that this node is not a heading. A value of 1 or greater From 54603886e24e1e81f11a0af7238bb13f4a458124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Wed, 20 Sep 2023 02:11:04 +0200 Subject: [PATCH 11/38] Add support for setting the heading level for web semantics (#97894) --- lib/web_ui/lib/src/engine/semantics/semantics.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/web_ui/lib/src/engine/semantics/semantics.dart b/lib/web_ui/lib/src/engine/semantics/semantics.dart index 3c47a1fec395b..0675f92b2778a 100644 --- a/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -985,8 +985,8 @@ class SemanticsObject { } /// See [ui.SemanticsUpdateBuilder.updateNode]. - int get headingLevel => _headingLevel; - int _headingLevel = -1; + int? get headingLevel => _headingLevel; + int? _headingLevel = -1; static const int _headingLevelIndex = 1 << 24; void _markHeadingLevelDirty() { From a526070664b21db718d76de41855f67a19cee1c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Wed, 20 Sep 2023 18:25:45 +0200 Subject: [PATCH 12/38] Add support for setting the heading level for web semantics (#97894) --- lib/web_ui/lib/src/engine/semantics/heading.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/web_ui/lib/src/engine/semantics/heading.dart b/lib/web_ui/lib/src/engine/semantics/heading.dart index dae76b71e33ce..15c5ed4a6513c 100644 --- a/lib/web_ui/lib/src/engine/semantics/heading.dart +++ b/lib/web_ui/lib/src/engine/semantics/heading.dart @@ -13,14 +13,16 @@ class Heading extends PrimaryRoleManager { addHeadingRole(); } + static const int defaultHeadingLevel = 1; + @override void update() { super.update(); if (semanticsObject.headingLevel != -1) { - addHeadingLevel(semanticsObject.headingLevel); + addHeadingLevel(semanticsObject.headingLevel ?? defaultHeadingLevel); } else { - addHeadingLevel(1); + addHeadingLevel(defaultHeadingLevel); } } From dceef3ca4aa8f1315c1c25db79b6f0f8c40cd8b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Thu, 21 Sep 2023 23:10:59 +0200 Subject: [PATCH 13/38] Add support for setting the heading level for web semantics (#97894) --- .../test/engine/semantics/semantics_test.dart | 45 +++++-------------- 1 file changed, 12 insertions(+), 33 deletions(-) diff --git a/lib/web_ui/test/engine/semantics/semantics_test.dart b/lib/web_ui/test/engine/semantics/semantics_test.dart index 7f5ef5c0143fc..a78868fa819aa 100644 --- a/lib/web_ui/test/engine/semantics/semantics_test.dart +++ b/lib/web_ui/test/engine/semantics/semantics_test.dart @@ -675,40 +675,19 @@ void _testHeader() { ..debugOverrideTimestampFunction(() => _testTime) ..semanticsEnabled = true; - // State 1: render element with an initial headingLevel. - { - final ui.SemanticsUpdateBuilder builder = ui.SemanticsUpdateBuilder(); - updateNode( - builder, - headingLevel: 2, - label: 'Heading of the page', - transform: Matrix4.identity().toFloat64(), - rect: const ui.Rect.fromLTRB(0, 0, 100, 50), - ); - - semantics().updateSemantics(builder.build()); - expectSemanticsTree(''' - - '''); - } - - // State 2: when the new state "clears" the headingLevel, a default value - // of 1 is assigned, as the aria-level is a required attribute for the - // heading role. - { - final ui.SemanticsUpdateBuilder builder = ui.SemanticsUpdateBuilder(); - updateNode( - builder, - label: 'Heading of the page', - transform: Matrix4.identity().toFloat64(), - rect: const ui.Rect.fromLTRB(0, 0, 100, 50), - ); + final ui.SemanticsUpdateBuilder builder = ui.SemanticsUpdateBuilder(); + updateNode( + builder, + headingLevel: 2, + label: 'Heading of the page', + transform: Matrix4.identity().toFloat64(), + rect: const ui.Rect.fromLTRB(0, 0, 100, 50), + ); - semantics().updateSemantics(builder.build()); - expectSemanticsTree(''' - - '''); - } + semantics().updateSemantics(builder.build()); + expectSemanticsTree(''' + +'''); semantics().semanticsEnabled = false; }); From 3a6e45dd222d9a9e4b9ea26a4a6f7c21853f51a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Mon, 25 Sep 2023 00:22:27 +0200 Subject: [PATCH 14/38] Add support for setting the heading level for web semantics (#97894) --- lib/ui/semantics.dart | 10 +++++++++- lib/web_ui/lib/src/engine/semantics/heading.dart | 4 ++++ lib/web_ui/lib/src/engine/semantics/semantics.dart | 4 ++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index 928e7a4a92377..1560cf0c0d067 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -790,7 +790,11 @@ abstract class SemanticsUpdateBuilder { /// The `headingLevel` describes that this node is a heading, additionally /// indicates the hierarchy level this node represents as a heading. A value /// of -1 indicates that this node is not a heading. A value of 1 or greater - /// indicates that this node is a heading at the specified level. + /// indicates that this node is a heading at the specified level. The valid + /// value range is from 1 to 6, inclusive. This attribute is only used for + /// Web platform, and it will have no effect on other platforms. See also: + /// https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/heading_role + /// https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-level void updateNode({ required int id, required int flags, @@ -899,6 +903,10 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 implem int? headingLevel, }) { assert(_matrix4IsValid(transform)); + assert ( + headingLevel! <= 6, + "Heading level can't be greater than 6", + ); _updateNode( id, flags, diff --git a/lib/web_ui/lib/src/engine/semantics/heading.dart b/lib/web_ui/lib/src/engine/semantics/heading.dart index 15c5ed4a6513c..3dbf5da071725 100644 --- a/lib/web_ui/lib/src/engine/semantics/heading.dart +++ b/lib/web_ui/lib/src/engine/semantics/heading.dart @@ -19,6 +19,10 @@ class Heading extends PrimaryRoleManager { void update() { super.update(); + if (!semanticsObject.isHeadingLevelDirty) { + return; + } + if (semanticsObject.headingLevel != -1) { addHeadingLevel(semanticsObject.headingLevel ?? defaultHeadingLevel); } else { diff --git a/lib/web_ui/lib/src/engine/semantics/semantics.dart b/lib/web_ui/lib/src/engine/semantics/semantics.dart index 0675f92b2778a..029cea8cd60f4 100644 --- a/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -989,6 +989,10 @@ class SemanticsObject { int? _headingLevel = -1; static const int _headingLevelIndex = 1 << 24; + + /// Whether the [headingLevel] field has been updated but has not been + /// applied to the DOM yet. + bool get isHeadingLevelDirty => _isDirty(_headingLevelIndex); void _markHeadingLevelDirty() { _dirtyFields |= _headingLevelIndex; } From b9bfb882a67ad6d12efc47e50437ceb39eeb966e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Mon, 25 Sep 2023 00:23:53 +0200 Subject: [PATCH 15/38] Add support for setting the heading level for web semantics (#97894) --- lib/ui/semantics.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index 1560cf0c0d067..127afcfc83233 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -904,7 +904,7 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 implem }) { assert(_matrix4IsValid(transform)); assert ( - headingLevel! <= 6, + headingLevel! <= 6, "Heading level can't be greater than 6", ); _updateNode( From 664c1e4d56ea0d19407126b7429e878145b31eeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Sun, 12 Nov 2023 15:23:00 +0100 Subject: [PATCH 16/38] Change headingLevel to not be nullable --- lib/ui/semantics.dart | 6 +++--- lib/web_ui/lib/semantics.dart | 2 +- lib/web_ui/lib/src/engine/semantics/semantics.dart | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index 127afcfc83233..8a618a721fb26 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -828,7 +828,7 @@ abstract class SemanticsUpdateBuilder { required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, - int? headingLevel, + int headingLevel, }); /// Update the custom semantics action associated with the given `id`. @@ -900,7 +900,7 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 implem required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, - int? headingLevel, + required int headingLevel, }) { assert(_matrix4IsValid(transform)); assert ( @@ -943,7 +943,7 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 implem childrenInTraversalOrder, childrenInHitTestOrder, additionalActions, - headingLevel ?? -1, + headingLevel, ); } @Native< diff --git a/lib/web_ui/lib/semantics.dart b/lib/web_ui/lib/semantics.dart index 9f19697c5c1f4..276c28d676e96 100644 --- a/lib/web_ui/lib/semantics.dart +++ b/lib/web_ui/lib/semantics.dart @@ -282,7 +282,7 @@ class SemanticsUpdateBuilder { required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, - int? headingLevel, + required int headingLevel, }) { if (transform.length != 16) { throw ArgumentError('transform argument must have 16 entries.'); diff --git a/lib/web_ui/lib/src/engine/semantics/semantics.dart b/lib/web_ui/lib/src/engine/semantics/semantics.dart index 029cea8cd60f4..55527f0255386 100644 --- a/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -230,7 +230,7 @@ class SemanticsNodeUpdate { required this.childrenInTraversalOrder, required this.childrenInHitTestOrder, required this.additionalActions, - this.headingLevel, + required this.headingLevel, }); /// See [ui.SemanticsUpdateBuilder.updateNode]. @@ -330,7 +330,7 @@ class SemanticsNodeUpdate { final double thickness; /// See [ui.SemanticsUpdateBuilder.updateNode]. - final int? headingLevel; + final int headingLevel; } /// Identifies [PrimaryRoleManager] implementations. @@ -985,8 +985,8 @@ class SemanticsObject { } /// See [ui.SemanticsUpdateBuilder.updateNode]. - int? get headingLevel => _headingLevel; - int? _headingLevel = -1; + int get headingLevel => _headingLevel; + int _headingLevel = -1; static const int _headingLevelIndex = 1 << 24; From 470f67f28e7f0eb453ca02cae8eda19e33287721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Sun, 12 Nov 2023 16:09:15 +0100 Subject: [PATCH 17/38] Change headingLevel to be non nullable --- lib/ui/semantics.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index ffe879af83425..9cf5b831bf345 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -828,7 +828,7 @@ abstract class SemanticsUpdateBuilder { required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, - int headingLevel, + required int headingLevel, }); /// Update the custom semantics action associated with the given `id`. From a56c39821808132f447208e3b3624e2375e6dd96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Sun, 12 Nov 2023 16:19:29 +0100 Subject: [PATCH 18/38] Change headingLevel to be non nullable --- lib/ui/semantics.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index 9cf5b831bf345..7e90258eabcec 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -902,7 +902,7 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 implem }) { assert(_matrix4IsValid(transform)); assert ( - headingLevel! <= 6, + headingLevel <= 6, "Heading level can't be greater than 6", ); _updateNode( From b31bd9f39d91dfe3133d6124ac46c94d80bd8d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Sun, 12 Nov 2023 17:14:15 +0100 Subject: [PATCH 19/38] Change headingLevel to be non nullable --- lib/web_ui/lib/src/engine/semantics/heading.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/web_ui/lib/src/engine/semantics/heading.dart b/lib/web_ui/lib/src/engine/semantics/heading.dart index 3dbf5da071725..da72862773dd4 100644 --- a/lib/web_ui/lib/src/engine/semantics/heading.dart +++ b/lib/web_ui/lib/src/engine/semantics/heading.dart @@ -24,14 +24,14 @@ class Heading extends PrimaryRoleManager { } if (semanticsObject.headingLevel != -1) { - addHeadingLevel(semanticsObject.headingLevel ?? defaultHeadingLevel); + addHeadingLevel(semanticsObject.headingLevel); } else { addHeadingLevel(defaultHeadingLevel); } } void addHeadingRole() { - semanticsObject.setAriaRole('heading'); + setAriaRole('heading'); } void addHeadingLevel(int headingLevel) { From 8305e4b9ff65d065210db4b0359b6cd5fd822749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Sun, 12 Nov 2023 18:03:48 +0100 Subject: [PATCH 20/38] Change headingLevel to be non nullable --- shell/platform/embedder/fixtures/main.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/shell/platform/embedder/fixtures/main.dart b/shell/platform/embedder/fixtures/main.dart index 11414fd31b282..681acbaff438c 100644 --- a/shell/platform/embedder/fixtures/main.dart +++ b/shell/platform/embedder/fixtures/main.dart @@ -364,6 +364,7 @@ Future a11y_string_attributes() async { decreasedValueAttributes: [], tooltip: 'tooltip', additionalActions: Int32List(0), + headingLevel: -1, ); PlatformDispatcher.instance.views.first.updateSemantics(builder.build()); From d860f217707db255b98b0bc9cd7fc2ec7f7288fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Tue, 14 Nov 2023 00:22:33 +0100 Subject: [PATCH 21/38] Make headingLevel temporarily optional until framework part is uploaded --- lib/ui/semantics.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index 7e90258eabcec..8d86cff44fdd6 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -828,7 +828,7 @@ abstract class SemanticsUpdateBuilder { required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, - required int headingLevel, + int headingLevel = -1, }); /// Update the custom semantics action associated with the given `id`. @@ -898,7 +898,7 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 implem required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, - required int headingLevel, + int headingLevel = -1, }) { assert(_matrix4IsValid(transform)); assert ( From ddeaefc800e778b3fed3c7d09645a8e923ae70ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Mon, 4 Dec 2023 23:24:33 +0100 Subject: [PATCH 22/38] Change headingLevel to be non nullable --- lib/ui/fixtures/ui_test.dart | 3 ++- lib/ui/semantics.dart | 27 +++++++++++++++------------ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/lib/ui/fixtures/ui_test.dart b/lib/ui/fixtures/ui_test.dart index 661cc57ad64a9..5d338d266afae 100644 --- a/lib/ui/fixtures/ui_test.dart +++ b/lib/ui/fixtures/ui_test.dart @@ -227,7 +227,8 @@ void sendSemanticsUpdate() { childrenInTraversalOrder: childrenInTraversalOrder, childrenInHitTestOrder: childrenInHitTestOrder, additionalActions: additionalActions, - headingLevel: -1); + headingLevel: -1, + ); _semanticsUpdate(builder.build()); } diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index 58889f4679afa..2f33b56c5caab 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -787,14 +787,17 @@ abstract class SemanticsUpdateBuilder { /// node starts at `elevation` above the parent and ends at `elevation` + /// `thickness` above the parent. /// - /// The `headingLevel` describes that this node is a heading, additionally - /// indicates the hierarchy level this node represents as a heading. A value - /// of -1 indicates that this node is not a heading. A value of 1 or greater - /// indicates that this node is a heading at the specified level. The valid - /// value range is from 1 to 6, inclusive. This attribute is only used for - /// Web platform, and it will have no effect on other platforms. See also: - /// https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/heading_role - /// https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-level + /// The `headingLevel` describes that this node is a heading and the hierarchy + /// level this node represents as a heading. A value of -1 indicates that this + /// node is not a heading. A value of 1 or greater indicates that this node is + /// a heading at the specified level. The valid value range is from 1 to 6, + /// inclusive. This attribute is only used for Web platform, and it will have + /// no effect on other platforms. + /// + /// See also: + /// + /// * https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/heading_role + /// * https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-level void updateNode({ required int id, required int flags, @@ -828,7 +831,7 @@ abstract class SemanticsUpdateBuilder { required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, - int headingLevel = -1, + required int headingLevel, }); /// Update the custom semantics action associated with the given `id`. @@ -898,12 +901,12 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 implem required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, - int headingLevel = -1, + required int headingLevel, }) { assert(_matrix4IsValid(transform)); assert ( - headingLevel <= 6, - "Heading level can't be greater than 6", + headingLevel == -1 || (headingLevel >= 1 && headingLevel <= 6), + 'Heading level must be between 1 and 6, or -1 to indicate that this node is not a heading.' ); _updateNode( id, From bcd3205ff533b500f32064185f90b4a1479209fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Mon, 4 Dec 2023 23:27:02 +0100 Subject: [PATCH 23/38] remove trailing whitespaces --- lib/ui/semantics.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index 2f33b56c5caab..71306d8486a1b 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -793,9 +793,9 @@ abstract class SemanticsUpdateBuilder { /// a heading at the specified level. The valid value range is from 1 to 6, /// inclusive. This attribute is only used for Web platform, and it will have /// no effect on other platforms. - /// + /// /// See also: - /// + /// /// * https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/heading_role /// * https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-level void updateNode({ From 268e31c2df2511fca24480180b6065e3c2703940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Fri, 19 Jan 2024 22:38:00 +0100 Subject: [PATCH 24/38] Change default value for headingLevel to 0 --- lib/ui/semantics.dart | 13 +++++++++---- lib/ui/semantics/semantics_node.h | 2 +- lib/web_ui/lib/semantics.dart | 2 ++ lib/web_ui/lib/src/engine/semantics/heading.dart | 2 +- lib/web_ui/lib/src/engine/semantics/semantics.dart | 4 ++-- .../test/engine/semantics/semantics_test.dart | 2 +- .../test/engine/semantics/semantics_tester.dart | 2 +- shell/platform/embedder/fixtures/main.dart | 8 ++++---- .../scenario_app/lib/src/locale_initialization.dart | 4 ++-- 9 files changed, 23 insertions(+), 16 deletions(-) diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index 1cb859854465f..092934f5dd116 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -913,8 +913,8 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 implem }) { assert(_matrix4IsValid(transform)); assert ( - headingLevel == -1 || (headingLevel >= 1 && headingLevel <= 6), - 'Heading level must be between 1 and 6, or -1 to indicate that this node is not a heading.' + headingLevel >= 0 && headingLevel <= 6, + 'Heading level must be between 1 and 6, or 0 to indicate that this node is not a heading.' ); _updateNode( id, @@ -1033,7 +1033,8 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 implem Float64List transform, Int32List childrenInTraversalOrder, Int32List childrenInHitTestOrder, - Int32List additionalActions); + Int32List additionalActions, + int headingLevel,); @override void updateCustomAction({required int id, String? label, String? hint, int overrideId = -1}) { @@ -1183,6 +1184,7 @@ abstract class SemanticsUpdateBuilderNew { required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, + required int headingLevel, }); /// Update the custom semantics action associated with the given `id`. @@ -1253,6 +1255,7 @@ base class _NativeSemanticsUpdateBuilderNew extends NativeFieldWrapperClass1 imp required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, + required int headingLevel, }) { assert(_matrix4IsValid(transform)); _updateNode( @@ -1292,6 +1295,7 @@ base class _NativeSemanticsUpdateBuilderNew extends NativeFieldWrapperClass1 imp childrenInTraversalOrder, childrenInHitTestOrder, additionalActions, + headingLevel, ); } @Native< @@ -1332,7 +1336,8 @@ base class _NativeSemanticsUpdateBuilderNew extends NativeFieldWrapperClass1 imp Handle, Handle, Handle, - Handle)>(symbol: 'SemanticsUpdateBuilder::updateNode') + Handle, + Int32)>(symbol: 'SemanticsUpdateBuilder::updateNode') external void _updateNode( int id, int flags, diff --git a/lib/ui/semantics/semantics_node.h b/lib/ui/semantics/semantics_node.h index 22b9c2b002c4a..6f27a72f965d1 100644 --- a/lib/ui/semantics/semantics_node.h +++ b/lib/ui/semantics/semantics_node.h @@ -142,7 +142,7 @@ struct SemanticsNode { std::vector childrenInTraversalOrder; std::vector childrenInHitTestOrder; std::vector customAccessibilityActions; - int32_t headingLevel = -1; + int32_t headingLevel = 0; }; // Contains semantic nodes that need to be updated. diff --git a/lib/web_ui/lib/semantics.dart b/lib/web_ui/lib/semantics.dart index 04ad634894a41..af5ca917436af 100644 --- a/lib/web_ui/lib/semantics.dart +++ b/lib/web_ui/lib/semantics.dart @@ -322,6 +322,7 @@ class SemanticsUpdateBuilderNew { childrenInHitTestOrder: childrenInHitTestOrder, additionalActions: additionalActions, platformViewId: platformViewId, + headingLevel: headingLevel, )); } @@ -379,6 +380,7 @@ class SemanticsUpdateBuilder { required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, + required int headingLevel, }) { if (transform.length != 16) { throw ArgumentError('transform argument must have 16 entries.'); diff --git a/lib/web_ui/lib/src/engine/semantics/heading.dart b/lib/web_ui/lib/src/engine/semantics/heading.dart index da72862773dd4..ddfe9eb32efc8 100644 --- a/lib/web_ui/lib/src/engine/semantics/heading.dart +++ b/lib/web_ui/lib/src/engine/semantics/heading.dart @@ -23,7 +23,7 @@ class Heading extends PrimaryRoleManager { return; } - if (semanticsObject.headingLevel != -1) { + if (semanticsObject.headingLevel != 0) { addHeadingLevel(semanticsObject.headingLevel); } else { addHeadingLevel(defaultHeadingLevel); diff --git a/lib/web_ui/lib/src/engine/semantics/semantics.dart b/lib/web_ui/lib/src/engine/semantics/semantics.dart index 49775119d6908..7c01d34f29b1b 100644 --- a/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -1027,7 +1027,7 @@ class SemanticsObject { /// See [ui.SemanticsUpdateBuilder.updateNode]. int get headingLevel => _headingLevel; - int _headingLevel = -1; + int _headingLevel = 0; static const int _headingLevelIndex = 1 << 24; @@ -1143,7 +1143,7 @@ class SemanticsObject { bool get isTextField => hasFlag(ui.SemanticsFlag.isTextField); /// Whether this object represents a heading element. - bool get isHeading => headingLevel != -1; + bool get isHeading => headingLevel != 0; /// Whether this object represents an editable text field. bool get isLink => hasFlag(ui.SemanticsFlag.isLink); diff --git a/lib/web_ui/test/engine/semantics/semantics_test.dart b/lib/web_ui/test/engine/semantics/semantics_test.dart index 681daac903187..6b01df088a229 100644 --- a/lib/web_ui/test/engine/semantics/semantics_test.dart +++ b/lib/web_ui/test/engine/semantics/semantics_test.dart @@ -3092,7 +3092,7 @@ void updateNode( Int32List? childrenInTraversalOrder, Int32List? childrenInHitTestOrder, Int32List? additionalActions, - int headingLevel = -1, + int headingLevel = 0, }) { transform ??= Float64List.fromList(Matrix4.identity().storage); childrenInTraversalOrder ??= Int32List(0); diff --git a/lib/web_ui/test/engine/semantics/semantics_tester.dart b/lib/web_ui/test/engine/semantics/semantics_tester.dart index 04c8e6f2a904e..f4641ecb3ec43 100644 --- a/lib/web_ui/test/engine/semantics/semantics_tester.dart +++ b/lib/web_ui/test/engine/semantics/semantics_tester.dart @@ -317,7 +317,7 @@ class SemanticsTester { childrenInTraversalOrder: childIds, childrenInHitTestOrder: childIds, additionalActions: additionalActions ?? Int32List(0), - headingLevel: headingLevel ?? -1, + headingLevel: headingLevel ?? 0, ); _nodeUpdates.add(update); return update; diff --git a/shell/platform/embedder/fixtures/main.dart b/shell/platform/embedder/fixtures/main.dart index 681acbaff438c..5b8d1261e9bc5 100644 --- a/shell/platform/embedder/fixtures/main.dart +++ b/shell/platform/embedder/fixtures/main.dart @@ -167,7 +167,7 @@ Future a11y_main() async { decreasedValueAttributes: [], tooltip: 'tooltip', additionalActions: Int32List(0), - headingLevel: -1 + headingLevel: 0 ) ..updateNode( id: 84, @@ -201,7 +201,7 @@ Future a11y_main() async { additionalActions: Int32List(0), childrenInHitTestOrder: Int32List(0), childrenInTraversalOrder: Int32List(0), - headingLevel: -1 + headingLevel: 0 ) ..updateNode( id: 96, @@ -269,7 +269,7 @@ Future a11y_main() async { tooltip: 'tooltip', childrenInHitTestOrder: Int32List(0), childrenInTraversalOrder: Int32List(0), - headingLevel: -1 + headingLevel: 0 ) ..updateCustomAction( id: 21, @@ -364,7 +364,7 @@ Future a11y_string_attributes() async { decreasedValueAttributes: [], tooltip: 'tooltip', additionalActions: Int32List(0), - headingLevel: -1, + headingLevel: 0, ); PlatformDispatcher.instance.views.first.updateSemantics(builder.build()); diff --git a/testing/scenario_app/lib/src/locale_initialization.dart b/testing/scenario_app/lib/src/locale_initialization.dart index abd24af882a5e..39d791447f360 100644 --- a/testing/scenario_app/lib/src/locale_initialization.dart +++ b/testing/scenario_app/lib/src/locale_initialization.dart @@ -77,7 +77,7 @@ class LocaleInitialization extends Scenario { childrenInTraversalOrder: Int32List(0), childrenInHitTestOrder: Int32List(0), additionalActions: Int32List(0), - headingLevel: -1, + headingLevel: 0, ); final SemanticsUpdate semanticsUpdate = semanticsUpdateBuilder.build(); @@ -136,7 +136,7 @@ class LocaleInitialization extends Scenario { childrenInTraversalOrder: Int32List(0), childrenInHitTestOrder: Int32List(0), additionalActions: Int32List(0), - headingLevel: -1, + headingLevel: 0, ); final SemanticsUpdate semanticsUpdate = semanticsUpdateBuilder.build(); From 0f72806297e30a6b940163e5d1323f64cda0be54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Sun, 21 Jan 2024 22:38:43 +0100 Subject: [PATCH 25/38] Change default value for headingLevel to 0 --- shell/platform/embedder/fixtures/main.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/embedder/fixtures/main.dart b/shell/platform/embedder/fixtures/main.dart index 4702911cc293a..129e24c29ab65 100644 --- a/shell/platform/embedder/fixtures/main.dart +++ b/shell/platform/embedder/fixtures/main.dart @@ -241,7 +241,7 @@ Future a11y_main() async { tooltip: 'tooltip', textDirection: TextDirection.ltr, additionalActions: Int32List(0), - headingLevel: -1 + headingLevel: 0 ) ..updateNode( id: 128, From 79e472859b7d0b6670a7f463f65cf21ac0aa050f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Sun, 21 Jan 2024 22:56:31 +0100 Subject: [PATCH 26/38] Add focusAsRouteDefault implementation to Heading primary role --- lib/web_ui/lib/src/engine/semantics/heading.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/web_ui/lib/src/engine/semantics/heading.dart b/lib/web_ui/lib/src/engine/semantics/heading.dart index ddfe9eb32efc8..e7645d99eb87c 100644 --- a/lib/web_ui/lib/src/engine/semantics/heading.dart +++ b/lib/web_ui/lib/src/engine/semantics/heading.dart @@ -30,6 +30,9 @@ class Heading extends PrimaryRoleManager { } } + @override + bool focusAsRouteDefault() => focusable?.focusAsRouteDefault() ?? false; + void addHeadingRole() { setAriaRole('heading'); } From 4b69d9fc22d52b9af5bdb85c14d9d9c4b5cb487a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Sun, 21 Jan 2024 23:02:10 +0100 Subject: [PATCH 27/38] Change default value for headingLevel to 0 --- lib/ui/fixtures/ui_test.dart | 2 +- lib/ui/semantics.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ui/fixtures/ui_test.dart b/lib/ui/fixtures/ui_test.dart index 8252148f6a4de..855d9eaddaf9a 100644 --- a/lib/ui/fixtures/ui_test.dart +++ b/lib/ui/fixtures/ui_test.dart @@ -232,7 +232,7 @@ void sendSemanticsUpdate() { childrenInTraversalOrder: childrenInTraversalOrder, childrenInHitTestOrder: childrenInHitTestOrder, additionalActions: additionalActions, - headingLevel: -1, + headingLevel: 0, ); _semanticsUpdate(builder.build()); } diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index 875c10141c62e..9520599adac8b 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -792,7 +792,7 @@ abstract class SemanticsUpdateBuilder { /// `thickness` above the parent. /// /// The `headingLevel` describes that this node is a heading and the hierarchy - /// level this node represents as a heading. A value of -1 indicates that this + /// level this node represents as a heading. A value of 0 indicates that this /// node is not a heading. A value of 1 or greater indicates that this node is /// a heading at the specified level. The valid value range is from 1 to 6, /// inclusive. This attribute is only used for Web platform, and it will have From 5705912143b568853f579f2de437c8b9bb2b2fdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Thu, 14 Mar 2024 00:17:04 +0100 Subject: [PATCH 28/38] Fix unit test for semantics heading level attribute --- lib/web_ui/test/engine/semantics/semantics_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/web_ui/test/engine/semantics/semantics_test.dart b/lib/web_ui/test/engine/semantics/semantics_test.dart index 7cd243a4c7143..4fba431e6c033 100644 --- a/lib/web_ui/test/engine/semantics/semantics_test.dart +++ b/lib/web_ui/test/engine/semantics/semantics_test.dart @@ -686,8 +686,8 @@ void _testHeader() { rect: const ui.Rect.fromLTRB(0, 0, 100, 50), ); - semantics().updateSemantics(builder.build()); - expectSemanticsTree(''' + owner().updateSemantics(builder.build()); + expectSemanticsTree(owner(), ''' '''); From e60c0a7961645d2670f13b14687a11d172bc3c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Fri, 15 Mar 2024 00:15:53 +0100 Subject: [PATCH 29/38] Change constructor for Heading role --- lib/web_ui/lib/src/engine/semantics/heading.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web_ui/lib/src/engine/semantics/heading.dart b/lib/web_ui/lib/src/engine/semantics/heading.dart index e7645d99eb87c..c2e890175dd94 100644 --- a/lib/web_ui/lib/src/engine/semantics/heading.dart +++ b/lib/web_ui/lib/src/engine/semantics/heading.dart @@ -9,7 +9,7 @@ import 'semantics.dart'; /// level (h1 ... h6). class Heading extends PrimaryRoleManager { Heading(SemanticsObject semanticsObject) - : super.withBasics(PrimaryRole.heading, semanticsObject) { + : super.blank(PrimaryRole.heading, semanticsObject) { addHeadingRole(); } From bb787e01d3e5fa5ff5d90d0e7b5739379b22c32f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Fri, 15 Mar 2024 08:02:38 +0100 Subject: [PATCH 30/38] Fix unit test for semantics heading level --- lib/web_ui/test/engine/semantics/semantics_test.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/web_ui/test/engine/semantics/semantics_test.dart b/lib/web_ui/test/engine/semantics/semantics_test.dart index 01bfa5f9525d3..7dd87911cefe1 100644 --- a/lib/web_ui/test/engine/semantics/semantics_test.dart +++ b/lib/web_ui/test/engine/semantics/semantics_test.dart @@ -681,14 +681,13 @@ void _testHeader() { updateNode( builder, headingLevel: 2, - label: 'Heading of the page', transform: Matrix4.identity().toFloat64(), rect: const ui.Rect.fromLTRB(0, 0, 100, 50), ); owner().updateSemantics(builder.build()); expectSemanticsTree(owner(), ''' - + '''); semantics().semanticsEnabled = false; From e38e3f3e99187717a2d0358c9a9bad9023b4e44a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Wed, 20 Sep 2023 01:15:24 +0200 Subject: [PATCH 31/38] Fix PR comments (41435) --- lib/web_ui/lib/semantics.dart | 2 +- lib/web_ui/lib/src/engine/semantics/semantics.dart | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/web_ui/lib/semantics.dart b/lib/web_ui/lib/semantics.dart index ae3042a44e7d5..7c2db51a22de5 100644 --- a/lib/web_ui/lib/semantics.dart +++ b/lib/web_ui/lib/semantics.dart @@ -283,7 +283,7 @@ class SemanticsUpdateBuilder { required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, - required int headingLevel, + int? headingLevel, }) { if (transform.length != 16) { throw ArgumentError('transform argument must have 16 entries.'); diff --git a/lib/web_ui/lib/src/engine/semantics/semantics.dart b/lib/web_ui/lib/src/engine/semantics/semantics.dart index b5aea642f8101..a1a94d3619cc8 100644 --- a/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -232,7 +232,7 @@ class SemanticsNodeUpdate { required this.childrenInTraversalOrder, required this.childrenInHitTestOrder, required this.additionalActions, - required this.headingLevel, + this.headingLevel, }); /// See [ui.SemanticsUpdateBuilder.updateNode]. @@ -335,7 +335,7 @@ class SemanticsNodeUpdate { final double thickness; /// See [ui.SemanticsUpdateBuilder.updateNode]. - final int headingLevel; + final int? headingLevel; } /// Identifies [PrimaryRoleManager] implementations. @@ -1643,6 +1643,7 @@ class SemanticsObject { PrimaryRole.platformView => PlatformViewRoleManager(this), PrimaryRole.heading => Heading(this), PrimaryRole.link => Link(this), + PrimaryRole.heading => Heading(this), PrimaryRole.generic => GenericRole(this), }; } From 1e570fb4bc1ba942f7377b5edafec9a6213d487e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Sun, 12 Nov 2023 15:23:00 +0100 Subject: [PATCH 32/38] Change headingLevel to not be nullable --- lib/web_ui/lib/semantics.dart | 2 +- lib/web_ui/lib/src/engine/semantics/semantics.dart | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/web_ui/lib/semantics.dart b/lib/web_ui/lib/semantics.dart index 7c2db51a22de5..ae3042a44e7d5 100644 --- a/lib/web_ui/lib/semantics.dart +++ b/lib/web_ui/lib/semantics.dart @@ -283,7 +283,7 @@ class SemanticsUpdateBuilder { required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, - int? headingLevel, + required int headingLevel, }) { if (transform.length != 16) { throw ArgumentError('transform argument must have 16 entries.'); diff --git a/lib/web_ui/lib/src/engine/semantics/semantics.dart b/lib/web_ui/lib/src/engine/semantics/semantics.dart index a1a94d3619cc8..e18e1bc30f107 100644 --- a/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -232,7 +232,7 @@ class SemanticsNodeUpdate { required this.childrenInTraversalOrder, required this.childrenInHitTestOrder, required this.additionalActions, - this.headingLevel, + required this.headingLevel, }); /// See [ui.SemanticsUpdateBuilder.updateNode]. @@ -335,7 +335,7 @@ class SemanticsNodeUpdate { final double thickness; /// See [ui.SemanticsUpdateBuilder.updateNode]. - final int? headingLevel; + final int headingLevel; } /// Identifies [PrimaryRoleManager] implementations. From ac1ec5e5a559424885529406621a3eaba18944ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Fri, 19 Jan 2024 22:38:00 +0100 Subject: [PATCH 33/38] Change default value for headingLevel to 0 --- lib/ui/semantics.dart | 4 +- lib/web_ui/lib/semantics.dart | 98 +++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index b99382caeba42..5ff86de30a054 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -1030,8 +1030,8 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 implem Float64List transform, Int32List childrenInTraversalOrder, Int32List childrenInHitTestOrder, - Int32List additionalAction, - int headingLevel); + int headingLevel, + Int32List additionalAction); @override void updateCustomAction({required int id, String? label, String? hint, int overrideId = -1}) { diff --git a/lib/web_ui/lib/semantics.dart b/lib/web_ui/lib/semantics.dart index ae3042a44e7d5..5ba5da68ceb90 100644 --- a/lib/web_ui/lib/semantics.dart +++ b/lib/web_ui/lib/semantics.dart @@ -341,6 +341,104 @@ class SemanticsUpdateBuilder { } } +class SemanticsUpdateBuilder { + SemanticsUpdateBuilder(); + + final List _nodeUpdates = []; + void updateNode({ + required int id, + required int flags, + required int actions, + required int maxValueLength, + required int currentValueLength, + required int textSelectionBase, + required int textSelectionExtent, + required int platformViewId, + required int scrollChildren, + required int scrollIndex, + required double scrollPosition, + required double scrollExtentMax, + required double scrollExtentMin, + required double elevation, + required double thickness, + required Rect rect, + // TODO(bartekpacia): Re-add once migration is complete + // String identifier, + required String label, + required List labelAttributes, + required String value, + required List valueAttributes, + required String increasedValue, + required List increasedValueAttributes, + required String decreasedValue, + required List decreasedValueAttributes, + required String hint, + required List hintAttributes, + String? tooltip, + TextDirection? textDirection, + required Float64List transform, + required Int32List childrenInTraversalOrder, + required Int32List childrenInHitTestOrder, + required Int32List additionalActions, + required int headingLevel, + }) { + if (transform.length != 16) { + throw ArgumentError('transform argument must have 16 entries.'); + } + _nodeUpdates.add(engine.SemanticsNodeUpdate( + id: id, + flags: flags, + actions: actions, + maxValueLength: maxValueLength, + currentValueLength: currentValueLength, + textSelectionBase: textSelectionBase, + textSelectionExtent: textSelectionExtent, + scrollChildren: scrollChildren, + scrollIndex: scrollIndex, + scrollPosition: scrollPosition, + scrollExtentMax: scrollExtentMax, + scrollExtentMin: scrollExtentMin, + rect: rect, + // TODO(bartekpacia): Pass real identifier parameter once migration is complete + identifier: '', + label: label, + labelAttributes: labelAttributes, + value: value, + valueAttributes: valueAttributes, + increasedValue: increasedValue, + increasedValueAttributes: increasedValueAttributes, + decreasedValue: decreasedValue, + decreasedValueAttributes: decreasedValueAttributes, + hint: hint, + hintAttributes: hintAttributes, + tooltip: tooltip, + textDirection: textDirection, + transform: engine.toMatrix32(transform), + elevation: elevation, + thickness: thickness, + childrenInTraversalOrder: childrenInTraversalOrder, + childrenInHitTestOrder: childrenInHitTestOrder, + additionalActions: additionalActions, + platformViewId: platformViewId, + headingLevel: headingLevel, + )); + } + + void updateCustomAction({ + required int id, + String? label, + String? hint, + int overrideId = -1, + }) { + // TODO(yjbanov): implement. + } + SemanticsUpdate build() { + return SemanticsUpdate._( + nodeUpdates: _nodeUpdates, + ); + } +} + abstract class SemanticsUpdate { factory SemanticsUpdate._({List? nodeUpdates}) = engine.SemanticsUpdate; From 0b9efa6ae19dd641e2b95367d7b04615c063f86a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Fri, 29 Mar 2024 21:44:39 +0100 Subject: [PATCH 34/38] Remove duplicated definition after fixing rebase conflicts --- lib/ui/semantics.dart | 4 +- lib/web_ui/lib/semantics.dart | 98 ----------------------------------- 2 files changed, 2 insertions(+), 100 deletions(-) diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index 5ff86de30a054..2f7dabafd43f1 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -1030,8 +1030,8 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 implem Float64List transform, Int32List childrenInTraversalOrder, Int32List childrenInHitTestOrder, - int headingLevel, - Int32List additionalAction); + Int32List additionalActions, + int headingLevel); @override void updateCustomAction({required int id, String? label, String? hint, int overrideId = -1}) { diff --git a/lib/web_ui/lib/semantics.dart b/lib/web_ui/lib/semantics.dart index 5ba5da68ceb90..ae3042a44e7d5 100644 --- a/lib/web_ui/lib/semantics.dart +++ b/lib/web_ui/lib/semantics.dart @@ -341,104 +341,6 @@ class SemanticsUpdateBuilder { } } -class SemanticsUpdateBuilder { - SemanticsUpdateBuilder(); - - final List _nodeUpdates = []; - void updateNode({ - required int id, - required int flags, - required int actions, - required int maxValueLength, - required int currentValueLength, - required int textSelectionBase, - required int textSelectionExtent, - required int platformViewId, - required int scrollChildren, - required int scrollIndex, - required double scrollPosition, - required double scrollExtentMax, - required double scrollExtentMin, - required double elevation, - required double thickness, - required Rect rect, - // TODO(bartekpacia): Re-add once migration is complete - // String identifier, - required String label, - required List labelAttributes, - required String value, - required List valueAttributes, - required String increasedValue, - required List increasedValueAttributes, - required String decreasedValue, - required List decreasedValueAttributes, - required String hint, - required List hintAttributes, - String? tooltip, - TextDirection? textDirection, - required Float64List transform, - required Int32List childrenInTraversalOrder, - required Int32List childrenInHitTestOrder, - required Int32List additionalActions, - required int headingLevel, - }) { - if (transform.length != 16) { - throw ArgumentError('transform argument must have 16 entries.'); - } - _nodeUpdates.add(engine.SemanticsNodeUpdate( - id: id, - flags: flags, - actions: actions, - maxValueLength: maxValueLength, - currentValueLength: currentValueLength, - textSelectionBase: textSelectionBase, - textSelectionExtent: textSelectionExtent, - scrollChildren: scrollChildren, - scrollIndex: scrollIndex, - scrollPosition: scrollPosition, - scrollExtentMax: scrollExtentMax, - scrollExtentMin: scrollExtentMin, - rect: rect, - // TODO(bartekpacia): Pass real identifier parameter once migration is complete - identifier: '', - label: label, - labelAttributes: labelAttributes, - value: value, - valueAttributes: valueAttributes, - increasedValue: increasedValue, - increasedValueAttributes: increasedValueAttributes, - decreasedValue: decreasedValue, - decreasedValueAttributes: decreasedValueAttributes, - hint: hint, - hintAttributes: hintAttributes, - tooltip: tooltip, - textDirection: textDirection, - transform: engine.toMatrix32(transform), - elevation: elevation, - thickness: thickness, - childrenInTraversalOrder: childrenInTraversalOrder, - childrenInHitTestOrder: childrenInHitTestOrder, - additionalActions: additionalActions, - platformViewId: platformViewId, - headingLevel: headingLevel, - )); - } - - void updateCustomAction({ - required int id, - String? label, - String? hint, - int overrideId = -1, - }) { - // TODO(yjbanov): implement. - } - SemanticsUpdate build() { - return SemanticsUpdate._( - nodeUpdates: _nodeUpdates, - ); - } -} - abstract class SemanticsUpdate { factory SemanticsUpdate._({List? nodeUpdates}) = engine.SemanticsUpdate; From 6d8d511da94ee0920e1d3f99f90a3a391c83b228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Galo?= Date: Sat, 11 May 2024 00:43:44 +0200 Subject: [PATCH 35/38] Remove unnecessary check for Heading primary role --- lib/web_ui/lib/src/engine/semantics/heading.dart | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/web_ui/lib/src/engine/semantics/heading.dart b/lib/web_ui/lib/src/engine/semantics/heading.dart index c2e890175dd94..eb97725bd5b7a 100644 --- a/lib/web_ui/lib/src/engine/semantics/heading.dart +++ b/lib/web_ui/lib/src/engine/semantics/heading.dart @@ -13,8 +13,6 @@ class Heading extends PrimaryRoleManager { addHeadingRole(); } - static const int defaultHeadingLevel = 1; - @override void update() { super.update(); @@ -23,11 +21,7 @@ class Heading extends PrimaryRoleManager { return; } - if (semanticsObject.headingLevel != 0) { - addHeadingLevel(semanticsObject.headingLevel); - } else { - addHeadingLevel(defaultHeadingLevel); - } + addHeadingLevel(semanticsObject.headingLevel); } @override From ca2d289c551226453913c2acbbcdd17f4b93aa2e Mon Sep 17 00:00:00 2001 From: victorgalo Date: Fri, 17 May 2024 20:21:13 +0200 Subject: [PATCH 36/38] Remove duplicated case in switch statement --- lib/web_ui/lib/src/engine/semantics/semantics.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/web_ui/lib/src/engine/semantics/semantics.dart b/lib/web_ui/lib/src/engine/semantics/semantics.dart index b2925f9e10be2..0fbd8596e9f00 100644 --- a/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -1654,7 +1654,6 @@ class SemanticsObject { PrimaryRole.dialog => Dialog(this), PrimaryRole.image => ImageRoleManager(this), PrimaryRole.platformView => PlatformViewRoleManager(this), - PrimaryRole.heading => Heading(this), PrimaryRole.link => Link(this), PrimaryRole.heading => Heading(this), PrimaryRole.generic => GenericRole(this), From 438346457c4aed1d57fea61fab3cdfc3e93f9be0 Mon Sep 17 00:00:00 2001 From: victorgalo Date: Sat, 1 Jun 2024 03:19:55 +0200 Subject: [PATCH 37/38] Change semantics headingLevel attribute to be not required until framework part is landed --- lib/ui/semantics.dart | 4 ++-- lib/web_ui/lib/semantics.dart | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ui/semantics.dart b/lib/ui/semantics.dart index 809381c1f8ec6..57bc1fa30726d 100644 --- a/lib/ui/semantics.dart +++ b/lib/ui/semantics.dart @@ -887,7 +887,7 @@ abstract class SemanticsUpdateBuilder { required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, - required int headingLevel, + int headingLevel = 0, }); /// Update the custom semantics action associated with the given `id`. @@ -958,7 +958,7 @@ base class _NativeSemanticsUpdateBuilder extends NativeFieldWrapperClass1 implem required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, - required int headingLevel, + int headingLevel = 0, }) { assert(_matrix4IsValid(transform)); assert ( diff --git a/lib/web_ui/lib/semantics.dart b/lib/web_ui/lib/semantics.dart index af74e73476029..e4698e40f2f2c 100644 --- a/lib/web_ui/lib/semantics.dart +++ b/lib/web_ui/lib/semantics.dart @@ -286,7 +286,7 @@ class SemanticsUpdateBuilder { required Int32List childrenInTraversalOrder, required Int32List childrenInHitTestOrder, required Int32List additionalActions, - required int headingLevel, + int headingLevel = 0, }) { if (transform.length != 16) { throw ArgumentError('transform argument must have 16 entries.'); From 518605585e3bece929d5b02c9430ce47a3a08bd0 Mon Sep 17 00:00:00 2001 From: Chun-Heng Tai Date: Tue, 4 Jun 2024 09:29:06 -0700 Subject: [PATCH 38/38] fix lint --- testing/scenario_app/lib/src/locale_initialization.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/testing/scenario_app/lib/src/locale_initialization.dart b/testing/scenario_app/lib/src/locale_initialization.dart index 40271f35caa77..74eceaa53a526 100644 --- a/testing/scenario_app/lib/src/locale_initialization.dart +++ b/testing/scenario_app/lib/src/locale_initialization.dart @@ -78,7 +78,6 @@ class LocaleInitialization extends Scenario { childrenInTraversalOrder: Int32List(0), childrenInHitTestOrder: Int32List(0), additionalActions: Int32List(0), - headingLevel: 0, ); final SemanticsUpdate semanticsUpdate = semanticsUpdateBuilder.build(); @@ -138,7 +137,6 @@ class LocaleInitialization extends Scenario { childrenInTraversalOrder: Int32List(0), childrenInHitTestOrder: Int32List(0), additionalActions: Int32List(0), - headingLevel: 0, ); final SemanticsUpdate semanticsUpdate = semanticsUpdateBuilder.build();