Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 445ef5ac4f91f6af821e2211bb4f507d7c66a390
      
https://github.com/WebKit/WebKit/commit/445ef5ac4f91f6af821e2211bb4f507d7c66a390
  Author: Yoel Hawa <[email protected]>
  Date:   2026-08-08 (Sat, 08 Aug 2026)

  Changed paths:
    M LayoutTests/spatial-css/resources/spatial-portal-utils.js
    A LayoutTests/spatial-css/spatial-portal-animation-currenttime-expected.txt
    A LayoutTests/spatial-css/spatial-portal-animation-currenttime.html
    A LayoutTests/spatial-css/spatial-portal-animation-dynamic-expected.txt
    A LayoutTests/spatial-css/spatial-portal-animation-dynamic.html
    A LayoutTests/spatial-css/spatial-portal-animation-independent-expected.txt
    A LayoutTests/spatial-css/spatial-portal-animation-independent.html
    A LayoutTests/spatial-css/spatial-portal-model-animations-expected.txt
    A LayoutTests/spatial-css/spatial-portal-model-animations.html
    M Source/WebCore/Modules/model-element/HTMLModelElement.cpp
    M Source/WebCore/Modules/model-element/HTMLModelElement.h
    M Source/WebCore/Modules/model-element/SpatialPortalController.cpp
    M Source/WebKit/ModelProcess/cocoa/ModelProcessModelPlayerProxy.h
    M Source/WebKit/ModelProcess/cocoa/ModelProcessModelPlayerProxy.mm
    M Source/WebKit/WebProcess/Model/ModelProcessModelPlayer.cpp
    M Source/WebKit/WebProcess/Model/ModelProcessModelPlayer.h

  Log Message:
  -----------
  Add animation forwarding to child models in spatial portals
https://bugs.webkit.org/show_bug.cgi?id=321050
rdar://182292543

Reviewed by Mike Wyrzykowski and Etienne Segonzac.

A <model> child of a spatial portal has no ModelPlayer of its own, so
its animation attributes and playback accessors went nowhere. Route them
through the portal's player, which addresses each child by
NodeIdentifier, and track playback state per node in both the Web and
Model processes, so the first model loaded no longer reports playback
for the whole portal.

Tests: spatial-css/spatial-portal-animation-currenttime.html
       spatial-css/spatial-portal-animation-dynamic.html
       spatial-css/spatial-portal-animation-independent.html
       spatial-css/spatial-portal-model-animations.html

* LayoutTests/spatial-css/resources/spatial-portal-utils.js:
(async waitFor):
* LayoutTests/spatial-css/spatial-portal-animation-currenttime-expected.txt: 
Added.
* LayoutTests/spatial-css/spatial-portal-animation-currenttime.html: Added.
* LayoutTests/spatial-css/spatial-portal-animation-dynamic-expected.txt: Added.
* LayoutTests/spatial-css/spatial-portal-animation-dynamic.html: Added.
* LayoutTests/spatial-css/spatial-portal-animation-independent-expected.txt: 
Added.
* LayoutTests/spatial-css/spatial-portal-animation-independent.html: Added.
* LayoutTests/spatial-css/spatial-portal-model-animations-expected.txt: Added.
* LayoutTests/spatial-css/spatial-portal-model-animations.html: Added.
Cover autoplay and loop reaching a child, seeking a child,
siblings playing, pausing and looping independently of one another, and
a re-added child not reusing the playback state it had before.

* Source/WebCore/Modules/model-element/HTMLModelElement.cpp:
(WebCore::HTMLModelElement::createModelPlayer):
(WebCore::HTMLModelElement::modelPlayerForAnimation const):
(WebCore::HTMLModelElement::applyInitialAnimationState):
(WebCore::HTMLModelElement::setPlaybackRate):
(WebCore::HTMLModelElement::duration const):
(WebCore::HTMLModelElement::paused const):
(WebCore::HTMLModelElement::setPaused):
(WebCore::HTMLModelElement::updateAutoplay):
(WebCore::HTMLModelElement::updateLoop):
(WebCore::HTMLModelElement::currentTime const):
(WebCore::HTMLModelElement::setCurrentTime):
* Source/WebCore/Modules/model-element/HTMLModelElement.h:
Reach the portal's player when the element has none of its own. The
attributes a standalone <model> pushes in createModelPlayer() move to
applyInitialAnimationState(), so the portal's load path can push the
same ones on the child's behalf.

* Source/WebCore/Modules/model-element/SpatialPortalController.cpp:
(WebCore::SpatialPortalController::ensureModelPlayer):
(WebCore::SpatialPortalController::loadChildModelIfReady):
(WebCore::SpatialPortalController::unregisterChildModel):
Reach the player of the portal this element is registered with when it
has none of its own. The attributes a standalone <model> pushes in
createModelPlayer() move to applyInitialAnimationState(), so the
portal's load path can push the same ones on the child's behalf.

* Source/WebKit/WebProcess/Model/ModelProcessModelPlayer.cpp:
(WebKit::ModelProcessModelPlayer::ensureAnimationState):
(WebKit::ModelProcessModelPlayer::animationStateIfExists):
(WebKit::ModelProcessModelPlayer::animationStateIfExists const):
(WebKit::ModelProcessModelPlayer::load):
(WebKit::ModelProcessModelPlayer::unload):
(WebKit::ModelProcessModelPlayer::reload):
(WebKit::ModelProcessModelPlayer::didFailLoading):
(WebKit::ModelProcessModelPlayer::didUpdateAnimationPlaybackState):
(WebKit::ModelProcessModelPlayer::currentAnimationState const):
(WebKit::ModelProcessModelPlayer::setAutoplay):
(WebKit::ModelProcessModelPlayer::setLoop):
(WebKit::ModelProcessModelPlayer::setPlaybackRate):
(WebKit::ModelProcessModelPlayer::duration const):
(WebKit::ModelProcessModelPlayer::paused const):
(WebKit::ModelProcessModelPlayer::currentTime const):
(WebKit::ModelProcessModelPlayer::setCurrentTime):
(WebKit::ModelProcessModelPlayer::didFailLoading):
* Source/WebKit/WebProcess/Model/ModelProcessModelPlayer.h:
Key animation state by NodeIdentifier rather than holding one set of
values per player. A playback report for a node the player does not
track is dropped instead of inventing state that would then be
reported to script, and a failed load drops the node's state, since the
model process drops its own entry for it.

* Source/WebKit/ModelProcess/cocoa/ModelProcessModelPlayerProxy.h:
* Source/WebKit/ModelProcess/cocoa/ModelProcessModelPlayerProxy.mm:
(-[WKModelProcessModelPlayerProxyObjCAdapter 
entityAnimationPlaybackStateDidUpdate:]):
(WebKit::ModelProcessModelPlayerProxy::entityForNode const):
(WebKit::ModelProcessModelPlayerProxy::loadModel):
(WebKit::ModelProcessModelPlayerProxy::reloadModel):
(WebKit::ModelProcessModelPlayerProxy::load):
(WebKit::ModelProcessModelPlayerProxy::didFinishLoading):
(WebKit::ModelProcessModelPlayerProxy::setUpLoadedEntity):
(WebKit::ModelProcessModelPlayerProxy::unloadModel):
(WebKit::ModelProcessModelPlayerProxy::animationPlaybackStateDidUpdate):
(WebKit::ModelProcessModelPlayerProxy::setAutoplay):
(WebKit::ModelProcessModelPlayerProxy::setLoop):
(WebKit::ModelProcessModelPlayerProxy::setPlaybackRate):
(WebKit::ModelProcessModelPlayerProxy::duration const):
(WebKit::ModelProcessModelPlayerProxy::paused const):
(WebKit::ModelProcessModelPlayerProxy::setPaused):
(WebKit::ModelProcessModelPlayerProxy::currentTime const):
(WebKit::ModelProcessModelPlayerProxy::setCurrentTime):
(WebKit::ModelProcessModelPlayerProxy::teardownEntity):
(WebKit::ModelProcessModelPlayerProxy::captureStateForReload):
(WebKit::ModelProcessModelPlayerProxy::computeTransform):
(WebKit::ModelProcessModelPlayerProxy::updateTransform):
(WebKit::ModelProcessModelPlayerProxy::updateOpacity):
(WebKit::ModelProcessModelPlayerProxy::didFailLoading):
(WebKit::ModelProcessModelPlayerProxy::reportingModelScale const):
(WebKit::ModelProcessModelPlayerProxy::findTrackedModelForLoader):
(WebKit::ModelProcessModelPlayerProxy::findTrackedModelForEntity):
(WebKit::ModelProcessModelPlayerProxy::ensureTrackedModel):
(WebKit::ModelProcessModelPlayerProxy::trackedModel):
(WebKit::ModelProcessModelPlayerProxy::trackedModel const):
(WebKit::ModelProcessModelPlayerProxy::cancelAllLoaders):
(WebKit::ModelProcessModelPlayerProxy::sizeDidChange):
(WebKit::ModelProcessModelPlayerProxy::ensureImmersivePresentation):
(WebKit::ModelProcessModelPlayerProxy::exitImmersivePresentation):
(WebKit::ModelProcessModelPlayerProxy::findHostedEntityForLoader): Deleted.
Hold autoplay, loop, playback rate and the state to restore on each
tracked model, and set the playback delegate on every entity so a
sibling reports its own state rather than the first model's. An
accessor for a node whose entity has not loaded now reports failure
rather than answering from a nil entity, so play() before load rejects.
teardownEntity() keeps its map entries, since captureStateForReload()
has just recorded playback state in them.

Canonical link: https://commits.webkit.org/318839@main



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications

Reply via email to