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

Conversation

@nbayati
Copy link
Contributor

@nbayati nbayati commented Sep 2, 2022

Fixes the scrolling issue when using assistive technology.
When the assistive technology gets to the last item on a scrollable list, the browser sets the scrollTop/scrollLeft to zero and the user is not able to scroll back up/left anymore. This PR fixes the issue by adding a dummy DOM element to the end of the scrollable list so we can prevent scrollTop/scrollLeft from becoming zero and getting stuck.

Here is a test app with the current engine build: https://negarb-testapp.web.app/#/
And here is the test app using this fix: https://a11y-scroll-fixed.web.app/#/

Fixes flutter/flutter#104036

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 Hixie said 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.

@flutter-dashboard flutter-dashboard bot added the platform-web Code specifically for the web engine label Sep 2, 2022
@nbayati nbayati requested a review from yjbanov September 2, 2022 23:22
@nbayati nbayati marked this pull request as ready for review September 9, 2022 21:27
@flutter-dashboard
Copy link

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat (don't just cc him here, he won't see it! He's on Discord!).

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

// We neutralize the scroll position after all children have been
// updated. Otherwise the browser does not yet have the sizes of the
// child nodes and resets the scrollTop value back to zero.
semanticsObject.owner.addOneTimePostUpdateCallback(() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is addOneTimePostUpdateCallback still necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Several tests will fail if we call _neutralizeDomScrollPosition() directly here without using addOneTimePostUpdateCallback(). I think we still need to wait for the update to finish before attempting to neutralize the scroll position.

// updated. Otherwise the browser does not yet have the sizes of the
// child nodes and resets the scrollTop value back to zero.
semanticsObject.owner.addOneTimePostUpdateCallback(() {
_neutralizeDomScrollPosition();
Copy link
Contributor

Choose a reason for hiding this comment

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

_neutralizeDomScrollPosition updates verticalContainerAdjustment and horizontalContainerAdjustment. Do we need to call recomputePositionAndSize after this?

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'm not sure. Was recomputePositionAndSize meant to be called every time we neutralize the position?

Currently we wait for everything to finish updating before we neutralize the scrolling position. Now is it possible that calling recomputePositionAndSize would cause unintended consequences and change the value of ScrollTop/ScrollLeft?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes. More generally, recomputePositionAndSize should be called every time a parameter that affects it changes. Position and size depend on a whole bunch of stuff, like rect, transform, vertical and horizontal adjustments, etc. If any of them change and we don't call recomputePositionAndSize we risk the position and size to go out of sync with the current state of the semantics tree.

I see two ways to fix this:

  1. Remove addOneTimePostUpdateCallback. This should work because roles are updated before calling recomputePositionAndSize. However, as you mention above, this breaks some tests.
  2. Call recomputePositionAndSize right after _neutralizeDomScrollPosition.

AFAICT, for the purposes of this bug fix either should work. Option 1 is probably a bigger yak shave though.

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'll go with option 2 for now.

@nbayati nbayati requested a review from yjbanov September 16, 2022 00:08
@skia-gold
Copy link

Gold has detected about 1 new digest(s) on patchset 9.
View them at https://flutter-engine-gold.skia.org/cl/github/35899

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.

Just a couple of non-blocking comments.

lgtm

});
// We neutralize the scroll position after all children have been
// updated. Otherwise the browser does not yet have the sizes of the
// child nodes and resets the scrollTop value back to zero.
Copy link
Contributor

Choose a reason for hiding this comment

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

This comment is no longer accurate and can be removed. After this change we can set scrollTop to a non-zero value even on empty containers. We should find out why tests are failing when addOneTimePostUpdateCallback is removed, and if there's a valid reason then document it, otherwise update tests. This can be done later. No need to block this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed!

// updated. Otherwise the browser does not yet have the sizes of the
// child nodes and resets the scrollTop value back to zero.
semanticsObject.owner.addOneTimePostUpdateCallback(() {
_neutralizeDomScrollPosition();
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes. More generally, recomputePositionAndSize should be called every time a parameter that affects it changes. Position and size depend on a whole bunch of stuff, like rect, transform, vertical and horizontal adjustments, etc. If any of them change and we don't call recomputePositionAndSize we risk the position and size to go out of sync with the current state of the semantics tree.

I see two ways to fix this:

  1. Remove addOneTimePostUpdateCallback. This should work because roles are updated before calling recomputePositionAndSize. However, as you mention above, this breaks some tests.
  2. Call recomputePositionAndSize right after _neutralizeDomScrollPosition.

AFAICT, for the purposes of this bug fix either should work. Option 1 is probably a bigger yak shave though.

@nbayati nbayati added the autosubmit Merge PR when tree becomes green via auto submit App label Sep 17, 2022
@auto-submit
Copy link
Contributor

auto-submit bot commented Sep 17, 2022

auto label is removed for flutter/engine, pr: 35899, due to - The status or check suite Linux Web Engine has failed. Please fix the issues identified (or deflake) before re-applying this label.

@auto-submit auto-submit bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Sep 17, 2022
@nbayati nbayati merged commit da248fd into flutter:main Sep 20, 2022
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Sep 20, 2022
Oleh-Sv pushed a commit to Oleh-Sv/engine that referenced this pull request Sep 28, 2022
* Fix the a11y scrolling issue

* Add scroll overflow dom element

* Add tests for scrollTop/scrollLeft

* Documentation and code clean-ups

* call recomputePositionAndSize() after neutralizing the scroll position

* Remove unnecessary imports
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

platform-web Code specifically for the web engine

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Screen does not scroll correctly when using an Accessibility Screen Reader

3 participants