Changeset 269407 in webkit
- Timestamp:
- Nov 4, 2020 5:05:14 PM (21 months ago)
- Location:
- trunk
- Files:
-
- 2 added
- 10 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/TestExpectations (modified) (1 diff)
-
LayoutTests/compositing/video/video-poster.html (modified) (3 diffs)
-
LayoutTests/media/video-poster-visible-after-first-video-frame-expected.txt (added)
-
LayoutTests/media/video-poster-visible-after-first-video-frame.html (added)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/html/HTMLMediaElement.cpp (modified) (23 diffs)
-
Source/WebCore/html/HTMLMediaElement.h (modified) (6 diffs)
-
Source/WebCore/html/HTMLVideoElement.cpp (modified) (5 diffs)
-
Source/WebCore/html/HTMLVideoElement.h (modified) (3 diffs)
-
Source/WebCore/rendering/RenderVideo.cpp (modified) (1 diff)
-
Source/WebCore/rendering/RenderVideo.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r269405 r269407 1 2020-11-04 Eric Carlson <eric.carlson@apple.com> 2 3 Transparent video poster image doesn't keep element transparent once first frame is preloaded 4 https://bugs.webkit.org/show_bug.cgi?id=218391 5 <rdar://problem/70916944> 6 7 Reviewed by Jer Noble. 8 9 * TestExpectations: Mark a test that expect video state changes to be visible on the 10 next rAF to be flaky. HTMLMediaElement uses taskQueues to change properties, and 11 taskQueue isn't synchronized to rAF, so sometimes the task runs before the next 12 rAF and sometimes after, making the test flaky. 13 14 * compositing/video/video-poster.html: Don't expect the transition to having layers 15 to be instantaneous. 16 17 * media/video-poster-visible-after-first-video-frame-expected.txt: Added. 18 * media/video-poster-visible-after-first-video-frame.html: Added. 19 1 20 2020-11-04 Truitt Savell <tsavell@apple.com> 2 21 -
trunk/LayoutTests/TestExpectations
r269394 r269407 3036 3036 3037 3037 webkit.org/b/198103 imported/w3c/web-platform-tests/html/semantics/embedded-content/media-elements/offsets-into-the-media-resource/currentTime.html [ Pass Failure ] 3038 3039 # This tests assumes that changes caused by removing 'video.src' will be visible immediately after the next rAF. 3040 # HTMLMediaElement uses a taskQueue to change video.src, but taskQueue isn't tied to rAF so the task sometimes 3041 # runs before rAF and the test passes, and sometimes run after and the test fails. 3042 imported/w3c/web-platform-tests/html/semantics/embedded-content/the-video-element/intrinsic_sizes.htm [ Pass Failure ] 3038 3043 3039 3044 # Flaky WebSocket tests. -
trunk/LayoutTests/compositing/video/video-poster.html
r130689 r269407 5 5 <script> 6 6 7 var count = 0;8 7 function log(str) 9 8 { … … 15 14 if (window.testRunner) 16 15 return window.internals.layerTreeAsText(document) != ""; 16 17 17 return false; 18 18 } 19 19 20 function checkLayers(prefix, wantsLayers)20 async function checkLayers(prefix, wantsLayers) 21 21 { 22 var layers = hasLayers(); 23 log(prefix + " <br> " + (wantsLayers == layers ? "PASS" : "FAIL") + ": wants layers = " + wantsLayers + ", has layers = " + layers); 24 log(""); 22 return new Promise(async resolve => { 23 let layers; 24 let count = 0; 25 while (true) { 26 27 layers = hasLayers(); 28 if (layers == wantsLayers) 29 break; 30 31 await new Promise(resolve => { setTimeout(resolve, 10); }); 32 if (++count > 10) 33 break; 34 } 35 36 log(`${prefix} <br> ${wantsLayers == layers ? "PASS" : "FAIL"}: wants layers = ${wantsLayers}, has layers = ${layers}<br>`); 37 resolve(); 38 }); 25 39 } 26 40 27 function layerTest()41 async function layerTest() 28 42 { 29 43 var video = document.getElementsByTagName('video')[0]; … … 32 46 { 33 47 case "load": 34 checkLayers("No src, no poster", false);48 await checkLayers("No src, no poster", false); 35 49 video.src = "../resources/video." + (video.canPlayType("video/ogg") ? "ogv" : "mp4"); 36 50 video.poster = "../resources/apple.jpg"; 37 51 break; 38 52 case "canplaythrough": 39 checkLayers("Displaying poster", false);53 await checkLayers("Displaying poster", false); 40 54 video.currentTime = 0.5; 41 55 break; 42 56 case "seeked": 43 checkLayers("Displaying movie", true);57 await checkLayers("Displaying movie", true); 44 58 if (window.testRunner) 45 59 testRunner.notifyDone(); -
trunk/Source/WebCore/ChangeLog
r269402 r269407 1 2020-11-04 Eric Carlson <eric.carlson@apple.com> 2 3 Transparent video poster image doesn't keep element transparent once first frame is preloaded 4 https://bugs.webkit.org/show_bug.cgi?id=218391 5 <rdar://problem/70916944> 6 7 Reviewed by Jer Noble. 8 9 Redo the poster frame logic to use the `show poster flag` logic from the spec. 10 11 Test: media/video-poster-visible-after-first-video-frame.html 12 13 * html/HTMLMediaElement.cpp: 14 (WebCore::HTMLMediaElement::HTMLMediaElement): Initialize m_showPoster. 15 (WebCore::HTMLMediaElement::prepareForLoad): m_displayMode was removed. 16 (WebCore::HTMLMediaElement::selectMediaResource): Call setShowPosterFlag. 17 (WebCore::HTMLMediaElement::loadResource): Remove calls to setDisplayMode and updateDisplayState, 18 they have been deleted. 19 (WebCore::HTMLMediaElement::waitForSourceChange): Call setShowPosterFlag. Update spec text. 20 (WebCore::HTMLMediaElement::noneSupported): Call setShowPosterFlag. 21 (WebCore::HTMLMediaElement::mediaLoadingFailed): Remove call to updateDisplayState. 22 (WebCore::HTMLMediaElement::setReadyState): Ditto. 23 (WebCore::HTMLMediaElement::seekWithTolerance): Call setShowPosterFlag. 24 (WebCore::HTMLMediaElement::seekTask): Check m_showPoster, not displayMode. 25 (WebCore::HTMLMediaElement::playInternal): Call setShowPosterFlag. 26 (WebCore::HTMLMediaElement::mediaPlayerCharacteristicChanged): Don't check displayMode. 27 (WebCore::HTMLMediaElement::updatePlayState): No more setDisplayMode. 28 (WebCore::HTMLMediaElement::userCancelledLoad): Call setShowPosterFlag. 29 (WebCore::HTMLMediaElement::setShowPosterFlag): 30 (WebCore::HTMLMediaElement::mediaPlayerFirstVideoFrameAvailable): Deleted. 31 * html/HTMLMediaElement.h: 32 (WebCore::HTMLMediaElement::showPosterFlag const): 33 (WebCore::HTMLMediaElement::setShowPosterFlag): 34 (WebCore::HTMLMediaElement::displayMode const): Deleted. 35 (WebCore::HTMLMediaElement::setDisplayMode): Deleted. 36 (WebCore::HTMLMediaElement::updateDisplayState): Deleted. 37 38 * html/HTMLVideoElement.cpp: 39 (WebCore::HTMLVideoElement::didAttachRenderers): No more updateDisplayState. 40 (WebCore::HTMLVideoElement::parseAttribute): Ditto. Call updateFromElement when poster is removed. 41 (WebCore::HTMLVideoElement::shouldDisplayPosterImage const): New. 42 (WebCore::HTMLVideoElement::mediaPlayerFirstVideoFrameAvailable): New, update player and 43 renderer if the poster isn't supposed to be visible. 44 (WebCore::HTMLVideoElement::setDisplayMode): Deleted. 45 (WebCore::HTMLVideoElement::updateDisplayState): Deleted. 46 * html/HTMLVideoElement.h: 47 48 * rendering/RenderVideo.cpp: 49 (WebCore::RenderVideo::failedToLoadPosterImage const): New. 50 * rendering/RenderVideo.h: 51 52 * testing/Internals.cpp: 53 (WebCore::Internals::elementShouldDisplayPosterImage const): 54 * testing/Internals.h: 55 * testing/Internals.idl: 56 1 57 2020-11-04 Zalan Bujtas <zalan@apple.com> 2 58 -
trunk/Source/WebCore/html/HTMLMediaElement.cpp
r269321 r269407 415 415 , m_isScrubbingRemotely(false) 416 416 , m_waitingToEnterFullscreen(false) 417 , m_showPoster(true) 417 418 , m_tracksAreReady(true) 418 419 , m_haveVisibleTextTrack(false) … … 1082 1083 m_completelyLoaded = false; 1083 1084 m_havePreparedToPlay = false; 1084 m_displayMode = Unknown;1085 1085 m_currentSrc = URL(); 1086 1086 … … 1186 1186 1187 1187 // 2. Set the element’s show poster flag to true. 1188 set DisplayMode(Poster);1188 setShowPosterFlag(true); 1189 1189 1190 1190 // 3. Set the media element’s delaying-the-load-event flag to true (this delays the load event). … … 1432 1432 m_player->setPrivateBrowsingMode(privateMode); 1433 1433 1434 // Reset display mode to force a recalculation of what to show because we are resetting the player.1435 setDisplayMode(Unknown);1436 1437 1434 if (!autoplay() && !m_havePreparedToPlay) 1438 1435 m_player->setPreload(m_mediaSession->effectivePreloadForElement()); … … 1488 1485 mediaLoadingFailed(MediaPlayer::NetworkState::FormatError); 1489 1486 1490 // If there is no poster to display, allow the media engine to render video frames as soon as 1491 // they are available. 1492 updateDisplayState(); 1493 1494 updateRenderer(); 1487 mediaPlayerRenderingModeChanged(); 1495 1488 } 1496 1489 … … 1981 1974 m_networkState = NETWORK_NO_SOURCE; 1982 1975 1983 // 6.18 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event. 1976 // 6.18 - Set the element's show poster flag to true. 1977 setShowPosterFlag(true); 1978 1979 // 6.19 - Queue a media element task given the media element given the element to set the 1980 // element's delaying-the-load-event flag to false. This stops delaying the load event. 1981 // FIXME: this should be done in a task queue 1984 1982 setShouldDelayLoadEvent(false); 1985 1983 1986 updateDisplayState();1987 1984 updateRenderer(); 1988 1985 } … … 2013 2010 m_networkState = NETWORK_NO_SOURCE; 2014 2011 2012 // 6.4 - Set the element's show poster flag to true. 2013 setShowPosterFlag(true); 2014 2015 2015 // 7 - Queue a task to fire a simple event named error at the media element. 2016 2016 scheduleEvent(eventNames().errorEvent); … … 2028 2028 // the element won't attempt to load another resource. 2029 2029 2030 updateDisplayState();2031 2030 updateRenderer(); 2032 2031 } … … 2141 2140 else if ((error == MediaPlayer::NetworkState::FormatError || error == MediaPlayer::NetworkState::NetworkError) && m_loadState == LoadingFromSrcAttr) 2142 2141 noneSupported(); 2143 2144 updateDisplayState();2145 2142 2146 2143 ERROR_LOG(LOGIDENTIFIER, "error = ", static_cast<int>(error)); … … 2344 2341 } 2345 2342 2346 bool shouldUpdateDisplayState = false;2347 2348 2343 if (m_readyState >= HAVE_CURRENT_DATA && oldState < HAVE_CURRENT_DATA) { 2349 2344 if (!m_haveFiredLoadedData) { 2350 2345 m_haveFiredLoadedData = true; 2351 2346 scheduleEvent(eventNames().loadeddataEvent); 2352 // FIXME: It's not clear that it's correct to skip these t wo operationsjust2347 // FIXME: It's not clear that it's correct to skip these this operation just 2353 2348 // because m_haveFiredLoadedData is already true. At one time we were skipping 2354 2349 // the call to setShouldDelayLoadEvent, which was definitely incorrect. 2355 shouldUpdateDisplayState = true;2356 2350 applyMediaFragmentURI(); 2357 2351 } … … 2359 2353 } 2360 2354 2361 if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA && tracksAreReady) {2355 if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA && tracksAreReady) 2362 2356 scheduleEvent(eventNames().canplayEvent); 2363 shouldUpdateDisplayState = true;2364 }2365 2357 2366 2358 if (m_readyState == HAVE_ENOUGH_DATA && oldState < HAVE_ENOUGH_DATA && tracksAreReady) { … … 2373 2365 if (success) { 2374 2366 m_paused = false; 2367 setShowPosterFlag(false); 2375 2368 invalidateCachedTime(); 2376 2369 setAutoplayEventPlaybackState(AutoplayEventPlaybackState::StartedWithoutUserGesture); … … 2381 2374 setAutoplayEventPlaybackState(AutoplayEventPlaybackState::PreventedAutoplay); 2382 2375 } 2383 2384 shouldUpdateDisplayState = true;2385 2376 } 2386 2377 … … 2395 2386 setAutoplayEventPlaybackState(AutoplayEventPlaybackState::PreventedAutoplay); 2396 2387 } 2397 2398 if (shouldUpdateDisplayState)2399 updateDisplayState();2400 2388 2401 2389 updatePlayState(); … … 2863 2851 2864 2852 // 1 - Set the media element's show poster flag to false. 2865 set DisplayMode(Video);2853 setShowPosterFlag(false); 2866 2854 2867 2855 // 2 - If the media element's readyState is HAVE_NOTHING, abort these steps. … … 2962 2950 // poster display), or 2) if there is a pending fast seek, or 3) if this seek is not an exact seek 2963 2951 SeekType thisSeekType = (negativeTolerance == MediaTime::zeroTime() && positiveTolerance == MediaTime::zeroTime()) ? Precise : Fast; 2964 if (!noSeekRequired && time == now && thisSeekType == Precise && m_pendingSeekType != Fast && displayMode() != Poster)2952 if (!noSeekRequired && time == now && thisSeekType == Precise && m_pendingSeekType != Fast && !showPosterFlag()) 2965 2953 noSeekRequired = true; 2966 2954 … … 3443 3431 if (m_paused) { 3444 3432 m_paused = false; 3433 setShowPosterFlag(false); 3445 3434 invalidateCachedTime(); 3446 3435 … … 4877 4866 { 4878 4867 beginProcessingMediaPlayerCallback(); 4879 updateDisplayState();4880 4868 if (auto* renderer = this->renderer()) 4881 4869 renderer->repaint(); … … 5010 4998 } 5011 4999 5012 void HTMLMediaElement::mediaPlayerFirstVideoFrameAvailable()5013 {5014 ALWAYS_LOG(LOGIDENTIFIER, "current display mode = ", (int)displayMode());5015 5016 beginProcessingMediaPlayerCallback();5017 if (displayMode() == PosterWaitingForVideo) {5018 setDisplayMode(Video);5019 mediaPlayerRenderingModeChanged();5020 }5021 endProcessingMediaPlayerCallback();5022 }5023 5024 5000 void HTMLMediaElement::mediaPlayerCharacteristicChanged() 5025 5001 { … … 5031 5007 markCaptionAndSubtitleTracksAsUnconfigured(AfterDelay); 5032 5008 5033 if (potentiallyPlaying() && displayMode() == PosterWaitingForVideo) { 5034 setDisplayMode(Video); 5009 if (potentiallyPlaying()) 5035 5010 mediaPlayerRenderingModeChanged(); 5036 }5037 5011 5038 5012 updateRenderer(); … … 5266 5240 schedulePlaybackControlsManagerUpdate(); 5267 5241 5268 setDisplayMode(Video);5269 5242 invalidateCachedTime(); 5270 5243 … … 5399 5372 5400 5373 // 4 - If the media element's readyState attribute has a value equal to HAVE_NOTHING, set the 5401 // element's networkState attribute to the NETWORK_EMPTY value and queue a task to fire a 5402 // simple event named emptied at the element. Otherwise, set the element's networkState 5403 // attribute to the NETWORK_IDLE value. 5374 // element's networkState attribute to the NETWORK_EMPTY value, set the element's show poster 5375 // flag to true, and fire an event named emptied at the element. 5404 5376 if (m_readyState == HAVE_NOTHING) { 5405 5377 m_networkState = NETWORK_EMPTY; 5378 setShowPosterFlag(true); 5406 5379 scheduleEvent(eventNames().emptiedEvent); 5407 5380 } … … 7943 7916 } 7944 7917 7945 } 7946 7947 #endif 7918 void HTMLMediaElement::setShowPosterFlag(bool flag) 7919 { 7920 if (m_showPoster == flag) 7921 return; 7922 7923 ALWAYS_LOG(LOGIDENTIFIER, flag); 7924 7925 m_showPoster = flag; 7926 invalidateStyleAndLayerComposition(); 7927 } 7928 7929 } 7930 7931 #endif -
trunk/Source/WebCore/html/HTMLMediaElement.h
r268865 r269407 587 587 void didMoveToNewDocument(Document& oldDocument, Document& newDocument) override; 588 588 589 enum DisplayMode { Unknown, None, Poster, PosterWaitingForVideo, Video };590 DisplayMode displayMode() const { return m_displayMode; }591 virtual void setDisplayMode(DisplayMode mode) { m_displayMode = mode; }592 593 589 bool isMediaElement() const final { return true; } 594 590 … … 606 602 void scheduleEvent(const AtomString&); 607 603 604 bool showPosterFlag() const { return m_showPoster; } 605 void setShowPosterFlag(bool); 606 608 607 void setChangingVideoFullscreenMode(bool value) { m_changingVideoFullscreenMode = value; } 609 608 bool isChangingVideoFullscreenMode() const { return m_changingVideoFullscreenMode; } … … 639 638 void visibilityStateChanged() final; 640 639 641 virtual void updateDisplayState() { }642 643 640 void setReadyState(MediaPlayer::ReadyState); 644 641 void setNetworkState(MediaPlayer::NetworkState); … … 666 663 void mediaEngineWasUpdated(); 667 664 668 void mediaPlayerFirstVideoFrameAvailable() final;669 665 void mediaPlayerCharacteristicChanged() final; 670 666 … … 1024 1020 MediaPlayer::Preload m_preload { Preload::Auto }; 1025 1021 1026 DisplayMode m_displayMode { Unknown };1027 1028 1022 // Counter incremented while processing a callback from the media player, so we can avoid 1029 1023 // calling the media engine recursively. … … 1097 1091 bool m_changingVideoFullscreenMode : 1; 1098 1092 1093 bool m_showPoster : 1; 1099 1094 bool m_tracksAreReady : 1; 1100 1095 bool m_haveVisibleTextTrack : 1; -
trunk/Source/WebCore/html/HTMLVideoElement.cpp
r269323 r269407 1 1 /* 2 * Copyright (C) 2007 , 2008, 2009, 2010 Apple Inc. All rights reserved.2 * Copyright (C) 2007-2020 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 104 104 HTMLMediaElement::didAttachRenderers(); 105 105 106 updateDisplayState();107 106 if (shouldDisplayPosterImage()) { 108 107 if (!m_imageLoader) … … 134 133 { 135 134 if (name == posterAttr) { 136 if (hasAvailableVideoFrame())137 return;138 139 // Force a poster recalc by setting m_displayMode to Unknown directly before calling updateDisplayState.140 HTMLMediaElement::setDisplayMode(Unknown);141 updateDisplayState();142 143 135 if (shouldDisplayPosterImage()) { 144 136 if (!m_imageLoader) … … 146 138 m_imageLoader->updateFromElementIgnoringPreviousError(); 147 139 } else { 148 if (auto* renderer = this->renderer()) 140 if (auto* renderer = this->renderer()) { 149 141 renderer->imageResource().setCachedImage(nullptr); 142 renderer->updateFromElement(); 143 } 150 144 } 151 145 } … … 259 253 } 260 254 261 void HTMLVideoElement::setDisplayMode(DisplayMode mode) 262 { 263 DisplayMode oldMode = displayMode(); 264 URL poster = posterImageURL(); 265 266 if (!poster.isEmpty()) { 267 // We have a poster path, but only show it until the user triggers display by playing or seeking and the 268 // media engine has something to display. 269 if (mode == Video) { 270 if (oldMode != Video && player()) 271 player()->prepareForRendering(); 272 if (!hasAvailableVideoFrame()) 273 mode = PosterWaitingForVideo; 274 } 275 } else if (oldMode != Video && player()) 276 player()->prepareForRendering(); 277 278 HTMLMediaElement::setDisplayMode(mode); 279 280 if (auto* renderer = this->renderer()) { 281 if (displayMode() != oldMode) 282 renderer->updateFromElement(); 283 } 284 } 285 286 void HTMLVideoElement::updateDisplayState() 287 { 288 if (posterImageURL().isEmpty() || hasAvailableVideoFrame()) 289 setDisplayMode(Video); 290 else if (displayMode() < Poster) 291 setDisplayMode(Poster); 255 bool HTMLVideoElement::shouldDisplayPosterImage() const 256 { 257 if (!showPosterFlag()) 258 return false; 259 260 if (posterImageURL().isEmpty()) 261 return false; 262 263 auto* renderer = this->renderer(); 264 if (renderer && renderer->failedToLoadPosterImage()) 265 return false; 266 267 return true; 268 } 269 270 void HTMLVideoElement::mediaPlayerFirstVideoFrameAvailable() 271 { 272 INFO_LOG(LOGIDENTIFIER, "m_showPoster = ", showPosterFlag()); 273 274 if (showPosterFlag()) 275 return; 276 277 invalidateStyleAndLayerComposition(); 278 279 if (auto player = this->player()) 280 player->prepareForRendering(); 281 282 if (auto* renderer = this->renderer()) 283 renderer->updateFromElement(); 292 284 } 293 285 -
trunk/Source/WebCore/html/HTMLVideoElement.h
r269323 r269407 1 1 /* 2 * Copyright (C) 2007 , 2008, 2009, 2010 Apple Inc. All rights reserved.2 * Copyright (C) 2007-2020 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 82 82 bool copyVideoTextureToPlatformTexture(GraphicsContextGLOpenGL*, PlatformGLObject texture, GCGLenum target, GCGLint level, GCGLenum internalFormat, GCGLenum format, GCGLenum type, bool premultiplyAlpha, bool flipY); 83 83 84 bool shouldDisplayPosterImage() const { return displayMode() == Poster || displayMode() == PosterWaitingForVideo; }84 WEBCORE_EXPORT bool shouldDisplayPosterImage() const; 85 85 86 86 URL posterImageURL() const; … … 128 128 const AtomString& imageSourceURL() const final; 129 129 130 void didMoveToNewDocument(Document& oldDocument, Document& newDocument) final; 131 130 132 bool hasAvailableVideoFrame() const; 131 void updateDisplayState() final; 132 void didMoveToNewDocument(Document& oldDocument, Document& newDocument) final; 133 void setDisplayMode(DisplayMode) final; 133 void mediaPlayerFirstVideoFrameAvailable() final; 134 134 135 135 PlatformMediaSession::MediaType presentationType() const final { return PlatformMediaSession::MediaType::Video; } -
trunk/Source/WebCore/rendering/RenderVideo.cpp
r268145 r269407 187 187 } 188 188 189 bool RenderVideo::failedToLoadPosterImage() const 190 { 191 return imageResource().errorOccurred(); 192 } 193 189 194 void RenderVideo::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 190 195 { -
trunk/Source/WebCore/rendering/RenderVideo.h
r261409 r269407 51 51 52 52 bool shouldDisplayVideo() const; 53 bool failedToLoadPosterImage() const; 53 54 54 55 void updateFromElement() final;
Note: See TracChangeset
for help on using the changeset viewer.