Changeset 261341 in webkit


Ignore:
Timestamp:
May 7, 2020, 4:05:40 PM (5 years ago)
Author:
eric.carlson@apple.com
Message:

Poster set after playback begins should be ignored
https://bugs.webkit.org/show_bug.cgi?id=211464

Reviewed by Jer Noble.
Source/WebCore:

Redo the poster frame logic to use the show poster flag logic from the spec.

Test: media/video-poster-set-after-playback.html

  • html/HTMLMediaElement.cpp:

(WebCore::HTMLMediaElement::HTMLMediaElement): Initialize m_showPoster.
(WebCore::HTMLMediaElement::prepareForLoad): m_displayMode was removed.
(WebCore::HTMLMediaElement::selectMediaResource): Call setShowPosterFlag.
(WebCore::HTMLMediaElement::loadResource): Remove calls to setDisplayMode and updateDisplayState,
they have been deleted.
(WebCore::HTMLMediaElement::waitForSourceChange): Call setShowPosterFlag. Update spec text.
(WebCore::HTMLMediaElement::noneSupported): Call setShowPosterFlag.
(WebCore::HTMLMediaElement::mediaLoadingFailed): Remove call to updateDisplayState.
(WebCore::HTMLMediaElement::setReadyState): Ditto.
(WebCore::HTMLMediaElement::seekWithTolerance): Call setShowPosterFlag.
(WebCore::HTMLMediaElement::seekTask): Check m_showPoster, not displayMode.
(WebCore::HTMLMediaElement::playInternal): Call setShowPosterFlag.
(WebCore::HTMLMediaElement::mediaPlayerCharacteristicChanged): Don't check displayMode.
(WebCore::HTMLMediaElement::updatePlayState): No more setDisplayMode.
(WebCore::HTMLMediaElement::userCancelledLoad): Call setShowPosterFlag.
(WebCore::HTMLMediaElement::mediaPlayerFirstVideoFrameAvailable): Deleted.

  • html/HTMLMediaElement.h:

(WebCore::HTMLMediaElement::showPosterFlag const):
(WebCore::HTMLMediaElement::setShowPosterFlag):
(WebCore::HTMLMediaElement::displayMode const): Deleted.
(WebCore::HTMLMediaElement::setDisplayMode): Deleted.
(WebCore::HTMLMediaElement::updateDisplayState): Deleted.

  • html/HTMLVideoElement.cpp:

(WebCore::HTMLVideoElement::didAttachRenderers): No more updateDisplayState.
(WebCore::HTMLVideoElement::parseAttribute): Ditto. Call updateFromElement when poster is removed.
(WebCore::HTMLVideoElement::shouldDisplayPosterImage const): New.
(WebCore::HTMLVideoElement::mediaPlayerFirstVideoFrameAvailable): New, update player and
renderer if the poster isn't supposed to be visible.
(WebCore::HTMLVideoElement::setDisplayMode): Deleted.
(WebCore::HTMLVideoElement::updateDisplayState): Deleted.

  • html/HTMLVideoElement.h:
  • rendering/RenderVideo.cpp:

(WebCore::RenderVideo::failedToLoadPosterImage const): New.

  • rendering/RenderVideo.h:
  • testing/Internals.cpp:

(WebCore::Internals::elementShouldDisplayPosterImage const):

  • testing/Internals.h:
  • testing/Internals.idl:

LayoutTests:

  • media/video-poster-set-after-playback-expected.txt: Added.
  • media/video-poster-set-after-playback.html: Added.
Location:
trunk
Files:
2 added
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r261334 r261341  
     12020-05-07  Eric Carlson  <eric.carlson@apple.com>
     2
     3        Poster set after playback begins should be ignored
     4        https://bugs.webkit.org/show_bug.cgi?id=211464
     5
     6        Reviewed by Jer Noble.
     7
     8        * media/video-poster-set-after-playback-expected.txt: Added.
     9        * media/video-poster-set-after-playback.html: Added.
     10
    1112020-05-07  Simon Fraser  <simon.fraser@apple.com>
    212
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/semantics/embedded-content/the-video-element/intrinsic_sizes-expected.txt

    r242595 r261341  
    66PASS default height is half the width
    77PASS default width is twice the height
    8 FAIL default object size after src is removed assert_equals: expected "320px" but got "300px"
     8FAIL default object size after src is removed assert_equals: expected "300px" but got "320px"
    99FAIL default object size after poster is removed assert_equals: expected "102px" but got "300px"
    1010
  • trunk/Source/WebCore/ChangeLog

    r261338 r261341  
     12020-05-07  Eric Carlson  <eric.carlson@apple.com>
     2
     3        Poster set after playback begins should be ignored
     4        https://bugs.webkit.org/show_bug.cgi?id=211464
     5
     6        Reviewed by Jer Noble.
     7       
     8        Redo the poster frame logic to use the `show poster flag` logic from the spec.
     9
     10        Test: media/video-poster-set-after-playback.html
     11
     12        * html/HTMLMediaElement.cpp:
     13        (WebCore::HTMLMediaElement::HTMLMediaElement): Initialize m_showPoster.
     14        (WebCore::HTMLMediaElement::prepareForLoad): m_displayMode was removed.
     15        (WebCore::HTMLMediaElement::selectMediaResource): Call setShowPosterFlag.
     16        (WebCore::HTMLMediaElement::loadResource): Remove calls to setDisplayMode and updateDisplayState,
     17        they have been deleted.
     18        (WebCore::HTMLMediaElement::waitForSourceChange): Call setShowPosterFlag. Update spec text.
     19        (WebCore::HTMLMediaElement::noneSupported): Call setShowPosterFlag.
     20        (WebCore::HTMLMediaElement::mediaLoadingFailed): Remove call to updateDisplayState.
     21        (WebCore::HTMLMediaElement::setReadyState): Ditto.
     22        (WebCore::HTMLMediaElement::seekWithTolerance): Call setShowPosterFlag.
     23        (WebCore::HTMLMediaElement::seekTask):  Check m_showPoster, not displayMode.
     24        (WebCore::HTMLMediaElement::playInternal): Call setShowPosterFlag.
     25        (WebCore::HTMLMediaElement::mediaPlayerCharacteristicChanged): Don't check displayMode.
     26        (WebCore::HTMLMediaElement::updatePlayState): No more setDisplayMode.
     27        (WebCore::HTMLMediaElement::userCancelledLoad):  Call setShowPosterFlag.
     28        (WebCore::HTMLMediaElement::mediaPlayerFirstVideoFrameAvailable): Deleted.
     29        * html/HTMLMediaElement.h:
     30        (WebCore::HTMLMediaElement::showPosterFlag const):
     31        (WebCore::HTMLMediaElement::setShowPosterFlag):
     32        (WebCore::HTMLMediaElement::displayMode const): Deleted.
     33        (WebCore::HTMLMediaElement::setDisplayMode): Deleted.
     34        (WebCore::HTMLMediaElement::updateDisplayState): Deleted.
     35
     36        * html/HTMLVideoElement.cpp:
     37        (WebCore::HTMLVideoElement::didAttachRenderers): No more updateDisplayState.
     38        (WebCore::HTMLVideoElement::parseAttribute): Ditto. Call updateFromElement when poster is removed.
     39        (WebCore::HTMLVideoElement::shouldDisplayPosterImage const): New.
     40        (WebCore::HTMLVideoElement::mediaPlayerFirstVideoFrameAvailable): New, update player and
     41        renderer if the poster isn't supposed to be visible.
     42        (WebCore::HTMLVideoElement::setDisplayMode): Deleted.
     43        (WebCore::HTMLVideoElement::updateDisplayState): Deleted.
     44        * html/HTMLVideoElement.h:
     45
     46        * rendering/RenderVideo.cpp:
     47        (WebCore::RenderVideo::failedToLoadPosterImage const): New.
     48        * rendering/RenderVideo.h:
     49
     50        * testing/Internals.cpp:
     51        (WebCore::Internals::elementShouldDisplayPosterImage const):
     52        * testing/Internals.h:
     53        * testing/Internals.idl:
     54
    1552020-05-07  Jack Lee  <shihchieh_lee@apple.com>
    256
  • trunk/Source/WebCore/html/HTMLMediaElement.cpp

    r261004 r261341  
    448448    , m_haveSetUpCaptionContainer(false)
    449449    , m_isScrubbingRemotely(false)
     450    , m_showPoster(true)
    450451#if ENABLE(VIDEO_TRACK)
    451452    , m_tracksAreReady(true)
     
    11411142    m_completelyLoaded = false;
    11421143    m_havePreparedToPlay = false;
    1143     m_displayMode = Unknown;
    11441144    m_currentSrc = URL();
    11451145
     
    12471247
    12481248    // 2. Set the element’s show poster flag to true.
    1249     setDisplayMode(Poster);
     1249    setShowPosterFlag(true);
    12501250
    12511251    // 3. Set the media element’s delaying-the-load-event flag to true (this delays the load event).
     
    14951495    m_player->setPrivateBrowsingMode(privateMode);
    14961496
    1497     // Reset display mode to force a recalculation of what to show because we are resetting the player.
    1498     setDisplayMode(Unknown);
    1499 
    15001497    if (!autoplay() && !m_havePreparedToPlay)
    15011498        m_player->setPreload(m_mediaSession->effectivePreloadForElement());
     
    15511548        mediaLoadingFailed(MediaPlayer::NetworkState::FormatError);
    15521549
    1553     // If there is no poster to display, allow the media engine to render video frames as soon as
    1554     // they are available.
    1555     updateDisplayState();
    1556 
    1557     updateRenderer();
     1550    mediaPlayerRenderingModeChanged();
    15581551}
    15591552
     
    20482041    m_networkState = NETWORK_NO_SOURCE;
    20492042
    2050     // 6.18 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
     2043    // 6.18 - Set the element's show poster flag to true.
     2044    setShowPosterFlag(true);
     2045
     2046    // 6.19 -  Queue a media element task given the media element given the element to set the
     2047    // element's delaying-the-load-event flag to false. This stops delaying the load event.
     2048    // FIXME: this should be done in a task queue
    20512049    setShouldDelayLoadEvent(false);
    20522050
    2053     updateDisplayState();
    20542051    updateRenderer();
    20552052}
     
    20802077    m_networkState = NETWORK_NO_SOURCE;
    20812078
     2079    // 6.4 - Set the element's show poster flag to true.
     2080    setShowPosterFlag(true);
     2081
    20822082    // 7 - Queue a task to fire a simple event named error at the media element.
    20832083    scheduleEvent(eventNames().errorEvent);
     
    20952095    // the element won't attempt to load another resource.
    20962096
    2097     updateDisplayState();
    20982097    updateRenderer();
    20992098}
     
    22082207    else if ((error == MediaPlayer::NetworkState::FormatError || error == MediaPlayer::NetworkState::NetworkError) && m_loadState == LoadingFromSrcAttr)
    22092208        noneSupported();
    2210 
    2211     updateDisplayState();
    22122209
    22132210    ERROR_LOG(LOGIDENTIFIER, "error = ", static_cast<int>(error));
     
    24172414    }
    24182415
    2419     bool shouldUpdateDisplayState = false;
    2420 
    24212416    if (m_readyState >= HAVE_CURRENT_DATA && oldState < HAVE_CURRENT_DATA) {
    24222417        if (!m_haveFiredLoadedData) {
     
    24262421            // because m_haveFiredLoadedData is already true. At one time we were skipping
    24272422            // the call to setShouldDelayLoadEvent, which was definitely incorrect.
    2428             shouldUpdateDisplayState = true;
    24292423            applyMediaFragmentURI();
    24302424        }
     
    24322426    }
    24332427
    2434     if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA && tracksAreReady) {
     2428    if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA && tracksAreReady)
    24352429        scheduleEvent(eventNames().canplayEvent);
    2436         shouldUpdateDisplayState = true;
    2437     }
    24382430
    24392431    if (m_readyState == HAVE_ENOUGH_DATA && oldState < HAVE_ENOUGH_DATA && tracksAreReady) {
     
    24462438        if (success) {
    24472439            m_paused = false;
     2440            setShowPosterFlag(false);
    24482441            invalidateCachedTime();
    24492442            setAutoplayEventPlaybackState(AutoplayEventPlaybackState::StartedWithoutUserGesture);
     
    24542447            setAutoplayEventPlaybackState(AutoplayEventPlaybackState::PreventedAutoplay);
    24552448        }
    2456 
    2457         shouldUpdateDisplayState = true;
    24582449    }
    24592450
     
    24682459        setAutoplayEventPlaybackState(AutoplayEventPlaybackState::PreventedAutoplay);
    24692460    }
    2470 
    2471     if (shouldUpdateDisplayState)
    2472         updateDisplayState();
    24732461
    24742462    updatePlayState();
     
    28952883
    28962884    // 1 - Set the media element's show poster flag to false.
    2897     setDisplayMode(Video);
     2885    setShowPosterFlag(false);
    28982886
    28992887    // 2 - If the media element's readyState is HAVE_NOTHING, abort these steps.
     
    29942982    // poster display), or 2) if there is a pending fast seek, or 3) if this seek is not an exact seek
    29952983    SeekType thisSeekType = (negativeTolerance == MediaTime::zeroTime() && positiveTolerance == MediaTime::zeroTime()) ? Precise : Fast;
    2996     if (!noSeekRequired && time == now && thisSeekType == Precise && m_pendingSeekType != Fast && displayMode() != Poster)
     2984    if (!noSeekRequired && time == now && thisSeekType == Precise && m_pendingSeekType != Fast && !showPosterFlag())
    29972985        noSeekRequired = true;
    29982986
     
    34753463    if (m_paused) {
    34763464        m_paused = false;
     3465        setShowPosterFlag(false);
    34773466        invalidateCachedTime();
    34783467
     
    49404929{
    49414930    beginProcessingMediaPlayerCallback();
    4942     updateDisplayState();
    49434931    if (auto* renderer = this->renderer())
    49444932        renderer->repaint();
     
    50655053}
    50665054
    5067 void HTMLMediaElement::mediaPlayerFirstVideoFrameAvailable()
    5068 {
    5069     INFO_LOG(LOGIDENTIFIER, "current display mode = ", (int)displayMode());
    5070 
    5071     beginProcessingMediaPlayerCallback();
    5072     if (displayMode() == PosterWaitingForVideo) {
    5073         setDisplayMode(Video);
    5074         mediaPlayerRenderingModeChanged();
    5075     }
    5076     endProcessingMediaPlayerCallback();
    5077 }
    5078 
    50795055void HTMLMediaElement::mediaPlayerCharacteristicChanged()
    50805056{
     
    50885064#endif
    50895065
    5090     if (potentiallyPlaying() && displayMode() == PosterWaitingForVideo) {
    5091         setDisplayMode(Video);
     5066    if (potentiallyPlaying())
    50925067        mediaPlayerRenderingModeChanged();
    5093     }
    50945068
    50955069    updateRenderer();
     
    53325306        schedulePlaybackControlsManagerUpdate();
    53335307
    5334         setDisplayMode(Video);
    53355308        invalidateCachedTime();
    53365309
     
    54695442
    54705443    // 4 - If the media element's readyState attribute has a value equal to HAVE_NOTHING, set the
    5471     // element's networkState attribute to the NETWORK_EMPTY value and queue a task to fire a
    5472     // simple event named emptied at the element. Otherwise, set the element's networkState
    5473     // attribute to the NETWORK_IDLE value.
     5444    // element's networkState attribute to the NETWORK_EMPTY value, set the element's show poster
     5445    // flag to true, and fire an event named emptied at the element.
    54745446    if (m_readyState == HAVE_NOTHING) {
    54755447        m_networkState = NETWORK_EMPTY;
     5448        setShowPosterFlag(true);
    54765449        scheduleEvent(eventNames().emptiedEvent);
    54775450    }
  • trunk/Source/WebCore/html/HTMLMediaElement.h

    r261004 r261341  
    600600    void didMoveToNewDocument(Document& oldDocument, Document& newDocument) override;
    601601
    602     enum DisplayMode { Unknown, None, Poster, PosterWaitingForVideo, Video };
    603     DisplayMode displayMode() const { return m_displayMode; }
    604     virtual void setDisplayMode(DisplayMode mode) { m_displayMode = mode; }
    605    
    606602    bool isMediaElement() const final { return true; }
    607603
     
    615611
    616612    void scheduleEvent(const AtomString&);
     613
     614    bool showPosterFlag() const { return m_showPoster; }
     615    void setShowPosterFlag(bool flag) { m_showPoster = flag; }
    617616
    618617private:
     
    644643    void visibilityStateChanged() final;
    645644
    646     virtual void updateDisplayState() { }
    647    
    648645    void setReadyState(MediaPlayer::ReadyState);
    649646    void setNetworkState(MediaPlayer::NetworkState);
     
    671668    void mediaEngineWasUpdated();
    672669
    673     void mediaPlayerFirstVideoFrameAvailable() final;
    674670    void mediaPlayerCharacteristicChanged() final;
    675671
     
    10351031    MediaPlayer::Preload m_preload { Preload::Auto };
    10361032
    1037     DisplayMode m_displayMode { Unknown };
    1038 
    10391033    // Counter incremented while processing a callback from the media player, so we can avoid
    10401034    // calling the media engine recursively.
     
    11141108    bool m_waitingToEnterFullscreen : 1;
    11151109
     1110    bool m_showPoster : 1;
     1111
    11161112#if ENABLE(VIDEO_TRACK)
    11171113    bool m_tracksAreReady : 1;
  • trunk/Source/WebCore/html/HTMLVideoElement.cpp

    r260259 r261341  
    103103    HTMLMediaElement::didAttachRenderers();
    104104
    105     updateDisplayState();
    106105    if (shouldDisplayPosterImage()) {
    107106        if (!m_imageLoader)
     
    133132{
    134133    if (name == posterAttr) {
    135         // Force a poster recalc by setting m_displayMode to Unknown directly before calling updateDisplayState.
    136         HTMLMediaElement::setDisplayMode(Unknown);
    137         updateDisplayState();
    138 
    139134        if (shouldDisplayPosterImage()) {
    140135            if (!m_imageLoader)
     
    142137            m_imageLoader->updateFromElementIgnoringPreviousError();
    143138        } else {
    144             if (auto* renderer = this->renderer())
     139            if (auto* renderer = this->renderer()) {
    145140                renderer->imageResource().setCachedImage(nullptr);
     141                renderer->updateFromElement();
     142            }
    146143        }
    147144    }
     
    162159#endif
    163160    }
    164 
    165161}
    166162
     
    252248}
    253249
    254 void HTMLVideoElement::setDisplayMode(DisplayMode mode)
    255 {
    256     DisplayMode oldMode = displayMode();
    257     URL poster = posterImageURL();
    258 
    259     if (!poster.isEmpty()) {
    260         // We have a poster path, but only show it until the user triggers display by playing or seeking and the
    261         // media engine has something to display.
    262         if (mode == Video) {
    263             if (oldMode != Video && player())
    264                 player()->prepareForRendering();
    265             if (!hasAvailableVideoFrame())
    266                 mode = PosterWaitingForVideo;
    267         }
    268     } else if (oldMode != Video && player())
    269         player()->prepareForRendering();
    270 
    271     HTMLMediaElement::setDisplayMode(mode);
    272 
    273     if (auto* renderer = this->renderer()) {
    274         if (displayMode() != oldMode)
    275             renderer->updateFromElement();
    276     }
    277 }
    278 
    279 void HTMLVideoElement::updateDisplayState()
    280 {
     250bool HTMLVideoElement::shouldDisplayPosterImage() const
     251{
     252    if (!showPosterFlag())
     253        return false;
     254
    281255    if (posterImageURL().isEmpty())
    282         setDisplayMode(Video);
    283     else if (displayMode() < Poster)
    284         setDisplayMode(Poster);
     256        return false;
     257
     258    auto* renderer = this->renderer();
     259    if (renderer && renderer->failedToLoadPosterImage())
     260        return false;
     261
     262    return true;
     263}
     264
     265void HTMLVideoElement::mediaPlayerFirstVideoFrameAvailable()
     266{
     267    INFO_LOG(LOGIDENTIFIER, "m_showPoster = ", showPosterFlag());
     268
     269    if (showPosterFlag())
     270        return;
     271
     272    invalidateStyleAndLayerComposition();
     273
     274    if (auto player = this->player())
     275        player->prepareForRendering();
     276
     277    if (auto* renderer = this->renderer())
     278        renderer->updateFromElement();
    285279}
    286280
  • trunk/Source/WebCore/html/HTMLVideoElement.h

    r260259 r261341  
    7777    bool copyVideoTextureToPlatformTexture(GraphicsContextGLOpenGL*, PlatformGLObject texture, GCGLenum target, GCGLint level, GCGLenum internalFormat, GCGLenum format, GCGLenum type, bool premultiplyAlpha, bool flipY);
    7878
    79     bool shouldDisplayPosterImage() const { return displayMode() == Poster || displayMode() == PosterWaitingForVideo; }
     79    WEBCORE_EXPORT bool shouldDisplayPosterImage() const;
    8080
    8181    URL posterImageURL() const;
     
    123123    const AtomString& imageSourceURL() const final;
    124124
     125    void didMoveToNewDocument(Document& oldDocument, Document& newDocument) final;
     126
    125127    bool hasAvailableVideoFrame() const;
    126     void updateDisplayState() final;
    127     void didMoveToNewDocument(Document& oldDocument, Document& newDocument) final;
    128     void setDisplayMode(DisplayMode) final;
     128    void mediaPlayerFirstVideoFrameAvailable() final;
    129129
    130130    PlatformMediaSession::MediaType presentationType() const final { return PlatformMediaSession::MediaType::Video; }
  • trunk/Source/WebCore/rendering/RenderVideo.cpp

    r260851 r261341  
    180180}
    181181
     182bool RenderVideo::failedToLoadPosterImage() const
     183{
     184    return imageResource().errorOccurred();
     185}
     186
    182187void RenderVideo::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    183188{
  • trunk/Source/WebCore/rendering/RenderVideo.h

    r228908 r261341  
    5151
    5252    bool shouldDisplayVideo() const;
     53    bool failedToLoadPosterImage() const;
    5354
    5455    void updateFromElement() final;
  • trunk/Source/WebCore/testing/Internals.cpp

    r261336 r261341  
    43344334}
    43354335
     4336ExceptionOr<bool> Internals::elementShouldDisplayPosterImage(HTMLVideoElement& element) const
     4337{
     4338#if ENABLE(VIDEO)
     4339    return element.shouldDisplayPosterImage();
     4340#else
     4341    UNUSED_PARAM(element);
     4342    return Exception { InvalidAccessError };
     4343#endif
     4344}
    43364345
    43374346#if ENABLE(WIRELESS_PLAYBACK_TARGET)
  • trunk/Source/WebCore/testing/Internals.h

    r261296 r261341  
    865865    ExceptionOr<MediaUsageState> mediaUsageState(HTMLMediaElement&) const;
    866866
     867    ExceptionOr<bool> elementShouldDisplayPosterImage(HTMLVideoElement&) const;
     868
    867869#if ENABLE(VIDEO)
    868870    using PlaybackControlsPurpose = MediaElementSession::PlaybackControlsPurpose;
  • trunk/Source/WebCore/testing/Internals.idl

    r261296 r261341  
    841841
    842842    [Conditional=VIDEO, MayThrowException] MediaUsageState mediaUsageState(HTMLMediaElement element);
     843    [Conditional=VIDEO, MayThrowException] boolean elementShouldDisplayPosterImage(HTMLVideoElement element);
    843844
    844845    DOMString ongoingLoadsDescriptions();
Note: See TracChangeset for help on using the changeset viewer.