Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Add link support in web accessibility #46117

Merged
merged 6 commits into from
Oct 20, 2023
Merged

Conversation

chunhtai
Copy link
Contributor

fixes flutter/flutter#134795

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide and the C++, Objective-C, Java style guides.
  • I listed at least one issue that this PR fixes in the description above.
  • I added new tests to check the change I am making or feature I am adding, or the PR is test-exempt. See testing the engine for instructions on writing and running engine tests.
  • I updated/added relevant documentation (doc comments with ///).
  • I signed the CLA.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@github-actions github-actions bot added the platform-web Code specifically for the web engine label Sep 20, 2023
Copy link
Contributor Author

@chunhtai chunhtai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @yjbanov and @mdebbar can you take a look at this draft pr to see if this is the direction we want to go before I add more tests?

}

/// The element used for link, i.e. `<a>`.
late DomHTMLElement anchorElement;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are still some more work needed to wire up the semantics action to this element, but I would like to know whether this is the way we want to pursuit.

An alternative is to Make semanticsObject.element to be a directly, that way I can reuse all the RoleManager like Tappable or Focusable.

@chunhtai chunhtai requested review from yjbanov and mdebbar September 20, 2023 19:36
..height = '${semanticsObject.rect!.height}px';
semanticsObject.element.append(anchorElement);
anchorElement.setAttribute('href', '#');
anchorElement.addEventListener('focus',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you reuse the Focusable role manager instead of implementing custom focus management?

Copy link
Contributor Author

@chunhtai chunhtai Sep 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The focusable role manager will only work on SemanticsObject.element I think? If I want to do that, I will need to add a way to create an <a> as SemanticsObject.element instead of the <flt-semantics-node> that it hardcoded to create. I am fine with that, but it seems to divert from what we were doing with text_field.dart

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, in that case you might want AccessibilityFocusManager.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the code to use RoleManager instead, PTAL

EnginePlatformDispatcher.instance.invokeOnSemanticsAction(
semanticsObject.id, ui.SemanticsAction.didLoseAccessibilityFocus, null);
}));
anchorElement.addEventListener('click',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly here, can we reuse the Tappable role manager?

@@ -1501,6 +1510,7 @@ class SemanticsObject {
PrimaryRole.image => ImageRoleManager(this),
PrimaryRole.platformView => PlatformViewRoleManager(this),
PrimaryRole.generic => GenericRole(this),
PrimaryRole.link => Link(this),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep the generic role last to underscore that it's the fallback role that we only use as a last resort.

@chunhtai chunhtai requested a review from yjbanov September 21, 2023 21:43
@chunhtai chunhtai marked this pull request as ready for review September 21, 2023 21:43
@chunhtai
Copy link
Contributor Author

a friendly bump

void _updateElement(PrimaryRole role) {
switch (role) {
case PrimaryRole.link:
element = domDocument.createElement('a');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The element field is designed to be final, as it participates in the parent's DOM structure. Simply swapping the element field will result in a dangling element not attached to anywhere. Let's chat about what you are trying to do and find a better solution.

@chunhtai chunhtai force-pushed the issues/134795 branch 2 times, most recently from e1589f3 to 69fd141 Compare October 2, 2023 18:11
@chunhtai chunhtai requested a review from yjbanov October 2, 2023 18:27
@@ -437,6 +441,8 @@ abstract class PrimaryRoleManager {
/// management intereferes with the widget's functionality.
PrimaryRoleManager.blank(this.role, this.semanticsObject);

late final DomElement element = _createAndInitElement();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it need to be late if it is initialized immediately? late has runtime cost (it uses a null check behind-the-scenes) and complexity cost (it is initialized upon first access, which is less predictable than constructor initialization).

Copy link
Contributor Author

@chunhtai chunhtai Oct 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non-late final can only accept static function as its initializer. In this case, there isn't a way for sub class to inject their logic

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see, you need to call this.createElement which not static. In that case late make sense. However, I'd still initialize it in the constructor. Otherwise, it gets initialized upon first read of the field, and since it's hard to predict when exactly that field is accessed we can get into race conditions, such as _createAndInitElement reading from semanticsObject that has changed its state after the constructor is finished. Can you move element = _createAndInitElement(); into the constructor body?

@override
DomElement createElement() {
final DomElement element = domDocument.createElement('a');
// TODO(chunhtai): Fill in the real link once the framework sends entire uri.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a Github issue this can point to?

@protected
DomElement createElement() => domDocument.createElement('flt-semantics');

DomElement _createAndInitElement() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: actually, I'd still keep this static and pass all the information it needs to initialize the element (I think all it needs is the element created by createElement and semanticsObject). This way this method will not need access to this.

@chunhtai chunhtai added the autosubmit Merge PR when tree becomes green via auto submit App label Oct 20, 2023
Copy link
Contributor

@yjbanov yjbanov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Oct 20, 2023
…136982)

flutter/engine@d46933e...b27e1b3

2023-10-20 [email protected] Add link support in web accessibility (flutter/engine#46117)
2023-10-20 [email protected] [web] Support `flutterViewId` in platform view messages (flutter/engine#46891)
2023-10-20 [email protected] Fix async image loading issues in skwasm. (flutter/engine#47117)
2023-10-20 [email protected] Add option to save Impeller failure images in rendertests (flutter/engine#47142)
2023-10-20 [email protected] Roll Skia from b960e9140f56 to 9ffd5ef9a9ed (3 revisions) (flutter/engine#47167)
2023-10-20 [email protected] [macOS] Eliminate extraneous loadView calls (flutter/engine#47166)
2023-10-20 [email protected] Roll Dart SDK from ba96a157a8eb to 53fee35b299f (1 revision) (flutter/engine#47165)
2023-10-20 [email protected] [Impeller] GPU Tracer for GLES. (flutter/engine#47080)
2023-10-20 [email protected] Roll Skia from de628929015d to b960e9140f56 (2 revisions) (flutter/engine#47164)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC [email protected],[email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
harryterkelsen pushed a commit that referenced this pull request Oct 23, 2023
fixes flutter/flutter#134795

## Pre-launch Checklist

- [ ] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [ ] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [ ] I read and followed the [Flutter Style Guide] and the [C++,
Objective-C, Java style guides].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I added new tests to check the change I am making or feature I am
adding, or the PR is [test-exempt]. See [testing the engine] for
instructions on writing and running engine tests.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [ ] I signed the [CLA].
- [ ] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#overview
[Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene
[test-exempt]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo
[C++, Objective-C, Java style guides]:
https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
[testing the engine]:
https://github.com/flutter/flutter/wiki/Testing-the-engine
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes
[Discord]: https://github.com/flutter/flutter/wiki/Chat
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
autosubmit Merge PR when tree becomes green via auto submit App platform-web Code specifically for the web engine
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Semantics link:true does not work on web.
2 participants