Home | History | Annotate | Download | only in html
      1 /*
      2  * Copyright (C) 2007, 2008, 2009, 2010, 2011 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 "Chrome.h"
     33 #include "ChromeClient.h"
     34 #include "ClientRect.h"
     35 #include "ClientRectList.h"
     36 #include "ContentSecurityPolicy.h"
     37 #include "ContentType.h"
     38 #include "CSSPropertyNames.h"
     39 #include "CSSValueKeywords.h"
     40 #include "Event.h"
     41 #include "EventNames.h"
     42 #include "ExceptionCode.h"
     43 #include "Frame.h"
     44 #include "FrameLoader.h"
     45 #include "FrameLoaderClient.h"
     46 #include "FrameView.h"
     47 #include "HTMLDocument.h"
     48 #include "HTMLNames.h"
     49 #include "HTMLSourceElement.h"
     50 #include "HTMLVideoElement.h"
     51 #include "Logging.h"
     52 #include "MediaControls.h"
     53 #include "MediaDocument.h"
     54 #include "MediaError.h"
     55 #include "MediaList.h"
     56 #include "MediaPlayer.h"
     57 #include "MediaQueryEvaluator.h"
     58 #include "MouseEvent.h"
     59 #include "MIMETypeRegistry.h"
     60 #include "Page.h"
     61 #include "RenderVideo.h"
     62 #include "RenderView.h"
     63 #include "ScriptEventListener.h"
     64 #include "Settings.h"
     65 #include "ShadowRoot.h"
     66 #include "TimeRanges.h"
     67 #include <limits>
     68 #include <wtf/CurrentTime.h>
     69 #include <wtf/MathExtras.h>
     70 #include <wtf/text/CString.h>
     71 
     72 #if USE(ACCELERATED_COMPOSITING)
     73 #include "RenderView.h"
     74 #include "RenderLayerCompositor.h"
     75 #endif
     76 
     77 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
     78 #include "RenderEmbeddedObject.h"
     79 #include "Widget.h"
     80 #endif
     81 
     82 #if PLATFORM(ANDROID)
     83 // For every touch, show the media control for 4 seconds.
     84 #define TOUCH_DELAY 4
     85 #endif
     86 
     87 using namespace std;
     88 
     89 namespace WebCore {
     90 
     91 #if !LOG_DISABLED
     92 static String urlForLogging(const String& url)
     93 {
     94     static const unsigned maximumURLLengthForLogging = 128;
     95 
     96     if (url.length() < maximumURLLengthForLogging)
     97         return url;
     98     return url.substring(0, maximumURLLengthForLogging) + "...";
     99 }
    100 
    101 static const char *boolString(bool val)
    102 {
    103     return val ? "true" : "false";
    104 }
    105 #endif
    106 
    107 #ifndef LOG_MEDIA_EVENTS
    108 // Default to not logging events because so many are generated they can overwhelm the rest of
    109 // the logging.
    110 #define LOG_MEDIA_EVENTS 0
    111 #endif
    112 
    113 #ifndef LOG_CACHED_TIME_WARNINGS
    114 // Default to not logging warnings about excessive drift in the cached media time because it adds a
    115 // fair amount of overhead and logging.
    116 #define LOG_CACHED_TIME_WARNINGS 0
    117 #endif
    118 
    119 static const float invalidMediaTime = -1;
    120 
    121 using namespace HTMLNames;
    122 
    123 HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* document)
    124     : HTMLElement(tagName, document)
    125     , ActiveDOMObject(document, this)
    126     , m_loadTimer(this, &HTMLMediaElement::loadTimerFired)
    127     , m_asyncEventTimer(this, &HTMLMediaElement::asyncEventTimerFired)
    128     , m_progressEventTimer(this, &HTMLMediaElement::progressEventTimerFired)
    129     , m_playbackProgressTimer(this, &HTMLMediaElement::playbackProgressTimerFired)
    130     , m_playedTimeRanges()
    131     , m_playbackRate(1.0f)
    132     , m_defaultPlaybackRate(1.0f)
    133     , m_webkitPreservesPitch(true)
    134     , m_networkState(NETWORK_EMPTY)
    135     , m_readyState(HAVE_NOTHING)
    136     , m_readyStateMaximum(HAVE_NOTHING)
    137     , m_volume(1.0f)
    138     , m_lastSeekTime(0)
    139     , m_previousProgress(0)
    140     , m_previousProgressTime(numeric_limits<double>::max())
    141     , m_lastTimeUpdateEventWallTime(0)
    142     , m_lastTimeUpdateEventMovieTime(numeric_limits<float>::max())
    143     , m_loadState(WaitingForSource)
    144     , m_currentSourceNode(0)
    145     , m_nextChildNodeToConsider(0)
    146     , m_player(0)
    147 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
    148     , m_proxyWidget(0)
    149 #endif
    150     , m_restrictions(RequireUserGestureForFullScreenRestriction)
    151     , m_preload(MediaPlayer::Auto)
    152     , m_displayMode(Unknown)
    153     , m_processingMediaPlayerCallback(0)
    154     , m_cachedTime(invalidMediaTime)
    155     , m_cachedTimeWallClockUpdateTime(0)
    156     , m_minimumWallClockTimeToCacheMediaTime(0)
    157     , m_playing(false)
    158     , m_isWaitingUntilMediaCanStart(false)
    159     , m_shouldDelayLoadEvent(false)
    160     , m_haveFiredLoadedData(false)
    161     , m_inActiveDocument(true)
    162     , m_autoplaying(true)
    163     , m_muted(false)
    164     , m_paused(true)
    165     , m_seeking(false)
    166     , m_sentStalledEvent(false)
    167     , m_sentEndEvent(false)
    168     , m_pausedInternal(false)
    169     , m_sendProgressEvents(true)
    170     , m_isFullscreen(false)
    171     , m_closedCaptionsVisible(false)
    172     , m_mouseOver(false)
    173 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
    174     , m_needWidgetUpdate(false)
    175 #endif
    176     , m_dispatchingCanPlayEvent(false)
    177     , m_loadInitiatedByUserGesture(false)
    178     , m_completelyLoaded(false)
    179 #if PLATFORM(ANDROID)
    180     , m_lastTouch(0)
    181     , m_userGestureInitiated(false)
    182 #endif
    183 {
    184     LOG(Media, "HTMLMediaElement::HTMLMediaElement");
    185     document->registerForDocumentActivationCallbacks(this);
    186     document->registerForMediaVolumeCallbacks(this);
    187     document->registerForPrivateBrowsingStateChangedCallbacks(this);
    188 
    189     if (document->settings() && document->settings()->mediaPlaybackRequiresUserGesture())
    190         m_restrictions |= RequireUserGestureForRateChangeRestriction;
    191 }
    192 
    193 HTMLMediaElement::~HTMLMediaElement()
    194 {
    195     LOG(Media, "HTMLMediaElement::~HTMLMediaElement");
    196     if (m_isWaitingUntilMediaCanStart)
    197         document()->removeMediaCanStartListener(this);
    198     setShouldDelayLoadEvent(false);
    199     document()->unregisterForDocumentActivationCallbacks(this);
    200     document()->unregisterForMediaVolumeCallbacks(this);
    201     document()->unregisterForPrivateBrowsingStateChangedCallbacks(this);
    202 }
    203 
    204 void HTMLMediaElement::willMoveToNewOwnerDocument()
    205 {
    206     if (m_isWaitingUntilMediaCanStart)
    207         document()->removeMediaCanStartListener(this);
    208     setShouldDelayLoadEvent(false);
    209     document()->unregisterForDocumentActivationCallbacks(this);
    210     document()->unregisterForMediaVolumeCallbacks(this);
    211     HTMLElement::willMoveToNewOwnerDocument();
    212 }
    213 
    214 void HTMLMediaElement::didMoveToNewOwnerDocument()
    215 {
    216     if (m_isWaitingUntilMediaCanStart)
    217         document()->addMediaCanStartListener(this);
    218     if (m_readyState < HAVE_CURRENT_DATA)
    219         setShouldDelayLoadEvent(true);
    220     document()->registerForDocumentActivationCallbacks(this);
    221     document()->registerForMediaVolumeCallbacks(this);
    222     HTMLElement::didMoveToNewOwnerDocument();
    223 }
    224 
    225 void HTMLMediaElement::attributeChanged(Attribute* attr, bool preserveDecls)
    226 {
    227     HTMLElement::attributeChanged(attr, preserveDecls);
    228 
    229     const QualifiedName& attrName = attr->name();
    230     if (attrName == srcAttr) {
    231         // Trigger a reload, as long as the 'src' attribute is present.
    232         if (!getAttribute(srcAttr).isEmpty())
    233             scheduleLoad();
    234     }
    235     else if (attrName == controlsAttr) {
    236 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
    237         if (controls()) {
    238             if (!hasMediaControls()) {
    239                 if (!createMediaControls())
    240                     return;
    241 
    242                 mediaControls()->reset();
    243             }
    244             mediaControls()->show();
    245         } else if (hasMediaControls())
    246             mediaControls()->hide();
    247 #else
    248         if (m_player)
    249             m_player->setControls(controls());
    250 #endif
    251     }
    252 }
    253 
    254 void HTMLMediaElement::parseMappedAttribute(Attribute* attr)
    255 {
    256     const QualifiedName& attrName = attr->name();
    257 
    258     if (attrName == preloadAttr) {
    259         String value = attr->value();
    260 
    261         if (equalIgnoringCase(value, "none"))
    262             m_preload = MediaPlayer::None;
    263         else if (equalIgnoringCase(value, "metadata"))
    264             m_preload = MediaPlayer::MetaData;
    265         else {
    266             // The spec does not define an "invalid value default" but "auto" is suggested as the
    267             // "missing value default", so use it for everything except "none" and "metadata"
    268             m_preload = MediaPlayer::Auto;
    269         }
    270 
    271         // The attribute must be ignored if the autoplay attribute is present
    272         if (!autoplay() && m_player)
    273             m_player->setPreload(m_preload);
    274 
    275     } else if (attrName == onabortAttr)
    276         setAttributeEventListener(eventNames().abortEvent, createAttributeEventListener(this, attr));
    277     else if (attrName == onbeforeloadAttr)
    278         setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, attr));
    279     else if (attrName == oncanplayAttr)
    280         setAttributeEventListener(eventNames().canplayEvent, createAttributeEventListener(this, attr));
    281     else if (attrName == oncanplaythroughAttr)
    282         setAttributeEventListener(eventNames().canplaythroughEvent, createAttributeEventListener(this, attr));
    283     else if (attrName == ondurationchangeAttr)
    284         setAttributeEventListener(eventNames().durationchangeEvent, createAttributeEventListener(this, attr));
    285     else if (attrName == onemptiedAttr)
    286         setAttributeEventListener(eventNames().emptiedEvent, createAttributeEventListener(this, attr));
    287     else if (attrName == onendedAttr)
    288         setAttributeEventListener(eventNames().endedEvent, createAttributeEventListener(this, attr));
    289     else if (attrName == onerrorAttr)
    290         setAttributeEventListener(eventNames().errorEvent, createAttributeEventListener(this, attr));
    291     else if (attrName == onloadeddataAttr)
    292         setAttributeEventListener(eventNames().loadeddataEvent, createAttributeEventListener(this, attr));
    293     else if (attrName == onloadedmetadataAttr)
    294         setAttributeEventListener(eventNames().loadedmetadataEvent, createAttributeEventListener(this, attr));
    295     else if (attrName == onloadstartAttr)
    296         setAttributeEventListener(eventNames().loadstartEvent, createAttributeEventListener(this, attr));
    297     else if (attrName == onpauseAttr)
    298         setAttributeEventListener(eventNames().pauseEvent, createAttributeEventListener(this, attr));
    299     else if (attrName == onplayAttr)
    300         setAttributeEventListener(eventNames().playEvent, createAttributeEventListener(this, attr));
    301     else if (attrName == onplayingAttr)
    302         setAttributeEventListener(eventNames().playingEvent, createAttributeEventListener(this, attr));
    303     else if (attrName == onprogressAttr)
    304         setAttributeEventListener(eventNames().progressEvent, createAttributeEventListener(this, attr));
    305     else if (attrName == onratechangeAttr)
    306         setAttributeEventListener(eventNames().ratechangeEvent, createAttributeEventListener(this, attr));
    307     else if (attrName == onseekedAttr)
    308         setAttributeEventListener(eventNames().seekedEvent, createAttributeEventListener(this, attr));
    309     else if (attrName == onseekingAttr)
    310         setAttributeEventListener(eventNames().seekingEvent, createAttributeEventListener(this, attr));
    311     else if (attrName == onstalledAttr)
    312         setAttributeEventListener(eventNames().stalledEvent, createAttributeEventListener(this, attr));
    313     else if (attrName == onsuspendAttr)
    314         setAttributeEventListener(eventNames().suspendEvent, createAttributeEventListener(this, attr));
    315     else if (attrName == ontimeupdateAttr)
    316         setAttributeEventListener(eventNames().timeupdateEvent, createAttributeEventListener(this, attr));
    317     else if (attrName == onvolumechangeAttr)
    318         setAttributeEventListener(eventNames().volumechangeEvent, createAttributeEventListener(this, attr));
    319     else if (attrName == onwaitingAttr)
    320         setAttributeEventListener(eventNames().waitingEvent, createAttributeEventListener(this, attr));
    321     else if (attrName == onwebkitbeginfullscreenAttr)
    322         setAttributeEventListener(eventNames().webkitbeginfullscreenEvent, createAttributeEventListener(this, attr));
    323     else if (attrName == onwebkitendfullscreenAttr)
    324         setAttributeEventListener(eventNames().webkitendfullscreenEvent, createAttributeEventListener(this, attr));
    325     else
    326         HTMLElement::parseMappedAttribute(attr);
    327 }
    328 
    329 bool HTMLMediaElement::rendererIsNeeded(RenderStyle* style)
    330 {
    331 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
    332     UNUSED_PARAM(style);
    333     Frame* frame = document()->frame();
    334     if (!frame)
    335         return false;
    336 
    337     return true;
    338 #else
    339     return controls() ? HTMLElement::rendererIsNeeded(style) : false;
    340 #endif
    341 }
    342 
    343 RenderObject* HTMLMediaElement::createRenderer(RenderArena* arena, RenderStyle*)
    344 {
    345 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
    346     // Setup the renderer if we already have a proxy widget.
    347     RenderEmbeddedObject* mediaRenderer = new (arena) RenderEmbeddedObject(this);
    348     if (m_proxyWidget) {
    349         mediaRenderer->setWidget(m_proxyWidget);
    350 
    351         Frame* frame = document()->frame();
    352         FrameLoader* loader = frame ? frame->loader() : 0;
    353         if (loader)
    354             loader->showMediaPlayerProxyPlugin(m_proxyWidget.get());
    355     }
    356     return mediaRenderer;
    357 #else
    358     return new (arena) RenderMedia(this);
    359 #endif
    360 }
    361 
    362 void HTMLMediaElement::insertedIntoDocument()
    363 {
    364     LOG(Media, "HTMLMediaElement::removedFromDocument");
    365     HTMLElement::insertedIntoDocument();
    366     if (!getAttribute(srcAttr).isEmpty() && m_networkState == NETWORK_EMPTY)
    367         scheduleLoad();
    368 }
    369 
    370 void HTMLMediaElement::removedFromDocument()
    371 {
    372     LOG(Media, "HTMLMediaElement::removedFromDocument");
    373     if (m_networkState > NETWORK_EMPTY)
    374         pause(processingUserGesture());
    375     if (m_isFullscreen)
    376         exitFullscreen();
    377     HTMLElement::removedFromDocument();
    378 }
    379 
    380 void HTMLMediaElement::attach()
    381 {
    382     ASSERT(!attached());
    383 
    384 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
    385     m_needWidgetUpdate = true;
    386 #endif
    387 
    388     HTMLElement::attach();
    389 
    390     if (renderer())
    391         renderer()->updateFromElement();
    392 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
    393     else if (m_proxyWidget) {
    394         Frame* frame = document()->frame();
    395         FrameLoader* loader = frame ? frame->loader() : 0;
    396         if (loader)
    397             loader->hideMediaPlayerProxyPlugin(m_proxyWidget.get());
    398     }
    399 #endif
    400 }
    401 
    402 void HTMLMediaElement::recalcStyle(StyleChange change)
    403 {
    404     HTMLElement::recalcStyle(change);
    405 
    406     if (renderer())
    407         renderer()->updateFromElement();
    408 }
    409 
    410 void HTMLMediaElement::scheduleLoad()
    411 {
    412     LOG(Media, "HTMLMediaElement::scheduleLoad");
    413 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
    414     createMediaPlayerProxy();
    415 #endif
    416 
    417     if (m_loadTimer.isActive())
    418         return;
    419     prepareForLoad();
    420     m_loadTimer.startOneShot(0);
    421 }
    422 
    423 void HTMLMediaElement::scheduleNextSourceChild()
    424 {
    425     // Schedule the timer to try the next <source> element WITHOUT resetting state ala prepareForLoad.
    426     m_loadTimer.startOneShot(0);
    427 }
    428 
    429 void HTMLMediaElement::scheduleEvent(const AtomicString& eventName)
    430 {
    431 #if LOG_MEDIA_EVENTS
    432     LOG(Media, "HTMLMediaElement::scheduleEvent - scheduling '%s'", eventName.string().ascii().data());
    433 #endif
    434     m_pendingEvents.append(Event::create(eventName, false, true));
    435     if (!m_asyncEventTimer.isActive())
    436         m_asyncEventTimer.startOneShot(0);
    437 }
    438 
    439 void HTMLMediaElement::asyncEventTimerFired(Timer<HTMLMediaElement>*)
    440 {
    441     Vector<RefPtr<Event> > pendingEvents;
    442     ExceptionCode ec = 0;
    443 
    444     m_pendingEvents.swap(pendingEvents);
    445     unsigned count = pendingEvents.size();
    446     for (unsigned ndx = 0; ndx < count; ++ndx) {
    447 #if LOG_MEDIA_EVENTS
    448         LOG(Media, "HTMLMediaElement::asyncEventTimerFired - dispatching '%s'", pendingEvents[ndx]->type().string().ascii().data());
    449 #endif
    450         if (pendingEvents[ndx]->type() == eventNames().canplayEvent) {
    451             m_dispatchingCanPlayEvent = true;
    452             dispatchEvent(pendingEvents[ndx].release(), ec);
    453             m_dispatchingCanPlayEvent = false;
    454         } else
    455             dispatchEvent(pendingEvents[ndx].release(), ec);
    456     }
    457 }
    458 
    459 void HTMLMediaElement::loadTimerFired(Timer<HTMLMediaElement>*)
    460 {
    461     if (m_loadState == LoadingFromSourceElement)
    462         loadNextSourceChild();
    463     else
    464         loadInternal();
    465 }
    466 
    467 PassRefPtr<MediaError> HTMLMediaElement::error() const
    468 {
    469     return m_error;
    470 }
    471 
    472 void HTMLMediaElement::setSrc(const String& url)
    473 {
    474     setAttribute(srcAttr, url);
    475 }
    476 
    477 String HTMLMediaElement::currentSrc() const
    478 {
    479     return m_currentSrc;
    480 }
    481 
    482 HTMLMediaElement::NetworkState HTMLMediaElement::networkState() const
    483 {
    484     return m_networkState;
    485 }
    486 
    487 String HTMLMediaElement::canPlayType(const String& mimeType) const
    488 {
    489     MediaPlayer::SupportsType support = MediaPlayer::supportsType(ContentType(mimeType));
    490     String canPlay;
    491 
    492     // 4.8.10.3
    493     switch (support)
    494     {
    495         case MediaPlayer::IsNotSupported:
    496             canPlay = "";
    497             break;
    498         case MediaPlayer::MayBeSupported:
    499             canPlay = "maybe";
    500             break;
    501         case MediaPlayer::IsSupported:
    502             canPlay = "probably";
    503             break;
    504     }
    505 
    506     LOG(Media, "HTMLMediaElement::canPlayType(%s) -> %s", mimeType.utf8().data(), canPlay.utf8().data());
    507 
    508     return canPlay;
    509 }
    510 
    511 void HTMLMediaElement::load(bool isUserGesture, ExceptionCode& ec)
    512 {
    513     LOG(Media, "HTMLMediaElement::load(isUserGesture : %s)", boolString(isUserGesture));
    514 
    515     if (m_restrictions & RequireUserGestureForLoadRestriction && !isUserGesture)
    516         ec = INVALID_STATE_ERR;
    517     else {
    518         m_loadInitiatedByUserGesture = isUserGesture;
    519 #if PLATFORM(ANDROID)
    520         m_userGestureInitiated |= isUserGesture;
    521 #endif
    522         prepareForLoad();
    523         loadInternal();
    524     }
    525 }
    526 
    527 void HTMLMediaElement::prepareForLoad()
    528 {
    529     LOG(Media, "HTMLMediaElement::prepareForLoad");
    530 
    531     // Perform the cleanup required for the resource load algorithm to run.
    532     stopPeriodicTimers();
    533     m_loadTimer.stop();
    534     m_sentStalledEvent = false;
    535     m_haveFiredLoadedData = false;
    536     m_completelyLoaded = false;
    537     m_displayMode = Unknown;
    538 
    539     // 1 - Abort any already-running instance of the resource selection algorithm for this element.
    540     m_loadState = WaitingForSource;
    541     m_currentSourceNode = 0;
    542 
    543     // 2 - If there are any tasks from the media element's media element event task source in
    544     // one of the task queues, then remove those tasks.
    545     cancelPendingEventsAndCallbacks();
    546 
    547     // 3 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, queue
    548     // a task to fire a simple event named abort at the media element.
    549     if (m_networkState == NETWORK_LOADING || m_networkState == NETWORK_IDLE)
    550         scheduleEvent(eventNames().abortEvent);
    551 
    552 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
    553     m_player = MediaPlayer::create(this);
    554 #else
    555     if (m_player)
    556         m_player->cancelLoad();
    557     else
    558         createMediaPlayerProxy();
    559 #endif
    560 
    561     // 4 - If the media element's networkState is not set to NETWORK_EMPTY, then run these substeps
    562     if (m_networkState != NETWORK_EMPTY) {
    563         m_networkState = NETWORK_EMPTY;
    564         m_readyState = HAVE_NOTHING;
    565         m_readyStateMaximum = HAVE_NOTHING;
    566         refreshCachedTime();
    567         m_paused = true;
    568         m_seeking = false;
    569         invalidateCachedTime();
    570         scheduleEvent(eventNames().emptiedEvent);
    571     }
    572 
    573     // 5 - Set the playbackRate attribute to the value of the defaultPlaybackRate attribute.
    574     setPlaybackRate(defaultPlaybackRate());
    575 
    576     // 6 - Set the error attribute to null and the autoplaying flag to true.
    577     m_error = 0;
    578     m_autoplaying = true;
    579 
    580     // 7 - Invoke the media element's resource selection algorithm.
    581 
    582     // 8 - Note: Playback of any previously playing media resource for this element stops.
    583 
    584     // The resource selection algorithm
    585     // 1 - Set the networkState to NETWORK_NO_SOURCE
    586     m_networkState = NETWORK_NO_SOURCE;
    587 
    588     // 2 - Asynchronously await a stable state.
    589 
    590     m_playedTimeRanges = TimeRanges::create();
    591     m_lastSeekTime = 0;
    592     m_closedCaptionsVisible = false;
    593 
    594     // The spec doesn't say to block the load event until we actually run the asynchronous section
    595     // algorithm, but do it now because we won't start that until after the timer fires and the
    596     // event may have already fired by then.
    597     setShouldDelayLoadEvent(true);
    598 }
    599 
    600 void HTMLMediaElement::loadInternal()
    601 {
    602     // If we can't start a load right away, start it later.
    603     Page* page = document()->page();
    604     if (page && !page->canStartMedia()) {
    605         if (m_isWaitingUntilMediaCanStart)
    606             return;
    607         document()->addMediaCanStartListener(this);
    608         m_isWaitingUntilMediaCanStart = true;
    609         return;
    610     }
    611 
    612     selectMediaResource();
    613 }
    614 
    615 void HTMLMediaElement::selectMediaResource()
    616 {
    617     LOG(Media, "HTMLMediaElement::selectMediaResource");
    618 
    619     enum Mode { attribute, children };
    620     Mode mode = attribute;
    621 
    622     // 3 - ... the media element has neither a src attribute ...
    623     if (!hasAttribute(srcAttr)) {
    624         // ... nor a source element child: ...
    625         Node* node;
    626         for (node = firstChild(); node; node = node->nextSibling()) {
    627             if (node->hasTagName(sourceTag))
    628                 break;
    629         }
    630 
    631         if (!node) {
    632             m_loadState = WaitingForSource;
    633             setShouldDelayLoadEvent(false);
    634 
    635             // ... set the networkState to NETWORK_EMPTY, and abort these steps
    636             m_networkState = NETWORK_EMPTY;
    637 
    638             LOG(Media, "HTMLMediaElement::selectMediaResource, nothing to load");
    639             return;
    640         }
    641 
    642         mode = children;
    643     }
    644 
    645     // 4 - Set the media element's delaying-the-load-event flag to true (this delays the load event),
    646     // and set its networkState to NETWORK_LOADING.
    647     setShouldDelayLoadEvent(true);
    648     m_networkState = NETWORK_LOADING;
    649 
    650     // 5
    651     scheduleEvent(eventNames().loadstartEvent);
    652 
    653     // 6 - If mode is attribute, then run these substeps
    654     if (mode == attribute) {
    655         // If the src attribute's value is the empty string ... jump down to the failed step below
    656         KURL mediaURL = getNonEmptyURLAttribute(srcAttr);
    657         if (mediaURL.isEmpty()) {
    658             noneSupported();
    659             LOG(Media, "HTMLMediaElement::selectMediaResource, empty 'src'");
    660             return;
    661         }
    662 
    663         if (isSafeToLoadURL(mediaURL, Complain) && dispatchBeforeLoadEvent(mediaURL.string())) {
    664             ContentType contentType("");
    665             m_loadState = LoadingFromSrcAttr;
    666             loadResource(mediaURL, contentType);
    667         } else
    668             noneSupported();
    669 
    670         LOG(Media, "HTMLMediaElement::selectMediaResource, 'src' not used");
    671         return;
    672     }
    673 
    674     // Otherwise, the source elements will be used
    675     m_currentSourceNode = 0;
    676     loadNextSourceChild();
    677 }
    678 
    679 void HTMLMediaElement::loadNextSourceChild()
    680 {
    681     ContentType contentType("");
    682     KURL mediaURL = selectNextSourceChild(&contentType, Complain);
    683     if (!mediaURL.isValid()) {
    684         waitForSourceChange();
    685         return;
    686     }
    687 
    688 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
    689     // Recreate the media player for the new url
    690     m_player = MediaPlayer::create(this);
    691 #endif
    692 
    693     m_loadState = LoadingFromSourceElement;
    694     loadResource(mediaURL, contentType);
    695 }
    696 
    697 void HTMLMediaElement::loadResource(const KURL& initialURL, ContentType& contentType)
    698 {
    699     ASSERT(isSafeToLoadURL(initialURL, Complain));
    700 
    701     LOG(Media, "HTMLMediaElement::loadResource(%s, %s)", urlForLogging(initialURL.string()).utf8().data(), contentType.raw().utf8().data());
    702 
    703     Frame* frame = document()->frame();
    704     if (!frame)
    705         return;
    706     FrameLoader* loader = frame->loader();
    707     if (!loader)
    708         return;
    709 
    710     KURL url(initialURL);
    711     if (!loader->willLoadMediaElementURL(url))
    712         return;
    713 
    714     // The resource fetch algorithm
    715     m_networkState = NETWORK_LOADING;
    716 
    717     m_currentSrc = url;
    718 
    719     LOG(Media, "HTMLMediaElement::loadResource - m_currentSrc -> %s", urlForLogging(m_currentSrc).utf8().data());
    720 
    721     if (m_sendProgressEvents)
    722         startProgressEventTimer();
    723 
    724     Settings* settings = document()->settings();
    725     bool privateMode = !settings || settings->privateBrowsingEnabled();
    726     m_player->setPrivateBrowsingMode(privateMode);
    727 
    728     if (!autoplay())
    729         m_player->setPreload(m_preload);
    730     m_player->setPreservesPitch(m_webkitPreservesPitch);
    731     updateVolume();
    732 
    733 #if PLATFORM(ANDROID)
    734     if (isVideo())
    735         m_player->setMediaElementType(MediaPlayer::Video);
    736     else
    737         m_player->setMediaElementType(MediaPlayer::Audio);
    738 #endif
    739     m_player->load(m_currentSrc, contentType);
    740 
    741     // If there is no poster to display, allow the media engine to render video frames as soon as
    742     // they are available.
    743     updateDisplayState();
    744 
    745     if (renderer())
    746         renderer()->updateFromElement();
    747 }
    748 
    749 bool HTMLMediaElement::isSafeToLoadURL(const KURL& url, InvalidSourceAction actionIfInvalid)
    750 {
    751     if (!url.isValid()) {
    752         LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%s) -> FALSE because url is invalid", urlForLogging(url.string()).utf8().data());
    753         return false;
    754     }
    755 
    756     Frame* frame = document()->frame();
    757     if (!frame || !document()->securityOrigin()->canDisplay(url)) {
    758         if (actionIfInvalid == Complain)
    759             FrameLoader::reportLocalLoadFailed(frame, url.string());
    760         LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%s) -> FALSE rejected by SecurityOrigin", urlForLogging(url.string()).utf8().data());
    761         return false;
    762     }
    763 
    764     if (!document()->contentSecurityPolicy()->allowMediaFromSource(url))
    765         return false;
    766 
    767     return true;
    768 }
    769 
    770 void HTMLMediaElement::startProgressEventTimer()
    771 {
    772     if (m_progressEventTimer.isActive())
    773         return;
    774 
    775     m_previousProgressTime = WTF::currentTime();
    776     m_previousProgress = 0;
    777     // 350ms is not magic, it is in the spec!
    778     m_progressEventTimer.startRepeating(0.350);
    779 }
    780 
    781 void HTMLMediaElement::waitForSourceChange()
    782 {
    783     LOG(Media, "HTMLMediaElement::waitForSourceChange");
    784 
    785     stopPeriodicTimers();
    786     m_loadState = WaitingForSource;
    787 
    788     // 6.17 - Waiting: Set the element's networkState attribute to the NETWORK_NO_SOURCE value
    789     m_networkState = NETWORK_NO_SOURCE;
    790 
    791     // 6.18 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
    792     setShouldDelayLoadEvent(false);
    793 }
    794 
    795 void HTMLMediaElement::noneSupported()
    796 {
    797     LOG(Media, "HTMLMediaElement::noneSupported");
    798 
    799     stopPeriodicTimers();
    800     m_loadState = WaitingForSource;
    801     m_currentSourceNode = 0;
    802 
    803     // 5 - Reaching this step indicates that either the URL failed to resolve, or the media
    804     // resource failed to load. Set the error attribute to a new MediaError object whose
    805     // code attribute is set to MEDIA_ERR_SRC_NOT_SUPPORTED.
    806     m_error = MediaError::create(MediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
    807 
    808     // 6 - Set the element's networkState attribute to the NETWORK_NO_SOURCE value.
    809     m_networkState = NETWORK_NO_SOURCE;
    810 
    811     // 7 - Queue a task to fire a progress event called error at the media element, in
    812     // the context of the fetching process that was used to try to obtain the media
    813     // resource in the resource fetch algorithm.
    814     scheduleEvent(eventNames().errorEvent);
    815 
    816     // 8 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
    817     setShouldDelayLoadEvent(false);
    818 
    819     // 9 -Abort these steps. Until the load() method is invoked, the element won't attempt to load another resource.
    820 
    821     updateDisplayState();
    822 
    823     if (renderer())
    824         renderer()->updateFromElement();
    825 }
    826 
    827 void HTMLMediaElement::mediaEngineError(PassRefPtr<MediaError> err)
    828 {
    829     LOG(Media, "HTMLMediaElement::mediaEngineError(%d)", static_cast<int>(err->code()));
    830 
    831     // 1 - The user agent should cancel the fetching process.
    832     stopPeriodicTimers();
    833     m_loadState = WaitingForSource;
    834 
    835     // 2 - Set the error attribute to a new MediaError object whose code attribute is
    836     // set to MEDIA_ERR_NETWORK/MEDIA_ERR_DECODE.
    837     m_error = err;
    838 
    839     // 3 - Queue a task to fire a simple event named error at the media element.
    840     scheduleEvent(eventNames().errorEvent);
    841 
    842     // 4 - Set the element's networkState attribute to the NETWORK_EMPTY value and queue a
    843     // task to fire a simple event called emptied at the element.
    844     m_networkState = NETWORK_EMPTY;
    845     scheduleEvent(eventNames().emptiedEvent);
    846 
    847     // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
    848     setShouldDelayLoadEvent(false);
    849 
    850     // 6 - Abort the overall resource selection algorithm.
    851     m_currentSourceNode = 0;
    852 }
    853 
    854 void HTMLMediaElement::cancelPendingEventsAndCallbacks()
    855 {
    856     LOG(Media, "HTMLMediaElement::cancelPendingEventsAndCallbacks");
    857 
    858     m_pendingEvents.clear();
    859 
    860     for (Node* node = firstChild(); node; node = node->nextSibling()) {
    861         if (node->hasTagName(sourceTag))
    862             static_cast<HTMLSourceElement*>(node)->cancelPendingErrorEvent();
    863     }
    864 }
    865 
    866 Document* HTMLMediaElement::mediaPlayerOwningDocument()
    867 {
    868     Document* d = document();
    869 
    870     if (!d)
    871         d = ownerDocument();
    872 
    873     return d;
    874 }
    875 
    876 void HTMLMediaElement::mediaPlayerNetworkStateChanged(MediaPlayer*)
    877 {
    878     beginProcessingMediaPlayerCallback();
    879     setNetworkState(m_player->networkState());
    880     endProcessingMediaPlayerCallback();
    881 }
    882 
    883 void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
    884 {
    885     LOG(Media, "HTMLMediaElement::setNetworkState(%d) - current state is %d", static_cast<int>(state), static_cast<int>(m_networkState));
    886 
    887     if (state == MediaPlayer::Empty) {
    888         // Just update the cached state and leave, we can't do anything.
    889         m_networkState = NETWORK_EMPTY;
    890         return;
    891     }
    892 
    893     if (state == MediaPlayer::FormatError || state == MediaPlayer::NetworkError || state == MediaPlayer::DecodeError) {
    894         stopPeriodicTimers();
    895 
    896         // If we failed while trying to load a <source> element, the movie was never parsed, and there are more
    897         // <source> children, schedule the next one
    898         if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement) {
    899 
    900             if (m_currentSourceNode)
    901                 m_currentSourceNode->scheduleErrorEvent();
    902             else
    903                 LOG(Media, "HTMLMediaElement::setNetworkState - error event not sent, <source> was removed");
    904 
    905             if (havePotentialSourceChild()) {
    906                 LOG(Media, "HTMLMediaElement::setNetworkState - scheduling next <source>");
    907                 scheduleNextSourceChild();
    908             } else {
    909                 LOG(Media, "HTMLMediaElement::setNetworkState - no more <source> elements, waiting");
    910                 waitForSourceChange();
    911             }
    912 
    913             return;
    914         }
    915 
    916         if (state == MediaPlayer::NetworkError)
    917             mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_NETWORK));
    918         else if (state == MediaPlayer::DecodeError)
    919             mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_DECODE));
    920         else if (state == MediaPlayer::FormatError && m_loadState == LoadingFromSrcAttr)
    921             noneSupported();
    922 
    923         updateDisplayState();
    924         if (hasMediaControls())
    925             mediaControls()->reportedError();
    926         return;
    927     }
    928 
    929     if (state == MediaPlayer::Idle) {
    930         if (m_networkState > NETWORK_IDLE) {
    931             m_progressEventTimer.stop();
    932             scheduleEvent(eventNames().suspendEvent);
    933             setShouldDelayLoadEvent(false);
    934         }
    935         m_networkState = NETWORK_IDLE;
    936     }
    937 
    938     if (state == MediaPlayer::Loading) {
    939         if (m_networkState < NETWORK_LOADING || m_networkState == NETWORK_NO_SOURCE)
    940             startProgressEventTimer();
    941         m_networkState = NETWORK_LOADING;
    942     }
    943 
    944     if (state == MediaPlayer::Loaded) {
    945         if (m_networkState != NETWORK_IDLE) {
    946             m_progressEventTimer.stop();
    947 
    948             // Schedule one last progress event so we guarantee that at least one is fired
    949             // for files that load very quickly.
    950             scheduleEvent(eventNames().progressEvent);
    951         }
    952         m_networkState = NETWORK_IDLE;
    953         m_completelyLoaded = true;
    954     }
    955 
    956     if (hasMediaControls())
    957         mediaControls()->changedNetworkState();
    958 }
    959 
    960 void HTMLMediaElement::mediaPlayerReadyStateChanged(MediaPlayer*)
    961 {
    962     beginProcessingMediaPlayerCallback();
    963 
    964     setReadyState(m_player->readyState());
    965 
    966     endProcessingMediaPlayerCallback();
    967 }
    968 
    969 void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
    970 {
    971     LOG(Media, "HTMLMediaElement::setReadyState(%d) - current state is %d,", static_cast<int>(state), static_cast<int>(m_readyState));
    972 
    973     // Set "wasPotentiallyPlaying" BEFORE updating m_readyState, potentiallyPlaying() uses it
    974     bool wasPotentiallyPlaying = potentiallyPlaying();
    975 
    976     ReadyState oldState = m_readyState;
    977     m_readyState = static_cast<ReadyState>(state);
    978 
    979     if (m_readyState == oldState)
    980         return;
    981 
    982     if (oldState > m_readyStateMaximum)
    983         m_readyStateMaximum = oldState;
    984 
    985     if (m_networkState == NETWORK_EMPTY)
    986         return;
    987 
    988     if (m_seeking) {
    989         // 4.8.10.9, step 11
    990         if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA)
    991             scheduleEvent(eventNames().waitingEvent);
    992 
    993         // 4.8.10.10 step 14 & 15.
    994         if (m_readyState >= HAVE_CURRENT_DATA)
    995             finishSeek();
    996     } else {
    997         if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA) {
    998             // 4.8.10.8
    999             scheduleTimeupdateEvent(false);
   1000             scheduleEvent(eventNames().waitingEvent);
   1001         }
   1002     }
   1003 
   1004     if (m_readyState >= HAVE_METADATA && oldState < HAVE_METADATA) {
   1005         scheduleEvent(eventNames().durationchangeEvent);
   1006         scheduleEvent(eventNames().loadedmetadataEvent);
   1007         if (hasMediaControls())
   1008             mediaControls()->loadedMetadata();
   1009         if (renderer())
   1010             renderer()->updateFromElement();
   1011         m_player->seek(0);
   1012     }
   1013 
   1014     bool shouldUpdateDisplayState = false;
   1015 
   1016     if (m_readyState >= HAVE_CURRENT_DATA && oldState < HAVE_CURRENT_DATA && !m_haveFiredLoadedData) {
   1017         m_haveFiredLoadedData = true;
   1018         shouldUpdateDisplayState = true;
   1019         scheduleEvent(eventNames().loadeddataEvent);
   1020         setShouldDelayLoadEvent(false);
   1021     }
   1022 
   1023     bool isPotentiallyPlaying = potentiallyPlaying();
   1024     if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA) {
   1025         scheduleEvent(eventNames().canplayEvent);
   1026         if (isPotentiallyPlaying)
   1027             scheduleEvent(eventNames().playingEvent);
   1028         shouldUpdateDisplayState = true;
   1029     }
   1030 
   1031     if (m_readyState == HAVE_ENOUGH_DATA && oldState < HAVE_ENOUGH_DATA) {
   1032         if (oldState <= HAVE_CURRENT_DATA)
   1033             scheduleEvent(eventNames().canplayEvent);
   1034 
   1035         scheduleEvent(eventNames().canplaythroughEvent);
   1036 
   1037         if (isPotentiallyPlaying && oldState <= HAVE_CURRENT_DATA)
   1038             scheduleEvent(eventNames().playingEvent);
   1039 #if PLATFORM(ANDROID)
   1040         // autoplay should not be honored if we require user gesture.
   1041         if (!(m_restrictions & RequireUserGestureForRateChangeRestriction))
   1042 #endif
   1043         if (m_autoplaying && m_paused && autoplay()) {
   1044             m_paused = false;
   1045             invalidateCachedTime();
   1046             scheduleEvent(eventNames().playEvent);
   1047             scheduleEvent(eventNames().playingEvent);
   1048         }
   1049 
   1050         shouldUpdateDisplayState = true;
   1051     }
   1052 
   1053     if (shouldUpdateDisplayState)
   1054         updateDisplayState();
   1055 
   1056     updatePlayState();
   1057 }
   1058 
   1059 void HTMLMediaElement::progressEventTimerFired(Timer<HTMLMediaElement>*)
   1060 {
   1061     ASSERT(m_player);
   1062     if (m_networkState != NETWORK_LOADING)
   1063         return;
   1064 
   1065     unsigned progress = m_player->bytesLoaded();
   1066     double time = WTF::currentTime();
   1067     double timedelta = time - m_previousProgressTime;
   1068 
   1069     if (progress == m_previousProgress) {
   1070         if (timedelta > 3.0 && !m_sentStalledEvent) {
   1071             scheduleEvent(eventNames().stalledEvent);
   1072             m_sentStalledEvent = true;
   1073             setShouldDelayLoadEvent(false);
   1074         }
   1075     } else {
   1076         scheduleEvent(eventNames().progressEvent);
   1077         m_previousProgress = progress;
   1078         m_previousProgressTime = time;
   1079         m_sentStalledEvent = false;
   1080         if (renderer())
   1081             renderer()->updateFromElement();
   1082     }
   1083 }
   1084 
   1085 void HTMLMediaElement::rewind(float timeDelta)
   1086 {
   1087     LOG(Media, "HTMLMediaElement::rewind(%f)", timeDelta);
   1088 
   1089     ExceptionCode e;
   1090     setCurrentTime(max(currentTime() - timeDelta, minTimeSeekable()), e);
   1091 }
   1092 
   1093 void HTMLMediaElement::returnToRealtime()
   1094 {
   1095     LOG(Media, "HTMLMediaElement::returnToRealtime");
   1096     ExceptionCode e;
   1097     setCurrentTime(maxTimeSeekable(), e);
   1098 }
   1099 
   1100 void HTMLMediaElement::addPlayedRange(float start, float end)
   1101 {
   1102     LOG(Media, "HTMLMediaElement::addPlayedRange(%f, %f)", start, end);
   1103     if (!m_playedTimeRanges)
   1104         m_playedTimeRanges = TimeRanges::create();
   1105     m_playedTimeRanges->add(start, end);
   1106 }
   1107 
   1108 bool HTMLMediaElement::supportsSave() const
   1109 {
   1110     return m_player ? m_player->supportsSave() : false;
   1111 }
   1112 
   1113 void HTMLMediaElement::seek(float time, ExceptionCode& ec)
   1114 {
   1115     LOG(Media, "HTMLMediaElement::seek(%f)", time);
   1116 
   1117     // 4.8.9.9 Seeking
   1118 
   1119     // 1 - If the media element's readyState is HAVE_NOTHING, then raise an INVALID_STATE_ERR exception.
   1120     if (m_readyState == HAVE_NOTHING || !m_player) {
   1121         ec = INVALID_STATE_ERR;
   1122         return;
   1123     }
   1124 
   1125     // Get the current time before setting m_seeking, m_lastSeekTime is returned once it is set.
   1126     refreshCachedTime();
   1127     float now = currentTime();
   1128 
   1129     // 2 - If the element's seeking IDL attribute is true, then another instance of this algorithm is
   1130     // already running. Abort that other instance of the algorithm without waiting for the step that
   1131     // it is running to complete.
   1132     // Nothing specific to be done here.
   1133 
   1134     // 3 - Set the seeking IDL attribute to true.
   1135     // The flag will be cleared when the engine tells us the time has actually changed.
   1136     m_seeking = true;
   1137 
   1138     // 5 - If the new playback position is later than the end of the media resource, then let it be the end
   1139     // of the media resource instead.
   1140     time = min(time, duration());
   1141 
   1142     // 6 - If the new playback position is less than the earliest possible position, let it be that position instead.
   1143     float earliestTime = m_player->startTime();
   1144     time = max(time, earliestTime);
   1145 
   1146     // Ask the media engine for the time value in the movie's time scale before comparing with current time. This
   1147     // is necessary because if the seek time is not equal to currentTime but the delta is less than the movie's
   1148     // time scale, we will ask the media engine to "seek" to the current movie time, which may be a noop and
   1149     // not generate a timechanged callback. This means m_seeking will never be cleared and we will never
   1150     // fire a 'seeked' event.
   1151 #if !LOG_DISABLED
   1152     float mediaTime = m_player->mediaTimeForTimeValue(time);
   1153     if (time != mediaTime)
   1154         LOG(Media, "HTMLMediaElement::seek(%f) - media timeline equivalent is %f", time, mediaTime);
   1155 #endif
   1156     time = m_player->mediaTimeForTimeValue(time);
   1157 
   1158     // 7 - If the (possibly now changed) new playback position is not in one of the ranges given in the
   1159     // seekable attribute, then let it be the position in one of the ranges given in the seekable attribute
   1160     // that is the nearest to the new playback position. ... If there are no ranges given in the seekable
   1161     // attribute then set the seeking IDL attribute to false and abort these steps.
   1162     RefPtr<TimeRanges> seekableRanges = seekable();
   1163 
   1164     // Short circuit seeking to the current time by just firing the events if no seek is required.
   1165     // Don't skip calling the media engine if we are in poster mode because a seek should always
   1166     // cancel poster display.
   1167     bool noSeekRequired = !seekableRanges->length() || (time == now && displayMode() != Poster);
   1168     if (noSeekRequired) {
   1169         if (time == now) {
   1170             scheduleEvent(eventNames().seekingEvent);
   1171             scheduleTimeupdateEvent(false);
   1172             scheduleEvent(eventNames().seekedEvent);
   1173         }
   1174         m_seeking = false;
   1175         return;
   1176     }
   1177     time = seekableRanges->nearest(time);
   1178 
   1179     if (m_playing) {
   1180         if (m_lastSeekTime < now)
   1181             addPlayedRange(m_lastSeekTime, now);
   1182     }
   1183     m_lastSeekTime = time;
   1184     m_sentEndEvent = false;
   1185 
   1186     // 8 - Set the current playback position to the given new playback position
   1187     m_player->seek(time);
   1188 
   1189     // 9 - Queue a task to fire a simple event named seeking at the element.
   1190     scheduleEvent(eventNames().seekingEvent);
   1191 
   1192     // 10 - Queue a task to fire a simple event named timeupdate at the element.
   1193     scheduleTimeupdateEvent(false);
   1194 
   1195     // 11-15 are handled, if necessary, when the engine signals a readystate change.
   1196 }
   1197 
   1198 void HTMLMediaElement::finishSeek()
   1199 {
   1200     LOG(Media, "HTMLMediaElement::finishSeek");
   1201 
   1202     // 4.8.10.9 Seeking step 14
   1203     m_seeking = false;
   1204 
   1205     // 4.8.10.9 Seeking step 15
   1206     scheduleEvent(eventNames().seekedEvent);
   1207 
   1208     setDisplayMode(Video);
   1209 }
   1210 
   1211 HTMLMediaElement::ReadyState HTMLMediaElement::readyState() const
   1212 {
   1213     return m_readyState;
   1214 }
   1215 
   1216 MediaPlayer::MovieLoadType HTMLMediaElement::movieLoadType() const
   1217 {
   1218     return m_player ? m_player->movieLoadType() : MediaPlayer::Unknown;
   1219 }
   1220 
   1221 bool HTMLMediaElement::hasAudio() const
   1222 {
   1223     return m_player ? m_player->hasAudio() : false;
   1224 }
   1225 
   1226 bool HTMLMediaElement::seeking() const
   1227 {
   1228     return m_seeking;
   1229 }
   1230 
   1231 void HTMLMediaElement::refreshCachedTime() const
   1232 {
   1233     m_cachedTime = m_player->currentTime();
   1234     m_cachedTimeWallClockUpdateTime = WTF::currentTime();
   1235 }
   1236 
   1237 void HTMLMediaElement::invalidateCachedTime()
   1238 {
   1239     LOG(Media, "HTMLMediaElement::invalidateCachedTime");
   1240 
   1241     // Don't try to cache movie time when playback first starts as the time reported by the engine
   1242     // sometimes fluctuates for a short amount of time, so the cached time will be off if we take it
   1243     // too early.
   1244     static const double minimumTimePlayingBeforeCacheSnapshot = 0.5;
   1245 
   1246     m_minimumWallClockTimeToCacheMediaTime = WTF::currentTime() + minimumTimePlayingBeforeCacheSnapshot;
   1247     m_cachedTime = invalidMediaTime;
   1248 }
   1249 
   1250 // playback state
   1251 float HTMLMediaElement::currentTime() const
   1252 {
   1253 #if LOG_CACHED_TIME_WARNINGS
   1254     static const double minCachedDeltaForWarning = 0.01;
   1255 #endif
   1256 
   1257     if (!m_player)
   1258         return 0;
   1259 
   1260     if (m_seeking) {
   1261         LOG(Media, "HTMLMediaElement::currentTime - seeking, returning %f", m_lastSeekTime);
   1262         return m_lastSeekTime;
   1263     }
   1264 
   1265     if (m_cachedTime != invalidMediaTime && m_paused) {
   1266 #if LOG_CACHED_TIME_WARNINGS
   1267         float delta = m_cachedTime - m_player->currentTime();
   1268         if (delta > minCachedDeltaForWarning)
   1269             LOG(Media, "HTMLMediaElement::currentTime - WARNING, cached time is %f seconds off of media time when paused", delta);
   1270 #endif
   1271         return m_cachedTime;
   1272     }
   1273 
   1274     // Is it too soon use a cached time?
   1275     double now = WTF::currentTime();
   1276     double maximumDurationToCacheMediaTime = m_player->maximumDurationToCacheMediaTime();
   1277 
   1278     if (maximumDurationToCacheMediaTime && m_cachedTime != invalidMediaTime && !m_paused && now > m_minimumWallClockTimeToCacheMediaTime) {
   1279         double wallClockDelta = now - m_cachedTimeWallClockUpdateTime;
   1280 
   1281         // Not too soon, use the cached time only if it hasn't expired.
   1282         if (wallClockDelta < maximumDurationToCacheMediaTime) {
   1283             float adjustedCacheTime = static_cast<float>(m_cachedTime + (m_playbackRate * wallClockDelta));
   1284 
   1285 #if LOG_CACHED_TIME_WARNINGS
   1286             float delta = adjustedCacheTime - m_player->currentTime();
   1287             if (delta > minCachedDeltaForWarning)
   1288                 LOG(Media, "HTMLMediaElement::currentTime - WARNING, cached time is %f seconds off of media time when playing", delta);
   1289 #endif
   1290             return adjustedCacheTime;
   1291         }
   1292     }
   1293 
   1294 #if LOG_CACHED_TIME_WARNINGS
   1295     if (maximumDurationToCacheMediaTime && now > m_minimumWallClockTimeToCacheMediaTime && m_cachedTime != invalidMediaTime) {
   1296         double wallClockDelta = now - m_cachedTimeWallClockUpdateTime;
   1297         float delta = m_cachedTime + (m_playbackRate * wallClockDelta) - m_player->currentTime();
   1298         LOG(Media, "HTMLMediaElement::currentTime - cached time was %f seconds off of media time when it expired", delta);
   1299     }
   1300 #endif
   1301 
   1302     refreshCachedTime();
   1303 
   1304     return m_cachedTime;
   1305 }
   1306 
   1307 void HTMLMediaElement::setCurrentTime(float time, ExceptionCode& ec)
   1308 {
   1309     seek(time, ec);
   1310 }
   1311 
   1312 float HTMLMediaElement::startTime() const
   1313 {
   1314     if (!m_player)
   1315         return 0;
   1316     return m_player->startTime();
   1317 }
   1318 
   1319 float HTMLMediaElement::duration() const
   1320 {
   1321     if (m_player && m_readyState >= HAVE_METADATA)
   1322         return m_player->duration();
   1323 
   1324     return numeric_limits<float>::quiet_NaN();
   1325 }
   1326 
   1327 bool HTMLMediaElement::paused() const
   1328 {
   1329     return m_paused;
   1330 }
   1331 
   1332 float HTMLMediaElement::defaultPlaybackRate() const
   1333 {
   1334     return m_defaultPlaybackRate;
   1335 }
   1336 
   1337 void HTMLMediaElement::setDefaultPlaybackRate(float rate)
   1338 {
   1339     if (m_defaultPlaybackRate != rate) {
   1340         m_defaultPlaybackRate = rate;
   1341         scheduleEvent(eventNames().ratechangeEvent);
   1342     }
   1343 }
   1344 
   1345 float HTMLMediaElement::playbackRate() const
   1346 {
   1347     return m_playbackRate;
   1348 }
   1349 
   1350 void HTMLMediaElement::setPlaybackRate(float rate)
   1351 {
   1352     LOG(Media, "HTMLMediaElement::setPlaybackRate(%f)", rate);
   1353 
   1354     if (m_playbackRate != rate) {
   1355         m_playbackRate = rate;
   1356         invalidateCachedTime();
   1357         scheduleEvent(eventNames().ratechangeEvent);
   1358     }
   1359     if (m_player && potentiallyPlaying() && m_player->rate() != rate)
   1360         m_player->setRate(rate);
   1361 }
   1362 
   1363 bool HTMLMediaElement::webkitPreservesPitch() const
   1364 {
   1365     return m_webkitPreservesPitch;
   1366 }
   1367 
   1368 void HTMLMediaElement::setWebkitPreservesPitch(bool preservesPitch)
   1369 {
   1370     LOG(Media, "HTMLMediaElement::setWebkitPreservesPitch(%s)", boolString(preservesPitch));
   1371 
   1372     m_webkitPreservesPitch = preservesPitch;
   1373 
   1374     if (!m_player)
   1375         return;
   1376 
   1377     m_player->setPreservesPitch(preservesPitch);
   1378 }
   1379 
   1380 bool HTMLMediaElement::ended() const
   1381 {
   1382     // 4.8.10.8 Playing the media resource
   1383     // The ended attribute must return true if the media element has ended
   1384     // playback and the direction of playback is forwards, and false otherwise.
   1385     return endedPlayback() && m_playbackRate > 0;
   1386 }
   1387 
   1388 bool HTMLMediaElement::autoplay() const
   1389 {
   1390     return hasAttribute(autoplayAttr);
   1391 }
   1392 
   1393 void HTMLMediaElement::setAutoplay(bool b)
   1394 {
   1395     LOG(Media, "HTMLMediaElement::setAutoplay(%s)", boolString(b));
   1396     setBooleanAttribute(autoplayAttr, b);
   1397 }
   1398 
   1399 String HTMLMediaElement::preload() const
   1400 {
   1401     switch (m_preload) {
   1402     case MediaPlayer::None:
   1403         return "none";
   1404         break;
   1405     case MediaPlayer::MetaData:
   1406         return "metadata";
   1407         break;
   1408     case MediaPlayer::Auto:
   1409         return "auto";
   1410         break;
   1411     }
   1412 
   1413     ASSERT_NOT_REACHED();
   1414     return String();
   1415 }
   1416 
   1417 void HTMLMediaElement::setPreload(const String& preload)
   1418 {
   1419     LOG(Media, "HTMLMediaElement::setPreload(%s)", preload.utf8().data());
   1420     setAttribute(preloadAttr, preload);
   1421 }
   1422 
   1423 void HTMLMediaElement::play(bool isUserGesture)
   1424 {
   1425     LOG(Media, "HTMLMediaElement::play(isUserGesture : %s)", boolString(isUserGesture));
   1426 
   1427     if (m_restrictions & RequireUserGestureForRateChangeRestriction && !isUserGesture
   1428 #if PLATFORM(ANDROID)
   1429         && !m_userGestureInitiated
   1430 #endif
   1431         )
   1432         return;
   1433 
   1434 #if PLATFORM(ANDROID)
   1435     // B/c we set the restriction to require gesture for rate change for
   1436     // Android, when we don't early return, we can safely set this to true.
   1437     m_userGestureInitiated = true;
   1438 #endif
   1439 
   1440     Document* doc = document();
   1441     Settings* settings = doc->settings();
   1442     if (settings && settings->needsSiteSpecificQuirks() && m_dispatchingCanPlayEvent && !m_loadInitiatedByUserGesture) {
   1443         // It should be impossible to be processing the canplay event while handling a user gesture
   1444         // since it is dispatched asynchronously.
   1445         ASSERT(!isUserGesture);
   1446         String host = doc->baseURL().host();
   1447         if (host.endsWith(".npr.org", false) || equalIgnoringCase(host, "npr.org"))
   1448             return;
   1449     }
   1450 
   1451     playInternal();
   1452 }
   1453 
   1454 void HTMLMediaElement::playInternal()
   1455 {
   1456     LOG(Media, "HTMLMediaElement::playInternal");
   1457 
   1458     // 4.8.10.9. Playing the media resource
   1459     if (!m_player || m_networkState == NETWORK_EMPTY)
   1460         scheduleLoad();
   1461 
   1462     if (endedPlayback()) {
   1463         ExceptionCode unused;
   1464         seek(0, unused);
   1465     }
   1466 
   1467     if (m_paused) {
   1468         m_paused = false;
   1469         invalidateCachedTime();
   1470         scheduleEvent(eventNames().playEvent);
   1471 
   1472         if (m_readyState <= HAVE_CURRENT_DATA)
   1473             scheduleEvent(eventNames().waitingEvent);
   1474         else if (m_readyState >= HAVE_FUTURE_DATA)
   1475             scheduleEvent(eventNames().playingEvent);
   1476     }
   1477     m_autoplaying = false;
   1478 
   1479     updatePlayState();
   1480 }
   1481 
   1482 void HTMLMediaElement::pause(bool isUserGesture)
   1483 {
   1484     LOG(Media, "HTMLMediaElement::pause(isUserGesture : %s)", boolString(isUserGesture));
   1485 
   1486     if (m_restrictions & RequireUserGestureForRateChangeRestriction && !isUserGesture
   1487 #if PLATFORM(ANDROID)
   1488         && !m_userGestureInitiated
   1489 #endif
   1490         )
   1491         return;
   1492 #if PLATFORM(ANDROID)
   1493     // B/c we set the restriction to require gesture for rate change for
   1494     // Android, when we don't early return, we can safely set this to true.
   1495     m_userGestureInitiated = true;
   1496 #endif
   1497     pauseInternal();
   1498 }
   1499 
   1500 
   1501 void HTMLMediaElement::pauseInternal()
   1502 {
   1503     LOG(Media, "HTMLMediaElement::pauseInternal");
   1504 
   1505     // 4.8.10.9. Playing the media resource
   1506     if (!m_player || m_networkState == NETWORK_EMPTY)
   1507         scheduleLoad();
   1508 
   1509     m_autoplaying = false;
   1510 
   1511     if (!m_paused) {
   1512         m_paused = true;
   1513         scheduleTimeupdateEvent(false);
   1514         scheduleEvent(eventNames().pauseEvent);
   1515     }
   1516 
   1517     updatePlayState();
   1518 }
   1519 
   1520 bool HTMLMediaElement::loop() const
   1521 {
   1522     return hasAttribute(loopAttr);
   1523 }
   1524 
   1525 void HTMLMediaElement::setLoop(bool b)
   1526 {
   1527     LOG(Media, "HTMLMediaElement::setLoop(%s)", boolString(b));
   1528     setBooleanAttribute(loopAttr, b);
   1529 }
   1530 
   1531 bool HTMLMediaElement::controls() const
   1532 {
   1533     Frame* frame = document()->frame();
   1534 
   1535     // always show controls when scripting is disabled
   1536     if (frame && !frame->script()->canExecuteScripts(NotAboutToExecuteScript))
   1537         return true;
   1538 
   1539     // always show controls for video when fullscreen playback is required.
   1540     if (isVideo() && document()->page() && document()->page()->chrome()->requiresFullscreenForVideoPlayback())
   1541         return true;
   1542 
   1543     // Always show controls when in full screen mode.
   1544     if (isFullscreen())
   1545         return true;
   1546 
   1547     return hasAttribute(controlsAttr);
   1548 }
   1549 
   1550 void HTMLMediaElement::setControls(bool b)
   1551 {
   1552     LOG(Media, "HTMLMediaElement::setControls(%s)", boolString(b));
   1553     setBooleanAttribute(controlsAttr, b);
   1554 }
   1555 
   1556 float HTMLMediaElement::volume() const
   1557 {
   1558     return m_volume;
   1559 }
   1560 
   1561 void HTMLMediaElement::setVolume(float vol, ExceptionCode& ec)
   1562 {
   1563     LOG(Media, "HTMLMediaElement::setVolume(%f)", vol);
   1564 
   1565     if (vol < 0.0f || vol > 1.0f) {
   1566         ec = INDEX_SIZE_ERR;
   1567         return;
   1568     }
   1569 
   1570     if (m_volume != vol) {
   1571         m_volume = vol;
   1572         updateVolume();
   1573         scheduleEvent(eventNames().volumechangeEvent);
   1574     }
   1575 }
   1576 
   1577 bool HTMLMediaElement::muted() const
   1578 {
   1579     return m_muted;
   1580 }
   1581 
   1582 void HTMLMediaElement::setMuted(bool muted)
   1583 {
   1584     LOG(Media, "HTMLMediaElement::setMuted(%s)", boolString(muted));
   1585 
   1586     if (m_muted != muted) {
   1587         m_muted = muted;
   1588         // Avoid recursion when the player reports volume changes.
   1589         if (!processingMediaPlayerCallback()) {
   1590             if (m_player) {
   1591                 m_player->setMuted(m_muted);
   1592                 if (hasMediaControls())
   1593                     mediaControls()->changedMute();
   1594             }
   1595         }
   1596         scheduleEvent(eventNames().volumechangeEvent);
   1597     }
   1598 }
   1599 
   1600 void HTMLMediaElement::togglePlayState()
   1601 {
   1602     LOG(Media, "HTMLMediaElement::togglePlayState - canPlay() is %s", boolString(canPlay()));
   1603 
   1604     // We can safely call the internal play/pause methods, which don't check restrictions, because
   1605     // this method is only called from the built-in media controller
   1606     if (canPlay()) {
   1607         setPlaybackRate(defaultPlaybackRate());
   1608         playInternal();
   1609     } else
   1610         pauseInternal();
   1611 }
   1612 
   1613 void HTMLMediaElement::beginScrubbing()
   1614 {
   1615     LOG(Media, "HTMLMediaElement::beginScrubbing - paused() is %s", boolString(paused()));
   1616 
   1617     if (!paused()) {
   1618         if (ended()) {
   1619             // Because a media element stays in non-paused state when it reaches end, playback resumes
   1620             // when the slider is dragged from the end to another position unless we pause first. Do
   1621             // a "hard pause" so an event is generated, since we want to stay paused after scrubbing finishes.
   1622             pause(processingUserGesture());
   1623         } else {
   1624             // Not at the end but we still want to pause playback so the media engine doesn't try to
   1625             // continue playing during scrubbing. Pause without generating an event as we will
   1626             // unpause after scrubbing finishes.
   1627             setPausedInternal(true);
   1628         }
   1629     }
   1630 }
   1631 
   1632 void HTMLMediaElement::endScrubbing()
   1633 {
   1634     LOG(Media, "HTMLMediaElement::endScrubbing - m_pausedInternal is %s", boolString(m_pausedInternal));
   1635 
   1636     if (m_pausedInternal)
   1637         setPausedInternal(false);
   1638 }
   1639 
   1640 // The spec says to fire periodic timeupdate events (those sent while playing) every
   1641 // "15 to 250ms", we choose the slowest frequency
   1642 static const double maxTimeupdateEventFrequency = 0.25;
   1643 
   1644 void HTMLMediaElement::startPlaybackProgressTimer()
   1645 {
   1646     if (m_playbackProgressTimer.isActive())
   1647         return;
   1648 
   1649     m_previousProgressTime = WTF::currentTime();
   1650     m_previousProgress = 0;
   1651     m_playbackProgressTimer.startRepeating(maxTimeupdateEventFrequency);
   1652 }
   1653 
   1654 void HTMLMediaElement::playbackProgressTimerFired(Timer<HTMLMediaElement>*)
   1655 {
   1656     ASSERT(m_player);
   1657     if (!m_playbackRate)
   1658         return;
   1659 
   1660     scheduleTimeupdateEvent(true);
   1661     if (hasMediaControls()) {
   1662 #if PLATFORM(ANDROID)
   1663         m_mouseOver = WTF::currentTime() - m_lastTouch <= TOUCH_DELAY;
   1664 #endif
   1665         if (!m_mouseOver && controls() && hasVideo())
   1666             mediaControls()->makeTransparent();
   1667 
   1668         mediaControls()->playbackProgressed();
   1669     }
   1670     // FIXME: deal with cue ranges here
   1671 }
   1672 
   1673 void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent)
   1674 {
   1675     double now = WTF::currentTime();
   1676     double timedelta = now - m_lastTimeUpdateEventWallTime;
   1677 
   1678     // throttle the periodic events
   1679     if (periodicEvent && timedelta < maxTimeupdateEventFrequency)
   1680         return;
   1681 
   1682     // Some media engines make multiple "time changed" callbacks at the same time, but we only want one
   1683     // event at a given time so filter here
   1684     float movieTime = currentTime();
   1685     if (movieTime != m_lastTimeUpdateEventMovieTime) {
   1686         scheduleEvent(eventNames().timeupdateEvent);
   1687         m_lastTimeUpdateEventWallTime = now;
   1688         m_lastTimeUpdateEventMovieTime = movieTime;
   1689     }
   1690 }
   1691 
   1692 bool HTMLMediaElement::canPlay() const
   1693 {
   1694     return paused() || ended() || m_readyState < HAVE_METADATA;
   1695 }
   1696 
   1697 float HTMLMediaElement::percentLoaded() const
   1698 {
   1699     if (!m_player)
   1700         return 0;
   1701     float duration = m_player->duration();
   1702 
   1703     if (!duration || isinf(duration))
   1704         return 0;
   1705 
   1706     float buffered = 0;
   1707     RefPtr<TimeRanges> timeRanges = m_player->buffered();
   1708     for (unsigned i = 0; i < timeRanges->length(); ++i) {
   1709         ExceptionCode ignoredException;
   1710         float start = timeRanges->start(i, ignoredException);
   1711         float end = timeRanges->end(i, ignoredException);
   1712         buffered += end - start;
   1713     }
   1714     return buffered / duration;
   1715 }
   1716 
   1717 bool HTMLMediaElement::havePotentialSourceChild()
   1718 {
   1719     // Stash the current <source> node and next nodes so we can restore them after checking
   1720     // to see there is another potential.
   1721     HTMLSourceElement* currentSourceNode = m_currentSourceNode;
   1722     Node* nextNode = m_nextChildNodeToConsider;
   1723 
   1724     KURL nextURL = selectNextSourceChild(0, DoNothing);
   1725 
   1726     m_currentSourceNode = currentSourceNode;
   1727     m_nextChildNodeToConsider = nextNode;
   1728 
   1729     return nextURL.isValid();
   1730 }
   1731 
   1732 KURL HTMLMediaElement::selectNextSourceChild(ContentType *contentType, InvalidSourceAction actionIfInvalid)
   1733 {
   1734 #if !LOG_DISABLED
   1735     // Don't log if this was just called to find out if there are any valid <source> elements.
   1736     bool shouldLog = actionIfInvalid != DoNothing;
   1737     if (shouldLog)
   1738         LOG(Media, "HTMLMediaElement::selectNextSourceChild(contentType : \"%s\")", contentType ? contentType->raw().utf8().data() : "");
   1739 #endif
   1740 
   1741     if (m_nextChildNodeToConsider == sourceChildEndOfListValue()) {
   1742 #if !LOG_DISABLED
   1743         if (shouldLog)
   1744             LOG(Media, "HTMLMediaElement::selectNextSourceChild -> 0x0000, \"\"");
   1745 #endif
   1746         return KURL();
   1747     }
   1748 
   1749     KURL mediaURL;
   1750     Node* node;
   1751     HTMLSourceElement* source = 0;
   1752     bool lookingForStartNode = m_nextChildNodeToConsider;
   1753     bool canUse = false;
   1754 
   1755     for (node = firstChild(); !canUse && node; node = node->nextSibling()) {
   1756         if (lookingForStartNode && m_nextChildNodeToConsider != node)
   1757             continue;
   1758         lookingForStartNode = false;
   1759 
   1760         if (!node->hasTagName(sourceTag))
   1761             continue;
   1762 
   1763         source = static_cast<HTMLSourceElement*>(node);
   1764 
   1765         // 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
   1766         mediaURL = source->getNonEmptyURLAttribute(srcAttr);
   1767 #if !LOG_DISABLED
   1768         if (shouldLog)
   1769             LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'src' is %s", urlForLogging(mediaURL).utf8().data());
   1770 #endif
   1771         if (mediaURL.isEmpty())
   1772             goto check_again;
   1773 
   1774         if (source->hasAttribute(mediaAttr)) {
   1775             MediaQueryEvaluator screenEval("screen", document()->frame(), renderer() ? renderer()->style() : 0);
   1776             RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(source->media());
   1777 #if !LOG_DISABLED
   1778             if (shouldLog)
   1779                 LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'media' is %s", source->media().utf8().data());
   1780 #endif
   1781             if (!screenEval.eval(media.get()))
   1782                 goto check_again;
   1783         }
   1784 
   1785         if (source->hasAttribute(typeAttr)) {
   1786 #if !LOG_DISABLED
   1787             if (shouldLog)
   1788                 LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'type' is %s", source->type().utf8().data());
   1789 #endif
   1790             if (!MediaPlayer::supportsType(ContentType(source->type())))
   1791                 goto check_again;
   1792         }
   1793 
   1794         // Is it safe to load this url?
   1795         if (!isSafeToLoadURL(mediaURL, actionIfInvalid) || !dispatchBeforeLoadEvent(mediaURL.string()))
   1796             goto check_again;
   1797 
   1798         // Making it this far means the <source> looks reasonable.
   1799         canUse = true;
   1800 
   1801 check_again:
   1802         if (!canUse && actionIfInvalid == Complain)
   1803             source->scheduleErrorEvent();
   1804     }
   1805 
   1806     if (canUse) {
   1807         if (contentType)
   1808             *contentType = ContentType(source->type());
   1809         m_currentSourceNode = source;
   1810         m_nextChildNodeToConsider = source->nextSibling();
   1811         if (!m_nextChildNodeToConsider)
   1812             m_nextChildNodeToConsider = sourceChildEndOfListValue();
   1813     } else {
   1814         m_currentSourceNode = 0;
   1815         m_nextChildNodeToConsider = sourceChildEndOfListValue();
   1816     }
   1817 
   1818 #if !LOG_DISABLED
   1819     if (shouldLog)
   1820         LOG(Media, "HTMLMediaElement::selectNextSourceChild -> %p, %s", m_currentSourceNode, canUse ? urlForLogging(mediaURL.string()).utf8().data() : "");
   1821 #endif
   1822     return canUse ? mediaURL : KURL();
   1823 }
   1824 
   1825 void HTMLMediaElement::sourceWasAdded(HTMLSourceElement* source)
   1826 {
   1827     LOG(Media, "HTMLMediaElement::sourceWasAdded(%p)", source);
   1828 
   1829 #if !LOG_DISABLED
   1830     if (source->hasTagName(sourceTag)) {
   1831         KURL url = source->getNonEmptyURLAttribute(srcAttr);
   1832         LOG(Media, "HTMLMediaElement::sourceWasAdded - 'src' is %s", urlForLogging(url).utf8().data());
   1833     }
   1834 #endif
   1835 
   1836     // We should only consider a <source> element when there is not src attribute at all.
   1837     if (hasAttribute(srcAttr))
   1838         return;
   1839 
   1840     // 4.8.8 - If a source element is inserted as a child of a media element that has no src
   1841     // attribute and whose networkState has the value NETWORK_EMPTY, the user agent must invoke
   1842     // the media element's resource selection algorithm.
   1843     if (networkState() == HTMLMediaElement::NETWORK_EMPTY) {
   1844         scheduleLoad();
   1845         return;
   1846     }
   1847 
   1848     if (m_currentSourceNode && source == m_currentSourceNode->nextSibling()) {
   1849         LOG(Media, "HTMLMediaElement::sourceWasAdded - <source> inserted immediately after current source");
   1850         m_nextChildNodeToConsider = source;
   1851         return;
   1852     }
   1853 
   1854     if (m_nextChildNodeToConsider != sourceChildEndOfListValue())
   1855         return;
   1856 
   1857     // 4.8.9.5, resource selection algorithm, source elements section:
   1858     // 20 - Wait until the node after pointer is a node other than the end of the list. (This step might wait forever.)
   1859     // 21 - Asynchronously await a stable state...
   1860     // 22 - Set the element's delaying-the-load-event flag back to true (this delays the load event again, in case
   1861     // it hasn't been fired yet).
   1862     setShouldDelayLoadEvent(true);
   1863 
   1864     // 23 - Set the networkState back to NETWORK_LOADING.
   1865     m_networkState = NETWORK_LOADING;
   1866 
   1867     // 24 - Jump back to the find next candidate step above.
   1868     m_nextChildNodeToConsider = source;
   1869     scheduleNextSourceChild();
   1870 }
   1871 
   1872 void HTMLMediaElement::sourceWillBeRemoved(HTMLSourceElement* source)
   1873 {
   1874     LOG(Media, "HTMLMediaElement::sourceWillBeRemoved(%p)", source);
   1875 
   1876 #if !LOG_DISABLED
   1877     if (source->hasTagName(sourceTag)) {
   1878         KURL url = source->getNonEmptyURLAttribute(srcAttr);
   1879         LOG(Media, "HTMLMediaElement::sourceWillBeRemoved - 'src' is %s", urlForLogging(url).utf8().data());
   1880     }
   1881 #endif
   1882 
   1883     if (source != m_currentSourceNode && source != m_nextChildNodeToConsider)
   1884         return;
   1885 
   1886     if (source == m_nextChildNodeToConsider) {
   1887         m_nextChildNodeToConsider = m_nextChildNodeToConsider->nextSibling();
   1888         if (!m_nextChildNodeToConsider)
   1889             m_nextChildNodeToConsider = sourceChildEndOfListValue();
   1890         LOG(Media, "HTMLMediaElement::sourceRemoved - m_nextChildNodeToConsider set to %p", m_nextChildNodeToConsider);
   1891     } else if (source == m_currentSourceNode) {
   1892         // Clear the current source node pointer, but don't change the movie as the spec says:
   1893         // 4.8.8 - Dynamically modifying a source element and its attribute when the element is already
   1894         // inserted in a video or audio element will have no effect.
   1895         m_currentSourceNode = 0;
   1896         LOG(Media, "HTMLMediaElement::sourceRemoved - m_currentSourceNode set to 0");
   1897     }
   1898 }
   1899 
   1900 void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
   1901 {
   1902     LOG(Media, "HTMLMediaElement::mediaPlayerTimeChanged");
   1903 
   1904     beginProcessingMediaPlayerCallback();
   1905 
   1906     invalidateCachedTime();
   1907 
   1908     // 4.8.10.9 step 14 & 15.  Needed if no ReadyState change is associated with the seek.
   1909     if (m_seeking && m_readyState >= HAVE_CURRENT_DATA)
   1910         finishSeek();
   1911 
   1912     // Always call scheduleTimeupdateEvent when the media engine reports a time discontinuity,
   1913     // it will only queue a 'timeupdate' event if we haven't already posted one at the current
   1914     // movie time.
   1915     scheduleTimeupdateEvent(false);
   1916 
   1917     float now = currentTime();
   1918     float dur = duration();
   1919     if (!isnan(dur) && dur && now >= dur) {
   1920         if (loop()) {
   1921             ExceptionCode ignoredException;
   1922             m_sentEndEvent = false;
   1923             seek(0, ignoredException);
   1924         } else {
   1925             if (!m_sentEndEvent) {
   1926                 m_sentEndEvent = true;
   1927                 scheduleEvent(eventNames().endedEvent);
   1928             }
   1929         }
   1930     }
   1931     else
   1932         m_sentEndEvent = false;
   1933 
   1934     updatePlayState();
   1935     endProcessingMediaPlayerCallback();
   1936 }
   1937 
   1938 void HTMLMediaElement::mediaPlayerVolumeChanged(MediaPlayer*)
   1939 {
   1940     LOG(Media, "HTMLMediaElement::mediaPlayerVolumeChanged");
   1941 
   1942     beginProcessingMediaPlayerCallback();
   1943     if (m_player) {
   1944         float vol = m_player->volume();
   1945         if (vol != m_volume) {
   1946             m_volume = vol;
   1947             updateVolume();
   1948             scheduleEvent(eventNames().volumechangeEvent);
   1949         }
   1950     }
   1951     endProcessingMediaPlayerCallback();
   1952 }
   1953 
   1954 void HTMLMediaElement::mediaPlayerMuteChanged(MediaPlayer*)
   1955 {
   1956     LOG(Media, "HTMLMediaElement::mediaPlayerMuteChanged");
   1957 
   1958     beginProcessingMediaPlayerCallback();
   1959     if (m_player)
   1960         setMuted(m_player->muted());
   1961     endProcessingMediaPlayerCallback();
   1962 }
   1963 
   1964 void HTMLMediaElement::mediaPlayerDurationChanged(MediaPlayer*)
   1965 {
   1966     LOG(Media, "HTMLMediaElement::mediaPlayerDurationChanged");
   1967 
   1968     beginProcessingMediaPlayerCallback();
   1969     scheduleEvent(eventNames().durationchangeEvent);
   1970     if (renderer())
   1971         renderer()->updateFromElement();
   1972     endProcessingMediaPlayerCallback();
   1973 
   1974 #if PLATFORM(ANDROID)
   1975     if (hasMediaControls())
   1976         mediaControls()->reset();
   1977 #endif
   1978 }
   1979 
   1980 void HTMLMediaElement::mediaPlayerRateChanged(MediaPlayer*)
   1981 {
   1982     LOG(Media, "HTMLMediaElement::mediaPlayerRateChanged");
   1983 
   1984     beginProcessingMediaPlayerCallback();
   1985 
   1986     invalidateCachedTime();
   1987 
   1988     // Stash the rate in case the one we tried to set isn't what the engine is
   1989     // using (eg. it can't handle the rate we set)
   1990     m_playbackRate = m_player->rate();
   1991     invalidateCachedTime();
   1992     endProcessingMediaPlayerCallback();
   1993 }
   1994 
   1995 void HTMLMediaElement::mediaPlayerPlaybackStateChanged(MediaPlayer*)
   1996 {
   1997     LOG(Media, "HTMLMediaElement::mediaPlayerPlaybackStateChanged");
   1998 
   1999     if (!m_player || m_pausedInternal)
   2000         return;
   2001 
   2002     beginProcessingMediaPlayerCallback();
   2003     if (m_player->paused())
   2004         pauseInternal();
   2005     else
   2006         playInternal();
   2007     endProcessingMediaPlayerCallback();
   2008 }
   2009 
   2010 void HTMLMediaElement::mediaPlayerSawUnsupportedTracks(MediaPlayer*)
   2011 {
   2012     LOG(Media, "HTMLMediaElement::mediaPlayerSawUnsupportedTracks");
   2013 
   2014     // The MediaPlayer came across content it cannot completely handle.
   2015     // This is normally acceptable except when we are in a standalone
   2016     // MediaDocument. If so, tell the document what has happened.
   2017     if (ownerDocument()->isMediaDocument()) {
   2018         MediaDocument* mediaDocument = static_cast<MediaDocument*>(ownerDocument());
   2019         mediaDocument->mediaElementSawUnsupportedTracks();
   2020     }
   2021 }
   2022 
   2023 // MediaPlayerPresentation methods
   2024 void HTMLMediaElement::mediaPlayerRepaint(MediaPlayer*)
   2025 {
   2026     beginProcessingMediaPlayerCallback();
   2027     updateDisplayState();
   2028     if (renderer())
   2029         renderer()->repaint();
   2030     endProcessingMediaPlayerCallback();
   2031 }
   2032 
   2033 void HTMLMediaElement::mediaPlayerSizeChanged(MediaPlayer*)
   2034 {
   2035     LOG(Media, "HTMLMediaElement::mediaPlayerSizeChanged");
   2036 
   2037     beginProcessingMediaPlayerCallback();
   2038     if (renderer())
   2039         renderer()->updateFromElement();
   2040     endProcessingMediaPlayerCallback();
   2041 }
   2042 
   2043 #if USE(ACCELERATED_COMPOSITING)
   2044 bool HTMLMediaElement::mediaPlayerRenderingCanBeAccelerated(MediaPlayer*)
   2045 {
   2046     if (renderer() && renderer()->isVideo()) {
   2047         ASSERT(renderer()->view());
   2048         return renderer()->view()->compositor()->canAccelerateVideoRendering(toRenderVideo(renderer()));
   2049     }
   2050     return false;
   2051 }
   2052 
   2053 void HTMLMediaElement::mediaPlayerRenderingModeChanged(MediaPlayer*)
   2054 {
   2055     LOG(Media, "HTMLMediaElement::mediaPlayerRenderingModeChanged");
   2056 
   2057     // Kick off a fake recalcStyle that will update the compositing tree.
   2058     setNeedsStyleRecalc(SyntheticStyleChange);
   2059 }
   2060 #endif
   2061 
   2062 void HTMLMediaElement::mediaPlayerEngineUpdated(MediaPlayer*)
   2063 {
   2064     LOG(Media, "HTMLMediaElement::mediaPlayerEngineUpdated");
   2065     beginProcessingMediaPlayerCallback();
   2066     if (renderer())
   2067         renderer()->updateFromElement();
   2068     endProcessingMediaPlayerCallback();
   2069 }
   2070 
   2071 void HTMLMediaElement::mediaPlayerFirstVideoFrameAvailable(MediaPlayer*)
   2072 {
   2073     LOG(Media, "HTMLMediaElement::mediaPlayerFirstVideoFrameAvailable");
   2074     beginProcessingMediaPlayerCallback();
   2075     if (displayMode() == PosterWaitingForVideo) {
   2076         setDisplayMode(Video);
   2077 #if USE(ACCELERATED_COMPOSITING)
   2078         mediaPlayerRenderingModeChanged(m_player.get());
   2079 #endif
   2080     }
   2081     endProcessingMediaPlayerCallback();
   2082 }
   2083 
   2084 PassRefPtr<TimeRanges> HTMLMediaElement::buffered() const
   2085 {
   2086     if (!m_player)
   2087         return TimeRanges::create();
   2088     return m_player->buffered();
   2089 }
   2090 
   2091 PassRefPtr<TimeRanges> HTMLMediaElement::played()
   2092 {
   2093     if (m_playing) {
   2094         float time = currentTime();
   2095         if (time > m_lastSeekTime)
   2096             addPlayedRange(m_lastSeekTime, time);
   2097     }
   2098 
   2099     if (!m_playedTimeRanges)
   2100         m_playedTimeRanges = TimeRanges::create();
   2101 
   2102     return m_playedTimeRanges->copy();
   2103 }
   2104 
   2105 PassRefPtr<TimeRanges> HTMLMediaElement::seekable() const
   2106 {
   2107     // FIXME real ranges support
   2108     if (!maxTimeSeekable())
   2109         return TimeRanges::create();
   2110     return TimeRanges::create(minTimeSeekable(), maxTimeSeekable());
   2111 }
   2112 
   2113 bool HTMLMediaElement::potentiallyPlaying() const
   2114 {
   2115     // "pausedToBuffer" means the media engine's rate is 0, but only because it had to stop playing
   2116     // when it ran out of buffered data. A movie is this state is "potentially playing", modulo the
   2117     // checks in couldPlayIfEnoughData().
   2118     bool pausedToBuffer = m_readyStateMaximum >= HAVE_FUTURE_DATA && m_readyState < HAVE_FUTURE_DATA;
   2119     return (pausedToBuffer || m_readyState >= HAVE_FUTURE_DATA) && couldPlayIfEnoughData();
   2120 }
   2121 
   2122 bool HTMLMediaElement::couldPlayIfEnoughData() const
   2123 {
   2124     return !paused() && !endedPlayback() && !stoppedDueToErrors() && !pausedForUserInteraction();
   2125 }
   2126 
   2127 bool HTMLMediaElement::endedPlayback() const
   2128 {
   2129     float dur = duration();
   2130     if (!m_player || isnan(dur))
   2131         return false;
   2132 
   2133     // 4.8.10.8 Playing the media resource
   2134 
   2135     // A media element is said to have ended playback when the element's
   2136     // readyState attribute is HAVE_METADATA or greater,
   2137     if (m_readyState < HAVE_METADATA)
   2138         return false;
   2139 
   2140     // and the current playback position is the end of the media resource and the direction
   2141     // of playback is forwards and the media element does not have a loop attribute specified,
   2142     float now = currentTime();
   2143     if (m_playbackRate > 0)
   2144         return dur > 0 && now >= dur && !loop();
   2145 
   2146     // or the current playback position is the earliest possible position and the direction
   2147     // of playback is backwards
   2148     if (m_playbackRate < 0)
   2149         return now <= 0;
   2150 
   2151     return false;
   2152 }
   2153 
   2154 bool HTMLMediaElement::stoppedDueToErrors() const
   2155 {
   2156     if (m_readyState >= HAVE_METADATA && m_error) {
   2157         RefPtr<TimeRanges> seekableRanges = seekable();
   2158         if (!seekableRanges->contain(currentTime()))
   2159             return true;
   2160     }
   2161 
   2162     return false;
   2163 }
   2164 
   2165 bool HTMLMediaElement::pausedForUserInteraction() const
   2166 {
   2167 //    return !paused() && m_readyState >= HAVE_FUTURE_DATA && [UA requires a decitions from the user]
   2168     return false;
   2169 }
   2170 
   2171 float HTMLMediaElement::minTimeSeekable() const
   2172 {
   2173     return 0;
   2174 }
   2175 
   2176 float HTMLMediaElement::maxTimeSeekable() const
   2177 {
   2178     return m_player ? m_player->maxTimeSeekable() : 0;
   2179 }
   2180 
   2181 void HTMLMediaElement::updateVolume()
   2182 {
   2183     if (!m_player)
   2184         return;
   2185 
   2186     // Avoid recursion when the player reports volume changes.
   2187     if (!processingMediaPlayerCallback()) {
   2188         Page* page = document()->page();
   2189         float volumeMultiplier = page ? page->mediaVolume() : 1;
   2190 
   2191         m_player->setMuted(m_muted);
   2192         m_player->setVolume(m_volume * volumeMultiplier);
   2193     }
   2194 
   2195     if (hasMediaControls())
   2196         mediaControls()->changedVolume();
   2197 }
   2198 
   2199 void HTMLMediaElement::updatePlayState()
   2200 {
   2201     if (!m_player)
   2202         return;
   2203 
   2204     if (m_pausedInternal) {
   2205         if (!m_player->paused())
   2206             m_player->pause();
   2207         refreshCachedTime();
   2208         m_playbackProgressTimer.stop();
   2209         if (hasMediaControls())
   2210             mediaControls()->playbackStopped();
   2211         return;
   2212     }
   2213 
   2214     bool shouldBePlaying = potentiallyPlaying();
   2215     bool playerPaused = m_player->paused();
   2216 
   2217     LOG(Media, "HTMLMediaElement::updatePlayState - shouldBePlaying = %s, playerPaused = %s",
   2218         boolString(shouldBePlaying), boolString(playerPaused));
   2219 
   2220     if (shouldBePlaying) {
   2221         setDisplayMode(Video);
   2222         invalidateCachedTime();
   2223 
   2224         if (playerPaused) {
   2225             if (!m_isFullscreen && isVideo() && document() && document()->page() && document()->page()->chrome()->requiresFullscreenForVideoPlayback())
   2226                 enterFullscreen();
   2227 
   2228             // Set rate, muted before calling play in case they were set before the media engine was setup.
   2229             // The media engine should just stash the rate and muted values since it isn't already playing.
   2230             m_player->setRate(m_playbackRate);
   2231             m_player->setMuted(m_muted);
   2232 
   2233             m_player->play();
   2234         }
   2235 
   2236         if (hasMediaControls())
   2237             mediaControls()->playbackStarted();
   2238         startPlaybackProgressTimer();
   2239         m_playing = true;
   2240 
   2241     } else { // Should not be playing right now
   2242         if (!playerPaused)
   2243             m_player->pause();
   2244         refreshCachedTime();
   2245 
   2246         m_playbackProgressTimer.stop();
   2247         m_playing = false;
   2248         float time = currentTime();
   2249         if (time > m_lastSeekTime)
   2250             addPlayedRange(m_lastSeekTime, time);
   2251 
   2252         if (couldPlayIfEnoughData())
   2253             m_player->prepareToPlay();
   2254 
   2255         if (hasMediaControls())
   2256             mediaControls()->playbackStopped();
   2257     }
   2258 
   2259     if (renderer())
   2260         renderer()->updateFromElement();
   2261 }
   2262 
   2263 void HTMLMediaElement::setPausedInternal(bool b)
   2264 {
   2265     m_pausedInternal = b;
   2266     updatePlayState();
   2267 }
   2268 
   2269 void HTMLMediaElement::stopPeriodicTimers()
   2270 {
   2271     m_progressEventTimer.stop();
   2272     m_playbackProgressTimer.stop();
   2273 }
   2274 
   2275 void HTMLMediaElement::userCancelledLoad()
   2276 {
   2277     LOG(Media, "HTMLMediaElement::userCancelledLoad");
   2278 #if PLATFORM(ANDROID)
   2279     if (m_networkState == NETWORK_EMPTY)
   2280 #else
   2281     if (m_networkState == NETWORK_EMPTY || m_completelyLoaded)
   2282 #endif
   2283         return;
   2284 
   2285     // If the media data fetching process is aborted by the user:
   2286 
   2287     // 1 - The user agent should cancel the fetching process.
   2288 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
   2289     m_player.clear();
   2290 #endif
   2291     stopPeriodicTimers();
   2292     m_loadTimer.stop();
   2293     m_loadState = WaitingForSource;
   2294 
   2295     // 2 - Set the error attribute to a new MediaError object whose code attribute is set to MEDIA_ERR_ABORTED.
   2296     m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
   2297 
   2298     // 3 - Queue a task to fire a simple event named error at the media element.
   2299     scheduleEvent(eventNames().abortEvent);
   2300 
   2301     // 4 - If the media element's readyState attribute has a value equal to HAVE_NOTHING, set the
   2302     // element's networkState attribute to the NETWORK_EMPTY value and queue a task to fire a
   2303     // simple event named emptied at the element. Otherwise, set the element's networkState
   2304     // attribute to the NETWORK_IDLE value.
   2305     if (m_readyState == HAVE_NOTHING) {
   2306         m_networkState = NETWORK_EMPTY;
   2307         scheduleEvent(eventNames().emptiedEvent);
   2308     }
   2309     else
   2310         m_networkState = NETWORK_IDLE;
   2311 
   2312     // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
   2313     setShouldDelayLoadEvent(false);
   2314 
   2315     // 6 - Abort the overall resource selection algorithm.
   2316     m_currentSourceNode = 0;
   2317 
   2318     // Reset m_readyState since m_player is gone.
   2319     m_readyState = HAVE_NOTHING;
   2320 }
   2321 
   2322 bool HTMLMediaElement::canSuspend() const
   2323 {
   2324     return true;
   2325 }
   2326 
   2327 void HTMLMediaElement::stop()
   2328 {
   2329     LOG(Media, "HTMLMediaElement::stop");
   2330     if (m_isFullscreen)
   2331         exitFullscreen();
   2332 
   2333     m_inActiveDocument = false;
   2334     userCancelledLoad();
   2335 
   2336     // Stop the playback without generating events
   2337     setPausedInternal(true);
   2338 
   2339     if (renderer())
   2340         renderer()->updateFromElement();
   2341 
   2342     stopPeriodicTimers();
   2343     cancelPendingEventsAndCallbacks();
   2344 }
   2345 
   2346 void HTMLMediaElement::suspend(ReasonForSuspension why)
   2347 {
   2348     LOG(Media, "HTMLMediaElement::suspend");
   2349 
   2350     switch (why)
   2351     {
   2352         case DocumentWillBecomeInactive:
   2353             stop();
   2354             break;
   2355         case JavaScriptDebuggerPaused:
   2356         case WillShowDialog:
   2357             // Do nothing, we don't pause media playback in these cases.
   2358             break;
   2359     }
   2360 }
   2361 
   2362 void HTMLMediaElement::resume()
   2363 {
   2364     LOG(Media, "HTMLMediaElement::resume");
   2365 
   2366     m_inActiveDocument = true;
   2367     setPausedInternal(false);
   2368 
   2369     if (m_error && m_error->code() == MediaError::MEDIA_ERR_ABORTED) {
   2370         // Restart the load if it was aborted in the middle by moving the document to the page cache.
   2371         // m_error is only left at MEDIA_ERR_ABORTED when the document becomes inactive (it is set to
   2372         //  MEDIA_ERR_ABORTED while the abortEvent is being sent, but cleared immediately afterwards).
   2373         // This behavior is not specified but it seems like a sensible thing to do.
   2374         ExceptionCode ec;
   2375         load(processingUserGesture(), ec);
   2376     }
   2377 
   2378     if (renderer())
   2379         renderer()->updateFromElement();
   2380 }
   2381 
   2382 bool HTMLMediaElement::hasPendingActivity() const
   2383 {
   2384     // Return true when we have pending events so we can't fire events after the JS
   2385     // object gets collected.
   2386     bool pending = m_pendingEvents.size();
   2387     LOG(Media, "HTMLMediaElement::hasPendingActivity -> %s", boolString(pending));
   2388     return pending;
   2389 }
   2390 
   2391 void HTMLMediaElement::mediaVolumeDidChange()
   2392 {
   2393     LOG(Media, "HTMLMediaElement::mediaVolumeDidChange");
   2394     updateVolume();
   2395 }
   2396 
   2397 void HTMLMediaElement::defaultEventHandler(Event* event)
   2398 {
   2399 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
   2400     RenderObject* r = renderer();
   2401     if (!r || !r->isWidget())
   2402         return;
   2403 
   2404     Widget* widget = toRenderWidget(r)->widget();
   2405     if (widget)
   2406         widget->handleEvent(event);
   2407 #else
   2408     if (event->isMouseEvent()) {
   2409 #if PLATFORM(ANDROID)
   2410         m_lastTouch = WTF::currentTime();
   2411 #endif
   2412         MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
   2413         if (mouseEvent->relatedTarget() != this) {
   2414             if (event->type() == eventNames().mouseoverEvent) {
   2415                 m_mouseOver = true;
   2416                 if (hasMediaControls() && controls() && !canPlay())
   2417                     mediaControls()->makeOpaque();
   2418             } else if (event->type() == eventNames().mouseoutEvent)
   2419                 m_mouseOver = false;
   2420         }
   2421     }
   2422 
   2423 #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS)
   2424     if (event->isTouchEvent()) {
   2425         m_mouseOver = !(event->type() == eventNames().touchendEvent || event->type() == eventNames().touchcancelEvent);
   2426         if (m_mouseOver && hasMediaControls() && controls() && !canPlay()) {
   2427             m_lastTouch = WTF::currentTime();
   2428             mediaControls()->makeOpaque();
   2429         }
   2430     }
   2431 #endif
   2432 
   2433 #if PLATFORM(ANDROID)
   2434     // It is really hard to hit the play/pause button on mobile devices.
   2435     // This allows user to click the video area to toggle play/pause state.
   2436     if (event->type() == eventNames().clickEvent
   2437         && !hasEventListeners(eventNames().clickEvent)) {
   2438         m_userGestureInitiated = processingUserGesture();
   2439         togglePlayState();
   2440     }
   2441 #endif
   2442     HTMLElement::defaultEventHandler(event);
   2443 #endif
   2444 }
   2445 
   2446 bool HTMLMediaElement::processingUserGesture() const
   2447 {
   2448     Frame* frame = document()->frame();
   2449     FrameLoader* loader = frame ? frame->loader() : 0;
   2450 
   2451     // return 'true' for safety if we don't know the answer
   2452     return loader ? loader->isProcessingUserGesture() : true;
   2453 }
   2454 
   2455 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
   2456 
   2457 void HTMLMediaElement::ensureMediaPlayer()
   2458 {
   2459     if (!m_player)
   2460         m_player = MediaPlayer::create(this);
   2461 }
   2462 
   2463 void HTMLMediaElement::deliverNotification(MediaPlayerProxyNotificationType notification)
   2464 {
   2465     if (notification == MediaPlayerNotificationPlayPauseButtonPressed) {
   2466         togglePlayState();
   2467         return;
   2468     }
   2469 
   2470     if (m_player)
   2471         m_player->deliverNotification(notification);
   2472 }
   2473 
   2474 void HTMLMediaElement::setMediaPlayerProxy(WebMediaPlayerProxy* proxy)
   2475 {
   2476     ensureMediaPlayer();
   2477     m_player->setMediaPlayerProxy(proxy);
   2478 }
   2479 
   2480 void HTMLMediaElement::getPluginProxyParams(KURL& url, Vector<String>& names, Vector<String>& values)
   2481 {
   2482     Frame* frame = document()->frame();
   2483     FrameLoader* loader = frame ? frame->loader() : 0;
   2484 
   2485     if (isVideo()) {
   2486         KURL posterURL = getNonEmptyURLAttribute(posterAttr);
   2487         if (!posterURL.isEmpty() && loader && loader->willLoadMediaElementURL(posterURL)) {
   2488             names.append("_media_element_poster_");
   2489             values.append(posterURL.string());
   2490         }
   2491     }
   2492 
   2493     if (controls()) {
   2494         names.append("_media_element_controls_");
   2495         values.append("true");
   2496     }
   2497 
   2498     url = src();
   2499     if (!isSafeToLoadURL(url, Complain))
   2500         url = selectNextSourceChild(0, DoNothing);
   2501 
   2502     m_currentSrc = url.string();
   2503     if (url.isValid() && loader && loader->willLoadMediaElementURL(url)) {
   2504         names.append("_media_element_src_");
   2505         values.append(m_currentSrc);
   2506     }
   2507 }
   2508 
   2509 void HTMLMediaElement::finishParsingChildren()
   2510 {
   2511     HTMLElement::finishParsingChildren();
   2512     document()->updateStyleIfNeeded();
   2513     createMediaPlayerProxy();
   2514 }
   2515 
   2516 void HTMLMediaElement::createMediaPlayerProxy()
   2517 {
   2518     ensureMediaPlayer();
   2519 
   2520     if (m_proxyWidget || (inDocument() && !m_needWidgetUpdate))
   2521         return;
   2522 
   2523     Frame* frame = document()->frame();
   2524     FrameLoader* loader = frame ? frame->loader() : 0;
   2525     if (!loader)
   2526         return;
   2527 
   2528     LOG(Media, "HTMLMediaElement::createMediaPlayerProxy");
   2529 
   2530     KURL url;
   2531     Vector<String> paramNames;
   2532     Vector<String> paramValues;
   2533 
   2534     getPluginProxyParams(url, paramNames, paramValues);
   2535 
   2536     // Hang onto the proxy widget so it won't be destroyed if the plug-in is set to
   2537     // display:none
   2538     m_proxyWidget = loader->subframeLoader()->loadMediaPlayerProxyPlugin(this, url, paramNames, paramValues);
   2539     if (m_proxyWidget)
   2540         m_needWidgetUpdate = false;
   2541 }
   2542 
   2543 void HTMLMediaElement::updateWidget(PluginCreationOption)
   2544 {
   2545     mediaElement->setNeedWidgetUpdate(false);
   2546 
   2547     Vector<String> paramNames;
   2548     Vector<String> paramValues;
   2549     KURL kurl;
   2550 
   2551     mediaElement->getPluginProxyParams(kurl, paramNames, paramValues);
   2552     SubframeLoader* loader = document()->frame()->loader()->subframeLoader();
   2553     loader->loadMediaPlayerProxyPlugin(mediaElement, kurl, paramNames, paramValues);
   2554 }
   2555 
   2556 #endif // ENABLE(PLUGIN_PROXY_FOR_VIDEO)
   2557 
   2558 bool HTMLMediaElement::isFullscreen() const
   2559 {
   2560     if (m_isFullscreen)
   2561         return true;
   2562 
   2563 #if ENABLE(FULLSCREEN_API)
   2564     if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == this)
   2565         return true;
   2566 #endif
   2567 
   2568     return false;
   2569 }
   2570 
   2571 void HTMLMediaElement::enterFullscreen()
   2572 {
   2573     LOG(Media, "HTMLMediaElement::enterFullscreen");
   2574 #if ENABLE(FULLSCREEN_API)
   2575     if (document() && document()->settings() && document()->settings()->fullScreenEnabled()) {
   2576         webkitRequestFullScreen(0);
   2577         return;
   2578     }
   2579 #endif
   2580     ASSERT(!m_isFullscreen);
   2581     m_isFullscreen = true;
   2582     if (hasMediaControls())
   2583         mediaControls()->enteredFullscreen();
   2584     if (document() && document()->page()) {
   2585         document()->page()->chrome()->client()->enterFullscreenForNode(this);
   2586         scheduleEvent(eventNames().webkitbeginfullscreenEvent);
   2587     }
   2588 }
   2589 
   2590 void HTMLMediaElement::exitFullscreen()
   2591 {
   2592     LOG(Media, "HTMLMediaElement::exitFullscreen");
   2593 #if ENABLE(FULLSCREEN_API)
   2594     if (document() && document()->settings() && document()->settings()->fullScreenEnabled()) {
   2595         if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == this)
   2596             document()->webkitCancelFullScreen();
   2597         return;
   2598     }
   2599 #endif
   2600     ASSERT(m_isFullscreen);
   2601     m_isFullscreen = false;
   2602     if (hasMediaControls())
   2603         mediaControls()->exitedFullscreen();
   2604     if (document() && document()->page()) {
   2605         if (document()->page()->chrome()->requiresFullscreenForVideoPlayback())
   2606             pauseInternal();
   2607         document()->page()->chrome()->client()->exitFullscreenForNode(this);
   2608         scheduleEvent(eventNames().webkitendfullscreenEvent);
   2609     }
   2610 }
   2611 
   2612 PlatformMedia HTMLMediaElement::platformMedia() const
   2613 {
   2614     return m_player ? m_player->platformMedia() : NoPlatformMedia;
   2615 }
   2616 
   2617 #if USE(ACCELERATED_COMPOSITING)
   2618 PlatformLayer* HTMLMediaElement::platformLayer() const
   2619 {
   2620     return m_player ? m_player->platformLayer() : 0;
   2621 }
   2622 #endif
   2623 
   2624 bool HTMLMediaElement::hasClosedCaptions() const
   2625 {
   2626     return m_player && m_player->hasClosedCaptions();
   2627 }
   2628 
   2629 bool HTMLMediaElement::closedCaptionsVisible() const
   2630 {
   2631     return m_closedCaptionsVisible;
   2632 }
   2633 
   2634 void HTMLMediaElement::setClosedCaptionsVisible(bool closedCaptionVisible)
   2635 {
   2636     LOG(Media, "HTMLMediaElement::setClosedCaptionsVisible(%s)", boolString(closedCaptionVisible));
   2637 
   2638     if (!m_player ||!hasClosedCaptions())
   2639         return;
   2640 
   2641     m_closedCaptionsVisible = closedCaptionVisible;
   2642     m_player->setClosedCaptionsVisible(closedCaptionVisible);
   2643     if (hasMediaControls())
   2644         mediaControls()->changedClosedCaptionsVisibility();
   2645 }
   2646 
   2647 void HTMLMediaElement::setWebkitClosedCaptionsVisible(bool visible)
   2648 {
   2649     setClosedCaptionsVisible(visible);
   2650 }
   2651 
   2652 bool HTMLMediaElement::webkitClosedCaptionsVisible() const
   2653 {
   2654     return closedCaptionsVisible();
   2655 }
   2656 
   2657 
   2658 bool HTMLMediaElement::webkitHasClosedCaptions() const
   2659 {
   2660     return hasClosedCaptions();
   2661 }
   2662 
   2663 #if ENABLE(MEDIA_STATISTICS)
   2664 unsigned HTMLMediaElement::webkitAudioDecodedByteCount() const
   2665 {
   2666     if (!m_player)
   2667         return 0;
   2668     return m_player->audioDecodedByteCount();
   2669 }
   2670 
   2671 unsigned HTMLMediaElement::webkitVideoDecodedByteCount() const
   2672 {
   2673     if (!m_player)
   2674         return 0;
   2675     return m_player->videoDecodedByteCount();
   2676 }
   2677 #endif
   2678 
   2679 void HTMLMediaElement::mediaCanStart()
   2680 {
   2681     LOG(Media, "HTMLMediaElement::mediaCanStart");
   2682 
   2683     ASSERT(m_isWaitingUntilMediaCanStart);
   2684     m_isWaitingUntilMediaCanStart = false;
   2685     loadInternal();
   2686 }
   2687 
   2688 bool HTMLMediaElement::isURLAttribute(Attribute* attribute) const
   2689 {
   2690     return attribute->name() == srcAttr;
   2691 }
   2692 
   2693 void HTMLMediaElement::setShouldDelayLoadEvent(bool shouldDelay)
   2694 {
   2695     if (m_shouldDelayLoadEvent == shouldDelay)
   2696         return;
   2697 
   2698     LOG(Media, "HTMLMediaElement::setShouldDelayLoadEvent(%s)", boolString(shouldDelay));
   2699 
   2700     m_shouldDelayLoadEvent = shouldDelay;
   2701     if (shouldDelay)
   2702         document()->incrementLoadEventDelayCount();
   2703     else
   2704         document()->decrementLoadEventDelayCount();
   2705 }
   2706 
   2707 
   2708 void HTMLMediaElement::getSitesInMediaCache(Vector<String>& sites)
   2709 {
   2710     MediaPlayer::getSitesInMediaCache(sites);
   2711 }
   2712 
   2713 void HTMLMediaElement::clearMediaCache()
   2714 {
   2715     MediaPlayer::clearMediaCache();
   2716 }
   2717 
   2718 void HTMLMediaElement::clearMediaCacheForSite(const String& site)
   2719 {
   2720     MediaPlayer::clearMediaCacheForSite(site);
   2721 }
   2722 
   2723 void HTMLMediaElement::privateBrowsingStateDidChange()
   2724 {
   2725     if (!m_player)
   2726         return;
   2727 
   2728     Settings* settings = document()->settings();
   2729     bool privateMode = !settings || settings->privateBrowsingEnabled();
   2730     LOG(Media, "HTMLMediaElement::privateBrowsingStateDidChange(%s)", boolString(privateMode));
   2731     m_player->setPrivateBrowsingMode(privateMode);
   2732 }
   2733 
   2734 MediaControls* HTMLMediaElement::mediaControls()
   2735 {
   2736     return toMediaControls(shadowRoot()->firstChild());
   2737 }
   2738 
   2739 bool HTMLMediaElement::hasMediaControls()
   2740 {
   2741     if (!shadowRoot())
   2742         return false;
   2743 
   2744     Node* node = shadowRoot()->firstChild();
   2745     return node && node->isMediaControls();
   2746 }
   2747 
   2748 bool HTMLMediaElement::createMediaControls()
   2749 {
   2750     if (hasMediaControls())
   2751         return true;
   2752 
   2753     ExceptionCode ec;
   2754     RefPtr<MediaControls> controls = MediaControls::create(this);
   2755     if (!controls)
   2756         return false;
   2757 
   2758     ensureShadowRoot()->appendChild(controls, ec);
   2759     return true;
   2760 }
   2761 
   2762 void* HTMLMediaElement::preDispatchEventHandler(Event* event)
   2763 {
   2764     if (event && event->type() == eventNames().webkitfullscreenchangeEvent) {
   2765         if (controls()) {
   2766             if (!hasMediaControls()) {
   2767                 if (!createMediaControls())
   2768                     return 0;
   2769 
   2770                 mediaControls()->reset();
   2771             }
   2772             mediaControls()->show();
   2773         } else if (hasMediaControls())
   2774             mediaControls()->hide();
   2775     }
   2776     return 0;
   2777 }
   2778 
   2779 
   2780 }
   2781 
   2782 #endif
   2783