Commit cf0b4687 authored by liberato's avatar liberato Committed by Commit bot

Repaint media controls when network state changes.

Cause any change in network state in HTMLMediaElement to repaint the media
controls, since they rely on it silently during painting.

BUG=545704

Review URL: https://codereview.chromium.org/1417683004

Cr-Commit-Position: refs/heads/master@{#357153}
parent c54fdd33
<!DOCTYPE html>
<style>
/* restrict to just the play button, so the slider doesn't mismatch */
audio {
width: 40px;
height: 40px;
}
</style>
<script src="../resources/run-after-layout-and-paint.js"></script>
<script src=media-file.js></script>
<script>
testRunner.waitUntilDone();
function test() {
var src = findMediaFile("audio", "content/empty");
document.getElementById("audio1").src = src;
runAfterLayoutAndPaint(function() {
testRunner.notifyDone();
});
}
</script>
<body onload="test()">
<audio controls></audio>
<audio id="audio1" controls></audio>
<p>Test that network state transitions paint audio controls properly.</p>
</body>
<!DOCTYPE html>
<style>
/* restrict to just the play button, so the slider doesn't mismatch */
audio {
width: 40px;
height: 40px;
}
</style>
<script src="../resources/run-after-layout-and-paint.js"></script>
<script src=media-file.js></script>
<audio controls></audio>
<audio controls></audio>
<p>Test that network state transitions paint audio controls properly.</p>
<script>
testRunner.waitUntilDone();
var audios = document.querySelectorAll("audio");
var src = findMediaFile("audio", "content/empty");
runAfterLayoutAndPaint(function() {
window.internals.setMediaElementNetworkState(audios[0], 0);
window.internals.setMediaElementNetworkState(audios[1], 0);
// These will cause the play buttons to become enabled, and should
// also cause a repaint.
window.internals.setMediaElementNetworkState(audios[1], 2);
testRunner.notifyDone();
});
</script>
......@@ -754,7 +754,7 @@ void HTMLMediaElement::prepareForLoad()
scheduleEvent(EventTypeNames::emptied);
// 4.2 - If a fetching process is in progress for the media element, the user agent should stop it.
m_networkState = NETWORK_EMPTY;
setNetworkState(NETWORK_EMPTY);
// 4.3 - Forget the media element's media-resource-specific tracks.
forgetResourceSpecificTracks();
......@@ -797,7 +797,7 @@ void HTMLMediaElement::prepareForLoad()
// The resource selection algorithm
// 1 - Set the networkState to NETWORK_NO_SOURCE
m_networkState = NETWORK_NO_SOURCE;
setNetworkState(NETWORK_NO_SOURCE);
// 2 - Asynchronously await a stable state.
......@@ -854,7 +854,7 @@ void HTMLMediaElement::selectMediaResource()
// synchronous section ends.
m_loadState = WaitingForSource;
setShouldDelayLoadEvent(false);
m_networkState = NETWORK_EMPTY;
setNetworkState(NETWORK_EMPTY);
updateDisplayState();
WTF_LOG(Media, "HTMLMediaElement::selectMediaResource(%p), nothing to load", this);
......@@ -865,7 +865,7 @@ void HTMLMediaElement::selectMediaResource()
// 4 - Set the media element's delaying-the-load-event flag to true (this delays the load event),
// and set its networkState to NETWORK_LOADING.
setShouldDelayLoadEvent(true);
m_networkState = NETWORK_LOADING;
setNetworkState(NETWORK_LOADING);
// 5 - Queue a task to fire a simple event named loadstart at the media element.
scheduleEvent(EventTypeNames::loadstart);
......@@ -931,7 +931,7 @@ void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType, c
}
// The resource fetch algorithm
m_networkState = NETWORK_LOADING;
setNetworkState(NETWORK_LOADING);
// Set m_currentSrc *before* changing to the cache url, the fact that we are loading from the app
// cache is an internal detail not exposed through the media element API.
......@@ -1103,7 +1103,7 @@ void HTMLMediaElement::executeDeferredLoad()
// delays the load event again, in case it hasn't been fired yet).
setShouldDelayLoadEvent(true);
// 7. Set the networkState to NETWORK_LOADING.
m_networkState = NETWORK_LOADING;
setNetworkState(NETWORK_LOADING);
startProgressEventTimer();
......@@ -1238,7 +1238,7 @@ void HTMLMediaElement::waitForSourceChange()
m_loadState = WaitingForSource;
// 6.17 - Waiting: Set the element's networkState attribute to the NETWORK_NO_SOURCE value
m_networkState = NETWORK_NO_SOURCE;
setNetworkState(NETWORK_NO_SOURCE);
// 6.18 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
setShouldDelayLoadEvent(false);
......@@ -1269,7 +1269,7 @@ void HTMLMediaElement::noneSupported()
forgetResourceSpecificTracks();
// 6.3 - Set the element's networkState attribute to the NETWORK_NO_SOURCE value.
m_networkState = NETWORK_NO_SOURCE;
setNetworkState(NETWORK_NO_SOURCE);
// 7 - Queue a task to fire a simple event named error at the media element.
scheduleEvent(EventTypeNames::error);
......@@ -1305,7 +1305,7 @@ void HTMLMediaElement::mediaEngineError(MediaError* err)
scheduleEvent(EventTypeNames::error);
// 4 - Set the element's networkState attribute to the NETWORK_IDLE value.
m_networkState = NETWORK_IDLE;
setNetworkState(NETWORK_IDLE);
// 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
setShouldDelayLoadEvent(false);
......@@ -1379,7 +1379,7 @@ void HTMLMediaElement::setNetworkState(WebMediaPlayer::NetworkState state)
if (state == WebMediaPlayer::NetworkStateEmpty) {
// Just update the cached state and leave, we can't do anything.
m_networkState = NETWORK_EMPTY;
setNetworkState(NETWORK_EMPTY);
return;
}
......@@ -1395,14 +1395,14 @@ void HTMLMediaElement::setNetworkState(WebMediaPlayer::NetworkState state)
changeNetworkStateFromLoadingToIdle();
setShouldDelayLoadEvent(false);
} else {
m_networkState = NETWORK_IDLE;
setNetworkState(NETWORK_IDLE);
}
}
if (state == WebMediaPlayer::NetworkStateLoading) {
if (m_networkState < NETWORK_LOADING || m_networkState == NETWORK_NO_SOURCE)
startProgressEventTimer();
m_networkState = NETWORK_LOADING;
setNetworkState(NETWORK_LOADING);
m_completelyLoaded = false;
}
......@@ -1422,7 +1422,7 @@ void HTMLMediaElement::changeNetworkStateFromLoadingToIdle()
if (webMediaPlayer() && webMediaPlayer()->didLoadingProgress())
scheduleEvent(EventTypeNames::progress);
scheduleEvent(EventTypeNames::suspend);
m_networkState = NETWORK_IDLE;
setNetworkState(NETWORK_IDLE);
}
void HTMLMediaElement::readyStateChanged()
......@@ -2659,7 +2659,7 @@ void HTMLMediaElement::sourceWasAdded(HTMLSourceElement* source)
setShouldDelayLoadEvent(true);
// 24. Set the networkState back to NETWORK_LOADING.
m_networkState = NETWORK_LOADING;
setNetworkState(NETWORK_LOADING);
// 25. Jump back to the find next candidate step above.
m_nextChildNodeToConsider = source;
......@@ -3003,10 +3003,10 @@ void HTMLMediaElement::userCancelledLoad()
// simple event named emptied at the element. Otherwise, set the element's networkState
// attribute to the NETWORK_IDLE value.
if (readyState == HAVE_NOTHING) {
m_networkState = NETWORK_EMPTY;
setNetworkState(NETWORK_EMPTY);
scheduleEvent(EventTypeNames::emptied);
} else {
m_networkState = NETWORK_IDLE;
setNetworkState(NETWORK_IDLE);
}
// 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
......@@ -3584,6 +3584,15 @@ void HTMLMediaElement::setInitialPlayWithoutUserGestures(bool value)
m_initialPlayWithoutUserGesture = value;
}
void HTMLMediaElement::setNetworkState(NetworkState state)
{
if (m_networkState != state) {
m_networkState = state;
if (MediaControls* controls = mediaControls())
controls->networkStateChanged();
}
}
#if ENABLE(WEB_AUDIO)
void HTMLMediaElement::clearWeakMembers(Visitor* visitor)
{
......
......@@ -442,6 +442,8 @@ private:
void removeUserGestureRequirement();
void setInitialPlayWithoutUserGestures(bool);
void setNetworkState(NetworkState);
void audioTracksTimerFired(Timer<HTMLMediaElement>*);
Timer<HTMLMediaElement> m_loadTimer;
......
......@@ -414,8 +414,7 @@ void MediaControls::updateVolume()
{
m_muteButton->updateDisplayType();
// Invalidate the mute button because it paints differently according to volume.
if (LayoutObject* layoutObject = m_muteButton->layoutObject())
layoutObject->setShouldDoFullPaintInvalidation();
invalidate(m_muteButton);
if (mediaElement().muted())
m_volumeSlider->setVolume(0);
......@@ -441,8 +440,7 @@ void MediaControls::updateVolume()
}
// Invalidate the volume slider because it paints differently according to volume.
if (LayoutObject* layoutObject = m_volumeSlider->layoutObject())
layoutObject->setShouldDoFullPaintInvalidation();
invalidate(m_volumeSlider);
}
void MediaControls::changedClosedCaptionsVisibility()
......@@ -708,6 +706,25 @@ void MediaControls::setAllowHiddenVolumeControls(bool allow)
updateVolume();
}
void MediaControls::invalidate(Element* element)
{
if (!element)
return;
if (LayoutObject* layoutObject = element->layoutObject())
layoutObject->setShouldDoFullPaintInvalidation();
}
void MediaControls::networkStateChanged()
{
invalidate(m_playButton);
invalidate(m_overlayPlayButton);
invalidate(m_muteButton);
invalidate(m_fullScreenButton);
invalidate(m_timeline);
invalidate(m_volumeSlider);
}
DEFINE_TRACE(MediaControls)
{
visitor->trace(m_mediaElement);
......
......@@ -82,9 +82,14 @@ public:
// Notify us that our controls enclosure has changed width.
void notifyPanelWidthChanged(const LayoutUnit& newWidth);
// Notify us that the media element's network state has changed.
void networkStateChanged();
DECLARE_VIRTUAL_TRACE();
private:
void invalidate(Element*);
class BatchedControlUpdate;
explicit MediaControls(HTMLMediaElement&);
......
......@@ -2561,4 +2561,12 @@ double Internals::monotonicTimeToZeroBasedDocumentTime(double platformTime, Exce
return document->loader()->timing().monotonicTimeToZeroBasedDocumentTime(platformTime);
}
void Internals::setMediaElementNetworkState(HTMLMediaElement* mediaElement, int32_t state)
{
ASSERT(mediaElement);
ASSERT(state >= HTMLMediaElement::NetworkState::NETWORK_EMPTY);
ASSERT(state <= HTMLMediaElement::NetworkState::NETWORK_NO_SOURCE);
mediaElement->setNetworkState(static_cast<WebMediaPlayer::NetworkState>(state));
}
} // namespace blink
......@@ -395,6 +395,9 @@ public:
// Translate given platform monotonic time in seconds to high resolution
// document time in seconds
double monotonicTimeToZeroBasedDocumentTime(double, ExceptionState&);
void setMediaElementNetworkState(HTMLMediaElement*, int32_t state);
private:
explicit Internals(ScriptState*);
Document* contextDocument() const;
......
......@@ -357,4 +357,6 @@
void forceRestrictIFramePermissions();
[RaisesException] double monotonicTimeToZeroBasedDocumentTime(double platformTime);
[TypeChecking=Interface] void setMediaElementNetworkState(HTMLMediaElement element, long state);
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment