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