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