Lazy Video Viewport Observer: GPU Layer Teardown for Off-Screen Videos
Source/WebCore/html/HTMLVideoElement.cpp
This commit introduces LazyLoadVideoObserver and a ViewportVisibility enum to track whether video elements intersect the viewport. When visibility drops to NotVisible, compositor layers are torn down for AVFoundation-backed players; when the element scrolls back into view, layers are recreated. This mirrors the existing LazyLoadImageObserver/LazyLoadFrameObserver pattern.
HTMLVideoElement (WebProcess)
│ viewportIntersectionChanged()
│ │
│ isVisibleInViewportChanged()
│ │
▼ MediaPlayer::setViewportVisibility()
│
▼ [IPC]
RemoteMediaPlayerProxy::setViewportVisibility() (GPUProcess)
│
▼ MediaPlayerPrivateAVFoundationObjC
platformViewportVisibilityChanged()
│
visibility == NotVisible?
├─ YES ──► updateLayerAttachment() → detach/destroy CALayer
└─ NO ──► updateLayerAttachment() → recreate CALayer if needed
The fix addresses window server jetsams (OOM kills of the compositor) on infinite-scroll video pages by releasing GPU-side layer resources for off-screen elements. A new three-state visibility model (NotVisible / IntersectingViewport / VisibleInViewport) replaces the previous boolean, where IntersectingViewport is triggered by an IntersectionObserver with a 100% rootMargin.
Significance
The layer teardown/recreation cycle adds a new state transition to media player lifecycle that must correctly handle all combinations of page visibility, viewport visibility, fullscreen, and PiP states.
The shouldAttachLayerToPlayer() decision function now integrates four flags — any disagreement between WebProcess-side state and GPUProcess-side state during rapid scroll transitions could leave a video in an inconsistent layer state.