Skip to content

[css-view-transitions-2] Editorial: refactor L2 concerns out of L1 #9892

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

Merged
merged 13 commits into from
Feb 13, 2024

Conversation

noamr
Copy link
Collaborator

@noamr noamr commented Feb 2, 2024

  • L2 redefines appropriate algorithms and additional fields instead of relying on L1
  • moved onReady to correct place, and renamed proceedWithNavigation.

See #9886, based on this resolution.

@noamr noamr requested a review from khushalsagar February 2, 2024 12:20
@noamr noamr changed the title [css-view-transitions-2] Move onReady to the correct place and rename [css-view-transitions-2] Editorial: refactor L2 concerns out of L1 Feb 6, 2024
@@ -1955,6 +1937,7 @@ Changes from <a href="https://www.w3.org/TR/2023/WD-css-view-transitions-1-20230
* Add note to explain paint order for entry animations. See <a href="https://github.com/w3c/csswg-drafts/issues/9672">issue 9672</a>.
* Add note to explain how the named elements are cleaned up. See <a href="https://github.com/w3c/csswg-drafts/issues/9669">issue 9669</a>.
* Refactor algorithm to clarify timing, especially of `updateCallbackDone. See <a href="https://github.com/w3c/csswg-drafts/issues/9762">issue 9762</a>.
* Remove references to cross-document view-transitions, to keep the L1 spec clean.
Copy link
Member

Choose a reason for hiding this comment

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

nit: Add a link to the relevant issue.


Issue: should we check for the opt-in again, in case there was a CSSOM change in a requestAnimationFrame callback?
1. Run the following steps when [=Perform pending transition operations|performing pending transition operations=]:
Copy link
Member

Choose a reason for hiding this comment

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

Hmmm, I actually liked your approach of stashing the proceedWithNavigation callback on the VT object. Because we also need to invoke it when the transition is skipped by script before the next frame could've run. In that case "perform pending transition operations" will never happen.

How about setting this as follows:

I'm reviewing the rest of the algorithm assuming |outboundTransition| is the document's active view transition referenced here.

Copy link
Member

Choose a reason for hiding this comment

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

Since we're dealing with task sources in this spec, good to document in the "setup-cross-doc-view-transition-on-old-doc" algo that it runs on the rendering task source.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's not though... it's running on the navigation and traversal task source.
Ack regarding calling the callback when skipped.


Note: The ViewTransition object on the old Document should be destroyed after its state has been copied to the new Document below.
We explicitly clear it here since the old Document may be cached by the UA.
1. [=Capture the old state=] for |outboundTransition|.
Copy link
Member

Choose a reason for hiding this comment

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

We need to handle the fact that capture is async, see note here.

I think that means setting the rendering suppression bit to true here and unsetting both rendering suppression + auto-skip VT in the task queued below?

Copy link
Member

Choose a reason for hiding this comment

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

Reminder for this. We need to set rendering suppression for view transitions to true here if capture old state succeeds and post a task to run the success steps which also reset this bit. This is to allow async capture.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Why is that needed? We don't render any more frames on the old page, so supposedly nothing to suppress.


1. Set |oldDocument|'s [=auto-skip view transitions=] to false.
1. If failure is returned, call |proceedWithNavigation| and return.
Copy link
Member

Choose a reason for hiding this comment

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

Simpler to call skip the VT here? Assuming you update the skip algorithm for the case I mentioned above.


1. Set |oldDocument|'s [=auto-skip view transitions=] to false.
1. If failure is returned, call |proceedWithNavigation| and return.
Copy link
Member

Choose a reason for hiding this comment

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

"proceedWithNavigation" will be invoked from the rendering task source if done from "perform pending transition operations". And whatever task source script runs in if done via viewTransition.skipTransition().

Also, in the case where we don't even set up an outbound transition, "proceedWithNavigation" is invoked synchronously at the html call-site. So now it will run on whatever source "setup cross-document view-transition" is called from.

It seems odd if the navigation steps are running on different task sources in the 3 cases. Can you document the API contract on where navigation steps should be run, based on what happens in the non-VT case. And ensure we consistently use the same task source for the VT case?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is handled in the HTML spec. The callback that's passed here queues steps on the traversal queue (browser process), so it doesn't matter who calls it.

@noamr
Copy link
Collaborator Author

noamr commented Feb 8, 2024

@khushalsagar I've moved things around a bit, take a look, I think it addresses your concerns.


1. Let |viewTransition| be the result of running [=method steps=] for {{Document/startViewTransition(updateCallback)}} given |callbackOptions|'s {{StartViewTransitionOptions/update}}.
1. Let |transition| be a new {{ViewTransition}} in |this|'s [=relevant realm=].
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand. We created transition, settled all its promises but then didn't do anything with it? I'm guessing you missed a return at the end. But even so, this misses dispatching the update callback.

My preference would be to set the update callback on |transition| and then invoke the skip algorithm, instead of duplicating the promise handling logic here. The only thing that needs to change in the skip algorithm for this case is to make this step conditional: "If document’s active view transition is transition, set rendering suppression for view transitions to false".


1. Return |viewTransition|.
</div>

A {{Document}} additionaly has:
Copy link
Member

Choose a reason for hiding this comment

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

nit: Move this to the "Data Structures" block below, similar to the L1 spec.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done


1. If |outboundTransition|'s [=ViewTransition/phase=] is "`done`", then call |onReady| and return.
1. Run the following steps when [=Perform pending transition operations|performing pending transition operations=]:

1. Assert: |outboundTransition|'s [=ViewTransition/phase=] is "`pending-capture`".
Copy link
Member

Choose a reason for hiding this comment

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

Use the document's active view transition here instead of binding these steps to |outboundTransition|.

The assert only makes sense if it's the document's active view transition. If the author skips |outboundTransition| in script before the next frame, then it will also be cleared as the active view transition.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done


1. If |outboundTransition|'s [=ViewTransition/phase=] is "`done`", then call |onReady| and return.
1. Run the following steps when [=Perform pending transition operations|performing pending transition operations=]:
Copy link
Member

Choose a reason for hiding this comment

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

Please move this to a separate "Additions to perform pending transition operations" section. Makes it much easier to see the diff where we're adding to existing algorithms in L2. And also when we eventually merge.

The text can say something like:

Prepend this to the perform pending transitions algorithm:
If document’s active view transition is not null and its is outbound cross-doc is true, then:
...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done


Note: The ViewTransition object on the old Document should be destroyed after its state has been copied to the new Document below.
We explicitly clear it here since the old Document may be cached by the UA.
1. [=Capture the old state=] for |outboundTransition|.
Copy link
Member

Choose a reason for hiding this comment

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

Reminder for this. We need to set rendering suppression for view transitions to true here if capture old state succeeds and post a task to run the success steps which also reset this bit. This is to allow async capture.


1. Let |initialSnapshotContainingBlockSize| to |outboundTransition|'s [=ViewTransition/initial snapshot containing block size=].

1. Set |newDocument|'s [=inbound view transition steps=] to the following steps:
Copy link
Member

Choose a reason for hiding this comment

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

I actually find it cleaner to stash initialSnapshotContainingBlockSize and clonedNamedElements on the Document and inline these steps into "resolve cross-document view-transition", where they run. Instead of binding them to a callback and then stashing that on the new Document.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done


1. If |callbackOptions| is an {{UpdateCallback}}, then run the [=method steps=] for {{Document/startViewTransition(updateCallback)}} given |callbackOptions| and return the result.
1. Let |preSkippedTransition| be a new {{ViewTransition}} in |this|'s [=relevant realm=].
Copy link
Member

Choose a reason for hiding this comment

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

We need to set up the update callback on |preSkippedTransition| before calling skip below, otherwise the update callback will never run.


1. Let |viewTransition| be the result of running [=method steps=] for {{Document/startViewTransition(updateCallback)}} given |callbackOptions|'s {{StartViewTransitionOptions/update}}.
1. [=Skip the view transition|Skip=] |preSkippedTransition| with an "{{InvalidStateError}}" {{DOMException}}.
Copy link
Member

Choose a reason for hiding this comment

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

Step 4 in "Skip the view transition" algorithm in L1 needs to be updated to: "If document’s active view transition is transition, Set rendering suppression for view transitions to false."

Otherwise this will resume rendering while the outbound transition is being captured.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I still don't understand why we need rendering suppression. Is that for that unspecified async capture?


: <dfn>active types</dfn>
:: Null or a [=list=] of strings, initially null.
</dl>

### [=Captured elements=] ### {#captured-elements}
Copy link
Member

Choose a reason for hiding this comment

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

Did you mean to add anything here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Oops


Note: |outboundTransition| is not exposed to JavaScript, it is used only for capturing
the state of the old document.
1. Call |proceedWithNavigation|.
Copy link
Member

Choose a reason for hiding this comment

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

nit: Update the note below, "The process continues in [=perform pending transition operations=]."

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done

transition was started before the {{Window/pagereveal}} event was fired.
Note: this means that starting a same-document transition before revealing the document would cancel a pending cross-document transition.

1. Let |transition| be a new {{ViewTransition}} in |document|'s [=relevant Realm=],
Copy link
Member

Choose a reason for hiding this comment

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

nit: Should we move this after resolving the rule below? Other |transition| is unused.

Note: The ViewTransition object on the old Document should be destroyed after its state has been copied to the new Document below.
We explicitly clear it here since the old Document may be cached by the UA.

1. Call |transition|'s [=outbound post-capture steps=] given |viewTransitionParams|.
Copy link
Member

Choose a reason for hiding this comment

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

This needs to be done in a posted task because "Capture the old state" can be async. So we set "rendering suppression" to true, post a task which resets that bit and then invoke [=outbound post-capture steps=]. In that task, also check in case the phase for the transition is done (skip might have been called).

The L1 spec does the same in the task posted here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The L1 spec in this case is a bit dodgy... posting a task doesn't guarantee anything wrt that async capture. We need to think about this further.


1. Set |oldDocument|'s [=active view transition=] to |outboundTransition|.
1. React to |outboundTransition|'s [=ViewTransition/finished promise=]:
Copy link
Member

Choose a reason for hiding this comment

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

I really don't like this. We're just making our spec unnecessarily complicated by relying on promises for browser steps. I also suggested adding an "addition to skip steps" style of update for this because that's what we'll do when the specs are eventually merged.

@noamr noamr merged commit 6b3259f into w3c:main Feb 13, 2024
@noamr noamr deleted the vt2-edits-2 branch February 13, 2024 19:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants