fix: Fix suspend caption rendering when captions container is not visible (#9959)

There are platforms (some WebKit STBs) where IntersectionObserver
doesn't work well with fullscreen.
Managing multiple videos on screen. Detecting which one opens in PiP and
Fullscreen.
This commit is contained in:
Álvaro Velad Galván
2026-04-11 23:00:27 +02:00
committed by GitHub
parent a090001426
commit d689f69c45
+53 -28
View File
@@ -79,6 +79,11 @@ shaka.text.UITextDisplayer = class {
});
this.configureCaptionsTimer_();
/** @private {shaka.util.Timer} */
this.applyVisibilityTimer_ = new shaka.util.Timer(() => {
this.applyVisibility_();
});
/**
* Maps cues to cue elements. Specifically points out the wrapper element of
* the cue (e.g. the HTML element to put nested cues inside).
@@ -165,7 +170,9 @@ shaka.text.UITextDisplayer = class {
const entry = entries[entries.length - 1];
this.isContainerActuallyVisible_ =
entry.isIntersecting && entry.intersectionRatio > 0;
this.applyVisibility_();
const captionsUpdatePeriod =
this.config_?.captionsUpdatePeriod || 0.25;
this.applyVisibilityTimer_.tickAfter(captionsUpdatePeriod);
}
}, options);
goog.asserts.assert(this.videoContainer_,
@@ -174,7 +181,11 @@ shaka.text.UITextDisplayer = class {
}
this.eventManager_.listen(document, 'visibilitychange', (e) => {
this.applyVisibility_();
this.applyVisibilityTimer_.tickNow();
});
this.eventManager_.listen(document, 'fullscreenchange', () => {
this.applyVisibilityTimer_.tickNow();
});
this.eventManager_.listenMulti(
@@ -183,18 +194,18 @@ shaka.text.UITextDisplayer = class {
'enterpictureinpicture',
'leavepictureinpicture',
], () => {
this.applyVisibility_();
this.applyVisibilityTimer_.tickNow();
});
if ('documentPictureInPicture' in window) {
this.eventManager_.listen(window.documentPictureInPicture, 'enter',
(e) => {
this.applyVisibility_();
this.applyVisibilityTimer_.tickNow();
const event = /** @type {DocumentPictureInPictureEvent} */(e);
const pipWindow = event.window;
this.eventManager_.listenOnce(pipWindow, 'pagehide', () => {
this.applyVisibility_();
this.applyVisibilityTimer_.tickNow();
});
});
}
@@ -202,7 +213,7 @@ shaka.text.UITextDisplayer = class {
const video = /** @type {HTMLVideoElement} */(this.video_);
if (video.webkitPresentationMode || video.webkitSupportsFullscreen) {
this.eventManager_.listen(video, 'webkitpresentationmodechanged', () => {
this.applyVisibility_();
this.applyVisibilityTimer_.tickNow();
});
}
@@ -267,28 +278,22 @@ shaka.text.UITextDisplayer = class {
this.isTextVisible_ = false;
this.cues_ = [];
if (this.captionsTimer_) {
this.captionsTimer_.stop();
this.captionsTimer_ = null;
}
this.captionsTimer_?.stop();
this.captionsTimer_ = null;
this.applyVisibilityTimer_?.stop();
this.applyVisibilityTimer_ = null;
this.currentCuesMap_.clear();
// Tear-down the event manager to ensure messages stop moving around.
if (this.eventManager_) {
this.eventManager_.release();
this.eventManager_ = null;
}
this.eventManager_?.release();
this.eventManager_ = null;
if (this.resizeObserver_) {
this.resizeObserver_.disconnect();
this.resizeObserver_ = null;
}
this.resizeObserver_?.disconnect();
this.resizeObserver_ = null;
if (this.visibilityObserver_) {
this.visibilityObserver_.disconnect();
this.visibilityObserver_ = null;
}
this.visibilityObserver_?.disconnect();
this.visibilityObserver_ = null;
return Promise.resolve();
}
@@ -380,17 +385,37 @@ shaka.text.UITextDisplayer = class {
* @private
*/
applyVisibility_() {
const isPiPActive = !!((window.documentPictureInPicture &&
window.documentPictureInPicture.window) ||
document.pictureInPictureElement);
const video = /** @type {HTMLVideoElement} */(this.video_);
let isPiPActive = false;
if (window.documentPictureInPicture &&
window.documentPictureInPicture.window) {
isPiPActive = true;
} else if (document.pictureInPictureElement === video) {
isPiPActive = true;
}
let isFullscreenActive = false;
if (document.fullscreenEnabled &&
document.fullscreenElement === this.videoContainer_) {
isFullscreenActive = true;
} else if (video.webkitSupportsFullscreen) {
isFullscreenActive = video.webkitDisplayingFullscreen;
}
const pageVisible = document.visibilityState === 'visible';
const actuallyVisible =
isPiPActive || (pageVisible && this.isContainerActuallyVisible_);
const actuallyVisible = isPiPActive || isFullscreenActive ||
(pageVisible && this.isContainerActuallyVisible_);
if (actuallyVisible) {
if (this.renderSuspended_) {
this.renderSuspended_ = false;
this.configureCaptionsTimer_();
this.updateCaptions_();
requestAnimationFrame(() => {
if (!this.textContainer_) {
return;
}
if (this.textContainer_.parentElement && this.isTextVisible_) {
this.updateCaptions_();
}
});
}
} else {
if (!this.renderSuspended_) {