From bb0a18c72f1a4956b4c0839c761a852265271c02 Mon Sep 17 00:00:00 2001 From: Liam Brady Date: Fri, 7 Apr 2023 14:48:51 -0400 Subject: [PATCH 01/10] start work --- spec.bs | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/spec.bs b/spec.bs index 9f5e6bf2..a7cc11b0 100644 --- a/spec.bs +++ b/spec.bs @@ -78,9 +78,17 @@ spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/ urlPrefix: interaction.html text: activation notification; url: activation-notification text: consume user activation; url: consume-user-activation + text: activation; url: activation + text: click focusable; url: click-focusable + text: focusable area; url: focusable-area + text: sequential focus navigation; url: sequential-focus-navigation + urlPefix: infrastructure.html + text: immediately; url: immediately urlPrefix: nav-history-apis.html for: Window text: navigable; url: window-navigable + urlPrefix: interactive-elements.html + text: accesskey attribute command; url: using-the-accesskey-attribute-to-define-a-command-on-other-elements spec: RFC8941; urlPrefix: https://www.rfc-editor.org/rfc/rfc8941.html type: dfn text: structured header; url: #section-1 @@ -651,6 +659,49 @@ traversables section. 1. Return |navigables|. +

Modifications to the focusing steps algorithm

+ + Modify the [=focusing steps=] algorithm to take a new optional [=boolean=] + argument unfenced that defaults to false. + + Add a new step after step 7 of the algorithm (that defines old chain and new chain) that reads: + + 8. If [=focus-unfenced|unfenced=] is set to false, new chain + contains a Document with a [=fenced navigable container/fenced navigable=] + nav, and old chain does not also contain + an entry with nav, then return. + + Modify the user agent note after the algorithm steps to read: + +

User agents must [=immediately=] run the [=focusing steps=] for a + [=focusable area=] or [=navigable=] candidate whenever the + user attempts to move the focus to candidate.

+ + Modify the action of the [=accesskey attribute command=] algorithm to be: + +
    +
  1. Run the [=focusing steps=] for the element with [=focus-unfenced|unfenced=] set to true.
  2. + +
  3. Fire a click event at the element.
  4. +
+ + Modify the behavior when a user [=activation|activates=] a [=click focusable=] [=focusable area=] to be: + +

When a user [=activation|activates=] a [=click focusable=] [=focusable area=], + the user agent must run the [=focusing steps=] on the [=focusable area=] + with focus trigger set to "click" and + [=focus-unfenced|unfenced=] set to true.

+ + Modify step 6 of the [=sequential focus navigation=] algorithm to be: + + 6. If candidate is not null, then run the [=focusing steps=] for + candidate with [=focus-unfenced|unfenced=] set to true and return. + + Modify step 10 of the [=hide popover algorithm=] to read: + + 10. + +

Modifications to the focus chain algorithm

The \`Supports-Loading-Mode\` HTTP response header

From 8bd6ee165901e415e57d3e63c13582741c585478 Mon Sep 17 00:00:00 2001 From: Liam Brady Date: Fri, 7 Apr 2023 15:59:29 -0400 Subject: [PATCH 02/10] add rest of cases in audit --- spec.bs | 50 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/spec.bs b/spec.bs index a7cc11b0..bb532d6a 100644 --- a/spec.bs +++ b/spec.bs @@ -89,6 +89,13 @@ spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/ text: navigable; url: window-navigable urlPrefix: interactive-elements.html text: accesskey attribute command; url: using-the-accesskey-attribute-to-define-a-command-on-other-elements + text: previously focused element; url: previously-focused-element + urlPrefix: popover.html + text: hide popover algorithm; url: hide-popover-algorithm + urlPrefix: form-control-infrastructure.html + text: interactively validate the constraints; url: interactively-validate-the-constraints + urlPrefix: custom-elements.html + text: face validation anchor; url: face-validation-anchor spec: RFC8941; urlPrefix: https://www.rfc-editor.org/rfc/rfc8941.html type: dfn text: structured header; url: #section-1 @@ -667,15 +674,15 @@ traversables section. Add a new step after step 7 of the algorithm (that defines old chain and new chain) that reads: 8. If [=focus-unfenced|unfenced=] is set to false, new chain - contains a Document with a [=fenced navigable container/fenced navigable=] - nav, and old chain does not also contain - an entry with nav, then return. + contains an [=element=] ele whose [=node navigable=]'s + [=traversable navigable=] is a [=fenced navigable container/fenced navigable=], + and old chain does not also contain ele, then return. - Modify the user agent note after the algorithm steps to read: + Modify the user agent sentence after the algorithm steps to read:

User agents must [=immediately=] run the [=focusing steps=] for a - [=focusable area=] or [=navigable=] candidate whenever the - user attempts to move the focus to candidate.

+ [=focusable area=] or [=navigable=] candidate with [=focus-unfenced|unfenced=] set + to true whenever the user attempts to move the focus to candidate.

Modify the action of the [=accesskey attribute command=] algorithm to be: @@ -699,9 +706,36 @@ traversables section. Modify step 10 of the [=hide popover algorithm=] to read: - 10. +
    +
  1. +

    If previouslyFocusedElement is not null, then:

    + +
      +
    1. Set element's [=previously focused element=] to null.

    2. + +
    3. If focusPreviousElement is true, then run the [=focusing steps=] for + previouslyFocusedElement; the viewport should not be scrolled by doing this + step.

    4. +
    +
  2. +
-

Modifications to the focus chain algorithm

+

Although dismissing a popover manually is a user-initiated gesture, the + [=focusing steps=] will be called with [=focus-unfenced|unfenced=] set to false regardless + of whether this was called from user gesture or via a script call.

+ + Modify the first bullet point of step 3 of the [=interactively validate the constraints=] algorithm to read: + +

The \`Supports-Loading-Mode\` HTTP response header

From 126aff20a230ce08fa4ba52f66458f21e174dd7d Mon Sep 17 00:00:00 2001 From: Liam Brady Date: Mon, 10 Apr 2023 12:37:44 -0400 Subject: [PATCH 03/10] add rest of focus algorithms --- spec.bs | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 3 deletions(-) diff --git a/spec.bs b/spec.bs index bb532d6a..9eeafc36 100644 --- a/spec.bs +++ b/spec.bs @@ -82,6 +82,12 @@ spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/ text: click focusable; url: click-focusable text: focusable area; url: focusable-area text: sequential focus navigation; url: sequential-focus-navigation + text: focus; url: dom-window-focus + text: focus chain; url: focus-chain + text: DOM anchor; url: dom-anchor + text: get the focusable area; url: get-the-focusable-area + text: currently focused area of a top-level traversable; url: currently-focused-area-of-a-top-level-traversable + text: focused area; url: focused-area-of-the-document urlPefix: infrastructure.html text: immediately; url: immediately urlPrefix: nav-history-apis.html @@ -666,18 +672,49 @@ traversables section. 1. Return |navigables|. -

Modifications to the focusing steps algorithm

+

Modifications to the focusing algorithms

+ + The [[HTML]] standard defines how to handle focusing elements, both by user gesture + and through script-based focus calls. Since fenced frames are designed to prevent + communication across a fenced frame boundary, we need to handle focusing carefully. + This is because, if focus is pulled across a fenced frame boundary, contexts on both + sides of the boundary can detect that change, which can be used to open a communication + channel between a fenced frame and its embedder. + + The way we do this is by not allowing [=focusing steps=] to move focus across a fenced frame boundary if the focus + call is script-initiated. + +

When a user clicks on an element like a text area, + because this is a user-initiated action, [=focusing steps=] will be called and will allow + focus to move across a fenced frame boundary. Without allowing that, an element inside of a fenced + frame would never be able to get focus if the user clicks on it.

+ +

If an element is focused using the [=focus=] method, an embedder + and its child fenced frame can use a sequence of focus calls and checking the focused element to send + arbitrary binary data across the fenced frame boundary. It is necessary for this to not be + allowed to happen. Therefore, in this case, we sacrifice some functionality for privacy.

+ +

Changes to the [=focusing steps=] algorithm

Modify the [=focusing steps=] algorithm to take a new optional [=boolean=] argument unfenced that defaults to false. - Add a new step after step 7 of the algorithm (that defines old chain and new chain) that reads: + Add a new step after step 3 of the algorithm (that changes new focus target) that reads: + + 4. If new focus target is a [=fenced navigable container=] with non-null + [=fenced navigable container/fenced navigable=], then set new focus target to the + [=fenced navigable container/fenced navigable=]'s [=navigable/active document=]. + + Add a new step after step 8 (step 7 in the existing version) of the algorithm + (that defines old chain and new chain) that reads: - 8. If [=focus-unfenced|unfenced=] is set to false, new chain + 9. If [=focus-unfenced|unfenced=] is set to false, new chain contains an [=element=] ele whose [=node navigable=]'s [=traversable navigable=] is a [=fenced navigable container/fenced navigable=], and old chain does not also contain ele, then return. +

Changes to the callers of the [=focusing steps=] algorithm

+ Modify the user agent sentence after the algorithm steps to read:

User agents must [=immediately=] run the [=focusing steps=] for a @@ -737,6 +774,51 @@ traversables section. +

Changes to the [=focus chain=] algorithm

+ + Modify step 3 of the while loop in the [=focus chain=] algorithm to read: +
    +
  1. +

    If currentObject is a [=focusable area=], then set + currentObject to currentObject's [=DOM anchor=]'s + [=Node/node document=].

    + +

    Otherwise, if currentObject is a Document whose + [=node navigable=]'s [=navigable/parent=] is non-null, then set + currentObject to currentObject's [=node navigable=]'s [=navigable/parent=].

    + +

    Otherwise, if currentObject is a Document whose + [=node navigable=]'s [=traversable navigable/unfenced parent=] is non-null, then set + currentObject to currentObject's [=node navigable=]'s [=traversable navigable/unfenced parent=].

    + +

    Otherwise, break.

    +
  2. +
+ +

Changes to the [=get the focusable area=] algorithm

+ + Add a new case to the switch statement: + +
+
If focus target is a [=fenced navigable container=] with a non-null + [=fenced navigable container/fenced navigable=]
+ +

Return the [=fenced navigable container=]'s [=fenced navigable container/fenced navigable=]'s + [=navigable/active document=].

+
+ +

Changes to the [=currently focused area of a top-level traversable=] algorithm

+ + Modify step 3 of the [=currently focused area of a top-level traversable=] algorithm to read: + +
    +
  1. While candidate's [=focused area=] is either a [=navigable container=] with a non-null [=navigable container/content navigable=] + or a [=fenced navigable container=] with a non-null [=fenced navigable container/fenced navigable=]: + set candidate to the [=navigable/active document=] of either that + [=navigable container=]'s [=navigable container/content navigable=] or + that [=fenced navigable container=]'s [=fenced navigable container/fenced navigable=], whichever is non-null.

  2. +
+

The \`Supports-Loading-Mode\` HTTP response header

Add the new [=structured header/token=] below to the list of valid [=structured header/tokens=] for the \` Date: Mon, 10 Apr 2023 12:50:35 -0400 Subject: [PATCH 04/10] fix build --- spec.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec.bs b/spec.bs index 9eeafc36..b0e96454 100644 --- a/spec.bs +++ b/spec.bs @@ -709,9 +709,9 @@ traversables section. (that defines old chain and new chain) that reads: 9. If [=focus-unfenced|unfenced=] is set to false, new chain - contains an [=element=] ele whose [=node navigable=]'s + contains an element |element| whose [=node navigable=]'s [=traversable navigable=] is a [=fenced navigable container/fenced navigable=], - and old chain does not also contain ele, then return. + and old chain does not also contain |element|, then return.

Changes to the callers of the [=focusing steps=] algorithm

From a06b7921f7a9569cd1b528fe4bd80df2dfa2f4cb Mon Sep 17 00:00:00 2001 From: Dominic Farolino Date: Mon, 10 Apr 2023 23:52:35 -0400 Subject: [PATCH 05/10] start work add rest of cases in audit add rest of focus algorithms fix build Some format nits --- spec.bs | 195 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 192 insertions(+), 3 deletions(-) diff --git a/spec.bs b/spec.bs index 10b00aeb..bad0d65c 100644 --- a/spec.bs +++ b/spec.bs @@ -30,6 +30,9 @@ spec: prerendering-revamped; urlPrefix: https://wicg.github.io/nav-speculation/p for: navigable text: loading mode; url: #navigable-loading-mode +spec: fetch; urlPrefix: https://fetch.spec.whatwg.org/ + type: dfn + text: queue a cross-origin embedder policy CORP violation report; url: queue-a-cross-origin-embedder-policy-corp-violation-report spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/ type: dfn urlPrefix: browsers.html @@ -86,12 +89,35 @@ spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/ urlPrefix: interaction.html text: activation notification; url: activation-notification text: consume user activation; url: consume-user-activation + text: activation; url: activation + text: click focusable; url: click-focusable + text: focusable area; url: focusable-area + text: sequential focus navigation; url: sequential-focus-navigation + text: focus; url: dom-window-focus + text: focus chain; url: focus-chain + text: focus update steps; url: focus-update-steps + text: focused; url: focused + text: gain focus; url: gains-focus + text: DOM anchor; url: dom-anchor + text: get the focusable area; url: get-the-focusable-area + text: currently focused area of a top-level traversable; url: currently-focused-area-of-a-top-level-traversable + text: focused area; url: focused-area-of-the-document + urlPefix: infrastructure.html + text: immediately; url: immediately urlPrefix: nav-history-apis.html for: Window text: navigable; url: window-navigable -spec: fetch; urlPrefix: https://fetch.spec.whatwg.org/ - type: dfn - text: queue a cross-origin embedder policy CORP violation report; url: queue-a-cross-origin-embedder-policy-corp-violation-report + urlPrefix: interactive-elements.html + text: accesskey attribute command; url: using-the-accesskey-attribute-to-define-a-command-on-other-elements + text: previously focused element; url: previously-focused-element + urlPrefix: popover.html + text: hide popover algorithm; url: hide-popover-algorithm + urlPrefix: form-control-infrastructure.html + text: interactively validate the constraints; url: interactively-validate-the-constraints + urlPrefix: custom-elements.html + text: face validation anchor; url: face-validation-anchor + urlPrefix: webappapis.html + text: fire a click event; url: fire-a-click-event spec: RFC8941; urlPrefix: https://www.rfc-editor.org/rfc/rfc8941.html type: dfn text: structured header; url: #section-1 @@ -759,6 +785,169 @@ in the [[#nested-traversables-intro]]. 1. Return |navigables|. +

Modifications to the focusing algorithms

+ +*This section is non-normative*. + +The [[HTML]] standard defines how to handle focusing elements and {{Window}}s, both by user gesture +and through script-initiated APIs. Since fenced frames are designed to prevent communication across +a fenced frame boundary, we need to handle focusing carefully. This is because when focus is pulled +across a fenced frame boundary, contexts on both sides of the boundary can detect that change, which +can be used to open a communication channel between a <{fencedframe}> and its embedder. + +We do this is by not allowing the [=focusing steps=] to move script-initiated focus across a fenced +frame boundary. + +

When a user clicks on an element like a <{button}> inside a +<{fencedframe}> while another element *outside* of the <{fencedframe}> is [=focused=], because this +is a user-initiated action, the [=focusing steps=] will allow the <{button}> to [=gain focus=]. +Without allowing that, no element inside of a <{fencedframe}> would never be able [=gain +focus=].

+ +

If we were to continue blindly allowing all elements to +be [=focused=] via the {{HTMLOrSVGElement/focus()}} method as is the status quo before this +specification, a [=fenced navigable container=] and its [=fenced navigable container/fenced +navigable=] could use a sequence of {{HTMLOrSVGElement/focus()}} calls to send arbitrary data across +the fenced frame boundary, which is a privacy leak. To avoid this, we effectively "fence" the +{{HTMLOrSVGElement/focus()}} method, which sacrifices some functionality for privacy.

+ +

Changes to the [=focusing steps=] algorithm

+ +
+ Modify the [=focusing steps=] to take a new optional [=boolean=] argument unfenced that defaults to false. + + Add a new step after step 3 of the algorithm (that changes new focus target) that reads: + + 4. If |new focus target| is a [=fenced navigable container=] with non-null + [=fenced navigable container/fenced navigable=], then set new focus target to the + [=fenced navigable container/fenced navigable=]'s [=navigable/active document=]. + + Add a new step after step 8 (step 7 in the existing version) of the algorithm (that defines |old + chain| and |new chain|) that reads: + + 9. If [=focus-unfenced|unfenced=] is false, |new chain| [=list/contains=] an element |element| + whose [=node navigable=]'s [=navigable/traversable navigable=] is a [=fenced navigable + container/fenced navigable=], and |old chain| does not also [=list/contain=] |element|, then + return. + + Note: This is how we bail-out early just before calling the [=focus update steps=], in the case + where focus is trying to cross the fence. +
+ +

Changes to the callers of the [=focusing steps=] algorithm

+ +Modify the user agent sentence after the algorithm steps to read: + +User agents must [=immediately=] run the [=focusing steps=] for a [=focusable area=] or +[=navigable=] |candidate| with [=focus-unfenced|unfenced=] set to true whenever the user attempts to +move the focus to |candidate|. + +
+ Modify the action of the [=accesskey attribute command=] algorithm to be: + + 1. Run the [=focusing steps=] for the element with [=focus-unfenced|unfenced=] set to true. + + 1. Fire a `click` event at the element. +
+ +
+ Modify the behavior when a user [=activation|activates=] a [=click focusable=] [=focusable area=] + to be: + + When a user [=activation|activates=] a [=click focusable=] [=focusable area=], the user agent must + run the [=focusing steps=] on the [=focusable area=] with focus trigger set + to "`click`" and [=focus-unfenced|unfenced=] set to true. +
+ +
+ Modify step 6 of the [=sequential focus navigation=] algorithm to be: + + 6. If candidate is not null, then run the [=focusing steps=] for + candidate with [=focus-unfenced|unfenced=] set to true and return. +
+ +
+ Modify step 10 of the [=hide popover algorithm=] to read: + +
    +
  1. +

    If previouslyFocusedElement is not null, then:

    + +
      +
    1. Set element's [=previously focused element=] to null.

    2. + +
    3. If focusPreviousElement is true, then run the [=focusing steps=] for + previouslyFocusedElement; the viewport should not be scrolled by doing this + step.

    4. +
    +
  2. +
+ +

Although dismissing a popover manually is a user-initiated gesture, the + [=focusing steps=] will be called with [=focus-unfenced|unfenced=] set to false regardless + of whether this was called from user gesture or via a script call.

+
+ +
+ Modify the first bullet point of step 3 of the [=interactively validate the constraints=] algorithm to read: + +
    +
  • +

    User agents may focus one of those elements in the process, by running the + [=focusing steps=] for that element, and may change the scrolling position of the + document, or perform some other action that brings the element to the user's attention. + If these steps were invoked by user gesture, [=focusing steps=] can be called with [=focus-unfenced|unfenced=] set to true. + For elements that are [=form-associated custom elements=], user agents + should use their [=face validation anchor=] instead, for the purposes of these actions.

    +
  • +
+
+ +

Changes to the [=focus chain=] algorithm

+ + Modify step 3 of the while loop in the [=focus chain=] algorithm to read: +
    +
  1. +

    If currentObject is a [=focusable area=], then set + currentObject to currentObject's [=DOM anchor=]'s + [=Node/node document=].

    + +

    Otherwise, if currentObject is a Document whose + [=node navigable=]'s [=navigable/parent=] is non-null, then set + currentObject to currentObject's [=node navigable=]'s [=navigable/parent=].

    + +

    Otherwise, if currentObject is a Document whose + [=node navigable=]'s [=traversable navigable/unfenced parent=] is non-null, then set + currentObject to currentObject's [=node navigable=]'s [=traversable navigable/unfenced parent=].

    + +

    Otherwise, break.

    +
  2. +
+ +

Changes to the [=get the focusable area=] algorithm

+ + Add a new case to the switch statement: + +
+
If focus target is a [=fenced navigable container=] with a non-null + [=fenced navigable container/fenced navigable=]
+ +

Return the [=fenced navigable container=]'s [=fenced navigable container/fenced navigable=]'s + [=navigable/active document=].

+
+ +

Changes to the [=currently focused area of a top-level traversable=] algorithm

+ + Modify step 3 of the [=currently focused area of a top-level traversable=] algorithm to read: + +
    +
  1. While candidate's [=focused area=] is either a [=navigable container=] with a non-null [=navigable container/content navigable=] + or a [=fenced navigable container=] with a non-null [=fenced navigable container/fenced navigable=]: + set candidate to the [=navigable/active document=] of either that + [=navigable container=]'s [=navigable container/content navigable=] or + that [=fenced navigable container=]'s [=fenced navigable container/fenced navigable=], whichever is non-null.

  2. +
From bb73af901193df1c585c91b4e8a9d1920f7bc3d6 Mon Sep 17 00:00:00 2001 From: Liam Brady Date: Tue, 11 Apr 2023 09:55:00 -0400 Subject: [PATCH 06/10] address review comments --- spec.bs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec.bs b/spec.bs index bad0d65c..2c71af00 100644 --- a/spec.bs +++ b/spec.bs @@ -826,9 +826,9 @@ the fenced frame boundary, which is a privacy leak. To avoid this, we effectivel Add a new step after step 8 (step 7 in the existing version) of the algorithm (that defines |old chain| and |new chain|) that reads: - 9. If [=focus-unfenced|unfenced=] is false, |new chain| [=list/contains=] an element |element| + 9. If [=focus-unfenced|unfenced=] is false, |new chain| [=list/contains=] a Document |document| whose [=node navigable=]'s [=navigable/traversable navigable=] is a [=fenced navigable - container/fenced navigable=], and |old chain| does not also [=list/contain=] |element|, then + container/fenced navigable=], and |old chain| does not also [=list/contain=] |document|, then return. Note: This is how we bail-out early just before calling the [=focus update steps=], in the case @@ -878,8 +878,8 @@ move the focus to |candidate|.
  • Set element's [=previously focused element=] to null.

  • If focusPreviousElement is true, then run the [=focusing steps=] for - previouslyFocusedElement; the viewport should not be scrolled by doing this - step.

  • + previouslyFocusedElement with [=focus-unfenced|unfenced=] set to true; the viewport + should not be scrolled by doing this step.

    From 2acc0037a222430034a98e0c595b5195d43248c5 Mon Sep 17 00:00:00 2001 From: Liam Brady Date: Tue, 11 Apr 2023 12:58:49 -0400 Subject: [PATCH 07/10] add patches for all focus-related entries in the audit --- spec.bs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/spec.bs b/spec.bs index 2c71af00..496e4174 100644 --- a/spec.bs +++ b/spec.bs @@ -102,6 +102,8 @@ spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/ text: get the focusable area; url: get-the-focusable-area text: currently focused area of a top-level traversable; url: currently-focused-area-of-a-top-level-traversable text: focused area; url: focused-area-of-the-document + text: sequential navigation search algorithm; url: sequential-navigation-search-algorithm + text: has focus steps; url: has-focus-steps urlPefix: infrastructure.html text: immediately; url: immediately urlPrefix: nav-history-apis.html @@ -860,13 +862,6 @@ move the focus to |candidate|. to "`click`" and [=focus-unfenced|unfenced=] set to true. -
    - Modify step 6 of the [=sequential focus navigation=] algorithm to be: - - 6. If candidate is not null, then run the [=focusing steps=] for - candidate with [=focus-unfenced|unfenced=] set to true and return. -
    -
    Modify step 10 of the [=hide popover algorithm=] to read: @@ -904,6 +899,17 @@ move the focus to |candidate|.
    +

    Changes to the [=has focus steps=] algorithm

    + + Add a step after step 2 of the while loop that reads: + +
      +
    1. If the [=focused area=] of + candidate is a [=fenced navigable container=] with a non-null [=fenced navigable container/fenced navigable=], + then set candidate to the [=navigable/active document=] of that + [=fenced navigable container=]'s [=fenced navigable container/fenced navigable=].

    2. +
    +

    Changes to the [=focus chain=] algorithm

    Modify step 3 of the while loop in the [=focus chain=] algorithm to read: @@ -949,6 +955,48 @@ move the focus to |candidate|. that [=fenced navigable container=]'s [=fenced navigable container/fenced navigable=], whichever is non-null.

    +

    Changes to sequential focusing

    + + Modify step 6 of the [=sequential focus navigation=] algorithm to read: + + 6. If candidate is not null, then run the [=focusing steps=] for + candidate with [=focus-unfenced|unfenced=] set to true and return. + + Modify step 9 of the [=sequential focus navigation=] algorithm to read: + +
      +
    1. Otherwise, starting point is a [=focusable area=] in a + [=child navigable=] or [=fenced navigable container/fenced navigable=]. + Set starting point to that + [=child navigable=] or [=fenced navigable container/fenced navigable=]'s + [=traversable navigable/unfenced parent=] and return to the step labeled loop.

    2. +
    + + Modify step 2 of the [=sequential navigation search algorithm=] to read: + +
      +
    1. +

      If candidate is a [=navigable container=] with a non-null [=navigable container/content navigable=], + then let new candidate be the result of running the + [=sequential navigation search algorithm=] with candidate's [=navigable container/content navigable=] + as the first argument, direction as the second, and + sequential as the third.

      + +

      If candidate is a [=fenced navigable container=] with a non-null [=fenced navigable container/fenced navigable=], + then let new candidate be the result of running the + [=sequential navigation search algorithm=] with candidate's [=fenced navigable container/fenced navigable=] + as the first argument, direction as the second, and + sequential as the third.

      + +

      If new candidate is null, then let starting point + be candidate, and return to the top of this algorithm. Otherwise, let + candidate be new candidate.

      +
    2. + +
    + This section describes how the <{fencedframe}> element interacts with the ever-complicated process From 17e4cb3463011cbe597d1a78bcecc907a3d6715d Mon Sep 17 00:00:00 2001 From: Liam Brady Date: Tue, 11 Apr 2023 13:33:07 -0400 Subject: [PATCH 08/10] address review comments --- spec.bs | 171 +++++++++++++++++++++++++------------------------------- 1 file changed, 75 insertions(+), 96 deletions(-) diff --git a/spec.bs b/spec.bs index 496e4174..0365fa7f 100644 --- a/spec.bs +++ b/spec.bs @@ -822,19 +822,19 @@ the fenced frame boundary, which is a privacy leak. To avoid this, we effectivel Add a new step after step 3 of the algorithm (that changes new focus target) that reads: 4. If |new focus target| is a [=fenced navigable container=] with non-null - [=fenced navigable container/fenced navigable=], then set new focus target to the - [=fenced navigable container/fenced navigable=]'s [=navigable/active document=]. + [=fenced navigable container/fenced navigable=], then set |new focus target| to the + [=fenced navigable container/fenced navigable=]'s [=navigable/active document=]. Add a new step after step 8 (step 7 in the existing version) of the algorithm (that defines |old chain| and |new chain|) that reads: - 9. If [=focus-unfenced|unfenced=] is false, |new chain| [=list/contains=] a Document |document| - whose [=node navigable=]'s [=navigable/traversable navigable=] is a [=fenced navigable - container/fenced navigable=], and |old chain| does not also [=list/contain=] |document|, then - return. + 9. If [=focus-unfenced|unfenced=] is false, |new chain| [=list/contains=] a Document + |document| whose [=node navigable=]'s [=navigable/traversable navigable=] is a + [=fenced navigable container/fenced navigable=], and |old chain| does not also [=list/contain=] + |document|, then return. - Note: This is how we bail-out early just before calling the [=focus update steps=], in the case - where focus is trying to cross the fence. + Note: This is how we bail-out early just before calling the [=focus update steps=], in the case + where focus is trying to cross the fence.

    Changes to the callers of the [=focusing steps=] algorithm

    @@ -858,144 +858,123 @@ move the focus to |candidate|. to be: When a user [=activation|activates=] a [=click focusable=] [=focusable area=], the user agent must - run the [=focusing steps=] on the [=focusable area=] with focus trigger set + run the [=focusing steps=] on the [=focusable area=] with focus trigger set to "`click`" and [=focus-unfenced|unfenced=] set to true.
    Modify step 10 of the [=hide popover algorithm=] to read: -
      -
    1. -

      If previouslyFocusedElement is not null, then:

      + 10. If |previouslyFocusedElement| is not null, then: + 1. Set element's [=previously focused element=] to null. + 2. If focusPreviousElement is true, then run the [=focusing steps=] for + |previouslyFocusedElement| with [=focus-unfenced|unfenced=] set to true; the viewport + should not be scrolled by doing this step. -
        -
      1. Set element's [=previously focused element=] to null.

      2. - -
      3. If focusPreviousElement is true, then run the [=focusing steps=] for - previouslyFocusedElement with [=focus-unfenced|unfenced=] set to true; the viewport - should not be scrolled by doing this step.

      4. -
      -
    2. -
    - -

    Although dismissing a popover manually is a user-initiated gesture, the + Note: Although dismissing a popover manually is a user-initiated gesture, the [=focusing steps=] will be called with [=focus-unfenced|unfenced=] set to false regardless - of whether this was called from user gesture or via a script call.

    + of whether this was called from user gesture or via a script call.
    - Modify the first bullet point of step 3 of the [=interactively validate the constraints=] algorithm to read: - -
      -
    • -

      User agents may focus one of those elements in the process, by running the - [=focusing steps=] for that element, and may change the scrolling position of the - document, or perform some other action that brings the element to the user's attention. - If these steps were invoked by user gesture, [=focusing steps=] can be called with [=focus-unfenced|unfenced=] set to true. - For elements that are [=form-associated custom elements=], user agents - should use their [=face validation anchor=] instead, for the purposes of these actions.

      -
    • -
    + Modify the first bullet point of step 3 of the [=interactively validate the constraints=] + algorithm to read: + + * User agents may focus one of those elements in the process, by running the + [=focusing steps=] for that element, and may change the scrolling position of the + document, or perform some other action that brings the element to the user's attention. + If these steps were invoked by user gesture, [=focusing steps=] can be called with + [=focus-unfenced|unfenced=] set to true. For elements that are + [=form-associated custom elements=], user agents should use their [=face validation anchor=] + instead, for the purposes of these actions.

    Changes to the [=has focus steps=] algorithm

    Add a step after step 2 of the while loop that reads: -
      -
    1. If the [=focused area=] of - candidate is a [=fenced navigable container=] with a non-null [=fenced navigable container/fenced navigable=], - then set candidate to the [=navigable/active document=] of that - [=fenced navigable container=]'s [=fenced navigable container/fenced navigable=].

    2. -
    + 3. If the [=focused area=] of + |candidate| is a [=fenced navigable container=] with a non-null + [=fenced navigable container/fenced navigable=], then set |candidate| to the + [=navigable/active document=] of that [=fenced navigable container=]'s + [=fenced navigable container/fenced navigable=].

    Changes to the [=focus chain=] algorithm

    Modify step 3 of the while loop in the [=focus chain=] algorithm to read: -
      -
    1. -

      If currentObject is a [=focusable area=], then set - currentObject to currentObject's [=DOM anchor=]'s - [=Node/node document=].

      + 3. If |currentObject| is a [=focusable area=], then set + |currentObject| to |currentObject|'s [=DOM anchor=]'s + [=Node/node document=]. -

      Otherwise, if currentObject is a Document whose - [=node navigable=]'s [=navigable/parent=] is non-null, then set - currentObject to currentObject's [=node navigable=]'s [=navigable/parent=].

      + Otherwise, if |currentObject| is a {{Document}} whose + [=node navigable=]'s [=navigable/parent=] is non-null, then set + |currentObject| to |currentObject|'s [=node navigable=]'s [=navigable/parent=]. -

      Otherwise, if currentObject is a Document whose - [=node navigable=]'s [=traversable navigable/unfenced parent=] is non-null, then set - currentObject to currentObject's [=node navigable=]'s [=traversable navigable/unfenced parent=].

      + Otherwise, if |currentObject| is a {{Document}} whose + [=node navigable=]'s [=traversable navigable/unfenced parent=] is non-null, then set + |currentObject| to |currentObject|'s [=node navigable=]'s + [=traversable navigable/unfenced parent=]. -

      Otherwise, break.

      -
    2. -
    + Otherwise, break.

    Changes to the [=get the focusable area=] algorithm

    Add a new case to the switch statement:
    -
    If focus target is a [=fenced navigable container=] with a non-null +
    If focus target is a [=fenced navigable container=] with a non-null [=fenced navigable container/fenced navigable=]
    -

    Return the [=fenced navigable container=]'s [=fenced navigable container/fenced navigable=]'s - [=navigable/active document=].

    +

    Return the [=fenced navigable container=]'s + [=fenced navigable container/fenced navigable=]'s [=navigable/active document=].

    Changes to the [=currently focused area of a top-level traversable=] algorithm

    Modify step 3 of the [=currently focused area of a top-level traversable=] algorithm to read: -
      -
    1. While candidate's [=focused area=] is either a [=navigable container=] with a non-null [=navigable container/content navigable=] - or a [=fenced navigable container=] with a non-null [=fenced navigable container/fenced navigable=]: - set candidate to the [=navigable/active document=] of either that - [=navigable container=]'s [=navigable container/content navigable=] or - that [=fenced navigable container=]'s [=fenced navigable container/fenced navigable=], whichever is non-null.

    2. -
    + 3. While |candidate|'s [=focused area=] is either a [=navigable container=] with a non-null + [=navigable container/content navigable=] or a [=fenced navigable container=] with a non-null + [=fenced navigable container/fenced navigable=]: set |candidate| to the + [=navigable/active document=] of either that [=navigable container=]'s + [=navigable container/content navigable=] or that [=fenced navigable container=]'s + [=fenced navigable container/fenced navigable=], whichever is non-null.

    Changes to sequential focusing

    +
    Modify step 6 of the [=sequential focus navigation=] algorithm to read: - 6. If candidate is not null, then run the [=focusing steps=] for - candidate with [=focus-unfenced|unfenced=] set to true and return. + 6. If |candidate| is not null, then run the [=focusing steps=] for + |candidate| with [=focus-unfenced|unfenced=] set to true and return. Modify step 9 of the [=sequential focus navigation=] algorithm to read: -
      -
    1. Otherwise, starting point is a [=focusable area=] in a - [=child navigable=] or [=fenced navigable container/fenced navigable=]. - Set starting point to that + 9. Otherwise, |starting point| is a [=focusable area=] in a [=child navigable=] or + [=fenced navigable container/fenced navigable=]. Set |starting point| to that [=child navigable=] or [=fenced navigable container/fenced navigable=]'s - [=traversable navigable/unfenced parent=] and return to the step labeled loop.

    2. -
    + [=traversable navigable/unfenced parent=] and return to the step labeled loop. +
    +
    Modify step 2 of the [=sequential navigation search algorithm=] to read: -
      -
    1. -

      If candidate is a [=navigable container=] with a non-null [=navigable container/content navigable=], - then let new candidate be the result of running the - [=sequential navigation search algorithm=] with candidate's [=navigable container/content navigable=] - as the first argument, direction as the second, and - sequential as the third.

      - -

      If candidate is a [=fenced navigable container=] with a non-null [=fenced navigable container/fenced navigable=], - then let new candidate be the result of running the - [=sequential navigation search algorithm=] with candidate's [=fenced navigable container/fenced navigable=] - as the first argument, direction as the second, and - sequential as the third.

      - -

      If new candidate is null, then let starting point - be candidate, and return to the top of this algorithm. Otherwise, let - candidate be new candidate.

      -
    2. - -
    + 2. If |candidate| is a [=navigable container=] with a non-null + [=navigable container/content navigable=], then let |new candidate| be the result of running the + [=sequential navigation search algorithm=] with |candidate|'s + [=navigable container/content navigable=] as the first argument, direction as + the second, and sequential as the third. + + If |candidate| is a [=fenced navigable container=] with a non-null + [=fenced navigable container/fenced navigable=], then let |new candidate| be the result of + running the [=sequential navigation search algorithm=] with |candidate|'s + [=fenced navigable container/fenced navigable=] as the first argument, + direction as the second, and sequential as the third. + + If |new candidate| is null, then let starting point + be |candidate|, and return to the top of this algorithm. Otherwise, let + |candidate| be |new candidate|. +
    From fbb1d4c45f8e8268b4239de06278b91a7d43e813 Mon Sep 17 00:00:00 2001 From: Liam Brady Date: Fri, 14 Apr 2023 11:31:11 -0400 Subject: [PATCH 09/10] replace h4 tags with algorithm divs --- spec.bs | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/spec.bs b/spec.bs index 0365fa7f..71956e71 100644 --- a/spec.bs +++ b/spec.bs @@ -813,8 +813,6 @@ navigable=] could use a sequence of {{HTMLOrSVGElement/focus()}} calls to send a the fenced frame boundary, which is a privacy leak. To avoid this, we effectively "fence" the {{HTMLOrSVGElement/focus()}} method, which sacrifices some functionality for privacy.

    -

    Changes to the [=focusing steps=] algorithm

    -
    Modify the [=focusing steps=] to take a new optional [=boolean=] argument unfenced that defaults to false. @@ -835,15 +833,13 @@ the fenced frame boundary, which is a privacy leak. To avoid this, we effectivel Note: This is how we bail-out early just before calling the [=focus update steps=], in the case where focus is trying to cross the fence. -
    -

    Changes to the callers of the [=focusing steps=] algorithm

    + Modify the user agent sentence after the algorithm steps in [=focusing steps=] to read: -Modify the user agent sentence after the algorithm steps to read: - -User agents must [=immediately=] run the [=focusing steps=] for a [=focusable area=] or -[=navigable=] |candidate| with [=focus-unfenced|unfenced=] set to true whenever the user attempts to -move the focus to |candidate|. + User agents must [=immediately=] run the [=focusing steps=] for a [=focusable area=] or + [=navigable=] |candidate| with [=focus-unfenced|unfenced=] set to true whenever the user attempts to + move the focus to |candidate|. +
    Modify the action of the [=accesskey attribute command=] algorithm to be: @@ -889,18 +885,17 @@ move the focus to |candidate|. instead, for the purposes of these actions.
    -

    Changes to the [=has focus steps=] algorithm

    - - Add a step after step 2 of the while loop that reads: +
    + Add a step after step 2 of the while loop in the [=has focus steps=] algorithm that reads: 3. If the [=focused area=] of |candidate| is a [=fenced navigable container=] with a non-null [=fenced navigable container/fenced navigable=], then set |candidate| to the [=navigable/active document=] of that [=fenced navigable container=]'s [=fenced navigable container/fenced navigable=]. +
    -

    Changes to the [=focus chain=] algorithm

    - +
    Modify step 3 of the while loop in the [=focus chain=] algorithm to read: 3. If |currentObject| is a [=focusable area=], then set |currentObject| to |currentObject|'s [=DOM anchor=]'s @@ -916,10 +911,10 @@ move the focus to |candidate|. [=traversable navigable/unfenced parent=]. Otherwise, break. - -

    Changes to the [=get the focusable area=] algorithm

    - - Add a new case to the switch statement: +
    + +
    + Modify the [=get the focusable area=] algorithm. Add a new case to the switch statement:
    If focus target is a [=fenced navigable container=] with a non-null @@ -928,9 +923,9 @@ move the focus to |candidate|.

    Return the [=fenced navigable container=]'s [=fenced navigable container/fenced navigable=]'s [=navigable/active document=].

    +
    -

    Changes to the [=currently focused area of a top-level traversable=] algorithm

    - +
    Modify step 3 of the [=currently focused area of a top-level traversable=] algorithm to read: 3. While |candidate|'s [=focused area=] is either a [=navigable container=] with a non-null @@ -939,8 +934,7 @@ move the focus to |candidate|. [=navigable/active document=] of either that [=navigable container=]'s [=navigable container/content navigable=] or that [=fenced navigable container=]'s [=fenced navigable container/fenced navigable=], whichever is non-null. - -

    Changes to sequential focusing

    +
    Modify step 6 of the [=sequential focus navigation=] algorithm to read: From 2e331e62c073452f4ed3ffa755a2595ca7aa9396 Mon Sep 17 00:00:00 2001 From: Dominic Farolino Date: Mon, 17 Apr 2023 14:08:42 +0200 Subject: [PATCH 10/10] Small clean-ups --- spec.bs | 52 ++++++++++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/spec.bs b/spec.bs index 71956e71..b7f4ebe4 100644 --- a/spec.bs +++ b/spec.bs @@ -103,7 +103,6 @@ spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/ text: currently focused area of a top-level traversable; url: currently-focused-area-of-a-top-level-traversable text: focused area; url: focused-area-of-the-document text: sequential navigation search algorithm; url: sequential-navigation-search-algorithm - text: has focus steps; url: has-focus-steps urlPefix: infrastructure.html text: immediately; url: immediately urlPrefix: nav-history-apis.html @@ -789,8 +788,6 @@ in the [[#nested-traversables-intro]].

    Modifications to the focusing algorithms

    -*This section is non-normative*. - The [[HTML]] standard defines how to handle focusing elements and {{Window}}s, both by user gesture and through script-initiated APIs. Since fenced frames are designed to prevent communication across a fenced frame boundary, we need to handle focusing carefully. This is because when focus is pulled @@ -823,13 +820,12 @@ the fenced frame boundary, which is a privacy leak. To avoid this, we effectivel [=fenced navigable container/fenced navigable=], then set |new focus target| to the [=fenced navigable container/fenced navigable=]'s [=navigable/active document=]. - Add a new step after step 8 (step 7 in the existing version) of the algorithm (that defines |old - chain| and |new chain|) that reads: + Add a new step after the step that defines the |new chain| variable, that reads: - 9. If [=focus-unfenced|unfenced=] is false, |new chain| [=list/contains=] a Document + 9. If [=focus-unfenced|unfenced=] is false, |new chain| [=list/contains=] a {{Document}} |document| whose [=node navigable=]'s [=navigable/traversable navigable=] is a - [=fenced navigable container/fenced navigable=], and |old chain| does not also [=list/contain=] - |document|, then return. + [=fenced navigable container/fenced navigable=], and old chain does not also + [=list/contain=] |document|, then return. Note: This is how we bail-out early just before calling the [=focus update steps=], in the case where focus is trying to cross the fence. @@ -888,41 +884,41 @@ the fenced frame boundary, which is a privacy leak. To avoid this, we effectivel
    Add a step after step 2 of the while loop in the [=has focus steps=] algorithm that reads: - 3. If the [=focused area=] of - |candidate| is a [=fenced navigable container=] with a non-null - [=fenced navigable container/fenced navigable=], then set |candidate| to the - [=navigable/active document=] of that [=fenced navigable container=]'s - [=fenced navigable container/fenced navigable=]. + 3. If the [=focused area=] of |candidate| is a [=fenced navigable container=] with a non-null + [=fenced navigable container/fenced navigable=], then set |candidate| to the [=navigable/active + document=] of that [=fenced navigable container=]'s [=fenced navigable container/fenced + navigable=].
    Modify step 3 of the while loop in the [=focus chain=] algorithm to read: - 3. If |currentObject| is a [=focusable area=], then set - |currentObject| to |currentObject|'s [=DOM anchor=]'s - [=Node/node document=]. + 3. If |currentObject| is a [=focusable area=], then set |currentObject| to |currentObject|'s [=DOM + anchor=]'s [=Node/node document=]. - Otherwise, if |currentObject| is a {{Document}} whose - [=node navigable=]'s [=navigable/parent=] is non-null, then set - |currentObject| to |currentObject|'s [=node navigable=]'s [=navigable/parent=]. + Otherwise, if |currentObject| is a {{Document}} whose [=node navigable=]'s [=navigable/parent=] + is non-null, then set |currentObject| to |currentObject|'s [=node navigable=]'s + [=navigable/parent=]. - Otherwise, if |currentObject| is a {{Document}} whose - [=node navigable=]'s [=traversable navigable/unfenced parent=] is non-null, then set - |currentObject| to |currentObject|'s [=node navigable=]'s - [=traversable navigable/unfenced parent=]. + Otherwise, if |currentObject| is a {{Document}} whose [=node navigable=] is a [=traversable + navigable=] whose [=traversable navigable/unfenced parent=] is non-null, then set + |currentObject| to |currentObject|'s [=node navigable=]'s [=traversable navigable/unfenced + parent=]. - Otherwise, break. + Otherwise, [=iteration/break=].
    Modify the [=get the focusable area=] algorithm. Add a new case to the switch statement:
    -
    If focus target is a [=fenced navigable container=] with a non-null - [=fenced navigable container/fenced navigable=]
    +
    If focus target is a [=fenced navigable container=] with a non-null [=fenced navigable container/fenced navigable=]
    -

    Return the [=fenced navigable container=]'s - [=fenced navigable container/fenced navigable=]'s [=navigable/active document=].

    +

    Return the [=fenced navigable container=]'s [=fenced navigable container/fenced + navigable=]'s [=navigable/active document=].

    + + Note: This algorithm can unconditionally "jump the fence" boundary because its return value always + feeds into an algorithm that _does_ carefully consider the fence boundary.