Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-nav-1] Consider candidates on the navigation direction. #4483

Open
jeonghee27 opened this issue Nov 5, 2019 · 11 comments
Open

[css-nav-1] Consider candidates on the navigation direction. #4483

jeonghee27 opened this issue Nov 5, 2019 · 11 comments
Assignees

Comments

@jeonghee27
Copy link
Contributor

jeonghee27 commented Nov 5, 2019

I want to resolve some unreachable cases caused by current spec about determining whether the candidate is on the navigation direction or not.

In the below example, Let's assume that user press right-button from A/C/E.

image

B and D is reachable from A /C.
According to current spec and chromium, F is not right side of E

*Spec :
https://drafts.csswg.org/css-nav-1/
-> "the item partially overlaps with searchOrigin and its two edges which are orthogonal to dir should be on the navigation direction of the respective ones of searchOrigin."

*Chromium : https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/page/spatial_navigation.cc?q=spatial_navigation.cc&sq=package:chromium&dr&l=117
static inline bool RightOf(const PhysicalRect& a, const PhysicalRect& b) {
return a.X() >= b.Right() || (a.X() >= b.X() && a.Right() > b.Right() &&
a.Y() < b.Bottom() && a.Bottom() > b.Y());
}

I hope to remove "a.Right() > b.Right()" part.
Is there a problem if User can go from E to F using right key?
I would like to know your opinions. (@jihyerish @frivoal @hugoholgersson @bokand @anawhj )

@anawhj
Copy link
Member

anawhj commented Nov 8, 2019

I simplify the problem and propose the candidate solution via the following example.
https://software.hixie.ch/utilities/js/live-dom-viewer/?saved=7345

The example above shows the current(As Is) behavior of SpatNav (polyfill and Chromium) as follows:

  • As Is: A-B-E (pressing the right arrow key from A to E)
  • To Be: A-B-C-D-E (pressing the right arrow key from A to E)

In the figure above, B is considered to be on the right of A, if the left and right edges of B are on the right of the respective ones of A as a rule specified in css-nav spec. For partially overlapping elements, D can't be a candidate if users press a right arrow key from B now. The reason is that the right edge of D isn't on the right of the right edge of B.

For securing D's reachability in a right direction from B, Jeonghee would suggest that we could modify the rule to ways only considering the left edge (of B) on partially overlapping elements when pressing a right arrow key.

It's definitely a heuristic rule that doesn't means a clear solution satisfying all people, but it definitely solves several abnormal behavior(e.g. unreachable element by arrow keys) in several general web sites such as https://naver.com

The modified logic for partially overlapping elements could be specified in css-nav spec as a non-normative, I'm not sure it makes sense. (@jihyerish) Also, I wonder there is something I missed on the logic modification. (@hugoholgersson @bokand)

@jihyerish
Copy link
Contributor

I think considering 'C' in the above example as a candidate, in general, is risky.
From 'B', and when pressing the right arrow key, 'D' needs to be included in the set of candidates because it'll be unreachable in any direction.
But for 'C', it can be reachable anyway when pressing the up arrow key from 'B'.
It's true that it will solve the issue of https://naver.com, but I'm not sure it will be okay for the other pages.

Therefore I've described how to select the partially overlapped element as the candidate as non-normative in step 4 of selecting the best candidate.

jihyerish pushed a commit to jihyerish/csswg-drafts that referenced this issue Nov 25, 2019
1. Modify the making the set of "insiders" in selecting the best candidate steps:
1) From the search origin, fully overlapped elements and partially overlapped elements depending on the requested direction are included in the "insiders"
2) Element which aren't overlapped with the search origin is "outsiders" (*outsider isn't specified in the spec)

2. Modify the selecting the best candidate steps as
1) find the closest element among "insiders"
  1-1) if there is one, it is the best candidate
  1-2) else fall back to the next step
2) find the closest element among "outsiders" using distance function (https://drafts.csswg.org/css-nav-1/#find-the-shortest-distance)

Related to : w3c#4483
@hugoholgersson
Copy link

Do Chromium's layout tests pass with this change?

@jeonghee27
Copy link
Contributor Author

jeonghee27 commented Dec 10, 2019

Do Chromium's layout tests pass with this change?

Yes, It did on https://chromium-review.googlesource.com/c/chromium/src/+/1905297
I am planning to add a bug page and resolve conflict soon.

@jeonghee27
Copy link
Contributor Author

jeonghee27 commented Jan 9, 2020

I'm trying to apply new direction rule to chromium likes below. (https://chromium-review.googlesource.com/c/chromium/src/+/1905297/14/)

AS-IS

// if both edges of |a| are below the respective ones of |b|.
static inline bool Below(const PhysicalRect& a, const PhysicalRect& b) {
  return a.Y() >= b.Bottom() || (a.Y() >= b.Y() && a.Bottom() > b.Bottom() &&
                                 a.X() < b.Right() && a.Right() > b.X());
}
// For overlapping rects, |a| is considered to be on the right of |b|
// if both edges of |a| are on the right of the respective ones of |b|.
static inline bool RightOf(const PhysicalRect& a, const PhysicalRect& b) {
  return a.X() >= b.Right() || (a.X() >= b.X() && a.Right() > b.Right() &&
                                a.Y() < b.Bottom() && a.Bottom() > b.Y());

TO-BE

// if the top edge of |a| is below the top edge of |b|.
static inline bool Below(const PhysicalRect& a, const PhysicalRect& b) {
  return a.Y() >= b.Bottom() ||
         (a.Y() > b.Y() && a.X() < b.Right() && a.Right() > b.X());
}

// For overlapping rects, |a| is considered to be above |b|,
// if the bottom edge of |a| is above the bottom edge of |b|.
static inline bool Above(const PhysicalRect& a, const PhysicalRect& b) {
  return a.Bottom() <= b.Y() ||
         (a.Bottom() < b.Bottom() && a.Right() > b.X() && a.X() < b.Right());
}

// For overlapping rects, |a| is considered to be on the right of |b|,
// if the left edge of |a| is on the right of the left edge of |b|.
static inline bool RightOf(const PhysicalRect& a, const PhysicalRect& b) {
  return a.X() >= b.Right() ||
         (a.X() > b.X() && a.Y() < b.Bottom() && a.Bottom() > b.Y());
}

// Return true if rect |a| is on the left of |b|. False otherwise.
// For overlapping rects, |a| is considered to be on the left of |b|,
// if the right edge of |a| is on the left of the right edge of |b|.
static inline bool LeftOf(const PhysicalRect& a, const PhysicalRect& b) {
  return a.Right() <= b.X() ||
         (a.Right() < b.Right() && a.Bottom() > b.Y() && a.Y() < b.Bottom());
}

But @hugoholgersson seems to have a different opinion.
I hope to make agreement here.

In below picture,
image

Let's assume we press DOWN key on "A", "C", "E"

  1. "B" is next target from A?
  2. "D" is next target from C?
  3. "F" is next target from E?

Let's assume we press UP key on "B", "D", "F"
4. "A" is next target from B?
5. "C" is next target from D?
6. "E" is next target from F?

In my opinion and by spec, SpatNav consider only top edge when user press down for overlap case.
So 1-3 and 5-6 are wrong.

@hugoholgersson
I wonder your idea about the rules.

@anawhj anawhj reopened this Jan 9, 2020
@anawhj anawhj closed this as completed Jan 10, 2020
@anawhj anawhj reopened this Jan 10, 2020
@hugoholgersson
Copy link

hugoholgersson commented Jan 10, 2020

Thanks for the example. It shows how to avoid loops such as [1]. I think you should emphasize this in a code comment and perhaps also in a spec comment.

[1] down, down, down: A, B, A

We avoid [1] thanks to Below()'s a.Y > b.Y. >= would cause [1].

(Please correct me if I'm wrong.)


By the way, why don't we relax the condition on the orthogonal axis? For example:

Below() {
  a.Y >= b.Bottom ||
    (a.Y > b.Y && a.X <= b.Right && a.Right >= b.X)
}

The current wording does not prevent <= and >= on the X-axis. [2] [3]

[2] "top edge is below the top edge of searchOrigin’s boundary box if dir is down"
[3] "whose boundary box partially overlaps with inside area of searchOrigin"

@jeonghee27
Copy link
Contributor Author

[1] down, down, down: A, B, A
We avoid [1] thanks to Below()'s a.Y > b.Y. >= would cause [1].

Yes right.

why don't we relax the condition on the orthogonal axis? For example:
[2] "top edge is below the top edge of searchOrigin’s boundary box if dir is down"

Do you think it is overlap even if 1px is attached?
I didn't. but It also makes sense. But it's a bit confusing to tell 1px overlap.
just confusing... I'll fix patch.
I hope there are no different opinion elsewhere in the formula.

@hugoholgersson
Copy link

Do you think it is overlap even if 1px is attached?

What do you mean by "attached"?

@jeonghee27
Copy link
Contributor Author

jeonghee27 commented Jan 13, 2020

image

I'm not sure which case is (a.X = b.Right)..
I thought we didn't need to include these two cases as overlap cases.
I wonder your opinion

@hugoholgersson
Copy link

hugoholgersson commented Jan 14, 2020

Good pictures!

Do you think it is overlap even if 1px is attached?

Yes. To me, [2] is overlapping but [1] is not.

I thought we didn't need to include these two cases as overlap cases.

Yeah, I don't know what's best either, but I'd say [2] should be considered "overlapping" even though only 1px overlaps. 1px gets bigger with zooming. :)

I wonder your opinion

With a.X <= b.Right, we include [2] but not [1] so let's use <= in the formula?

Otherwise, I think the formula looks good!

When implementing this in Chrome, you will need to use PhysicalRect::IntersectsInclusively, not PhysicalRect::Intersects.

@jeonghee27
Copy link
Contributor Author

Thanks for your guide. and I understand your opinion.
I'll use PhysicalRect::IntersectsInclusively and fix "a.X <= b.Right," in this week.
then, I'm going to ping you on chromium review page.

aarongable pushed a commit to chromium/chromium that referenced this issue Aug 14, 2024
Background:
In SpatNav, users can reach focusable elements that are
fully contained by the search origin, http://crrev.com/c/1587559.

Problem:
Partially contained elements are handled differently.
The current logic can cause unexpected focus navigation
because partially contained elements are unreachable. The
difference between a fully and a partially contained
element may be just 1 pixel.

Solution:
Handle partially and fully contained elements in the same way.
That is, give equal priority to candidates that are partially
and fully contained by SearchOrigin.

In this patch, we extend the criteria for being prioritized to
also include partially overlapping (or partially contained, if
you wish) elements so they become reachable.

Discussion in the spec :
https://drafts.csswg.org/css-nav-1/#select-the-best-candidate
w3c/csswg-drafts#4483
Previous CL: http://crrev.com/c/1905297

Bug: 1033403
Change-Id: I556a69606b36bbc094440cdb1e08e9238c4a94e6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5561524
Reviewed-by: JunHo Seo <junho0924.seo@lge.com>
Commit-Queue: Jeonghee Ahn <jeonghee27.ahn@lge.com>
Reviewed-by: David Bokan <bokan@chromium.org>
Auto-Submit: Jeonghee Ahn <jeonghee27.ahn@lge.com>
Cr-Commit-Position: refs/heads/main@{#1341432}
aarongable pushed a commit to chromium/chromium that referenced this issue Aug 14, 2024
This reverts commit ddea91b.

Reason for revert: Suspicious about causing test failures of
fast/spatial-navigation/snav-contained-elements-with-same-distance.html
https://ci.chromium.org/ui/p/chromium/builders/ci/mac13-arm64-rel-tests/30725/overview

Original change's description:
> [SpatNav] Equally favor intersecting and contained candidates
>
> Background:
> In SpatNav, users can reach focusable elements that are
> fully contained by the search origin, http://crrev.com/c/1587559.
>
> Problem:
> Partially contained elements are handled differently.
> The current logic can cause unexpected focus navigation
> because partially contained elements are unreachable. The
> difference between a fully and a partially contained
> element may be just 1 pixel.
>
> Solution:
> Handle partially and fully contained elements in the same way.
> That is, give equal priority to candidates that are partially
> and fully contained by SearchOrigin.
>
> In this patch, we extend the criteria for being prioritized to
> also include partially overlapping (or partially contained, if
> you wish) elements so they become reachable.
>
> Discussion in the spec :
> https://drafts.csswg.org/css-nav-1/#select-the-best-candidate
> w3c/csswg-drafts#4483
> Previous CL: http://crrev.com/c/1905297
>
> Bug: 1033403
> Change-Id: I556a69606b36bbc094440cdb1e08e9238c4a94e6
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5561524
> Reviewed-by: JunHo Seo <junho0924.seo@lge.com>
> Commit-Queue: Jeonghee Ahn <jeonghee27.ahn@lge.com>
> Reviewed-by: David Bokan <bokan@chromium.org>
> Auto-Submit: Jeonghee Ahn <jeonghee27.ahn@lge.com>
> Cr-Commit-Position: refs/heads/main@{#1341432}

Bug: 1033403
Change-Id: I6c99006eec5425a32a91a18b631fff73c9958f7c
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5782516
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Yuki Shiino <yukishiino@chromium.org>
Owners-Override: Yuki Shiino <yukishiino@chromium.org>
Auto-Submit: Yuki Shiino <yukishiino@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1341445}
aarongable pushed a commit to chromium/chromium that referenced this issue Aug 26, 2024
This is a reland of commit ddea91b

Reason for revert:
The layout test snav-contained-elements-with-same-distance.html
which was merged at a similar time was failed.
(commit 12aaf28)
Because it have a different expected result from the overlap case rule.
In snav-contained-elements-with-same-distance.html,
Since e2 is not below e3, focus could not be moved to e2 using down key
at e3 in this patch. Likewise, focus could not be moved to e5 using
right key at e6.

Solution:
Even if the opposite edge is on the same line and is not recognized as
being in the corresponding direction, it is allowed to enter the
insider as an exception case.

Original change's description:
> [SpatNav] Equally favor intersecting and contained candidates
>
> Background:
> In SpatNav, users can reach focusable elements that are
> fully contained by the search origin, http://crrev.com/c/1587559.
>
> Problem:
> Partially contained elements are handled differently.
> The current logic can cause unexpected focus navigation
> because partially contained elements are unreachable. The
> difference between a fully and a partially contained
> element may be just 1 pixel.
>
> Solution:
> Handle partially and fully contained elements in the same way.
> That is, give equal priority to candidates that are partially
> and fully contained by SearchOrigin.
>
> In this patch, we extend the criteria for being prioritized to
> also include partially overlapping (or partially contained, if
> you wish) elements so they become reachable.
>
> Discussion in the spec :
> https://drafts.csswg.org/css-nav-1/#select-the-best-candidate
> w3c/csswg-drafts#4483
> Previous CL: http://crrev.com/c/1905297
>
> Bug: 1033403
> Change-Id: I556a69606b36bbc094440cdb1e08e9238c4a94e6
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5561524
> Reviewed-by: JunHo Seo <junho0924.seo@lge.com>
> Commit-Queue: Jeonghee Ahn <jeonghee27.ahn@lge.com>
> Reviewed-by: David Bokan <bokan@chromium.org>
> Auto-Submit: Jeonghee Ahn <jeonghee27.ahn@lge.com>
> Cr-Commit-Position: refs/heads/main@{#1341432}

Bug: 1033403
Change-Id: I8c102dc751136c67ac0886109c23cfff614808a5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5782687
Reviewed-by: JunHo Seo <junho0924.seo@lge.com>
Reviewed-by: Fredrik Söderquist <fs@opera.com>
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Auto-Submit: Jeonghee Ahn <jeonghee27.ahn@lge.com>
Cr-Commit-Position: refs/heads/main@{#1346618}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants