WebCore/html/HTMLMediaElement.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  * 1. Redistributions of source code must retain the above copyright
       
     8  *    notice, this list of conditions and the following disclaimer.
       
     9  * 2. Redistributions in binary form must reproduce the above copyright
       
    10  *    notice, this list of conditions and the following disclaimer in the
       
    11  *    documentation and/or other materials provided with the distribution.
       
    12  *
       
    13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
       
    14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
    15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
       
    17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
       
    21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
       
    24  */
       
    25 
       
    26 #include "config.h"
       
    27 
       
    28 #if ENABLE(VIDEO)
       
    29 #include "HTMLMediaElement.h"
       
    30 
       
    31 #include "Attribute.h"
       
    32 #include "CSSHelper.h"
       
    33 #include "CSSPropertyNames.h"
       
    34 #include "CSSValueKeywords.h"
       
    35 #include "Chrome.h"
       
    36 #include "ChromeClient.h"
       
    37 #include "ClientRect.h"
       
    38 #include "ClientRectList.h"
       
    39 #include "ContentType.h"
       
    40 #include "DocLoader.h"
       
    41 #include "Event.h"
       
    42 #include "EventNames.h"
       
    43 #include "ExceptionCode.h"
       
    44 #include "Frame.h"
       
    45 #include "FrameLoader.h"
       
    46 #include "FrameLoaderClient.h"
       
    47 #include "FrameView.h"
       
    48 #include "HTMLDocument.h"
       
    49 #include "HTMLNames.h"
       
    50 #include "HTMLSourceElement.h"
       
    51 #include "HTMLVideoElement.h"
       
    52 #include "MIMETypeRegistry.h"
       
    53 #include "MediaDocument.h"
       
    54 #include "MediaError.h"
       
    55 #include "MediaList.h"
       
    56 #include "MediaPlayer.h"
       
    57 #include "MediaQueryEvaluator.h"
       
    58 #include "Page.h"
       
    59 #include "RenderVideo.h"
       
    60 #include "RenderView.h"
       
    61 #include "ScriptEventListener.h"
       
    62 #include "Settings.h"
       
    63 #include "TimeRanges.h"
       
    64 #include <limits>
       
    65 #include <wtf/CurrentTime.h>
       
    66 #include <wtf/MathExtras.h>
       
    67 
       
    68 #if USE(ACCELERATED_COMPOSITING)
       
    69 #include "RenderView.h"
       
    70 #include "RenderLayerCompositor.h"
       
    71 #endif
       
    72 
       
    73 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
    74 #include "RenderEmbeddedObject.h"
       
    75 #include "Widget.h"
       
    76 #endif
       
    77 
       
    78 using namespace std;
       
    79 
       
    80 namespace WebCore {
       
    81 
       
    82 using namespace HTMLNames;
       
    83 
       
    84 HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* doc)
       
    85     : HTMLElement(tagName, doc)
       
    86     , m_loadTimer(this, &HTMLMediaElement::loadTimerFired)
       
    87     , m_asyncEventTimer(this, &HTMLMediaElement::asyncEventTimerFired)
       
    88     , m_progressEventTimer(this, &HTMLMediaElement::progressEventTimerFired)
       
    89     , m_playbackProgressTimer(this, &HTMLMediaElement::playbackProgressTimerFired)
       
    90     , m_playedTimeRanges()
       
    91     , m_playbackRate(1.0f)
       
    92     , m_defaultPlaybackRate(1.0f)
       
    93     , m_webkitPreservesPitch(true)
       
    94     , m_networkState(NETWORK_EMPTY)
       
    95     , m_readyState(HAVE_NOTHING)
       
    96     , m_readyStateMaximum(HAVE_NOTHING)
       
    97     , m_volume(1.0f)
       
    98     , m_lastSeekTime(0)
       
    99     , m_previousProgress(0)
       
   100     , m_previousProgressTime(numeric_limits<double>::max())
       
   101     , m_lastTimeUpdateEventWallTime(0)
       
   102     , m_lastTimeUpdateEventMovieTime(numeric_limits<float>::max())
       
   103     , m_loadState(WaitingForSource)
       
   104     , m_currentSourceNode(0)
       
   105     , m_player(0)
       
   106 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
   107     , m_proxyWidget(0)
       
   108 #endif
       
   109     , m_restrictions(NoRestrictions)
       
   110     , m_preload(MediaPlayer::Auto)
       
   111     , m_playing(false)
       
   112     , m_processingMediaPlayerCallback(0)
       
   113     , m_isWaitingUntilMediaCanStart(false)
       
   114     , m_processingLoad(false)
       
   115     , m_delayingTheLoadEvent(false)
       
   116     , m_haveFiredLoadedData(false)
       
   117     , m_inActiveDocument(true)
       
   118     , m_autoplaying(true)
       
   119     , m_muted(false)
       
   120     , m_paused(true)
       
   121     , m_seeking(false)
       
   122     , m_sentStalledEvent(false)
       
   123     , m_sentEndEvent(false)
       
   124     , m_pausedInternal(false)
       
   125     , m_sendProgressEvents(true)
       
   126     , m_isFullscreen(false)
       
   127     , m_closedCaptionsVisible(false)
       
   128 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
   129     , m_needWidgetUpdate(false)
       
   130 #endif
       
   131     , m_dispatchingCanPlayEvent(false)
       
   132     , m_loadInitiatedByUserGesture(false)
       
   133     , m_completelyLoaded(false)
       
   134 {
       
   135     document()->registerForDocumentActivationCallbacks(this);
       
   136     document()->registerForMediaVolumeCallbacks(this);
       
   137 }
       
   138 
       
   139 HTMLMediaElement::~HTMLMediaElement()
       
   140 {
       
   141     if (m_isWaitingUntilMediaCanStart)
       
   142         document()->removeMediaCanStartListener(this);
       
   143     document()->unregisterForDocumentActivationCallbacks(this);
       
   144     document()->unregisterForMediaVolumeCallbacks(this);
       
   145 }
       
   146 
       
   147 void HTMLMediaElement::willMoveToNewOwnerDocument()
       
   148 {
       
   149     if (m_isWaitingUntilMediaCanStart)
       
   150         document()->removeMediaCanStartListener(this);
       
   151     document()->unregisterForDocumentActivationCallbacks(this);
       
   152     document()->unregisterForMediaVolumeCallbacks(this);
       
   153     HTMLElement::willMoveToNewOwnerDocument();
       
   154 }
       
   155 
       
   156 void HTMLMediaElement::didMoveToNewOwnerDocument()
       
   157 {
       
   158     if (m_isWaitingUntilMediaCanStart)
       
   159         document()->addMediaCanStartListener(this);
       
   160     document()->registerForDocumentActivationCallbacks(this);
       
   161     document()->registerForMediaVolumeCallbacks(this);
       
   162     HTMLElement::didMoveToNewOwnerDocument();
       
   163 }
       
   164 
       
   165 
       
   166 bool HTMLMediaElement::checkDTD(const Node* newChild)
       
   167 {
       
   168     return newChild->hasTagName(sourceTag) || HTMLElement::checkDTD(newChild);
       
   169 }
       
   170 
       
   171 void HTMLMediaElement::attributeChanged(Attribute* attr, bool preserveDecls)
       
   172 {
       
   173     HTMLElement::attributeChanged(attr, preserveDecls);
       
   174 
       
   175     const QualifiedName& attrName = attr->name();
       
   176     if (attrName == srcAttr) {
       
   177         // Trigger a reload, as long as the 'src' attribute is present.
       
   178         if (!getAttribute(srcAttr).isEmpty())
       
   179             scheduleLoad();
       
   180     }
       
   181     else if (attrName == controlsAttr) {
       
   182 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
   183         if (!isVideo() && attached() && (controls() != (renderer() != 0))) {
       
   184             detach();
       
   185             attach();
       
   186         }
       
   187         if (renderer())
       
   188             renderer()->updateFromElement();
       
   189 #else
       
   190         if (m_player)
       
   191             m_player->setControls(controls());
       
   192 #endif
       
   193     }
       
   194 }
       
   195 
       
   196 void HTMLMediaElement::parseMappedAttribute(Attribute* attr)
       
   197 {
       
   198     const QualifiedName& attrName = attr->name();
       
   199 
       
   200     if (attrName == preloadAttr) {
       
   201         String value = attr->value();
       
   202 
       
   203         if (equalIgnoringCase(value, "none"))
       
   204             m_preload = MediaPlayer::None;
       
   205         else if (equalIgnoringCase(value, "metadata"))
       
   206             m_preload = MediaPlayer::MetaData;
       
   207         else {
       
   208             // The spec does not define an "invalid value default" but "auto" is suggested as the
       
   209             // "missing value default", so use it for everything except "none" and "metadata"
       
   210             m_preload = MediaPlayer::Auto;
       
   211         }
       
   212 
       
   213         // The attribute must be ignored if the autoplay attribute is present
       
   214         if (!autoplay() && m_player)
       
   215             m_player->setPreload(m_preload);
       
   216 
       
   217     } else if (attrName == onabortAttr)
       
   218         setAttributeEventListener(eventNames().abortEvent, createAttributeEventListener(this, attr));
       
   219     else if (attrName == onbeforeloadAttr)
       
   220         setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, attr));
       
   221     else if (attrName == oncanplayAttr)
       
   222         setAttributeEventListener(eventNames().canplayEvent, createAttributeEventListener(this, attr));
       
   223     else if (attrName == oncanplaythroughAttr)
       
   224         setAttributeEventListener(eventNames().canplaythroughEvent, createAttributeEventListener(this, attr));
       
   225     else if (attrName == ondurationchangeAttr)
       
   226         setAttributeEventListener(eventNames().durationchangeEvent, createAttributeEventListener(this, attr));
       
   227     else if (attrName == onemptiedAttr)
       
   228         setAttributeEventListener(eventNames().emptiedEvent, createAttributeEventListener(this, attr));
       
   229     else if (attrName == onendedAttr)
       
   230         setAttributeEventListener(eventNames().endedEvent, createAttributeEventListener(this, attr));
       
   231     else if (attrName == onerrorAttr)
       
   232         setAttributeEventListener(eventNames().errorEvent, createAttributeEventListener(this, attr));
       
   233     else if (attrName == onloadeddataAttr)
       
   234         setAttributeEventListener(eventNames().loadeddataEvent, createAttributeEventListener(this, attr));
       
   235     else if (attrName == onloadedmetadataAttr)
       
   236         setAttributeEventListener(eventNames().loadedmetadataEvent, createAttributeEventListener(this, attr));
       
   237     else if (attrName == onloadstartAttr)
       
   238         setAttributeEventListener(eventNames().loadstartEvent, createAttributeEventListener(this, attr));
       
   239     else if (attrName == onpauseAttr)
       
   240         setAttributeEventListener(eventNames().pauseEvent, createAttributeEventListener(this, attr));
       
   241     else if (attrName == onplayAttr)
       
   242         setAttributeEventListener(eventNames().playEvent, createAttributeEventListener(this, attr));
       
   243     else if (attrName == onplayingAttr)
       
   244         setAttributeEventListener(eventNames().playingEvent, createAttributeEventListener(this, attr));
       
   245     else if (attrName == onprogressAttr)
       
   246         setAttributeEventListener(eventNames().progressEvent, createAttributeEventListener(this, attr));
       
   247     else if (attrName == onratechangeAttr)
       
   248         setAttributeEventListener(eventNames().ratechangeEvent, createAttributeEventListener(this, attr));
       
   249     else if (attrName == onseekedAttr)
       
   250         setAttributeEventListener(eventNames().seekedEvent, createAttributeEventListener(this, attr));
       
   251     else if (attrName == onseekingAttr)
       
   252         setAttributeEventListener(eventNames().seekingEvent, createAttributeEventListener(this, attr));
       
   253     else if (attrName == onstalledAttr)
       
   254         setAttributeEventListener(eventNames().stalledEvent, createAttributeEventListener(this, attr));
       
   255     else if (attrName == onsuspendAttr)
       
   256         setAttributeEventListener(eventNames().suspendEvent, createAttributeEventListener(this, attr));
       
   257     else if (attrName == ontimeupdateAttr)
       
   258         setAttributeEventListener(eventNames().timeupdateEvent, createAttributeEventListener(this, attr));
       
   259     else if (attrName == onvolumechangeAttr)
       
   260         setAttributeEventListener(eventNames().volumechangeEvent, createAttributeEventListener(this, attr));
       
   261     else if (attrName == onwaitingAttr)
       
   262         setAttributeEventListener(eventNames().waitingEvent, createAttributeEventListener(this, attr));
       
   263     else if (attrName == onwebkitbeginfullscreenAttr)
       
   264         setAttributeEventListener(eventNames().webkitbeginfullscreenEvent, createAttributeEventListener(this, attr));
       
   265     else if (attrName == onwebkitendfullscreenAttr)
       
   266         setAttributeEventListener(eventNames().webkitendfullscreenEvent, createAttributeEventListener(this, attr));
       
   267     else
       
   268         HTMLElement::parseMappedAttribute(attr);
       
   269 }
       
   270 
       
   271 bool HTMLMediaElement::rendererIsNeeded(RenderStyle* style)
       
   272 {
       
   273 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
   274     UNUSED_PARAM(style);
       
   275     Frame* frame = document()->frame();
       
   276     if (!frame)
       
   277         return false;
       
   278 
       
   279     return true;
       
   280 #else
       
   281     return controls() ? HTMLElement::rendererIsNeeded(style) : false;
       
   282 #endif
       
   283 }
       
   284 
       
   285 RenderObject* HTMLMediaElement::createRenderer(RenderArena* arena, RenderStyle*)
       
   286 {
       
   287 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
   288     // Setup the renderer if we already have a proxy widget.
       
   289     RenderEmbeddedObject* mediaRenderer = new (arena) RenderEmbeddedObject(this);
       
   290     if (m_proxyWidget) {
       
   291         mediaRenderer->setWidget(m_proxyWidget);
       
   292 
       
   293         Frame* frame = document()->frame();
       
   294         FrameLoader* loader = frame ? frame->loader() : 0;
       
   295         if (loader)
       
   296             loader->showMediaPlayerProxyPlugin(m_proxyWidget.get());
       
   297     }
       
   298     return mediaRenderer;
       
   299 #else
       
   300     return new (arena) RenderMedia(this);
       
   301 #endif
       
   302 }
       
   303  
       
   304 void HTMLMediaElement::insertedIntoDocument()
       
   305 {
       
   306     HTMLElement::insertedIntoDocument();
       
   307     if (!src().isEmpty() && m_networkState == NETWORK_EMPTY)
       
   308         scheduleLoad();
       
   309 }
       
   310 
       
   311 void HTMLMediaElement::removedFromDocument()
       
   312 {
       
   313     if (m_networkState > NETWORK_EMPTY)
       
   314         pause(processingUserGesture());
       
   315     if (m_isFullscreen)
       
   316         exitFullscreen();
       
   317     HTMLElement::removedFromDocument();
       
   318 }
       
   319 
       
   320 void HTMLMediaElement::attach()
       
   321 {
       
   322     ASSERT(!attached());
       
   323 
       
   324 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
   325     m_needWidgetUpdate = true;
       
   326 #endif
       
   327 
       
   328     HTMLElement::attach();
       
   329 
       
   330     if (renderer())
       
   331         renderer()->updateFromElement();
       
   332 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
   333     else if (m_proxyWidget) {
       
   334         Frame* frame = document()->frame();
       
   335         FrameLoader* loader = frame ? frame->loader() : 0;
       
   336         if (loader)
       
   337             loader->hideMediaPlayerProxyPlugin(m_proxyWidget.get());
       
   338     }
       
   339 #endif
       
   340 }
       
   341 
       
   342 void HTMLMediaElement::recalcStyle(StyleChange change)
       
   343 {
       
   344     HTMLElement::recalcStyle(change);
       
   345 
       
   346     if (renderer())
       
   347         renderer()->updateFromElement();
       
   348 }
       
   349 
       
   350 void HTMLMediaElement::scheduleLoad()
       
   351 {
       
   352 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
   353     createMediaPlayerProxy();
       
   354 #endif
       
   355 
       
   356     if (m_loadTimer.isActive())
       
   357         return;
       
   358     prepareForLoad();
       
   359     m_loadTimer.startOneShot(0);
       
   360 }
       
   361 
       
   362 void HTMLMediaElement::scheduleNextSourceChild()
       
   363 {
       
   364     // Schedule the timer to try the next <source> element WITHOUT resetting state ala prepareForLoad.
       
   365     m_loadTimer.startOneShot(0);
       
   366 }
       
   367 
       
   368 void HTMLMediaElement::scheduleEvent(const AtomicString& eventName)
       
   369 {
       
   370     m_pendingEvents.append(Event::create(eventName, false, true));
       
   371     if (!m_asyncEventTimer.isActive())
       
   372         m_asyncEventTimer.startOneShot(0);
       
   373 }
       
   374 
       
   375 void HTMLMediaElement::asyncEventTimerFired(Timer<HTMLMediaElement>*)
       
   376 {
       
   377     Vector<RefPtr<Event> > pendingEvents;
       
   378     ExceptionCode ec = 0;
       
   379 
       
   380     m_pendingEvents.swap(pendingEvents);
       
   381     unsigned count = pendingEvents.size();
       
   382     for (unsigned ndx = 0; ndx < count; ++ndx) {
       
   383         if (pendingEvents[ndx]->type() == eventNames().canplayEvent) {
       
   384             m_dispatchingCanPlayEvent = true;
       
   385             dispatchEvent(pendingEvents[ndx].release(), ec);
       
   386             m_dispatchingCanPlayEvent = false;
       
   387         } else
       
   388             dispatchEvent(pendingEvents[ndx].release(), ec);
       
   389     }
       
   390 }
       
   391 
       
   392 void HTMLMediaElement::loadTimerFired(Timer<HTMLMediaElement>*)
       
   393 {
       
   394     if (m_loadState == LoadingFromSourceElement)
       
   395         loadNextSourceChild();
       
   396     else
       
   397         loadInternal();
       
   398 }
       
   399 
       
   400 static String serializeTimeOffset(float time)
       
   401 {
       
   402     String timeString = String::number(time);
       
   403     // FIXME serialize time offset values properly (format not specified yet)
       
   404     timeString.append("s");
       
   405     return timeString;
       
   406 }
       
   407 
       
   408 static float parseTimeOffset(const String& timeString, bool* ok = 0)
       
   409 {
       
   410     const UChar* characters = timeString.characters();
       
   411     unsigned length = timeString.length();
       
   412     
       
   413     if (length && characters[length - 1] == 's')
       
   414         length--;
       
   415     
       
   416     // FIXME parse time offset values (format not specified yet)
       
   417     float val = charactersToFloat(characters, length, ok);
       
   418     return val;
       
   419 }
       
   420 
       
   421 float HTMLMediaElement::getTimeOffsetAttribute(const QualifiedName& name, float valueOnError) const
       
   422 {
       
   423     bool ok;
       
   424     String timeString = getAttribute(name);
       
   425     float result = parseTimeOffset(timeString, &ok);
       
   426     if (ok)
       
   427         return result;
       
   428     return valueOnError;
       
   429 }
       
   430 
       
   431 void HTMLMediaElement::setTimeOffsetAttribute(const QualifiedName& name, float value)
       
   432 {
       
   433     setAttribute(name, serializeTimeOffset(value));
       
   434 }
       
   435 
       
   436 PassRefPtr<MediaError> HTMLMediaElement::error() const 
       
   437 {
       
   438     return m_error;
       
   439 }
       
   440 
       
   441 KURL HTMLMediaElement::src() const
       
   442 {
       
   443     return getNonEmptyURLAttribute(srcAttr);
       
   444 }
       
   445 
       
   446 void HTMLMediaElement::setSrc(const String& url)
       
   447 {
       
   448     setAttribute(srcAttr, url);
       
   449 }
       
   450 
       
   451 String HTMLMediaElement::currentSrc() const
       
   452 {
       
   453     return m_currentSrc;
       
   454 }
       
   455 
       
   456 HTMLMediaElement::NetworkState HTMLMediaElement::networkState() const
       
   457 {
       
   458     return m_networkState;
       
   459 }
       
   460 
       
   461 String HTMLMediaElement::canPlayType(const String& mimeType) const
       
   462 {
       
   463     MediaPlayer::SupportsType support = MediaPlayer::supportsType(ContentType(mimeType));
       
   464     String canPlay;
       
   465 
       
   466     // 4.8.10.3
       
   467     switch (support)
       
   468     {
       
   469         case MediaPlayer::IsNotSupported:
       
   470             canPlay = "";
       
   471             break;
       
   472         case MediaPlayer::MayBeSupported:
       
   473             canPlay = "maybe";
       
   474             break;
       
   475         case MediaPlayer::IsSupported:
       
   476             canPlay = "probably";
       
   477             break;
       
   478     }
       
   479     
       
   480     return canPlay;
       
   481 }
       
   482 
       
   483 void HTMLMediaElement::load(bool isUserGesture, ExceptionCode& ec)
       
   484 {
       
   485     if (m_restrictions & RequireUserGestureForLoadRestriction && !isUserGesture)
       
   486         ec = INVALID_STATE_ERR;
       
   487     else {
       
   488         m_loadInitiatedByUserGesture = isUserGesture;
       
   489         prepareForLoad();
       
   490         loadInternal();
       
   491     }
       
   492 }
       
   493 
       
   494 void HTMLMediaElement::prepareForLoad()
       
   495 {
       
   496     // Perform the cleanup required for the resource load algorithm to run.
       
   497     stopPeriodicTimers();
       
   498     m_loadTimer.stop();
       
   499     m_sentStalledEvent = false;
       
   500     m_haveFiredLoadedData = false;
       
   501     m_completelyLoaded = false;
       
   502 
       
   503     // 1 - Abort any already-running instance of the resource selection algorithm for this element.
       
   504     m_currentSourceNode = 0;
       
   505 
       
   506     // 2 - If there are any tasks from the media element's media element event task source in 
       
   507     // one of the task queues, then remove those tasks.
       
   508     cancelPendingEventsAndCallbacks();
       
   509 
       
   510     // 3 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, queue
       
   511     // a task to fire a simple event named abort at the media element.
       
   512     if (m_networkState == NETWORK_LOADING || m_networkState == NETWORK_IDLE)
       
   513         scheduleEvent(eventNames().abortEvent);
       
   514 
       
   515 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
   516     m_player = MediaPlayer::create(this);
       
   517 #else
       
   518     createMediaPlayerProxy();
       
   519 #endif
       
   520 
       
   521     // 4 - If the media element's networkState is not set to NETWORK_EMPTY, then run these substeps
       
   522     if (m_networkState != NETWORK_EMPTY) {
       
   523         m_networkState = NETWORK_EMPTY;
       
   524         m_readyState = HAVE_NOTHING;
       
   525         m_readyStateMaximum = HAVE_NOTHING;
       
   526         m_paused = true;
       
   527         m_seeking = false;
       
   528         scheduleEvent(eventNames().emptiedEvent);
       
   529     }
       
   530 
       
   531     // 5 - Set the playbackRate attribute to the value of the defaultPlaybackRate attribute.
       
   532     setPlaybackRate(defaultPlaybackRate());
       
   533 
       
   534     // 6 - Set the error attribute to null and the autoplaying flag to true.
       
   535     m_error = 0;
       
   536     m_autoplaying = true;
       
   537 
       
   538     m_playedTimeRanges = TimeRanges::create();
       
   539     m_lastSeekTime = 0;
       
   540     m_closedCaptionsVisible = false;
       
   541 
       
   542 }
       
   543 
       
   544 void HTMLMediaElement::loadInternal()
       
   545 {
       
   546     // If we can't start a load right away, start it later.
       
   547     Page* page = document()->page();
       
   548     if (page && !page->canStartMedia()) {
       
   549         if (m_isWaitingUntilMediaCanStart)
       
   550             return;
       
   551         document()->addMediaCanStartListener(this);
       
   552         m_isWaitingUntilMediaCanStart = true;
       
   553         return;
       
   554     }
       
   555 
       
   556     // Steps 1 - 6 were done in prepareForLoad
       
   557 
       
   558     // 7 - Invoke the media element's resource selection algorithm.
       
   559     selectMediaResource();
       
   560     m_processingLoad = false;
       
   561 }
       
   562 
       
   563 void HTMLMediaElement::selectMediaResource()
       
   564 {
       
   565     enum Mode { attribute, children };
       
   566     Mode mode = attribute;
       
   567 
       
   568     // 1 - Set the networkState to NETWORK_NO_SOURCE
       
   569     m_networkState = NETWORK_NO_SOURCE;
       
   570 
       
   571     // 2 - Asynchronously await a stable state.
       
   572 
       
   573     // 3 - ... the media element has neither a src attribute ...
       
   574     if (!hasAttribute(srcAttr)) {
       
   575         // ... nor a source element child: ...
       
   576         Node* node;
       
   577         for (node = firstChild(); node; node = node->nextSibling()) {
       
   578             if (node->hasTagName(sourceTag))
       
   579                 break;
       
   580         }
       
   581 
       
   582         if (!node) {
       
   583             m_loadState = WaitingForSource;
       
   584 
       
   585             // ... set the networkState to NETWORK_EMPTY, and abort these steps
       
   586             m_networkState = NETWORK_EMPTY;
       
   587             ASSERT(!m_delayingTheLoadEvent);
       
   588             return;
       
   589         }
       
   590 
       
   591         mode = children;
       
   592     }
       
   593 
       
   594     // 4
       
   595     m_delayingTheLoadEvent = true;
       
   596     m_networkState = NETWORK_LOADING;
       
   597 
       
   598     // 5
       
   599     scheduleEvent(eventNames().loadstartEvent);
       
   600 
       
   601     // 6 - If mode is attribute, then run these substeps
       
   602     if (mode == attribute) {
       
   603         // If the src attribute's value is the empty string ... jump down to the failed step below
       
   604         KURL mediaURL = getNonEmptyURLAttribute(srcAttr);
       
   605         if (mediaURL.isEmpty()) {
       
   606             noneSupported();
       
   607             return;
       
   608         }
       
   609 
       
   610         if (isSafeToLoadURL(mediaURL, Complain) && dispatchBeforeLoadEvent(mediaURL.string())) {
       
   611             ContentType contentType("");
       
   612             m_loadState = LoadingFromSrcAttr;
       
   613             loadResource(mediaURL, contentType);
       
   614         } else 
       
   615             noneSupported();
       
   616 
       
   617         return;
       
   618     }
       
   619 
       
   620     // Otherwise, the source elements will be used
       
   621     m_currentSourceNode = 0;
       
   622     loadNextSourceChild();
       
   623 }
       
   624 
       
   625 void HTMLMediaElement::loadNextSourceChild()
       
   626 {
       
   627     ContentType contentType("");
       
   628     KURL mediaURL = selectNextSourceChild(&contentType, Complain);
       
   629     if (!mediaURL.isValid()) {
       
   630         waitForSourceChange();
       
   631         return;
       
   632     }
       
   633 
       
   634 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
   635     // Recreate the media player for the new url
       
   636     m_player = MediaPlayer::create(this);
       
   637 #endif
       
   638 
       
   639     m_loadState = LoadingFromSourceElement;
       
   640     loadResource(mediaURL, contentType);
       
   641 }
       
   642 
       
   643 void HTMLMediaElement::loadResource(const KURL& initialURL, ContentType& contentType)
       
   644 {
       
   645     ASSERT(isSafeToLoadURL(initialURL, Complain));
       
   646 
       
   647     Frame* frame = document()->frame();
       
   648     if (!frame)
       
   649         return;
       
   650     FrameLoader* loader = frame->loader();
       
   651     if (!loader)
       
   652         return;
       
   653 
       
   654     KURL url(initialURL);
       
   655     if (!loader->willLoadMediaElementURL(url))
       
   656         return;
       
   657 
       
   658     // The resource fetch algorithm 
       
   659     m_networkState = NETWORK_LOADING;
       
   660 
       
   661     m_currentSrc = url;
       
   662 
       
   663     if (m_sendProgressEvents) 
       
   664         startProgressEventTimer();
       
   665 
       
   666     if (!autoplay())
       
   667         m_player->setPreload(m_preload);
       
   668     m_player->setPreservesPitch(m_webkitPreservesPitch);
       
   669     updateVolume();
       
   670 
       
   671     m_player->load(m_currentSrc, contentType);
       
   672 
       
   673     if (isVideo() && m_player->canLoadPoster()) {
       
   674         KURL posterUrl = poster();
       
   675         if (!posterUrl.isEmpty())
       
   676             m_player->setPoster(posterUrl);
       
   677     }
       
   678 
       
   679     if (renderer())
       
   680         renderer()->updateFromElement();
       
   681 }
       
   682 
       
   683 bool HTMLMediaElement::isSafeToLoadURL(const KURL& url, InvalidSourceAction actionIfInvalid)
       
   684 {
       
   685     if (!url.isValid())
       
   686         return false;
       
   687     
       
   688     Frame* frame = document()->frame();
       
   689     FrameLoader* loader = frame ? frame->loader() : 0;
       
   690 
       
   691     // don't allow remote to local urls, and check with the frame loader client.
       
   692     if (!loader || !SecurityOrigin::canLoad(url, String(), document())) {
       
   693         if (actionIfInvalid == Complain)
       
   694             FrameLoader::reportLocalLoadFailed(frame, url.string());
       
   695         return false;
       
   696     }
       
   697     
       
   698     return true;
       
   699 }
       
   700 
       
   701 void HTMLMediaElement::startProgressEventTimer()
       
   702 {
       
   703     if (m_progressEventTimer.isActive())
       
   704         return;
       
   705 
       
   706     m_previousProgressTime = WTF::currentTime();
       
   707     m_previousProgress = 0;
       
   708     // 350ms is not magic, it is in the spec!
       
   709     m_progressEventTimer.startRepeating(0.350);
       
   710 }
       
   711 
       
   712 void HTMLMediaElement::waitForSourceChange()
       
   713 {
       
   714     stopPeriodicTimers();
       
   715     m_loadState = WaitingForSource;
       
   716 
       
   717     // 6.17 - Waiting: Set the element's networkState attribute to the NETWORK_NO_SOURCE value
       
   718     m_networkState = NETWORK_NO_SOURCE;
       
   719 
       
   720     // 6.18 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
       
   721     m_delayingTheLoadEvent = false;
       
   722 }
       
   723 
       
   724 void HTMLMediaElement::noneSupported()
       
   725 {
       
   726     stopPeriodicTimers();
       
   727     m_loadState = WaitingForSource;
       
   728     m_currentSourceNode = 0;
       
   729 
       
   730     // 5 - Reaching this step indicates that either the URL failed to resolve, or the media
       
   731     // resource failed to load. Set the error attribute to a new MediaError object whose
       
   732     // code attribute is set to MEDIA_ERR_SRC_NOT_SUPPORTED.
       
   733     m_error = MediaError::create(MediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
       
   734 
       
   735     // 6 - Set the element's networkState attribute to the NETWORK_NO_SOURCE value.
       
   736     m_networkState = NETWORK_NO_SOURCE;
       
   737 
       
   738     // 7 - Queue a task to fire a progress event called error at the media element, in
       
   739     // the context of the fetching process that was used to try to obtain the media
       
   740     // resource in the resource fetch algorithm.
       
   741     scheduleEvent(eventNames().errorEvent);
       
   742 
       
   743     // 8 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
       
   744     m_delayingTheLoadEvent = false;
       
   745 
       
   746     // 9 -Abort these steps. Until the load() method is invoked, the element won't attempt to load another resource.
       
   747 
       
   748     updatePosterImage();
       
   749 
       
   750     if (renderer())
       
   751         renderer()->updateFromElement();
       
   752 }
       
   753 
       
   754 void HTMLMediaElement::mediaEngineError(PassRefPtr<MediaError> err)
       
   755 {
       
   756     // 1 - The user agent should cancel the fetching process.
       
   757     stopPeriodicTimers();
       
   758     m_loadState = WaitingForSource;
       
   759 
       
   760     // 2 - Set the error attribute to a new MediaError object whose code attribute is 
       
   761     // set to MEDIA_ERR_NETWORK/MEDIA_ERR_DECODE.
       
   762     m_error = err;
       
   763 
       
   764     // 3 - Queue a task to fire a progress event called error at the media element, in
       
   765     // the context of the fetching process started by this instance of this algorithm.
       
   766     scheduleEvent(eventNames().errorEvent);
       
   767 
       
   768     // 4 - Set the element's networkState attribute to the NETWORK_EMPTY value and queue a
       
   769     // task to fire a simple event called emptied at the element.
       
   770     m_networkState = NETWORK_EMPTY;
       
   771     scheduleEvent(eventNames().emptiedEvent);
       
   772 
       
   773     // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
       
   774     m_delayingTheLoadEvent = false;
       
   775 
       
   776     // 6 - Abort the overall resource selection algorithm.
       
   777     m_currentSourceNode = 0;
       
   778 }
       
   779 
       
   780 void HTMLMediaElement::cancelPendingEventsAndCallbacks()
       
   781 {
       
   782     m_pendingEvents.clear();
       
   783 
       
   784     for (Node* node = firstChild(); node; node = node->nextSibling()) {
       
   785         if (node->hasTagName(sourceTag))
       
   786             static_cast<HTMLSourceElement*>(node)->cancelPendingErrorEvent();
       
   787     }
       
   788 }
       
   789 
       
   790 Document* HTMLMediaElement::mediaPlayerOwningDocument()
       
   791 {
       
   792     Document* d = document();
       
   793     
       
   794     if (!d)
       
   795         d = ownerDocument();
       
   796     
       
   797     return d;
       
   798 }
       
   799 
       
   800 void HTMLMediaElement::mediaPlayerNetworkStateChanged(MediaPlayer*)
       
   801 {
       
   802     beginProcessingMediaPlayerCallback();
       
   803     setNetworkState(m_player->networkState());
       
   804     endProcessingMediaPlayerCallback();
       
   805 }
       
   806 
       
   807 void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
       
   808 {
       
   809     if (state == MediaPlayer::Empty) {
       
   810         // just update the cached state and leave, we can't do anything 
       
   811         m_networkState = NETWORK_EMPTY;
       
   812         return;
       
   813     }
       
   814 
       
   815     if (state == MediaPlayer::FormatError || state == MediaPlayer::NetworkError || state == MediaPlayer::DecodeError) {
       
   816         stopPeriodicTimers();
       
   817 
       
   818         // If we failed while trying to load a <source> element, the movie was never parsed, and there are more
       
   819         // <source> children, schedule the next one
       
   820         if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement) {
       
   821             m_currentSourceNode->scheduleErrorEvent();
       
   822             if (havePotentialSourceChild())
       
   823                 scheduleNextSourceChild();
       
   824             else
       
   825                 waitForSourceChange();
       
   826 
       
   827             return;
       
   828         }
       
   829 
       
   830         if (state == MediaPlayer::NetworkError)
       
   831             mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_NETWORK));
       
   832         else if (state == MediaPlayer::DecodeError)
       
   833             mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_DECODE));
       
   834         else if (state == MediaPlayer::FormatError && m_loadState == LoadingFromSrcAttr)
       
   835             noneSupported();
       
   836 
       
   837         updatePosterImage();
       
   838         return;
       
   839     }
       
   840 
       
   841     if (state == MediaPlayer::Idle) {
       
   842         if (m_networkState > NETWORK_IDLE) {
       
   843             m_progressEventTimer.stop();
       
   844             scheduleEvent(eventNames().suspendEvent);
       
   845         }
       
   846         m_networkState = NETWORK_IDLE;
       
   847     }
       
   848 
       
   849     if (state == MediaPlayer::Loading) {
       
   850         if (m_networkState < NETWORK_LOADING || m_networkState == NETWORK_NO_SOURCE)
       
   851             startProgressEventTimer();
       
   852         m_networkState = NETWORK_LOADING;
       
   853     }
       
   854 
       
   855     if (state == MediaPlayer::Loaded) {
       
   856         if (m_networkState != NETWORK_IDLE) {
       
   857             m_progressEventTimer.stop();
       
   858 
       
   859             // Schedule one last progress event so we guarantee that at least one is fired
       
   860             // for files that load very quickly.
       
   861             scheduleEvent(eventNames().progressEvent);
       
   862         }
       
   863         m_networkState = NETWORK_IDLE;
       
   864         m_completelyLoaded = true;
       
   865     }
       
   866 }
       
   867 
       
   868 void HTMLMediaElement::mediaPlayerReadyStateChanged(MediaPlayer*)
       
   869 {
       
   870     beginProcessingMediaPlayerCallback();
       
   871 
       
   872     setReadyState(m_player->readyState());
       
   873 
       
   874     endProcessingMediaPlayerCallback();
       
   875 }
       
   876 
       
   877 void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
       
   878 {
       
   879     // Set "wasPotentiallyPlaying" BEFORE updating m_readyState, potentiallyPlaying() uses it
       
   880     bool wasPotentiallyPlaying = potentiallyPlaying();
       
   881 
       
   882     ReadyState oldState = m_readyState;
       
   883     m_readyState = static_cast<ReadyState>(state);
       
   884 
       
   885     if (m_readyState == oldState)
       
   886         return;
       
   887     
       
   888     if (oldState > m_readyStateMaximum)
       
   889         m_readyStateMaximum = oldState;
       
   890 
       
   891     if (m_networkState == NETWORK_EMPTY)
       
   892         return;
       
   893 
       
   894     if (m_seeking) {
       
   895         // 4.8.10.10, step 8
       
   896         if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA)
       
   897             scheduleEvent(eventNames().waitingEvent);
       
   898 
       
   899         // 4.8.10.10, step 9
       
   900         if (m_readyState < HAVE_CURRENT_DATA) {
       
   901             if (oldState >= HAVE_CURRENT_DATA)
       
   902                 scheduleEvent(eventNames().seekingEvent);
       
   903         } else {
       
   904             // 4.8.10.10 step 12 & 13.
       
   905             finishSeek();
       
   906         }
       
   907 
       
   908     } else {
       
   909         if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA) {
       
   910             // 4.8.10.9
       
   911             scheduleTimeupdateEvent(false);
       
   912             scheduleEvent(eventNames().waitingEvent);
       
   913         }
       
   914     }
       
   915 
       
   916     if (m_readyState >= HAVE_METADATA && oldState < HAVE_METADATA) {
       
   917         scheduleEvent(eventNames().durationchangeEvent);
       
   918         scheduleEvent(eventNames().loadedmetadataEvent);
       
   919 
       
   920 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
   921         if (renderer() && renderer()->isVideo()) {
       
   922             toRenderVideo(renderer())->videoSizeChanged();
       
   923         }
       
   924 #endif        
       
   925         m_delayingTheLoadEvent = false;
       
   926         m_player->seek(0);
       
   927     }
       
   928 
       
   929     bool shouldUpdatePosterImage = false;
       
   930 
       
   931     // 4.8.10.7 says loadeddata is sent only when the new state *is* HAVE_CURRENT_DATA: "If the
       
   932     // previous ready state was HAVE_METADATA and the new ready state is HAVE_CURRENT_DATA", 
       
   933     // but the event table at the end of the spec says it is sent when: "readyState newly 
       
   934     // increased to HAVE_CURRENT_DATA  or greater for the first time"
       
   935     // We go with the later because it seems useful to count on getting this event
       
   936     if (m_readyState >= HAVE_CURRENT_DATA && oldState < HAVE_CURRENT_DATA && !m_haveFiredLoadedData) {
       
   937         m_haveFiredLoadedData = true;
       
   938         shouldUpdatePosterImage = true;
       
   939         scheduleEvent(eventNames().loadeddataEvent);
       
   940     }
       
   941 
       
   942     bool isPotentiallyPlaying = potentiallyPlaying();
       
   943     if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA) {
       
   944         scheduleEvent(eventNames().canplayEvent);
       
   945         if (isPotentiallyPlaying)
       
   946             scheduleEvent(eventNames().playingEvent);
       
   947         shouldUpdatePosterImage = true;
       
   948     }
       
   949 
       
   950     if (m_readyState == HAVE_ENOUGH_DATA && oldState < HAVE_ENOUGH_DATA) {
       
   951         if (oldState <= HAVE_CURRENT_DATA)
       
   952             scheduleEvent(eventNames().canplayEvent);
       
   953 
       
   954         scheduleEvent(eventNames().canplaythroughEvent);
       
   955 
       
   956         if (isPotentiallyPlaying && oldState <= HAVE_CURRENT_DATA)
       
   957             scheduleEvent(eventNames().playingEvent);
       
   958 
       
   959         if (m_autoplaying && m_paused && autoplay()) {
       
   960             m_paused = false;
       
   961             scheduleEvent(eventNames().playEvent);
       
   962             scheduleEvent(eventNames().playingEvent);
       
   963         }
       
   964 
       
   965         shouldUpdatePosterImage = true;
       
   966     }
       
   967 
       
   968     if (shouldUpdatePosterImage)
       
   969         updatePosterImage();
       
   970 
       
   971     updatePlayState();
       
   972 }
       
   973 
       
   974 void HTMLMediaElement::progressEventTimerFired(Timer<HTMLMediaElement>*)
       
   975 {
       
   976     ASSERT(m_player);
       
   977     if (m_networkState != NETWORK_LOADING)
       
   978         return;
       
   979 
       
   980     unsigned progress = m_player->bytesLoaded();
       
   981     double time = WTF::currentTime();
       
   982     double timedelta = time - m_previousProgressTime;
       
   983 
       
   984     if (progress == m_previousProgress) {
       
   985         if (timedelta > 3.0 && !m_sentStalledEvent) {
       
   986             scheduleEvent(eventNames().stalledEvent);
       
   987             m_sentStalledEvent = true;
       
   988         }
       
   989     } else {
       
   990         scheduleEvent(eventNames().progressEvent);
       
   991         m_previousProgress = progress;
       
   992         m_previousProgressTime = time;
       
   993         m_sentStalledEvent = false;
       
   994         if (renderer())
       
   995             renderer()->updateFromElement();
       
   996     }
       
   997 }
       
   998 
       
   999 void HTMLMediaElement::rewind(float timeDelta)
       
  1000 {
       
  1001     ExceptionCode e;
       
  1002     setCurrentTime(max(currentTime() - timeDelta, minTimeSeekable()), e);
       
  1003 }
       
  1004 
       
  1005 void HTMLMediaElement::returnToRealtime()
       
  1006 {
       
  1007     ExceptionCode e;
       
  1008     setCurrentTime(maxTimeSeekable(), e);
       
  1009 }  
       
  1010 
       
  1011 void HTMLMediaElement::addPlayedRange(float start, float end)
       
  1012 {
       
  1013     if (!m_playedTimeRanges)
       
  1014         m_playedTimeRanges = TimeRanges::create();
       
  1015     m_playedTimeRanges->add(start, end);
       
  1016 }  
       
  1017 
       
  1018 bool HTMLMediaElement::supportsSave() const
       
  1019 {
       
  1020     return m_player ? m_player->supportsSave() : false;
       
  1021 }
       
  1022     
       
  1023 void HTMLMediaElement::seek(float time, ExceptionCode& ec)
       
  1024 {
       
  1025     // 4.8.9.9 Seeking
       
  1026 
       
  1027     // 1 - If the media element's readyState is HAVE_NOTHING, then raise an INVALID_STATE_ERR exception.
       
  1028     if (m_readyState == HAVE_NOTHING || !m_player) {
       
  1029         ec = INVALID_STATE_ERR;
       
  1030         return;
       
  1031     }
       
  1032 
       
  1033     // Get the current time before setting m_seeking, m_lastSeekTime is returned once it is set.
       
  1034     float now = currentTime();
       
  1035 
       
  1036     // 3 - Set the seeking IDL attribute to true.
       
  1037     // The flag will be cleared when the engine tells is the time has actually changed
       
  1038     m_seeking = true;
       
  1039 
       
  1040     // 4 - Queue a task to fire a simple event named timeupdate at the element.
       
  1041     scheduleTimeupdateEvent(false);
       
  1042 
       
  1043     // 6 - If the new playback position is later than the end of the media resource, then let it be the end 
       
  1044     // of the media resource instead.
       
  1045     time = min(time, duration());
       
  1046 
       
  1047     // 7 - If the new playback position is less than the earliest possible position, let it be that position instead.
       
  1048     float earliestTime = m_player->startTime();
       
  1049     time = max(time, earliestTime);
       
  1050 
       
  1051     // 8 - If the (possibly now changed) new playback position is not in one of the ranges given in the 
       
  1052     // seekable attribute, then let it be the position in one of the ranges given in the seekable attribute 
       
  1053     // that is the nearest to the new playback position. ... If there are no ranges given in the seekable
       
  1054     // attribute then set the seeking IDL attribute to false and abort these steps.
       
  1055     RefPtr<TimeRanges> seekableRanges = seekable();
       
  1056     if (!seekableRanges->length() || time == now) {
       
  1057         m_seeking = false;
       
  1058         return;
       
  1059     }
       
  1060     time = seekableRanges->nearest(time);
       
  1061 
       
  1062     if (m_playing) {
       
  1063         if (m_lastSeekTime < now)
       
  1064             addPlayedRange(m_lastSeekTime, now);
       
  1065     }
       
  1066     m_lastSeekTime = time;
       
  1067     m_sentEndEvent = false;
       
  1068 
       
  1069     // 9 - Set the current playback position to the given new playback position
       
  1070     m_player->seek(time);
       
  1071 
       
  1072     // 10-15 are handled, if necessary, when the engine signals a readystate change.
       
  1073 
       
  1074 }
       
  1075 
       
  1076 void HTMLMediaElement::finishSeek()
       
  1077 {
       
  1078     // 4.8.10.10 Seeking step 12
       
  1079     m_seeking = false;
       
  1080 
       
  1081     // 4.8.10.10 Seeking step 13
       
  1082     scheduleEvent(eventNames().seekedEvent);
       
  1083 }
       
  1084 
       
  1085 HTMLMediaElement::ReadyState HTMLMediaElement::readyState() const
       
  1086 {
       
  1087     return m_readyState;
       
  1088 }
       
  1089 
       
  1090 MediaPlayer::MovieLoadType HTMLMediaElement::movieLoadType() const
       
  1091 {
       
  1092     return m_player ? m_player->movieLoadType() : MediaPlayer::Unknown;
       
  1093 }
       
  1094 
       
  1095 bool HTMLMediaElement::hasAudio() const
       
  1096 {
       
  1097     return m_player ? m_player->hasAudio() : false;
       
  1098 }
       
  1099 
       
  1100 bool HTMLMediaElement::seeking() const
       
  1101 {
       
  1102     return m_seeking;
       
  1103 }
       
  1104 
       
  1105 // playback state
       
  1106 float HTMLMediaElement::currentTime() const
       
  1107 {
       
  1108     if (!m_player)
       
  1109         return 0;
       
  1110     if (m_seeking)
       
  1111         return m_lastSeekTime;
       
  1112     return m_player->currentTime();
       
  1113 }
       
  1114 
       
  1115 void HTMLMediaElement::setCurrentTime(float time, ExceptionCode& ec)
       
  1116 {
       
  1117     seek(time, ec);
       
  1118 }
       
  1119 
       
  1120 float HTMLMediaElement::startTime() const
       
  1121 {
       
  1122     if (!m_player)
       
  1123         return 0;
       
  1124     return m_player->startTime();
       
  1125 }
       
  1126 
       
  1127 float HTMLMediaElement::duration() const
       
  1128 {
       
  1129     if (m_player && m_readyState >= HAVE_METADATA)
       
  1130         return m_player->duration();
       
  1131 
       
  1132     return numeric_limits<float>::quiet_NaN();
       
  1133 }
       
  1134 
       
  1135 bool HTMLMediaElement::paused() const
       
  1136 {
       
  1137     return m_paused;
       
  1138 }
       
  1139 
       
  1140 float HTMLMediaElement::defaultPlaybackRate() const
       
  1141 {
       
  1142     return m_defaultPlaybackRate;
       
  1143 }
       
  1144 
       
  1145 void HTMLMediaElement::setDefaultPlaybackRate(float rate)
       
  1146 {
       
  1147     if (m_defaultPlaybackRate != rate) {
       
  1148         m_defaultPlaybackRate = rate;
       
  1149         scheduleEvent(eventNames().ratechangeEvent);
       
  1150     }
       
  1151 }
       
  1152 
       
  1153 float HTMLMediaElement::playbackRate() const
       
  1154 {
       
  1155     return m_player ? m_player->rate() : 0;
       
  1156 }
       
  1157 
       
  1158 void HTMLMediaElement::setPlaybackRate(float rate)
       
  1159 {
       
  1160     if (m_playbackRate != rate) {
       
  1161         m_playbackRate = rate;
       
  1162         scheduleEvent(eventNames().ratechangeEvent);
       
  1163     }
       
  1164     if (m_player && potentiallyPlaying() && m_player->rate() != rate)
       
  1165         m_player->setRate(rate);
       
  1166 }
       
  1167 
       
  1168 bool HTMLMediaElement::webkitPreservesPitch() const
       
  1169 {
       
  1170     return m_webkitPreservesPitch;
       
  1171 }
       
  1172 
       
  1173 void HTMLMediaElement::setWebkitPreservesPitch(bool preservesPitch)
       
  1174 {
       
  1175     m_webkitPreservesPitch = preservesPitch;
       
  1176     
       
  1177     if (!m_player)
       
  1178         return;
       
  1179 
       
  1180     m_player->setPreservesPitch(preservesPitch);
       
  1181 }
       
  1182 
       
  1183 bool HTMLMediaElement::ended() const
       
  1184 {
       
  1185     // 4.8.10.8 Playing the media resource
       
  1186     // The ended attribute must return true if the media element has ended 
       
  1187     // playback and the direction of playback is forwards, and false otherwise.
       
  1188     return endedPlayback() && m_playbackRate > 0;
       
  1189 }
       
  1190 
       
  1191 bool HTMLMediaElement::autoplay() const
       
  1192 {
       
  1193     return hasAttribute(autoplayAttr);
       
  1194 }
       
  1195 
       
  1196 void HTMLMediaElement::setAutoplay(bool b)
       
  1197 {
       
  1198     setBooleanAttribute(autoplayAttr, b);
       
  1199 }
       
  1200 
       
  1201 String HTMLMediaElement::preload() const
       
  1202 {
       
  1203     switch (m_preload) {
       
  1204     case MediaPlayer::None:
       
  1205         return "none";
       
  1206         break;
       
  1207     case MediaPlayer::MetaData:
       
  1208         return "metadata";
       
  1209         break;
       
  1210     case MediaPlayer::Auto:
       
  1211         return "auto";
       
  1212         break;
       
  1213     }
       
  1214 
       
  1215     ASSERT_NOT_REACHED();
       
  1216     return String();
       
  1217 }
       
  1218 
       
  1219 void HTMLMediaElement::setPreload(const String& preload)
       
  1220 {
       
  1221     setAttribute(preloadAttr, preload);
       
  1222 }
       
  1223 
       
  1224 void HTMLMediaElement::play(bool isUserGesture)
       
  1225 {
       
  1226     if (m_restrictions & RequireUserGestureForRateChangeRestriction && !isUserGesture)
       
  1227         return;
       
  1228 
       
  1229     Document* doc = document();
       
  1230     Settings* settings = doc->settings();
       
  1231     if (settings && settings->needsSiteSpecificQuirks() && m_dispatchingCanPlayEvent && !m_loadInitiatedByUserGesture) {
       
  1232         // It should be impossible to be processing the canplay event while handling a user gesture
       
  1233         // since it is dispatched asynchronously.
       
  1234         ASSERT(!isUserGesture);
       
  1235         String host = doc->baseURL().host();
       
  1236         if (host.endsWith(".npr.org", false) || equalIgnoringCase(host, "npr.org"))
       
  1237             return;
       
  1238     }
       
  1239     
       
  1240     playInternal();
       
  1241 }
       
  1242 
       
  1243 void HTMLMediaElement::playInternal()
       
  1244 {
       
  1245     // 4.8.10.9. Playing the media resource
       
  1246     if (!m_player || m_networkState == NETWORK_EMPTY)
       
  1247         scheduleLoad();
       
  1248 
       
  1249     if (endedPlayback()) {
       
  1250         ExceptionCode unused;
       
  1251         seek(0, unused);
       
  1252     }
       
  1253     
       
  1254     setPlaybackRate(defaultPlaybackRate());
       
  1255     
       
  1256     if (m_paused) {
       
  1257         m_paused = false;
       
  1258         scheduleEvent(eventNames().playEvent);
       
  1259 
       
  1260         if (m_readyState <= HAVE_CURRENT_DATA)
       
  1261             scheduleEvent(eventNames().waitingEvent);
       
  1262         else if (m_readyState >= HAVE_FUTURE_DATA)
       
  1263             scheduleEvent(eventNames().playingEvent);
       
  1264     }
       
  1265     m_autoplaying = false;
       
  1266 
       
  1267     updatePlayState();
       
  1268 }
       
  1269 
       
  1270 void HTMLMediaElement::pause(bool isUserGesture)
       
  1271 {
       
  1272     if (m_restrictions & RequireUserGestureForRateChangeRestriction && !isUserGesture)
       
  1273         return;
       
  1274 
       
  1275     pauseInternal();
       
  1276 }
       
  1277 
       
  1278 
       
  1279 void HTMLMediaElement::pauseInternal()
       
  1280 {
       
  1281     // 4.8.10.9. Playing the media resource
       
  1282     if (!m_player || m_networkState == NETWORK_EMPTY)
       
  1283         scheduleLoad();
       
  1284 
       
  1285     m_autoplaying = false;
       
  1286     
       
  1287     if (!m_paused) {
       
  1288         m_paused = true;
       
  1289         scheduleTimeupdateEvent(false);
       
  1290         scheduleEvent(eventNames().pauseEvent);
       
  1291     }
       
  1292 
       
  1293     updatePlayState();
       
  1294 }
       
  1295 
       
  1296 bool HTMLMediaElement::loop() const
       
  1297 {
       
  1298     return hasAttribute(loopAttr);
       
  1299 }
       
  1300 
       
  1301 void HTMLMediaElement::setLoop(bool b)
       
  1302 {
       
  1303     setBooleanAttribute(loopAttr, b);
       
  1304 }
       
  1305 
       
  1306 bool HTMLMediaElement::controls() const
       
  1307 {
       
  1308     Frame* frame = document()->frame();
       
  1309 
       
  1310     // always show controls when scripting is disabled
       
  1311     if (frame && !frame->script()->canExecuteScripts(NotAboutToExecuteScript))
       
  1312         return true;
       
  1313 
       
  1314     return hasAttribute(controlsAttr);
       
  1315 }
       
  1316 
       
  1317 void HTMLMediaElement::setControls(bool b)
       
  1318 {
       
  1319     setBooleanAttribute(controlsAttr, b);
       
  1320 }
       
  1321 
       
  1322 float HTMLMediaElement::volume() const
       
  1323 {
       
  1324     return m_volume;
       
  1325 }
       
  1326 
       
  1327 void HTMLMediaElement::setVolume(float vol, ExceptionCode& ec)
       
  1328 {
       
  1329     if (vol < 0.0f || vol > 1.0f) {
       
  1330         ec = INDEX_SIZE_ERR;
       
  1331         return;
       
  1332     }
       
  1333     
       
  1334     if (m_volume != vol) {
       
  1335         m_volume = vol;
       
  1336         updateVolume();
       
  1337         scheduleEvent(eventNames().volumechangeEvent);
       
  1338     }
       
  1339 }
       
  1340 
       
  1341 bool HTMLMediaElement::muted() const
       
  1342 {
       
  1343     return m_muted;
       
  1344 }
       
  1345 
       
  1346 void HTMLMediaElement::setMuted(bool muted)
       
  1347 {
       
  1348     if (m_muted != muted) {
       
  1349         m_muted = muted;
       
  1350         // Avoid recursion when the player reports volume changes.
       
  1351         if (!processingMediaPlayerCallback()) {
       
  1352             if (m_player) {
       
  1353                 m_player->setMuted(m_muted);
       
  1354                 if (renderer())
       
  1355                     renderer()->updateFromElement();
       
  1356             } else
       
  1357                 updateVolume();
       
  1358         }
       
  1359         scheduleEvent(eventNames().volumechangeEvent);
       
  1360     }
       
  1361 }
       
  1362 
       
  1363 void HTMLMediaElement::togglePlayState()
       
  1364 {
       
  1365     // We can safely call the internal play/pause methods, which don't check restrictions, because
       
  1366     // this method is only called from the built-in media controller
       
  1367     if (canPlay())
       
  1368         playInternal();
       
  1369     else 
       
  1370         pauseInternal();
       
  1371 }
       
  1372 
       
  1373 void HTMLMediaElement::beginScrubbing()
       
  1374 {
       
  1375     if (!paused()) {
       
  1376         if (ended()) {
       
  1377             // Because a media element stays in non-paused state when it reaches end, playback resumes 
       
  1378             // when the slider is dragged from the end to another position unless we pause first. Do 
       
  1379             // a "hard pause" so an event is generated, since we want to stay paused after scrubbing finishes.
       
  1380             pause(processingUserGesture());
       
  1381         } else {
       
  1382             // Not at the end but we still want to pause playback so the media engine doesn't try to
       
  1383             // continue playing during scrubbing. Pause without generating an event as we will 
       
  1384             // unpause after scrubbing finishes.
       
  1385             setPausedInternal(true);
       
  1386         }
       
  1387     }
       
  1388 }
       
  1389 
       
  1390 void HTMLMediaElement::endScrubbing()
       
  1391 {
       
  1392     if (m_pausedInternal)
       
  1393         setPausedInternal(false);
       
  1394 }
       
  1395 
       
  1396 // The spec says to fire periodic timeupdate events (those sent while playing) every
       
  1397 // "15 to 250ms", we choose the slowest frequency
       
  1398 static const double maxTimeupdateEventFrequency = 0.25;
       
  1399 
       
  1400 void HTMLMediaElement::startPlaybackProgressTimer()
       
  1401 {
       
  1402     if (m_playbackProgressTimer.isActive())
       
  1403         return;
       
  1404 
       
  1405     m_previousProgressTime = WTF::currentTime();
       
  1406     m_previousProgress = 0;
       
  1407     m_playbackProgressTimer.startRepeating(maxTimeupdateEventFrequency);
       
  1408 }
       
  1409 
       
  1410 void HTMLMediaElement::playbackProgressTimerFired(Timer<HTMLMediaElement>*)
       
  1411 {
       
  1412     ASSERT(m_player);
       
  1413     if (!m_playbackRate)
       
  1414         return;
       
  1415 
       
  1416     scheduleTimeupdateEvent(true);
       
  1417     
       
  1418     // FIXME: deal with cue ranges here
       
  1419 }
       
  1420 
       
  1421 void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent)
       
  1422 {
       
  1423     double now = WTF::currentTime();
       
  1424     double timedelta = now - m_lastTimeUpdateEventWallTime;
       
  1425 
       
  1426     // throttle the periodic events
       
  1427     if (periodicEvent && timedelta < maxTimeupdateEventFrequency)
       
  1428         return;
       
  1429 
       
  1430     // Some media engines make multiple "time changed" callbacks at the same time, but we only want one
       
  1431     // event at a given time so filter here
       
  1432     float movieTime = m_player ? m_player->currentTime() : 0;
       
  1433     if (movieTime != m_lastTimeUpdateEventMovieTime) {
       
  1434         scheduleEvent(eventNames().timeupdateEvent);
       
  1435         m_lastTimeUpdateEventWallTime = now;
       
  1436         m_lastTimeUpdateEventMovieTime = movieTime;
       
  1437     }
       
  1438 }
       
  1439 
       
  1440 bool HTMLMediaElement::canPlay() const
       
  1441 {
       
  1442     return paused() || ended() || m_readyState < HAVE_METADATA;
       
  1443 }
       
  1444 
       
  1445 float HTMLMediaElement::percentLoaded() const
       
  1446 {
       
  1447     if (!m_player)
       
  1448         return 0;
       
  1449     float duration = m_player->duration();
       
  1450 
       
  1451     if (!duration || isinf(duration))
       
  1452         return 0;
       
  1453 
       
  1454     float buffered = 0;
       
  1455     RefPtr<TimeRanges> timeRanges = m_player->buffered();
       
  1456     for (unsigned i = 0; i < timeRanges->length(); ++i) {
       
  1457         ExceptionCode ignoredException;
       
  1458         float start = timeRanges->start(i, ignoredException);
       
  1459         float end = timeRanges->end(i, ignoredException);
       
  1460         buffered += end - start;
       
  1461     }
       
  1462     return buffered / duration;
       
  1463 }
       
  1464 
       
  1465 bool HTMLMediaElement::havePotentialSourceChild()
       
  1466 {
       
  1467     // Stash the current <source> node so we can restore it after checking
       
  1468     // to see there is another potential
       
  1469     HTMLSourceElement* currentSourceNode = m_currentSourceNode;
       
  1470     KURL nextURL = selectNextSourceChild(0, DoNothing);
       
  1471     m_currentSourceNode = currentSourceNode;
       
  1472 
       
  1473     return nextURL.isValid();
       
  1474 }
       
  1475 
       
  1476 KURL HTMLMediaElement::selectNextSourceChild(ContentType *contentType, InvalidSourceAction actionIfInvalid)
       
  1477 {
       
  1478     KURL mediaURL;
       
  1479     Node* node;
       
  1480     bool lookingForPreviousNode = m_currentSourceNode;
       
  1481     bool canUse = false;
       
  1482 
       
  1483     for (node = firstChild(); !canUse && node; node = node->nextSibling()) {
       
  1484         if (!node->hasTagName(sourceTag))
       
  1485             continue;
       
  1486 
       
  1487         if (lookingForPreviousNode) {
       
  1488             if (m_currentSourceNode == static_cast<HTMLSourceElement*>(node))
       
  1489                 lookingForPreviousNode = false;
       
  1490             continue;
       
  1491         }
       
  1492 
       
  1493         HTMLSourceElement* source = static_cast<HTMLSourceElement*>(node);
       
  1494 
       
  1495         // If candidate does not have a src attribute, or if its src attribute's value is the empty string ... jump down to the failed step below
       
  1496         mediaURL = source->getNonEmptyURLAttribute(srcAttr);
       
  1497         if (mediaURL.isEmpty())
       
  1498             goto check_again;
       
  1499         
       
  1500         if (source->hasAttribute(mediaAttr)) {
       
  1501             MediaQueryEvaluator screenEval("screen", document()->frame(), renderer() ? renderer()->style() : 0);
       
  1502             RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(source->media());
       
  1503             if (!screenEval.eval(media.get())) 
       
  1504                 goto check_again;
       
  1505         }
       
  1506 
       
  1507         if (source->hasAttribute(typeAttr)) {
       
  1508             if (!MediaPlayer::supportsType(ContentType(source->type())))
       
  1509                 goto check_again;
       
  1510         }
       
  1511 
       
  1512         // Is it safe to load this url?
       
  1513         if (!isSafeToLoadURL(mediaURL, actionIfInvalid) || !dispatchBeforeLoadEvent(mediaURL.string()))
       
  1514             goto check_again;
       
  1515 
       
  1516         // Making it this far means the <source> looks reasonable
       
  1517         canUse = true;
       
  1518         if (contentType)
       
  1519             *contentType = ContentType(source->type());
       
  1520 
       
  1521 check_again:
       
  1522         if (!canUse && actionIfInvalid == Complain)
       
  1523             source->scheduleErrorEvent();
       
  1524         m_currentSourceNode = static_cast<HTMLSourceElement*>(node);
       
  1525     }
       
  1526 
       
  1527     if (!canUse)
       
  1528         m_currentSourceNode = 0;
       
  1529     return canUse ? mediaURL : KURL();
       
  1530 }
       
  1531 
       
  1532 void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
       
  1533 {
       
  1534     beginProcessingMediaPlayerCallback();
       
  1535 
       
  1536     // Always call scheduleTimeupdateEvent when the media engine reports a time discontinuity, 
       
  1537     // it will only queue a 'timeupdate' event if we haven't already posted one at the current
       
  1538     // movie time.
       
  1539     scheduleTimeupdateEvent(false);
       
  1540 
       
  1541     // 4.8.10.10 step 12 & 13.  Needed if no ReadyState change is associated with the seek.
       
  1542     if (m_readyState >= HAVE_CURRENT_DATA && m_seeking)
       
  1543         finishSeek();
       
  1544     
       
  1545     float now = currentTime();
       
  1546     float dur = duration();
       
  1547     if (!isnan(dur) && dur && now >= dur) {
       
  1548         if (loop()) {
       
  1549             ExceptionCode ignoredException;
       
  1550             m_sentEndEvent = false;
       
  1551             seek(0, ignoredException);
       
  1552         } else {
       
  1553             if (!m_sentEndEvent) {
       
  1554                 m_sentEndEvent = true;
       
  1555                 scheduleEvent(eventNames().endedEvent);
       
  1556             }
       
  1557         }
       
  1558     }
       
  1559     else
       
  1560         m_sentEndEvent = false;
       
  1561 
       
  1562     updatePlayState();
       
  1563     endProcessingMediaPlayerCallback();
       
  1564 }
       
  1565 
       
  1566 void HTMLMediaElement::mediaPlayerVolumeChanged(MediaPlayer*)
       
  1567 {
       
  1568     beginProcessingMediaPlayerCallback();
       
  1569     if (m_player)
       
  1570         m_volume = m_player->volume();
       
  1571     updateVolume();
       
  1572     endProcessingMediaPlayerCallback();
       
  1573 }
       
  1574 
       
  1575 void HTMLMediaElement::mediaPlayerMuteChanged(MediaPlayer*)
       
  1576 {
       
  1577     beginProcessingMediaPlayerCallback();
       
  1578     if (m_player)
       
  1579         setMuted(m_player->muted());
       
  1580     endProcessingMediaPlayerCallback();
       
  1581 }
       
  1582 
       
  1583 void HTMLMediaElement::mediaPlayerDurationChanged(MediaPlayer*)
       
  1584 {
       
  1585     beginProcessingMediaPlayerCallback();
       
  1586     scheduleEvent(eventNames().durationchangeEvent);
       
  1587 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
  1588     if (renderer()) {
       
  1589         renderer()->updateFromElement();
       
  1590         if (renderer()->isVideo())
       
  1591             toRenderVideo(renderer())->videoSizeChanged();
       
  1592     }
       
  1593 #endif        
       
  1594     endProcessingMediaPlayerCallback();
       
  1595 }
       
  1596 
       
  1597 void HTMLMediaElement::mediaPlayerRateChanged(MediaPlayer*)
       
  1598 {
       
  1599     beginProcessingMediaPlayerCallback();
       
  1600     // Stash the rate in case the one we tried to set isn't what the engine is
       
  1601     // using (eg. it can't handle the rate we set)
       
  1602     m_playbackRate = m_player->rate();
       
  1603     endProcessingMediaPlayerCallback();
       
  1604 }
       
  1605 
       
  1606 void HTMLMediaElement::mediaPlayerSawUnsupportedTracks(MediaPlayer*)
       
  1607 {
       
  1608     // The MediaPlayer came across content it cannot completely handle.
       
  1609     // This is normally acceptable except when we are in a standalone
       
  1610     // MediaDocument. If so, tell the document what has happened.
       
  1611     if (ownerDocument()->isMediaDocument()) {
       
  1612         MediaDocument* mediaDocument = static_cast<MediaDocument*>(ownerDocument());
       
  1613         mediaDocument->mediaElementSawUnsupportedTracks();
       
  1614     }
       
  1615 }
       
  1616 
       
  1617 // MediaPlayerPresentation methods
       
  1618 void HTMLMediaElement::mediaPlayerRepaint(MediaPlayer*)
       
  1619 {
       
  1620     beginProcessingMediaPlayerCallback();
       
  1621     if (renderer())
       
  1622         renderer()->repaint();
       
  1623 
       
  1624     updatePosterImage();
       
  1625     endProcessingMediaPlayerCallback();
       
  1626 }
       
  1627 
       
  1628 void HTMLMediaElement::mediaPlayerSizeChanged(MediaPlayer*)
       
  1629 {
       
  1630     beginProcessingMediaPlayerCallback();
       
  1631 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
  1632     if (renderer() && renderer()->isVideo())
       
  1633         toRenderVideo(renderer())->videoSizeChanged();
       
  1634 #endif        
       
  1635     endProcessingMediaPlayerCallback();
       
  1636 }
       
  1637 
       
  1638 #if USE(ACCELERATED_COMPOSITING)
       
  1639 bool HTMLMediaElement::mediaPlayerRenderingCanBeAccelerated(MediaPlayer*)
       
  1640 {
       
  1641     if (renderer() && renderer()->isVideo()) {
       
  1642         ASSERT(renderer()->view());
       
  1643         return renderer()->view()->compositor()->canAccelerateVideoRendering(toRenderVideo(renderer()));
       
  1644     }
       
  1645     return false;
       
  1646 }
       
  1647 
       
  1648 void HTMLMediaElement::mediaPlayerRenderingModeChanged(MediaPlayer*)
       
  1649 {
       
  1650     // Kick off a fake recalcStyle that will update the compositing tree.
       
  1651     setNeedsStyleRecalc(SyntheticStyleChange);
       
  1652 }
       
  1653 #endif
       
  1654 
       
  1655 PassRefPtr<TimeRanges> HTMLMediaElement::buffered() const
       
  1656 {
       
  1657     if (!m_player)
       
  1658         return TimeRanges::create();
       
  1659     return m_player->buffered();
       
  1660 }
       
  1661 
       
  1662 PassRefPtr<TimeRanges> HTMLMediaElement::played()
       
  1663 {
       
  1664     if (m_playing) {
       
  1665         float time = currentTime();
       
  1666         if (time > m_lastSeekTime)
       
  1667             addPlayedRange(m_lastSeekTime, time);
       
  1668     }
       
  1669 
       
  1670     if (!m_playedTimeRanges)
       
  1671         m_playedTimeRanges = TimeRanges::create();
       
  1672 
       
  1673     return m_playedTimeRanges->copy();
       
  1674 }
       
  1675 
       
  1676 PassRefPtr<TimeRanges> HTMLMediaElement::seekable() const
       
  1677 {
       
  1678     // FIXME real ranges support
       
  1679     if (!maxTimeSeekable())
       
  1680         return TimeRanges::create();
       
  1681     return TimeRanges::create(minTimeSeekable(), maxTimeSeekable());
       
  1682 }
       
  1683 
       
  1684 bool HTMLMediaElement::potentiallyPlaying() const
       
  1685 {
       
  1686     // "pausedToBuffer" means the media engine's rate is 0, but only because it had to stop playing
       
  1687     // when it ran out of buffered data. A movie is this state is "potentially playing", modulo the
       
  1688     // checks in couldPlayIfEnoughData().
       
  1689     bool pausedToBuffer = m_readyStateMaximum >= HAVE_FUTURE_DATA && m_readyState < HAVE_FUTURE_DATA;
       
  1690     return (pausedToBuffer || m_readyState >= HAVE_FUTURE_DATA) && couldPlayIfEnoughData();
       
  1691 }
       
  1692 
       
  1693 bool HTMLMediaElement::couldPlayIfEnoughData() const
       
  1694 {
       
  1695     return !paused() && !endedPlayback() && !stoppedDueToErrors() && !pausedForUserInteraction();
       
  1696 }
       
  1697 
       
  1698 bool HTMLMediaElement::endedPlayback() const
       
  1699 {
       
  1700     float dur = duration();
       
  1701     if (!m_player || isnan(dur))
       
  1702         return false;
       
  1703 
       
  1704     // 4.8.10.8 Playing the media resource
       
  1705 
       
  1706     // A media element is said to have ended playback when the element's 
       
  1707     // readyState attribute is HAVE_METADATA or greater, 
       
  1708     if (m_readyState < HAVE_METADATA)
       
  1709         return false;
       
  1710     
       
  1711     // and the current playback position is the end of the media resource and the direction 
       
  1712     // of playback is forwards and the media element does not have a loop attribute specified,
       
  1713     float now = currentTime();
       
  1714     if (m_playbackRate > 0)
       
  1715         return now >= dur && !loop();
       
  1716     
       
  1717     // or the current playback position is the earliest possible position and the direction 
       
  1718     // of playback is backwards
       
  1719     if (m_playbackRate < 0)
       
  1720         return now <= 0;
       
  1721 
       
  1722     return false;
       
  1723 }
       
  1724 
       
  1725 bool HTMLMediaElement::stoppedDueToErrors() const
       
  1726 {
       
  1727     if (m_readyState >= HAVE_METADATA && m_error) {
       
  1728         RefPtr<TimeRanges> seekableRanges = seekable();
       
  1729         if (!seekableRanges->contain(currentTime()))
       
  1730             return true;
       
  1731     }
       
  1732     
       
  1733     return false;
       
  1734 }
       
  1735 
       
  1736 bool HTMLMediaElement::pausedForUserInteraction() const
       
  1737 {
       
  1738 //    return !paused() && m_readyState >= HAVE_FUTURE_DATA && [UA requires a decitions from the user]
       
  1739     return false;
       
  1740 }
       
  1741 
       
  1742 float HTMLMediaElement::minTimeSeekable() const
       
  1743 {
       
  1744     return 0;
       
  1745 }
       
  1746 
       
  1747 float HTMLMediaElement::maxTimeSeekable() const
       
  1748 {
       
  1749     return m_player ? m_player->maxTimeSeekable() : 0;
       
  1750 }
       
  1751     
       
  1752 void HTMLMediaElement::updateVolume()
       
  1753 {
       
  1754     if (!m_player)
       
  1755         return;
       
  1756 
       
  1757     // Avoid recursion when the player reports volume changes.
       
  1758     if (!processingMediaPlayerCallback()) {
       
  1759         Page* page = document()->page();
       
  1760         float volumeMultiplier = page ? page->mediaVolume() : 1;
       
  1761     
       
  1762         m_player->setMuted(m_muted);
       
  1763         m_player->setVolume(m_volume * volumeMultiplier);
       
  1764     }
       
  1765     
       
  1766     if (renderer())
       
  1767         renderer()->updateFromElement();
       
  1768 }
       
  1769 
       
  1770 void HTMLMediaElement::updatePlayState()
       
  1771 {
       
  1772     if (!m_player)
       
  1773         return;
       
  1774 
       
  1775     if (m_pausedInternal) {
       
  1776         if (!m_player->paused())
       
  1777             m_player->pause();
       
  1778         m_playbackProgressTimer.stop();
       
  1779         return;
       
  1780     }
       
  1781     
       
  1782     bool shouldBePlaying = potentiallyPlaying();
       
  1783     bool playerPaused = m_player->paused();
       
  1784     if (shouldBePlaying && playerPaused) {
       
  1785         // Set rate before calling play in case the rate was set before the media engine wasn't setup.
       
  1786         // The media engine should just stash the rate since it isn't already playing.
       
  1787         m_player->setRate(m_playbackRate);
       
  1788         m_player->play();
       
  1789         startPlaybackProgressTimer();
       
  1790         m_playing = true;
       
  1791     } else if (!shouldBePlaying && !playerPaused) {
       
  1792         m_player->pause();
       
  1793         m_playbackProgressTimer.stop();
       
  1794         m_playing = false;
       
  1795         float time = currentTime();
       
  1796         if (time > m_lastSeekTime)
       
  1797             addPlayedRange(m_lastSeekTime, time);
       
  1798     } else if (couldPlayIfEnoughData() && playerPaused)
       
  1799         m_player->prepareToPlay();
       
  1800     
       
  1801     if (renderer())
       
  1802         renderer()->updateFromElement();
       
  1803 }
       
  1804     
       
  1805 void HTMLMediaElement::setPausedInternal(bool b)
       
  1806 {
       
  1807     m_pausedInternal = b;
       
  1808     updatePlayState();
       
  1809 }
       
  1810 
       
  1811 void HTMLMediaElement::stopPeriodicTimers()
       
  1812 {
       
  1813     m_progressEventTimer.stop();
       
  1814     m_playbackProgressTimer.stop();
       
  1815 }
       
  1816 
       
  1817 void HTMLMediaElement::userCancelledLoad()
       
  1818 {
       
  1819     if (m_networkState == NETWORK_EMPTY || m_completelyLoaded)
       
  1820         return;
       
  1821 
       
  1822     // If the media data fetching process is aborted by the user:
       
  1823 
       
  1824     // 1 - The user agent should cancel the fetching process.
       
  1825 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
  1826     m_player.clear();
       
  1827 #endif
       
  1828     stopPeriodicTimers();
       
  1829 
       
  1830     // 2 - Set the error attribute to a new MediaError object whose code attribute is set to MEDIA_ERR_ABORTED.
       
  1831     m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
       
  1832 
       
  1833     // 3 - Queue a task to fire a progress event called abort at the media element, in the context
       
  1834     // of the fetching process started by this instance of this algorithm.
       
  1835     scheduleEvent(eventNames().abortEvent);
       
  1836 
       
  1837     // 5 - If the media element's readyState attribute has a value equal to HAVE_NOTHING, set the
       
  1838     // element's networkState attribute to the NETWORK_EMPTY value and queue a task to fire a
       
  1839     // simple event called emptied at the element. Otherwise, set set the element's networkState
       
  1840     // attribute to the NETWORK_IDLE value.
       
  1841     if (m_readyState == HAVE_NOTHING) {
       
  1842         m_networkState = NETWORK_EMPTY;
       
  1843         scheduleEvent(eventNames().emptiedEvent);
       
  1844     }
       
  1845     else
       
  1846         m_networkState = NETWORK_IDLE;
       
  1847 
       
  1848     // 6 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
       
  1849     m_delayingTheLoadEvent = false;
       
  1850 
       
  1851     // 7 - Abort the overall resource selection algorithm.
       
  1852     m_currentSourceNode = 0;
       
  1853 
       
  1854     // Reset m_readyState since m_player is gone.
       
  1855     m_readyState = HAVE_NOTHING;
       
  1856 }
       
  1857 
       
  1858 void HTMLMediaElement::documentWillBecomeInactive()
       
  1859 {
       
  1860     if (m_isFullscreen)
       
  1861         exitFullscreen();
       
  1862 
       
  1863     m_inActiveDocument = false;
       
  1864     userCancelledLoad();
       
  1865 
       
  1866     // Stop the playback without generating events
       
  1867     setPausedInternal(true);
       
  1868 
       
  1869     if (renderer())
       
  1870         renderer()->updateFromElement();
       
  1871 
       
  1872     stopPeriodicTimers();
       
  1873     cancelPendingEventsAndCallbacks();
       
  1874 }
       
  1875 
       
  1876 void HTMLMediaElement::documentDidBecomeActive()
       
  1877 {
       
  1878     m_inActiveDocument = true;
       
  1879     setPausedInternal(false);
       
  1880 
       
  1881     if (m_error && m_error->code() == MediaError::MEDIA_ERR_ABORTED) {
       
  1882         // Restart the load if it was aborted in the middle by moving the document to the page cache.
       
  1883         // m_error is only left at MEDIA_ERR_ABORTED when the document becomes inactive (it is set to
       
  1884         //  MEDIA_ERR_ABORTED while the abortEvent is being sent, but cleared immediately afterwards).
       
  1885         // This behavior is not specified but it seems like a sensible thing to do.
       
  1886         ExceptionCode ec;
       
  1887         load(processingUserGesture(), ec);
       
  1888     }
       
  1889 
       
  1890     if (renderer())
       
  1891         renderer()->updateFromElement();
       
  1892 }
       
  1893 
       
  1894 void HTMLMediaElement::mediaVolumeDidChange()
       
  1895 {
       
  1896     updateVolume();
       
  1897 }
       
  1898 
       
  1899 IntRect HTMLMediaElement::screenRect()
       
  1900 {
       
  1901     if (!renderer())
       
  1902         return IntRect();
       
  1903     return renderer()->view()->frameView()->contentsToScreen(renderer()->absoluteBoundingBoxRect());
       
  1904 }
       
  1905     
       
  1906 void HTMLMediaElement::defaultEventHandler(Event* event)
       
  1907 {
       
  1908 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
  1909     RenderObject* r = renderer();
       
  1910     if (!r || !r->isWidget())
       
  1911         return;
       
  1912 
       
  1913     Widget* widget = toRenderWidget(r)->widget();
       
  1914     if (widget)
       
  1915         widget->handleEvent(event);
       
  1916 #else
       
  1917     if (renderer() && renderer()->isMedia())
       
  1918         toRenderMedia(renderer())->forwardEvent(event);
       
  1919     if (event->defaultHandled())
       
  1920         return;
       
  1921     HTMLElement::defaultEventHandler(event);
       
  1922 #endif
       
  1923 }
       
  1924 
       
  1925 bool HTMLMediaElement::processingUserGesture() const
       
  1926 {
       
  1927     Frame* frame = document()->frame();
       
  1928     FrameLoader* loader = frame ? frame->loader() : 0;
       
  1929 
       
  1930     // return 'true' for safety if we don't know the answer 
       
  1931     return loader ? loader->isProcessingUserGesture() : true;
       
  1932 }
       
  1933 
       
  1934 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
  1935 
       
  1936 void HTMLMediaElement::ensureMediaPlayer()
       
  1937 {
       
  1938     if (!m_player)
       
  1939         m_player = MediaPlayer::create(this);
       
  1940 }
       
  1941 
       
  1942 void HTMLMediaElement::deliverNotification(MediaPlayerProxyNotificationType notification)
       
  1943 {
       
  1944     if (notification == MediaPlayerNotificationPlayPauseButtonPressed) {
       
  1945         togglePlayState();
       
  1946         return;
       
  1947     }
       
  1948 
       
  1949     if (m_player)
       
  1950         m_player->deliverNotification(notification);
       
  1951 }
       
  1952 
       
  1953 void HTMLMediaElement::setMediaPlayerProxy(WebMediaPlayerProxy* proxy)
       
  1954 {
       
  1955     ensureMediaPlayer();
       
  1956     m_player->setMediaPlayerProxy(proxy);
       
  1957 }
       
  1958 
       
  1959 void HTMLMediaElement::getPluginProxyParams(KURL& url, Vector<String>& names, Vector<String>& values)
       
  1960 {
       
  1961     Frame* frame = document()->frame();
       
  1962     FrameLoader* loader = frame ? frame->loader() : 0;
       
  1963 
       
  1964     if (isVideo()) {
       
  1965         String poster = poster();
       
  1966         if (!poster.isEmpty() && loader) {
       
  1967             KURL posterURL = loader->completeURL(poster);
       
  1968             if (posterURL.isValid() && loader->willLoadMediaElementURL(posterURL)) {
       
  1969                 names.append("_media_element_poster_");
       
  1970                 values.append(posterURL.string());
       
  1971             }
       
  1972         }
       
  1973     }
       
  1974 
       
  1975     if (controls()) {
       
  1976         names.append("_media_element_controls_");
       
  1977         values.append("true");
       
  1978     }
       
  1979 
       
  1980     url = src();
       
  1981     if (!isSafeToLoadURL(url, Complain))
       
  1982         url = selectNextSourceChild(0, DoNothing);
       
  1983 
       
  1984     m_currentSrc = url.string();
       
  1985     if (url.isValid() && loader && loader->willLoadMediaElementURL(url)) {
       
  1986         names.append("_media_element_src_");
       
  1987         values.append(m_currentSrc);
       
  1988     }
       
  1989 }
       
  1990 
       
  1991 void HTMLMediaElement::finishParsingChildren()
       
  1992 {
       
  1993     HTMLElement::finishParsingChildren();
       
  1994     document()->updateStyleIfNeeded();
       
  1995     createMediaPlayerProxy();
       
  1996 }
       
  1997 
       
  1998 void HTMLMediaElement::createMediaPlayerProxy()
       
  1999 {
       
  2000     ensureMediaPlayer();
       
  2001 
       
  2002     if (m_proxyWidget || (inDocument() && !m_needWidgetUpdate))
       
  2003         return;
       
  2004 
       
  2005     Frame* frame = document()->frame();
       
  2006     FrameLoader* loader = frame ? frame->loader() : 0;
       
  2007     if (!loader)
       
  2008         return;
       
  2009 
       
  2010     KURL url;
       
  2011     Vector<String> paramNames;
       
  2012     Vector<String> paramValues;
       
  2013 
       
  2014     getPluginProxyParams(url, paramNames, paramValues);
       
  2015     
       
  2016     // Hang onto the proxy widget so it won't be destroyed if the plug-in is set to
       
  2017     // display:none
       
  2018     m_proxyWidget = loader->subframeLoader()->loadMediaPlayerProxyPlugin(this, url, paramNames, paramValues);
       
  2019     if (m_proxyWidget)
       
  2020         m_needWidgetUpdate = false;
       
  2021 }
       
  2022 #endif // ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
  2023 
       
  2024 void HTMLMediaElement::enterFullscreen()
       
  2025 {
       
  2026     ASSERT(!m_isFullscreen);
       
  2027     m_isFullscreen = true;
       
  2028     if (document() && document()->page()) {
       
  2029         document()->page()->chrome()->client()->enterFullscreenForNode(this);
       
  2030         scheduleEvent(eventNames().webkitbeginfullscreenEvent);
       
  2031     }
       
  2032 }
       
  2033 
       
  2034 void HTMLMediaElement::exitFullscreen()
       
  2035 {
       
  2036     ASSERT(m_isFullscreen);
       
  2037     m_isFullscreen = false;
       
  2038     if (document() && document()->page()) {
       
  2039         document()->page()->chrome()->client()->exitFullscreenForNode(this);
       
  2040         scheduleEvent(eventNames().webkitendfullscreenEvent);
       
  2041     }
       
  2042 }
       
  2043 
       
  2044 PlatformMedia HTMLMediaElement::platformMedia() const
       
  2045 {
       
  2046     return m_player ? m_player->platformMedia() : NoPlatformMedia;
       
  2047 }
       
  2048 
       
  2049 #if USE(ACCELERATED_COMPOSITING)
       
  2050 PlatformLayer* HTMLMediaElement::platformLayer() const
       
  2051 {
       
  2052     return m_player ? m_player->platformLayer() : 0;
       
  2053 }
       
  2054 #endif
       
  2055 
       
  2056 bool HTMLMediaElement::hasClosedCaptions() const
       
  2057 {
       
  2058     return m_player && m_player->hasClosedCaptions();
       
  2059 }
       
  2060 
       
  2061 bool HTMLMediaElement::closedCaptionsVisible() const
       
  2062 {
       
  2063     return m_closedCaptionsVisible;
       
  2064 }
       
  2065 
       
  2066 void HTMLMediaElement::setClosedCaptionsVisible(bool closedCaptionVisible)
       
  2067 {
       
  2068     if (!m_player ||!hasClosedCaptions())
       
  2069         return;
       
  2070 
       
  2071     m_closedCaptionsVisible = closedCaptionVisible;
       
  2072     m_player->setClosedCaptionsVisible(closedCaptionVisible);
       
  2073     if (renderer())
       
  2074         renderer()->updateFromElement();
       
  2075 }
       
  2076 
       
  2077 void HTMLMediaElement::setWebkitClosedCaptionsVisible(bool visible)
       
  2078 {
       
  2079     setClosedCaptionsVisible(visible);
       
  2080 }
       
  2081 
       
  2082 bool HTMLMediaElement::webkitClosedCaptionsVisible() const
       
  2083 {
       
  2084     return closedCaptionsVisible();
       
  2085 }
       
  2086 
       
  2087 
       
  2088 bool HTMLMediaElement::webkitHasClosedCaptions() const
       
  2089 {
       
  2090     return hasClosedCaptions();
       
  2091 }
       
  2092 
       
  2093 void HTMLMediaElement::mediaCanStart()
       
  2094 {
       
  2095     ASSERT(m_isWaitingUntilMediaCanStart);
       
  2096     m_isWaitingUntilMediaCanStart = false;
       
  2097     loadInternal();
       
  2098 }
       
  2099 
       
  2100 bool HTMLMediaElement::isURLAttribute(Attribute* attribute) const
       
  2101 {
       
  2102     return attribute->name() == srcAttr;
       
  2103 }
       
  2104 
       
  2105 }
       
  2106 
       
  2107 #endif