summaryrefslogtreecommitdiffstats
path: root/WebCore/html/HTMLMediaElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/html/HTMLMediaElement.cpp')
-rw-r--r--WebCore/html/HTMLMediaElement.cpp324
1 files changed, 229 insertions, 95 deletions
diff --git a/WebCore/html/HTMLMediaElement.cpp b/WebCore/html/HTMLMediaElement.cpp
index f98200d..0136e08 100644
--- a/WebCore/html/HTMLMediaElement.cpp
+++ b/WebCore/html/HTMLMediaElement.cpp
@@ -28,6 +28,9 @@
#if ENABLE(VIDEO)
#include "HTMLMediaElement.h"
+#include "ClientRect.h"
+#include "ClientRectList.h"
+#include "ChromeClient.h"
#include "CSSHelper.h"
#include "CSSPropertyNames.h"
#include "CSSValueKeywords.h"
@@ -38,6 +41,8 @@
#include "ExceptionCode.h"
#include "Frame.h"
#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
+#include "FrameView.h"
#include "HTMLDocument.h"
#include "HTMLNames.h"
#include "HTMLSourceElement.h"
@@ -52,6 +57,7 @@
#include "Page.h"
#include "ProgressEvent.h"
#include "RenderVideo.h"
+#include "RenderView.h"
#include "ScriptEventListener.h"
#include "TimeRanges.h"
#include <limits>
@@ -110,6 +116,7 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* doc)
, m_sentEndEvent(false)
, m_pausedInternal(false)
, m_sendProgressEvents(true)
+ , m_isFullscreen(false)
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
, m_needWidgetUpdate(false)
#endif
@@ -178,6 +185,8 @@ void HTMLMediaElement::parseMappedAttribute(MappedAttribute* attr)
setAttributeEventListener(eventNames().loadeddataEvent, createAttributeEventListener(this, attr));
else if (attrName == onloadedmetadataAttr)
setAttributeEventListener(eventNames().loadedmetadataEvent, createAttributeEventListener(this, attr));
+ else if (attrName == onloadendAttr)
+ setAttributeEventListener(eventNames().loadendEvent, createAttributeEventListener(this, attr));
else if (attrName == onloadstartAttr)
setAttributeEventListener(eventNames().loadstartEvent, createAttributeEventListener(this, attr));
else if (attrName == onpauseAttr)
@@ -238,6 +247,12 @@ void HTMLMediaElement::insertedIntoDocument()
scheduleLoad();
}
+void HTMLMediaElement::willRemove()
+{
+ if (m_isFullscreen)
+ exitFullscreen();
+ HTMLElement::willRemove();
+}
void HTMLMediaElement::removedFromDocument()
{
if (m_networkState > NETWORK_EMPTY)
@@ -269,6 +284,15 @@ void HTMLMediaElement::recalcStyle(StyleChange change)
void HTMLMediaElement::scheduleLoad()
{
+ if (m_loadTimer.isActive())
+ return;
+ prepareForLoad();
+ m_loadTimer.startOneShot(0);
+}
+
+void HTMLMediaElement::scheduleNextSourceChild()
+{
+ // Schedule the timer to try the next <source> element WITHOUT resetting state ala prepareForLoad.
m_loadTimer.startOneShot(0);
}
@@ -408,17 +432,15 @@ void HTMLMediaElement::load(ExceptionCode& ec)
{
if (m_restrictions & RequireUserGestureForLoadRestriction && !processingUserGesture())
ec = INVALID_STATE_ERR;
- else
+ else {
+ prepareForLoad();
loadInternal();
+ }
}
-void HTMLMediaElement::loadInternal()
+void HTMLMediaElement::prepareForLoad()
{
- // 1 - If the load() method for this element is already being invoked, then abort these steps.
- if (m_processingLoad)
- return;
- m_processingLoad = true;
-
+ // Perform the cleanup required for the resource load algorithm to run.
stopPeriodicTimers();
m_loadTimer.stop();
m_sentStalledEvent = false;
@@ -430,21 +452,34 @@ void HTMLMediaElement::loadInternal()
// 3 - If there are any tasks from the media element's media element event task source in
// one of the task queues, then remove those tasks.
cancelPendingEventsAndCallbacks();
+}
+
+void HTMLMediaElement::loadInternal()
+{
+ // 1 - If the load() method for this element is already being invoked, then abort these steps.
+ if (m_processingLoad)
+ return;
+ m_processingLoad = true;
+
+ // Steps 2 and 3 were done in prepareForLoad()
- // 4 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, set the
- // error attribute to a new MediaError object whose code attribute is set to MEDIA_ERR_ABORTED,
- // and fire a progress event called abort at the media element.
+ // 4 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, set
+ // the error attribute to a new MediaError object whose code attribute is set to
+ // MEDIA_ERR_ABORTED, fire a progress event called abort at the media element, in the
+ // context of the fetching process that is in progress for the element, and fire a progress
+ // event called loadend at the media element, in the context of the same fetching process.
if (m_networkState == NETWORK_LOADING || m_networkState == NETWORK_IDLE) {
m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
-
- // fire synchronous 'abort'
+
+ // fire synchronous 'abort' and 'loadend'
bool totalKnown = m_player && m_player->totalBytesKnown();
unsigned loaded = m_player ? m_player->bytesLoaded() : 0;
unsigned total = m_player ? m_player->totalBytes() : 0;
- dispatchProgressEvent(eventNames().abortEvent, totalKnown, loaded, total);
+ dispatchEvent(ProgressEvent::create(eventNames().abortEvent, totalKnown, loaded, total));
+ dispatchEvent(ProgressEvent::create(eventNames().loadendEvent, totalKnown, loaded, total));
}
-
- // 5
+
+ // 5
m_error = 0;
m_autoplaying = true;
m_playedTimeRanges = TimeRanges::create();
@@ -452,7 +487,7 @@ void HTMLMediaElement::loadInternal()
// 6
setPlaybackRate(defaultPlaybackRate());
-
+
// 7
if (m_networkState != NETWORK_EMPTY) {
m_networkState = NETWORK_EMPTY;
@@ -464,9 +499,9 @@ void HTMLMediaElement::loadInternal()
m_playing = false;
m_player->seek(0);
}
- dispatchEvent(eventNames().emptiedEvent, false, true);
+ dispatchEvent(Event::create(eventNames().emptiedEvent, false, true));
}
-
+
selectMediaResource();
m_processingLoad = false;
}
@@ -530,9 +565,20 @@ void HTMLMediaElement::loadNextSourceChild()
loadResource(mediaURL, contentType);
}
-void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType)
+void HTMLMediaElement::loadResource(const KURL& initialURL, ContentType& contentType)
{
- ASSERT(isSafeToLoadURL(url, Complain));
+ ASSERT(isSafeToLoadURL(initialURL, Complain));
+
+ Frame* frame = document()->frame();
+ if (!frame)
+ return;
+ FrameLoader* loader = frame->loader();
+ if (!loader)
+ return;
+
+ KURL url(initialURL);
+ if (!loader->willLoadMediaElementURL(url))
+ return;
// The resource fetch algorithm
m_networkState = NETWORK_LOADING;
@@ -555,13 +601,11 @@ void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType)
m_player->load(m_currentSrc, contentType);
-#if PLATFORM(ANDROID)
if (isVideo() && m_player->canLoadPoster()) {
KURL posterUrl = static_cast<HTMLVideoElement*>(this)->poster();
if (!posterUrl.isEmpty())
m_player->setPoster(posterUrl);
}
-#endif
if (renderer())
renderer()->updateFromElement();
@@ -572,8 +616,8 @@ bool HTMLMediaElement::isSafeToLoadURL(const KURL& url, InvalidSourceAction acti
Frame* frame = document()->frame();
FrameLoader* loader = frame ? frame->loader() : 0;
- // don't allow remote to local urls
- if (!loader || !loader->canLoad(url, String(), document())) {
+ // don't allow remote to local urls, and check with the frame loader client.
+ if (!loader || !SecurityOrigin::canLoad(url, String(), document())) {
if (actionIfInvalid == Complain)
FrameLoader::reportLocalLoadFailed(frame, url.string());
return false;
@@ -599,22 +643,29 @@ void HTMLMediaElement::noneSupported()
m_loadState = WaitingForSource;
m_currentSourceNode = 0;
- // 3 - Reaching this step indicates that either the URL failed to resolve, or the media
- // resource failed to load. Set the error attribute to a new MediaError object whose
+ // 4 - Reaching this step indicates that either the URL failed to resolve, or the media
+ // resource failed to load. Set the error attribute to a new MediaError object whose
// code attribute is set to MEDIA_ERR_SRC_NOT_SUPPORTED.
m_error = MediaError::create(MediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
- // 4- Set the element's networkState attribute to the NETWORK_NO_SOURCE value.
+ // 5 - Set the element's networkState attribute to the NETWORK_NO_SOURCE value.
m_networkState = NETWORK_NO_SOURCE;
- // 5 - Queue a task to fire a progress event called error at the media element.
- scheduleProgressEvent(eventNames().errorEvent);
+ // 6 - Queue a task to fire a progress event called error at the media element, in
+ // the context of the fetching process that was used to try to obtain the media
+ // resource in the resource fetch algorithm.
+ scheduleProgressEvent(eventNames().errorEvent);
- // 6 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
+ // 7 - Queue a task to fire a progress event called loadend at the media element, in
+ // the context of the fetching process that was used to try to obtain the media
+ // resource in the resource fetch algorithm.
+ scheduleProgressEvent(eventNames().loadendEvent);
+
+ // 8 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
m_delayingTheLoadEvent = false;
- // Abort these steps. Until the load() method is invoked, the element won't attempt to load another resource.
-
+ // 9 -Abort these steps. Until the load() method is invoked, the element won't attempt to load another resource.
+
if (isVideo())
static_cast<HTMLVideoElement*>(this)->updatePosterImage();
if (renderer())
@@ -631,20 +682,24 @@ void HTMLMediaElement::mediaEngineError(PassRefPtr<MediaError> err)
// set to MEDIA_ERR_NETWORK/MEDIA_ERR_DECODE.
m_error = err;
- // 3 - Queue a task to fire a progress event called error at the media element.
- scheduleProgressEvent(eventNames().errorEvent);
+ // 3 - Queue a task to fire a progress event called error at the media element, in
+ // the context of the fetching process started by this instance of this algorithm.
+ scheduleProgressEvent(eventNames().errorEvent);
+
+ // 4 - Queue a task to fire a progress event called loadend at the media element, in
+ // the context of the fetching process started by this instance of this algorithm.
+ scheduleProgressEvent(eventNames().loadendEvent);
- // 3 - Set the element's networkState attribute to the NETWORK_EMPTY value and queue a
+ // 5 - Set the element's networkState attribute to the NETWORK_EMPTY value and queue a
// task to fire a simple event called emptied at the element.
m_networkState = NETWORK_EMPTY;
scheduleEvent(eventNames().emptiedEvent);
- // 4 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
+ // 6 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
m_delayingTheLoadEvent = false;
- // 5 - Abort the overall resource selection algorithm.
+ // 7 - Abort the overall resource selection algorithm.
m_currentSourceNode = 0;
-
}
void HTMLMediaElement::cancelPendingEventsAndCallbacks()
@@ -680,7 +735,7 @@ void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement) {
m_currentSourceNode->scheduleErrorEvent();
if (havePotentialSourceChild())
- scheduleLoad();
+ scheduleNextSourceChild();
return;
}
@@ -718,6 +773,10 @@ void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
if (oldState < NETWORK_LOADED || oldState == NETWORK_NO_SOURCE) {
m_progressEventTimer.stop();
+ // Schedule one last progress event so we guarantee that at least one is fired
+ // for files that load very quickly.
+ scheduleProgressEvent(eventNames().progressEvent);
+
// Check to see if readyState changes need to be dealt with before sending the
// 'load' event so we report 'canplaythrough' first. This is necessary because a
// media engine reports readyState and networkState changes separately
@@ -725,7 +784,8 @@ void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
if (static_cast<ReadyState>(currentState) != m_readyState)
setReadyState(currentState);
- scheduleProgressEvent(eventNames().loadEvent);
+ scheduleProgressEvent(eventNames().loadEvent);
+ scheduleProgressEvent(eventNames().loadendEvent);
}
}
}
@@ -750,21 +810,29 @@ void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
if (m_readyState == oldState)
return;
- if (m_readyState >= HAVE_CURRENT_DATA)
- m_seeking = false;
-
if (m_networkState == NETWORK_EMPTY)
return;
- if (m_seeking && m_readyState < HAVE_CURRENT_DATA) {
+ if (m_seeking) {
+ // 4.8.10.10, step 8
+ if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA)
+ scheduleEvent(eventNames().waitingEvent);
+
// 4.8.10.10, step 9
- scheduleEvent(eventNames().seekingEvent);
- }
+ if (m_readyState < HAVE_CURRENT_DATA) {
+ if (oldState >= HAVE_CURRENT_DATA)
+ scheduleEvent(eventNames().seekingEvent);
+ } else {
+ // 4.8.10.10 step 12 & 13.
+ finishSeek();
+ }
- if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA) {
- // 4.8.10.9
- scheduleTimeupdateEvent(false);
- scheduleEvent(eventNames().waitingEvent);
+ } else {
+ if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA) {
+ // 4.8.10.9
+ scheduleTimeupdateEvent(false);
+ scheduleEvent(eventNames().waitingEvent);
+ }
}
if (m_readyState >= HAVE_METADATA && oldState < HAVE_METADATA) {
@@ -857,6 +925,13 @@ void HTMLMediaElement::returnToRealtime()
setCurrentTime(maxTimeSeekable(), e);
}
+void HTMLMediaElement::addPlayedRange(float start, float end)
+{
+ if (!m_playedTimeRanges)
+ m_playedTimeRanges = TimeRanges::create();
+ m_playedTimeRanges->add(start, end);
+}
+
bool HTMLMediaElement::supportsSave() const
{
return m_player ? m_player->supportsSave() : false;
@@ -892,7 +967,7 @@ void HTMLMediaElement::seek(float time, ExceptionCode& ec)
// 5
if (m_playing) {
if (m_lastSeekTime < now)
- m_playedTimeRanges->add(m_lastSeekTime, now);
+ addPlayedRange(m_lastSeekTime, now);
}
m_lastSeekTime = time;
@@ -909,6 +984,15 @@ void HTMLMediaElement::seek(float time, ExceptionCode& ec)
m_sentEndEvent = false;
}
+void HTMLMediaElement::finishSeek()
+{
+ // 4.8.10.10 Seeking step 12
+ m_seeking = false;
+
+ // 4.8.10.10 Seeking step 13
+ scheduleEvent(eventNames().seekedEvent);
+}
+
HTMLMediaElement::ReadyState HTMLMediaElement::readyState() const
{
return m_readyState;
@@ -919,6 +1003,11 @@ MediaPlayer::MovieLoadType HTMLMediaElement::movieLoadType() const
return m_player ? m_player->movieLoadType() : MediaPlayer::Unknown;
}
+bool HTMLMediaElement::hasAudio() const
+{
+ return m_player ? m_player->hasAudio() : false;
+}
+
bool HTMLMediaElement::seeking() const
{
return m_seeking;
@@ -1234,7 +1323,19 @@ float HTMLMediaElement::percentLoaded() const
if (!m_player)
return 0;
float duration = m_player->duration();
- return duration ? m_player->maxTimeBuffered() / duration : 0;
+
+ if (!duration || isinf(duration))
+ return 0;
+
+ float buffered = 0;
+ RefPtr<TimeRanges> timeRanges = m_player->buffered();
+ for (unsigned i = 0; i < timeRanges->length(); ++i) {
+ ExceptionCode ignoredException;
+ float start = timeRanges->start(i, ignoredException);
+ float end = timeRanges->end(i, ignoredException);
+ buffered += end - start;
+ }
+ return buffered / duration;
}
bool HTMLMediaElement::havePotentialSourceChild()
@@ -1306,9 +1407,9 @@ void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
{
beginProcessingMediaPlayerCallback();
+ // 4.8.10.10 step 12 & 13. Needed if no ReadyState change is associated with the seek.
if (m_readyState >= HAVE_CURRENT_DATA && m_seeking) {
- scheduleEvent(eventNames().seekedEvent);
- m_seeking = false;
+ finishSeek();
}
float now = currentTime();
@@ -1413,23 +1514,22 @@ GraphicsLayer* HTMLMediaElement::mediaPlayerGraphicsLayer(MediaPlayer*)
PassRefPtr<TimeRanges> HTMLMediaElement::buffered() const
{
- // FIXME real ranges support
- if (!m_player || !m_player->maxTimeBuffered())
+ if (!m_player)
return TimeRanges::create();
- return TimeRanges::create(0, m_player->maxTimeBuffered());
+ return m_player->buffered();
}
-PassRefPtr<TimeRanges> HTMLMediaElement::played() const
+PassRefPtr<TimeRanges> HTMLMediaElement::played()
{
- if (!m_playedTimeRanges) {
- // We are not yet loaded
- return TimeRanges::create();
- }
if (m_playing) {
float time = currentTime();
- if (m_lastSeekTime < time)
- m_playedTimeRanges->add(m_lastSeekTime, time);
+ if (time > m_lastSeekTime)
+ addPlayedRange(m_lastSeekTime, time);
}
+
+ if (!m_playedTimeRanges)
+ m_playedTimeRanges = TimeRanges::create();
+
return m_playedTimeRanges->copy();
}
@@ -1443,15 +1543,13 @@ PassRefPtr<TimeRanges> HTMLMediaElement::seekable() const
bool HTMLMediaElement::potentiallyPlaying() const
{
- return !paused() && m_readyState >= HAVE_FUTURE_DATA && !endedPlayback() && !stoppedDueToErrors() && !pausedForUserInteraction();
+ return m_readyState >= HAVE_FUTURE_DATA && couldPlayIfEnoughData();
}
-#if PLATFORM(ANDROID)
bool HTMLMediaElement::couldPlayIfEnoughData() const
{
return !paused() && !endedPlayback() && !stoppedDueToErrors() && !pausedForUserInteraction();
}
-#endif
bool HTMLMediaElement::endedPlayback() const
{
@@ -1532,13 +1630,10 @@ void HTMLMediaElement::updatePlayState()
m_playbackProgressTimer.stop();
m_playing = false;
float time = currentTime();
- if (m_lastSeekTime < time)
- m_playedTimeRanges->add(m_lastSeekTime, time);
-#if PLATFORM(ANDROID)
- } else if (couldPlayIfEnoughData() && playerPaused) {
+ if (time > m_lastSeekTime)
+ addPlayedRange(m_lastSeekTime, time);
+ } else if (couldPlayIfEnoughData() && playerPaused)
m_player->prepareToPlay();
-#endif
- }
if (renderer())
renderer()->updateFromElement();
@@ -1558,35 +1653,44 @@ void HTMLMediaElement::stopPeriodicTimers()
void HTMLMediaElement::userCancelledLoad()
{
- if (m_networkState != NETWORK_EMPTY) {
+ if (m_networkState == NETWORK_EMPTY || m_networkState >= NETWORK_LOADED)
+ return;
- // If the media data fetching process is aborted by the user:
+ // If the media data fetching process is aborted by the user:
- // 1 - The user agent should cancel the fetching process.
+ // 1 - The user agent should cancel the fetching process.
#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
- m_player.clear();
+ m_player.clear();
#endif
- stopPeriodicTimers();
+ stopPeriodicTimers();
- // 2 - Set the error attribute to a new MediaError object whose code attribute is set to MEDIA_ERR_ABORT.
- m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
+ // 2 - Set the error attribute to a new MediaError object whose code attribute is set to MEDIA_ERR_ABORT.
+ m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
- // 3 - Queue a task to fire a progress event called abort at the media element.
- scheduleProgressEvent(eventNames().abortEvent);
-
- // 4 - If the media element's readyState attribute has a value equal to HAVE_NOTHING, set the
- // element's networkState attribute to the NETWORK_EMPTY value and queue a task to fire a
- // simple event called emptied at the element. Otherwise, set set the element's networkState
- // attribute to the NETWORK_IDLE value.
- if (m_networkState >= NETWORK_LOADING) {
- m_networkState = NETWORK_EMPTY;
- m_readyState = HAVE_NOTHING;
- scheduleEvent(eventNames().emptiedEvent);
- }
+ // 3 - Queue a task to fire a progress event called abort at the media element, in the context
+ // of the fetching process started by this instance of this algorithm.
+ scheduleProgressEvent(eventNames().abortEvent);
- // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
- m_delayingTheLoadEvent = false;
+ // 4 - Queue a task to fire a progress event called loadend at the media element, in the context
+ // of the fetching process started by this instance of this algorithm.
+ scheduleProgressEvent(eventNames().loadendEvent);
+
+ // 5 - If the media element's readyState attribute has a value equal to HAVE_NOTHING, set the
+ // element's networkState attribute to the NETWORK_EMPTY value and queue a task to fire a
+ // simple event called emptied at the element. Otherwise, set set the element's networkState
+ // attribute to the NETWORK_IDLE value.
+ if (m_readyState == HAVE_NOTHING) {
+ m_networkState = NETWORK_EMPTY;
+ scheduleEvent(eventNames().emptiedEvent);
}
+ else
+ m_networkState = NETWORK_IDLE;
+
+ // 6 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
+ m_delayingTheLoadEvent = false;
+
+ // 7 - Abort the overall resource selection algorithm.
+ m_currentSourceNode = 0;
}
void HTMLMediaElement::documentWillBecomeInactive()
@@ -1617,7 +1721,7 @@ void HTMLMediaElement::documentDidBecomeActive()
ExceptionCode ec;
load(ec);
}
-
+
if (renderer())
renderer()->updateFromElement();
}
@@ -1627,6 +1731,14 @@ void HTMLMediaElement::mediaVolumeDidChange()
updateVolume();
}
+const IntRect HTMLMediaElement::screenRect()
+{
+ IntRect elementRect;
+ if (renderer())
+ elementRect = renderer()->view()->frameView()->contentsToScreen(renderer()->absoluteBoundingBoxRect());
+ return elementRect;
+}
+
void HTMLMediaElement::defaultEventHandler(Event* event)
{
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
@@ -1699,6 +1811,28 @@ void HTMLMediaElement::finishParsingChildren()
#endif
+void HTMLMediaElement::enterFullscreen()
+{
+ ASSERT(!m_isFullscreen);
+ if (!renderer())
+ return;
+ if (document() && document()->page())
+ document()->page()->chrome()->client()->enterFullscreenForNode(this);
+ m_isFullscreen = true;
+}
+
+void HTMLMediaElement::exitFullscreen()
+{
+ ASSERT(m_isFullscreen);
+ if (document() && document()->page())
+ document()->page()->chrome()->client()->exitFullscreenForNode(this);
+ m_isFullscreen = false;
+}
+
+PlatformMedia HTMLMediaElement::platformMedia() const
+{
+ return m_player ? m_player->platformMedia() : NoPlatformMedia;
+}
}
#endif