Render text tracks
[WebKit-https.git] / Source / WebCore / html / HTMLMediaElement.cpp
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 "ApplicationCacheHost.h"
32 #include "ApplicationCacheResource.h"
33 #include "Attribute.h"
34 #include "Chrome.h"
35 #include "ChromeClient.h"
36 #include "ClientRect.h"
37 #include "ClientRectList.h"
38 #include "ContentSecurityPolicy.h"
39 #include "ContentType.h"
40 #include "CSSPropertyNames.h"
41 #include "CSSValueKeywords.h"
42 #include "DocumentLoader.h"
43 #include "Event.h"
44 #include "EventNames.h"
45 #include "ExceptionCode.h"
46 #include "Frame.h"
47 #include "FrameLoader.h"
48 #include "FrameLoaderClient.h"
49 #include "FrameView.h"
50 #include "HTMLDocument.h"
51 #include "HTMLNames.h"
52 #include "HTMLSourceElement.h"
53 #include "HTMLVideoElement.h"
54 #include "Logging.h"
55 #include "MediaController.h"
56 #include "MediaControls.h"
57 #include "MediaDocument.h"
58 #include "MediaError.h"
59 #include "MediaList.h"
60 #include "MediaPlayer.h"
61 #include "MediaQueryEvaluator.h"
62 #include "MouseEvent.h"
63 #include "MIMETypeRegistry.h"
64 #include "Page.h"
65 #include "RenderVideo.h"
66 #include "RenderView.h"
67 #include "ScriptController.h"
68 #include "ScriptEventListener.h"
69 #include "SecurityOrigin.h"
70 #include "Settings.h"
71 #include "ShadowRoot.h"
72 #include "TimeRanges.h"
73 #include "UUID.h"
74 #include <limits>
75 #include <wtf/CurrentTime.h>
76 #include <wtf/MathExtras.h>
77 #include <wtf/Uint8Array.h>
78 #include <wtf/text/CString.h>
79
80 #if USE(ACCELERATED_COMPOSITING)
81 #include "RenderView.h"
82 #include "RenderLayerCompositor.h"
83 #endif
84
85 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
86 #include "RenderEmbeddedObject.h"
87 #include "Widget.h"
88 #endif
89
90 #if ENABLE(VIDEO_TRACK)
91 #include "HTMLTrackElement.h"
92 #include "RuntimeEnabledFeatures.h"
93 #include "TextTrackCueList.h"
94 #include "TextTrackList.h"
95 #endif
96
97 #if ENABLE(WEB_AUDIO)
98 #include "AudioSourceProvider.h"
99 #include "MediaElementAudioSourceNode.h"
100 #endif
101
102 #if PLATFORM(MAC)
103 #include "DisplaySleepDisabler.h"
104 #endif
105
106 using namespace std;
107
108 namespace WebCore {
109
110 #if !LOG_DISABLED
111 static String urlForLogging(const KURL& url)
112 {
113     static const unsigned maximumURLLengthForLogging = 128;
114
115     if (url.string().length() < maximumURLLengthForLogging)
116         return url.string();
117     return url.string().substring(0, maximumURLLengthForLogging) + "...";
118 }
119
120 static const char* boolString(bool val)
121 {
122     return val ? "true" : "false";
123 }
124 #endif
125
126 #ifndef LOG_MEDIA_EVENTS
127 // Default to not logging events because so many are generated they can overwhelm the rest of 
128 // the logging.
129 #define LOG_MEDIA_EVENTS 0
130 #endif
131
132 #ifndef LOG_CACHED_TIME_WARNINGS
133 // Default to not logging warnings about excessive drift in the cached media time because it adds a
134 // fair amount of overhead and logging.
135 #define LOG_CACHED_TIME_WARNINGS 0
136 #endif
137
138 static const float invalidMediaTime = -1;
139
140 #if ENABLE(MEDIA_SOURCE)
141 // URL protocol used to signal that the media source API is being used.
142 static const char* mediaSourceURLProtocol = "x-media-source";
143 #endif
144
145 using namespace HTMLNames;
146 using namespace std;
147
148 typedef HashMap<Document*, HashSet<HTMLMediaElement*> > DocumentElementSetMap;
149 static DocumentElementSetMap& documentToElementSetMap()
150 {
151     DEFINE_STATIC_LOCAL(DocumentElementSetMap, map, ());
152     return map;
153 }
154
155 static void addElementToDocumentMap(HTMLMediaElement* element, Document* document)
156 {
157     DocumentElementSetMap& map = documentToElementSetMap();
158     HashSet<HTMLMediaElement*> set = map.take(document);
159     set.add(element);
160     map.add(document, set);
161 }
162
163 static void removeElementFromDocumentMap(HTMLMediaElement* element, Document* document)
164 {
165     DocumentElementSetMap& map = documentToElementSetMap();
166     HashSet<HTMLMediaElement*> set = map.take(document);
167     set.remove(element);
168     if (!set.isEmpty())
169         map.add(document, set);
170 }
171
172 HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* document, bool createdByParser)
173     : HTMLElement(tagName, document)
174     , ActiveDOMObject(document, this)
175     , m_loadTimer(this, &HTMLMediaElement::loadTimerFired)
176     , m_asyncEventTimer(this, &HTMLMediaElement::asyncEventTimerFired)
177     , m_progressEventTimer(this, &HTMLMediaElement::progressEventTimerFired)
178     , m_playbackProgressTimer(this, &HTMLMediaElement::playbackProgressTimerFired)
179     , m_playedTimeRanges()
180     , m_playbackRate(1.0f)
181     , m_defaultPlaybackRate(1.0f)
182     , m_webkitPreservesPitch(true)
183     , m_networkState(NETWORK_EMPTY)
184     , m_readyState(HAVE_NOTHING)
185     , m_readyStateMaximum(HAVE_NOTHING)
186     , m_volume(1.0f)
187     , m_lastSeekTime(0)
188     , m_previousProgress(0)
189     , m_previousProgressTime(numeric_limits<double>::max())
190     , m_lastTimeUpdateEventWallTime(0)
191     , m_lastTimeUpdateEventMovieTime(numeric_limits<float>::max())
192     , m_loadState(WaitingForSource)
193     , m_currentSourceNode(0)
194     , m_nextChildNodeToConsider(0)
195 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
196     , m_proxyWidget(0)
197 #endif
198     , m_restrictions(RequireUserGestureForFullscreenRestriction | RequirePageConsentToLoadMediaRestriction)
199     , m_preload(MediaPlayer::Auto)
200     , m_displayMode(Unknown)
201     , m_processingMediaPlayerCallback(0)
202 #if ENABLE(MEDIA_SOURCE)      
203     , m_sourceState(SOURCE_CLOSED)
204 #endif
205     , m_cachedTime(invalidMediaTime)
206     , m_cachedTimeWallClockUpdateTime(0)
207     , m_minimumWallClockTimeToCacheMediaTime(0)
208     , m_pendingLoadFlags(0)
209     , m_playing(false)
210     , m_isWaitingUntilMediaCanStart(false)
211     , m_shouldDelayLoadEvent(false)
212     , m_haveFiredLoadedData(false)
213     , m_inActiveDocument(true)
214     , m_autoplaying(true)
215     , m_muted(false)
216     , m_paused(true)
217     , m_seeking(false)
218     , m_sentStalledEvent(false)
219     , m_sentEndEvent(false)
220     , m_pausedInternal(false)
221     , m_sendProgressEvents(true)
222     , m_isFullscreen(false)
223     , m_closedCaptionsVisible(false)
224 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
225     , m_needWidgetUpdate(false)
226 #endif
227     , m_dispatchingCanPlayEvent(false)
228     , m_loadInitiatedByUserGesture(false)
229     , m_completelyLoaded(false)
230     , m_havePreparedToPlay(false)
231     , m_parsingInProgress(createdByParser)
232 #if ENABLE(VIDEO_TRACK)
233     , m_tracksAreReady(true)
234     , m_haveVisibleTextTrack(false)
235     , m_textTracks(0)
236 #endif
237 #if ENABLE(WEB_AUDIO)
238     , m_audioSourceNode(0)
239 #endif
240 {
241     LOG(Media, "HTMLMediaElement::HTMLMediaElement");
242     document->registerForMediaVolumeCallbacks(this);
243     document->registerForPrivateBrowsingStateChangedCallbacks(this);
244     
245     if (document->settings() && document->settings()->mediaPlaybackRequiresUserGesture())
246         addBehaviorRestriction(RequireUserGestureForRateChangeRestriction);
247
248 #if ENABLE(MEDIA_SOURCE)
249     m_mediaSourceURL.setProtocol(mediaSourceURLProtocol);
250     m_mediaSourceURL.setPath(createCanonicalUUIDString());
251 #endif
252
253     setHasCustomWillOrDidRecalcStyle();
254     addElementToDocumentMap(this, document);
255 }
256
257 HTMLMediaElement::~HTMLMediaElement()
258 {
259     LOG(Media, "HTMLMediaElement::~HTMLMediaElement");
260     if (m_isWaitingUntilMediaCanStart)
261         document()->removeMediaCanStartListener(this);
262     setShouldDelayLoadEvent(false);
263     document()->unregisterForMediaVolumeCallbacks(this);
264     document()->unregisterForPrivateBrowsingStateChangedCallbacks(this);
265 #if ENABLE(VIDEO_TRACK)
266     if (m_textTracks)
267         m_textTracks->clearOwner();
268     if (m_textTracks) {
269         for (unsigned i = 0; i < m_textTracks->length(); ++i)
270             m_textTracks->item(i)->clearClient();
271     }
272 #endif
273
274     if (m_mediaController)
275         m_mediaController->removeMediaElement(this);
276
277     removeElementFromDocumentMap(this, document());
278 }
279
280 void HTMLMediaElement::willMoveToNewOwnerDocument()
281 {
282     if (m_isWaitingUntilMediaCanStart)
283         document()->removeMediaCanStartListener(this);
284     setShouldDelayLoadEvent(false);
285     document()->unregisterForMediaVolumeCallbacks(this);
286     removeElementFromDocumentMap(this, document());
287     HTMLElement::willMoveToNewOwnerDocument();
288 }
289
290 void HTMLMediaElement::didMoveToNewOwnerDocument()
291 {
292     if (m_isWaitingUntilMediaCanStart)
293         document()->addMediaCanStartListener(this);
294     if (m_readyState < HAVE_CURRENT_DATA)
295         setShouldDelayLoadEvent(true);
296     document()->registerForMediaVolumeCallbacks(this);
297     addElementToDocumentMap(this, document());
298     HTMLElement::didMoveToNewOwnerDocument();
299 }
300
301 bool HTMLMediaElement::supportsFocus() const
302 {
303     if (ownerDocument()->isMediaDocument())
304         return false;
305
306     // If no controls specified, we should still be able to focus the element if it has tabIndex.
307     return controls() ||  HTMLElement::supportsFocus();
308 }
309
310 void HTMLMediaElement::attributeChanged(Attribute* attr, bool preserveDecls)
311 {
312     HTMLElement::attributeChanged(attr, preserveDecls);
313
314     const QualifiedName& attrName = attr->name();
315     if (attrName == srcAttr) {
316         // Trigger a reload, as long as the 'src' attribute is present.
317         if (!getAttribute(srcAttr).isEmpty())
318             scheduleLoad(MediaResource);
319     } else if (attrName == controlsAttr)
320         configureMediaControls();
321 }
322
323 void HTMLMediaElement::parseMappedAttribute(Attribute* attr)
324 {
325     const QualifiedName& attrName = attr->name();
326
327     if (attrName == preloadAttr) {
328         String value = attr->value();
329
330         if (equalIgnoringCase(value, "none"))
331             m_preload = MediaPlayer::None;
332         else if (equalIgnoringCase(value, "metadata"))
333             m_preload = MediaPlayer::MetaData;
334         else {
335             // The spec does not define an "invalid value default" but "auto" is suggested as the
336             // "missing value default", so use it for everything except "none" and "metadata"
337             m_preload = MediaPlayer::Auto;
338         }
339
340         // The attribute must be ignored if the autoplay attribute is present
341         if (!autoplay() && m_player)
342             m_player->setPreload(m_preload);
343
344     } else if (attrName == mediagroupAttr)
345         setMediaGroup(attr->value());
346     else if (attrName == onabortAttr)
347         setAttributeEventListener(eventNames().abortEvent, createAttributeEventListener(this, attr));
348     else if (attrName == onbeforeloadAttr)
349         setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, attr));
350     else if (attrName == oncanplayAttr)
351         setAttributeEventListener(eventNames().canplayEvent, createAttributeEventListener(this, attr));
352     else if (attrName == oncanplaythroughAttr)
353         setAttributeEventListener(eventNames().canplaythroughEvent, createAttributeEventListener(this, attr));
354     else if (attrName == ondurationchangeAttr)
355         setAttributeEventListener(eventNames().durationchangeEvent, createAttributeEventListener(this, attr));
356     else if (attrName == onemptiedAttr)
357         setAttributeEventListener(eventNames().emptiedEvent, createAttributeEventListener(this, attr));
358     else if (attrName == onendedAttr)
359         setAttributeEventListener(eventNames().endedEvent, createAttributeEventListener(this, attr));
360     else if (attrName == onerrorAttr)
361         setAttributeEventListener(eventNames().errorEvent, createAttributeEventListener(this, attr));
362     else if (attrName == onloadeddataAttr)
363         setAttributeEventListener(eventNames().loadeddataEvent, createAttributeEventListener(this, attr));
364     else if (attrName == onloadedmetadataAttr)
365         setAttributeEventListener(eventNames().loadedmetadataEvent, createAttributeEventListener(this, attr));
366     else if (attrName == onloadstartAttr)
367         setAttributeEventListener(eventNames().loadstartEvent, createAttributeEventListener(this, attr));
368     else if (attrName == onpauseAttr)
369         setAttributeEventListener(eventNames().pauseEvent, createAttributeEventListener(this, attr));
370     else if (attrName == onplayAttr)
371         setAttributeEventListener(eventNames().playEvent, createAttributeEventListener(this, attr));
372     else if (attrName == onplayingAttr)
373         setAttributeEventListener(eventNames().playingEvent, createAttributeEventListener(this, attr));
374     else if (attrName == onprogressAttr)
375         setAttributeEventListener(eventNames().progressEvent, createAttributeEventListener(this, attr));
376     else if (attrName == onratechangeAttr)
377         setAttributeEventListener(eventNames().ratechangeEvent, createAttributeEventListener(this, attr));
378     else if (attrName == onseekedAttr)
379         setAttributeEventListener(eventNames().seekedEvent, createAttributeEventListener(this, attr));
380     else if (attrName == onseekingAttr)
381         setAttributeEventListener(eventNames().seekingEvent, createAttributeEventListener(this, attr));
382     else if (attrName == onstalledAttr)
383         setAttributeEventListener(eventNames().stalledEvent, createAttributeEventListener(this, attr));
384     else if (attrName == onsuspendAttr)
385         setAttributeEventListener(eventNames().suspendEvent, createAttributeEventListener(this, attr));
386     else if (attrName == ontimeupdateAttr)
387         setAttributeEventListener(eventNames().timeupdateEvent, createAttributeEventListener(this, attr));
388     else if (attrName == onvolumechangeAttr)
389         setAttributeEventListener(eventNames().volumechangeEvent, createAttributeEventListener(this, attr));
390     else if (attrName == onwaitingAttr)
391         setAttributeEventListener(eventNames().waitingEvent, createAttributeEventListener(this, attr));
392     else if (attrName == onwebkitbeginfullscreenAttr)
393         setAttributeEventListener(eventNames().webkitbeginfullscreenEvent, createAttributeEventListener(this, attr));
394     else if (attrName == onwebkitendfullscreenAttr)
395         setAttributeEventListener(eventNames().webkitendfullscreenEvent, createAttributeEventListener(this, attr));
396     else
397         HTMLElement::parseMappedAttribute(attr);
398 }
399
400 void HTMLMediaElement::finishParsingChildren()
401 {
402     HTMLElement::finishParsingChildren();
403     m_parsingInProgress = false;
404
405 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
406     document()->updateStyleIfNeeded();
407     createMediaPlayerProxy();
408 #endif
409     
410 #if ENABLE(VIDEO_TRACK)
411     if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
412         return;
413     
414     for (Node* node = firstChild(); node; node = node->nextSibling()) {
415         if (node->hasTagName(trackTag)) {
416             scheduleLoad(TextTrackResource);
417             break;
418         }
419     }
420 #endif
421 }
422
423 bool HTMLMediaElement::rendererIsNeeded(const NodeRenderingContext& context)
424 {
425 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
426     UNUSED_PARAM(context);
427     Frame* frame = document()->frame();
428     if (!frame)
429         return false;
430
431     return true;
432 #else
433     return controls() ? HTMLElement::rendererIsNeeded(context) : false;
434 #endif
435 }
436
437 RenderObject* HTMLMediaElement::createRenderer(RenderArena* arena, RenderStyle*)
438 {
439 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
440     // Setup the renderer if we already have a proxy widget.
441     RenderEmbeddedObject* mediaRenderer = new (arena) RenderEmbeddedObject(this);
442     if (m_proxyWidget) {
443         mediaRenderer->setWidget(m_proxyWidget);
444
445         if (Frame* frame = document()->frame())
446             frame->loader()->client()->showMediaPlayerProxyPlugin(m_proxyWidget.get());
447     }
448     return mediaRenderer;
449 #else
450     return new (arena) RenderMedia(this);
451 #endif
452 }
453  
454 void HTMLMediaElement::insertedIntoDocument()
455 {
456     LOG(Media, "HTMLMediaElement::insertedIntoDocument");
457     HTMLElement::insertedIntoDocument();
458     if (!getAttribute(srcAttr).isEmpty() && m_networkState == NETWORK_EMPTY)
459         scheduleLoad(MediaResource);
460 }
461
462 void HTMLMediaElement::removedFromDocument()
463 {
464     LOG(Media, "HTMLMediaElement::removedFromDocument");
465     if (m_networkState > NETWORK_EMPTY)
466         pause();
467     if (m_isFullscreen)
468         exitFullscreen();
469     HTMLElement::removedFromDocument();
470 }
471
472 void HTMLMediaElement::attach()
473 {
474     ASSERT(!attached());
475
476 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
477     m_needWidgetUpdate = true;
478 #endif
479
480     HTMLElement::attach();
481
482     if (renderer())
483         renderer()->updateFromElement();
484 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
485     else if (m_proxyWidget) {
486         if (Frame* frame = document()->frame())
487             frame->loader()->client()->hideMediaPlayerProxyPlugin(m_proxyWidget.get());
488     }
489 #endif
490 }
491
492 void HTMLMediaElement::didRecalcStyle(StyleChange)
493 {
494     if (renderer())
495         renderer()->updateFromElement();
496 }
497
498 void HTMLMediaElement::scheduleLoad(LoadType loadType)
499 {
500     LOG(Media, "HTMLMediaElement::scheduleLoad");
501
502     if ((loadType & MediaResource) && !(m_pendingLoadFlags & MediaResource)) {
503 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
504         createMediaPlayerProxy();
505 #endif
506         
507         prepareForLoad();
508         m_pendingLoadFlags |= MediaResource;
509     }
510
511 #if ENABLE(VIDEO_TRACK)
512     if (loadType & TextTrackResource)
513         m_pendingLoadFlags |= TextTrackResource;
514 #endif
515
516     if (!m_loadTimer.isActive())
517         m_loadTimer.startOneShot(0);
518 }
519
520 void HTMLMediaElement::scheduleNextSourceChild()
521 {
522     // Schedule the timer to try the next <source> element WITHOUT resetting state ala prepareForLoad.
523     m_pendingLoadFlags |= MediaResource;
524     m_loadTimer.startOneShot(0);
525 }
526
527 void HTMLMediaElement::scheduleEvent(const AtomicString& eventName)
528 {
529 #if LOG_MEDIA_EVENTS
530     LOG(Media, "HTMLMediaElement::scheduleEvent - scheduling '%s'", eventName.string().ascii().data());
531 #endif
532     m_pendingEvents.append(Event::create(eventName, false, true));
533     if (!m_asyncEventTimer.isActive())
534         m_asyncEventTimer.startOneShot(0);
535 }
536
537 void HTMLMediaElement::asyncEventTimerFired(Timer<HTMLMediaElement>*)
538 {
539     Vector<RefPtr<Event> > pendingEvents;
540     ExceptionCode ec = 0;
541
542     m_pendingEvents.swap(pendingEvents);
543     unsigned count = pendingEvents.size();
544     for (unsigned ndx = 0; ndx < count; ++ndx) {
545 #if LOG_MEDIA_EVENTS
546         LOG(Media, "HTMLMediaElement::asyncEventTimerFired - dispatching '%s'", pendingEvents[ndx]->type().string().ascii().data());
547 #endif
548         if (pendingEvents[ndx]->type() == eventNames().canplayEvent) {
549             m_dispatchingCanPlayEvent = true;
550             dispatchEvent(pendingEvents[ndx].release(), ec);
551             m_dispatchingCanPlayEvent = false;
552         } else
553             dispatchEvent(pendingEvents[ndx].release(), ec);
554     }
555 }
556
557 void HTMLMediaElement::loadTimerFired(Timer<HTMLMediaElement>*)
558 {
559     if (m_pendingLoadFlags & MediaResource) {
560         if (m_loadState == LoadingFromSourceElement)
561             loadNextSourceChild();
562         else
563             loadInternal();
564     }
565
566 #if ENABLE(VIDEO_TRACK)
567     if (m_pendingLoadFlags & TextTrackResource)
568         configureTextTracks();
569 #endif
570
571     m_pendingLoadFlags = 0;
572 }
573
574 PassRefPtr<MediaError> HTMLMediaElement::error() const 
575 {
576     return m_error;
577 }
578
579 void HTMLMediaElement::setSrc(const String& url)
580 {
581     setAttribute(srcAttr, url);
582 }
583
584 HTMLMediaElement::NetworkState HTMLMediaElement::networkState() const
585 {
586     return m_networkState;
587 }
588
589 String HTMLMediaElement::canPlayType(const String& mimeType) const
590 {
591     MediaPlayer::SupportsType support = MediaPlayer::supportsType(ContentType(mimeType));
592     String canPlay;
593
594     // 4.8.10.3
595     switch (support)
596     {
597         case MediaPlayer::IsNotSupported:
598             canPlay = "";
599             break;
600         case MediaPlayer::MayBeSupported:
601             canPlay = "maybe";
602             break;
603         case MediaPlayer::IsSupported:
604             canPlay = "probably";
605             break;
606     }
607     
608     LOG(Media, "HTMLMediaElement::canPlayType(%s) -> %s", mimeType.utf8().data(), canPlay.utf8().data());
609
610     return canPlay;
611 }
612
613 void HTMLMediaElement::load(ExceptionCode& ec)
614 {
615     LOG(Media, "HTMLMediaElement::load()");
616
617     if (userGestureRequiredForLoad() && !ScriptController::processingUserGesture())
618         ec = INVALID_STATE_ERR;
619     else {
620         m_loadInitiatedByUserGesture = ScriptController::processingUserGesture();
621         prepareForLoad();
622         loadInternal();
623     }
624     prepareToPlay();
625 }
626
627 void HTMLMediaElement::prepareForLoad()
628 {
629     LOG(Media, "HTMLMediaElement::prepareForLoad");
630
631     // Perform the cleanup required for the resource load algorithm to run.
632     stopPeriodicTimers();
633     m_loadTimer.stop();
634     m_sentEndEvent = false;
635     m_sentStalledEvent = false;
636     m_haveFiredLoadedData = false;
637     m_completelyLoaded = false;
638     m_havePreparedToPlay = false;
639     m_displayMode = Unknown;
640
641     // 1 - Abort any already-running instance of the resource selection algorithm for this element.
642     m_loadState = WaitingForSource;
643     m_currentSourceNode = 0;
644
645     // 2 - If there are any tasks from the media element's media element event task source in 
646     // one of the task queues, then remove those tasks.
647     cancelPendingEventsAndCallbacks();
648
649     // 3 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, queue
650     // a task to fire a simple event named abort at the media element.
651     if (m_networkState == NETWORK_LOADING || m_networkState == NETWORK_IDLE)
652         scheduleEvent(eventNames().abortEvent);
653
654 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
655     createMediaPlayer();
656 #else
657     if (m_player)
658         m_player->cancelLoad();
659     else
660         createMediaPlayerProxy();
661 #endif
662
663 #if ENABLE(MEDIA_SOURCE)
664     if (m_sourceState != SOURCE_CLOSED)
665         setSourceState(SOURCE_CLOSED);
666 #endif
667
668     // 4 - If the media element's networkState is not set to NETWORK_EMPTY, then run these substeps
669     if (m_networkState != NETWORK_EMPTY) {
670         m_networkState = NETWORK_EMPTY;
671         m_readyState = HAVE_NOTHING;
672         m_readyStateMaximum = HAVE_NOTHING;
673         refreshCachedTime();
674         m_paused = true;
675         m_seeking = false;
676         invalidateCachedTime();
677         scheduleEvent(eventNames().emptiedEvent);
678         updateMediaController();
679     }
680
681     // 5 - Set the playbackRate attribute to the value of the defaultPlaybackRate attribute.
682     setPlaybackRate(defaultPlaybackRate());
683
684     // 6 - Set the error attribute to null and the autoplaying flag to true.
685     m_error = 0;
686     m_autoplaying = true;
687
688     // 7 - Invoke the media element's resource selection algorithm.
689
690     // 8 - Note: Playback of any previously playing media resource for this element stops.
691
692     // The resource selection algorithm
693     // 1 - Set the networkState to NETWORK_NO_SOURCE
694     m_networkState = NETWORK_NO_SOURCE;
695
696     // 2 - Asynchronously await a stable state.
697
698     m_playedTimeRanges = TimeRanges::create();
699     m_lastSeekTime = 0;
700     m_closedCaptionsVisible = false;
701
702     // The spec doesn't say to block the load event until we actually run the asynchronous section
703     // algorithm, but do it now because we won't start that until after the timer fires and the 
704     // event may have already fired by then.
705     setShouldDelayLoadEvent(true);
706
707 #if ENABLE(VIDEO_TRACK)
708     // HTMLMediaElement::textTracksAreReady will need "... the text tracks whose mode was not in the
709     // disabled state when the element's resource selection algorithm last started".
710     m_textTracksWhenResourceSelectionBegan.clear();
711     if (m_textTracks) {
712         for (unsigned i = 0; i < m_textTracks->length(); ++i) {
713             TextTrack* track = m_textTracks->item(i);
714             if (track->mode() != TextTrack::DISABLED)
715                 m_textTracksWhenResourceSelectionBegan.append(track);
716         }
717     }
718 #endif
719
720     configureMediaControls();
721 }
722
723 void HTMLMediaElement::loadInternal()
724 {
725     // If we can't start a load right away, start it later.
726     Page* page = document()->page();
727     if (pageConsentRequiredForLoad() && page && !page->canStartMedia()) {
728         if (m_isWaitingUntilMediaCanStart)
729             return;
730         document()->addMediaCanStartListener(this);
731         m_isWaitingUntilMediaCanStart = true;
732         return;
733     }
734     
735     // Once the page has allowed an element to load media, it is free to load at will. This allows a 
736     // playlist that starts in a foreground tab to continue automatically if the tab is subsequently 
737     // put in the the background.
738     removeBehaviorRestriction(RequirePageConsentToLoadMediaRestriction);
739
740     selectMediaResource();
741 }
742
743 void HTMLMediaElement::selectMediaResource()
744 {
745     LOG(Media, "HTMLMediaElement::selectMediaResource");
746
747     enum Mode { attribute, children };
748
749     // 3 - If the media element has a src attribute, then let mode be attribute.
750     Mode mode = attribute;
751     if (!fastHasAttribute(srcAttr)) {
752         Node* node;
753         for (node = firstChild(); node; node = node->nextSibling()) {
754             if (node->hasTagName(sourceTag))
755                 break;
756         }
757
758         // Otherwise, if the media element does not have a src attribute but has a source 
759         // element child, then let mode be children and let candidate be the first such 
760         // source element child in tree order.
761         if (node) {
762             mode = children;
763             m_nextChildNodeToConsider = 0;
764             m_currentSourceNode = 0;
765         } else {
766             // Otherwise the media element has neither a src attribute nor a source element 
767             // child: set the networkState to NETWORK_EMPTY, and abort these steps; the 
768             // synchronous section ends.
769             m_loadState = WaitingForSource;
770             setShouldDelayLoadEvent(false);
771             m_networkState = NETWORK_EMPTY;
772
773             LOG(Media, "HTMLMediaElement::selectMediaResource, nothing to load");
774             return;
775         }
776     }
777
778     // 4 - Set the media element's delaying-the-load-event flag to true (this delays the load event), 
779     // and set its networkState to NETWORK_LOADING.
780     setShouldDelayLoadEvent(true);
781     m_networkState = NETWORK_LOADING;
782
783     // 5 - Queue a task to fire a simple event named loadstart at the media element.
784     scheduleEvent(eventNames().loadstartEvent);
785
786     // 6 - If mode is attribute, then run these substeps
787     if (mode == attribute) {
788         m_loadState = LoadingFromSrcAttr;
789
790         // If the src attribute's value is the empty string ... jump down to the failed step below
791         KURL mediaURL = getNonEmptyURLAttribute(srcAttr);
792         if (mediaURL.isEmpty()) {
793             mediaLoadingFailed(MediaPlayer::FormatError);
794             LOG(Media, "HTMLMediaElement::selectMediaResource, empty 'src'");
795             return;
796         }
797
798         if (!isSafeToLoadURL(mediaURL, Complain) || !dispatchBeforeLoadEvent(mediaURL.string())) {
799             mediaLoadingFailed(MediaPlayer::FormatError);
800             return;
801         }
802
803         // No type information is available when the url comes from the 'src' attribute so MediaPlayer
804         // will have to pick a media engine based on the file extension.
805         ContentType contentType("");
806         loadResource(mediaURL, contentType);
807         LOG(Media, "HTMLMediaElement::selectMediaResource, using 'src' attribute url");
808         return;
809     }
810
811     // Otherwise, the source elements will be used
812     loadNextSourceChild();
813 }
814
815 void HTMLMediaElement::loadNextSourceChild()
816 {
817     ContentType contentType("");
818     KURL mediaURL = selectNextSourceChild(&contentType, Complain);
819     if (!mediaURL.isValid()) {
820         waitForSourceChange();
821         return;
822     }
823
824 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
825     // Recreate the media player for the new url
826     createMediaPlayer();
827 #endif
828
829     m_loadState = LoadingFromSourceElement;
830     loadResource(mediaURL, contentType);
831 }
832
833 #if !PLATFORM(CHROMIUM)
834 static KURL createFileURLForApplicationCacheResource(const String& path)
835 {
836     // KURL should have a function to create a url from a path, but it does not. This function
837     // is not suitable because KURL::setPath uses encodeWithURLEscapeSequences, which it notes
838     // does not correctly escape '#' and '?'. This function works for our purposes because
839     // app cache media files are always created with encodeForFileName(createCanonicalUUIDString()).
840
841 #if USE(CF) && PLATFORM(WIN)
842     RetainPtr<CFStringRef> cfPath(AdoptCF, path.createCFString());
843     RetainPtr<CFURLRef> cfURL(AdoptCF, CFURLCreateWithFileSystemPath(0, cfPath.get(), kCFURLWindowsPathStyle, false));
844     KURL url(cfURL.get());
845 #else
846     KURL url;
847
848     url.setProtocol("file");
849     url.setPath(path);
850 #endif
851     return url;
852 }
853 #endif
854
855 void HTMLMediaElement::loadResource(const KURL& initialURL, ContentType& contentType)
856 {
857     ASSERT(isSafeToLoadURL(initialURL, Complain));
858
859     LOG(Media, "HTMLMediaElement::loadResource(%s, %s)", urlForLogging(initialURL).utf8().data(), contentType.raw().utf8().data());
860
861     Frame* frame = document()->frame();
862     if (!frame) {
863         mediaLoadingFailed(MediaPlayer::FormatError);
864         return;
865     }
866
867     KURL url = initialURL;
868     if (!frame->loader()->willLoadMediaElementURL(url)) {
869         mediaLoadingFailed(MediaPlayer::FormatError);
870         return;
871     }
872     
873 #if ENABLE(MEDIA_SOURCE)
874     // If this is a media source URL, make sure it is the one for this media element.
875     if (url.protocolIs(mediaSourceURLProtocol) && url != m_mediaSourceURL) {
876         mediaLoadingFailed(MediaPlayer::FormatError);
877         return;
878     }
879 #endif
880
881     // The resource fetch algorithm 
882     m_networkState = NETWORK_LOADING;
883
884 #if !PLATFORM(CHROMIUM)
885     // If the url should be loaded from the application cache, pass the url of the cached file
886     // to the media engine.
887     ApplicationCacheHost* cacheHost = frame->loader()->documentLoader()->applicationCacheHost();
888     ApplicationCacheResource* resource = 0;
889     if (cacheHost && cacheHost->shouldLoadResourceFromApplicationCache(ResourceRequest(url), resource)) {
890         // Resources that are not present in the manifest will always fail to load (at least, after the
891         // cache has been primed the first time), making the testing of offline applications simpler.
892         if (!resource || resource->path().isEmpty()) {
893             mediaLoadingFailed(MediaPlayer::NetworkError);
894             return;
895         }
896     }
897 #endif
898
899     // Set m_currentSrc *before* changing to the cache url, the fact that we are loading from the app
900     // cache is an internal detail not exposed through the media element API.
901     m_currentSrc = url;
902
903 #if !PLATFORM(CHROMIUM)
904     if (resource) {
905         url = createFileURLForApplicationCacheResource(resource->path());
906         LOG(Media, "HTMLMediaElement::loadResource - will load from app cache -> %s", urlForLogging(url).utf8().data());
907     }
908 #endif
909
910     LOG(Media, "HTMLMediaElement::loadResource - m_currentSrc -> %s", urlForLogging(m_currentSrc).utf8().data());
911
912     if (m_sendProgressEvents) 
913         startProgressEventTimer();
914
915     Settings* settings = document()->settings();
916     bool privateMode = !settings || settings->privateBrowsingEnabled();
917     m_player->setPrivateBrowsingMode(privateMode);
918
919     // Reset display mode to force a recalculation of what to show because we are resetting the player.
920     setDisplayMode(Unknown);
921
922     if (!autoplay())
923         m_player->setPreload(m_preload);
924     m_player->setPreservesPitch(m_webkitPreservesPitch);
925
926     if (fastHasAttribute(mutedAttr))
927         m_muted = true;
928     updateVolume();
929
930     if (!m_player->load(url, contentType))
931         mediaLoadingFailed(MediaPlayer::FormatError);
932
933     // If there is no poster to display, allow the media engine to render video frames as soon as
934     // they are available.
935     updateDisplayState();
936
937     if (renderer())
938         renderer()->updateFromElement();
939 }
940
941 #if ENABLE(VIDEO_TRACK)
942 void HTMLMediaElement::updateActiveTextTrackCues(float movieTime)
943 {
944     CueList previouslyActiveCues = m_currentlyActiveCues;
945     bool activeSetChanged = false;
946
947     m_currentlyActiveCues = m_cueTree.allOverlaps(m_cueTree.createInterval(movieTime, movieTime));
948     
949     // FIXME(72171): Events need to be sorted and filtered before dispatching.
950
951     for (size_t i = 0; i < previouslyActiveCues.size(); ++i) {
952         if (!m_currentlyActiveCues.contains(previouslyActiveCues[i])) {
953             previouslyActiveCues[i].data()->setIsActive(false);
954             activeSetChanged = true;
955         }
956     }
957     for (size_t i = 0; i < m_currentlyActiveCues.size(); ++i) {
958         if (!previouslyActiveCues.contains(m_currentlyActiveCues[i])) {
959             m_currentlyActiveCues[i].data()->setIsActive(true);
960             activeSetChanged = true;
961         }
962     }
963     
964     // FIXME(72173): Pause the media element for cues going past their endTime
965     // during a monotonic time increase.
966
967     if (activeSetChanged && hasMediaControls())
968         mediaControls()->updateTextTrackDisplay();
969 }
970
971 bool HTMLMediaElement::textTracksAreReady() const
972 {
973     // The text tracks of a media element are ready if all the text tracks whose mode was not 
974     // in the disabled state when the element's resource selection algorithm last started now
975     // have a text track readiness state of loaded or failed to load.
976     for (unsigned i = 0; i < m_textTracksWhenResourceSelectionBegan.size(); ++i) {
977         if (m_textTracksWhenResourceSelectionBegan[i]->readinessState() == TextTrack::Loading)
978             return false;
979     }
980
981     return true;
982 }
983
984 void HTMLMediaElement::textTrackReadyStateChanged(TextTrack* track)
985 {
986     if (m_player && m_textTracksWhenResourceSelectionBegan.contains(track)) {
987         if (track->readinessState() != TextTrack::Loading)
988             setReadyState(m_player->readyState());
989     }
990 }
991
992 void HTMLMediaElement::textTrackModeChanged(TextTrack* track)
993 {
994     if (track->trackType() == TextTrack::TrackElement) {
995         // 4.8.10.12.3 Sourcing out-of-band text tracks
996         // ... when a text track corresponding to a track element is created with text track
997         // mode set to disabled and subsequently changes its text track mode to hidden, showing,
998         // or showing by default for the first time, the user agent must immediately and synchronously
999         // run the following algorithm ...
1000
1001         for (Node* node = firstChild(); node; node = node->nextSibling()) {
1002             if (!node->hasTagName(trackTag))
1003                 continue;
1004             HTMLTrackElement* trackElement = static_cast<HTMLTrackElement*>(node);
1005             if (trackElement->track() != track)
1006                 continue;
1007             
1008             // Mark this track as "configured" so configureTextTrack won't change the mode again.
1009             trackElement->setHasBeenConfigured(true);
1010             if (track->mode() != TextTrack::DISABLED && trackElement->readyState() == HTMLTrackElement::NONE)
1011                 trackElement->scheduleLoad();
1012             break;
1013         }
1014     }
1015
1016     configureTextTrackDisplay();
1017 }
1018
1019 void HTMLMediaElement::textTrackKindChanged(TextTrack*)
1020 {
1021     // FIXME(62885): Implement.
1022 }
1023
1024 void HTMLMediaElement::textTrackAddCues(TextTrack*, const TextTrackCueList* cues) 
1025 {
1026     for (size_t i = 0; i < cues->length(); ++i)
1027         textTrackAddCue(cues->item(i)->track(), cues->item(i));
1028 }
1029
1030 void HTMLMediaElement::textTrackRemoveCues(TextTrack*, const TextTrackCueList* cues) 
1031 {
1032     for (size_t i = 0; i < cues->length(); ++i)
1033         textTrackRemoveCue(cues->item(i)->track(), cues->item(i));
1034 }
1035
1036 void HTMLMediaElement::textTrackAddCue(TextTrack*, PassRefPtr<TextTrackCue> cue)
1037 {
1038     m_cueTree.add(m_cueTree.createInterval(cue->startTime(), cue->endTime(), cue.get()));
1039 }
1040
1041 void HTMLMediaElement::textTrackRemoveCue(TextTrack*, PassRefPtr<TextTrackCue> cue)
1042 {
1043     m_cueTree.remove(m_cueTree.createInterval(cue->startTime(), cue->endTime(), cue.get()));
1044 }
1045
1046 #endif
1047
1048 bool HTMLMediaElement::isSafeToLoadURL(const KURL& url, InvalidURLAction actionIfInvalid)
1049 {
1050     if (!url.isValid()) {
1051         LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%s) -> FALSE because url is invalid", urlForLogging(url).utf8().data());
1052         return false;
1053     }
1054
1055     Frame* frame = document()->frame();
1056     if (!frame || !document()->securityOrigin()->canDisplay(url)) {
1057         if (actionIfInvalid == Complain)
1058             FrameLoader::reportLocalLoadFailed(frame, url.string());
1059         LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%s) -> FALSE rejected by SecurityOrigin", urlForLogging(url).utf8().data());
1060         return false;
1061     }
1062
1063     if (!document()->contentSecurityPolicy()->allowMediaFromSource(url)) {
1064         LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%s) -> rejected by Content Security Policy", urlForLogging(url).utf8().data());
1065         return false;
1066     }
1067
1068     return true;
1069 }
1070
1071 void HTMLMediaElement::startProgressEventTimer()
1072 {
1073     if (m_progressEventTimer.isActive())
1074         return;
1075
1076     m_previousProgressTime = WTF::currentTime();
1077     m_previousProgress = 0;
1078     // 350ms is not magic, it is in the spec!
1079     m_progressEventTimer.startRepeating(0.350);
1080 }
1081
1082 void HTMLMediaElement::waitForSourceChange()
1083 {
1084     LOG(Media, "HTMLMediaElement::waitForSourceChange");
1085
1086     stopPeriodicTimers();
1087     m_loadState = WaitingForSource;
1088
1089     // 6.17 - Waiting: Set the element's networkState attribute to the NETWORK_NO_SOURCE value
1090     m_networkState = NETWORK_NO_SOURCE;
1091
1092     // 6.18 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
1093     setShouldDelayLoadEvent(false);
1094
1095     updateDisplayState();
1096
1097     if (renderer())
1098         renderer()->updateFromElement();
1099 }
1100
1101 void HTMLMediaElement::noneSupported()
1102 {
1103     LOG(Media, "HTMLMediaElement::noneSupported");
1104
1105     stopPeriodicTimers();
1106     m_loadState = WaitingForSource;
1107     m_currentSourceNode = 0;
1108
1109     // 4.8.10.5 
1110     // 6 - Reaching this step indicates that the media resource failed to load or that the given 
1111     // URL could not be resolved. In one atomic operation, run the following steps:
1112
1113     // 6.1 - Set the error attribute to a new MediaError object whose code attribute is set to
1114     // MEDIA_ERR_SRC_NOT_SUPPORTED.
1115     m_error = MediaError::create(MediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
1116
1117     // 6.2 - Forget the media element's media-resource-specific text tracks.
1118
1119     // 6.3 - Set the element's networkState attribute to the NETWORK_NO_SOURCE value.
1120     m_networkState = NETWORK_NO_SOURCE;
1121
1122     // 7 - Queue a task to fire a simple event named error at the media element.
1123     scheduleEvent(eventNames().errorEvent);
1124
1125     // 8 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
1126     setShouldDelayLoadEvent(false);
1127
1128     // 9 - Abort these steps. Until the load() method is invoked or the src attribute is changed, 
1129     // the element won't attempt to load another resource.
1130
1131     updateDisplayState();
1132
1133     if (renderer())
1134         renderer()->updateFromElement();
1135 }
1136
1137 void HTMLMediaElement::mediaEngineError(PassRefPtr<MediaError> err)
1138 {
1139     LOG(Media, "HTMLMediaElement::mediaEngineError(%d)", static_cast<int>(err->code()));
1140
1141     // 1 - The user agent should cancel the fetching process.
1142     stopPeriodicTimers();
1143     m_loadState = WaitingForSource;
1144
1145     // 2 - Set the error attribute to a new MediaError object whose code attribute is 
1146     // set to MEDIA_ERR_NETWORK/MEDIA_ERR_DECODE.
1147     m_error = err;
1148
1149     // 3 - Queue a task to fire a simple event named error at the media element.
1150     scheduleEvent(eventNames().errorEvent);
1151
1152 #if ENABLE(MEDIA_SOURCE)
1153     if (m_sourceState != SOURCE_CLOSED)
1154         setSourceState(SOURCE_CLOSED);
1155 #endif
1156
1157     // 4 - Set the element's networkState attribute to the NETWORK_EMPTY value and queue a
1158     // task to fire a simple event called emptied at the element.
1159     m_networkState = NETWORK_EMPTY;
1160     scheduleEvent(eventNames().emptiedEvent);
1161
1162     // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
1163     setShouldDelayLoadEvent(false);
1164
1165     // 6 - Abort the overall resource selection algorithm.
1166     m_currentSourceNode = 0;
1167 }
1168
1169 void HTMLMediaElement::cancelPendingEventsAndCallbacks()
1170 {
1171     LOG(Media, "HTMLMediaElement::cancelPendingEventsAndCallbacks");
1172
1173     m_pendingEvents.clear();
1174
1175     for (Node* node = firstChild(); node; node = node->nextSibling()) {
1176         if (node->hasTagName(sourceTag))
1177             static_cast<HTMLSourceElement*>(node)->cancelPendingErrorEvent();
1178     }
1179 }
1180
1181 Document* HTMLMediaElement::mediaPlayerOwningDocument()
1182 {
1183     Document* d = document();
1184     
1185     if (!d)
1186         d = ownerDocument();
1187     
1188     return d;
1189 }
1190
1191 void HTMLMediaElement::mediaPlayerNetworkStateChanged(MediaPlayer*)
1192 {
1193     beginProcessingMediaPlayerCallback();
1194     setNetworkState(m_player->networkState());
1195     endProcessingMediaPlayerCallback();
1196 }
1197
1198 void HTMLMediaElement::mediaLoadingFailed(MediaPlayer::NetworkState error)
1199 {
1200     stopPeriodicTimers();
1201     
1202     // If we failed while trying to load a <source> element, the movie was never parsed, and there are more
1203     // <source> children, schedule the next one
1204     if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement) {
1205         
1206         if (m_currentSourceNode)
1207             m_currentSourceNode->scheduleErrorEvent();
1208         else
1209             LOG(Media, "HTMLMediaElement::setNetworkState - error event not sent, <source> was removed");
1210         
1211         if (havePotentialSourceChild()) {
1212             LOG(Media, "HTMLMediaElement::setNetworkState - scheduling next <source>");
1213             scheduleNextSourceChild();
1214         } else {
1215             LOG(Media, "HTMLMediaElement::setNetworkState - no more <source> elements, waiting");
1216             waitForSourceChange();
1217         }
1218         
1219         return;
1220     }
1221     
1222     if (error == MediaPlayer::NetworkError && m_readyState >= HAVE_METADATA)
1223         mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_NETWORK));
1224     else if (error == MediaPlayer::DecodeError)
1225         mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_DECODE));
1226     else if ((error == MediaPlayer::FormatError || error == MediaPlayer::NetworkError) && m_loadState == LoadingFromSrcAttr)
1227         noneSupported();
1228     
1229     updateDisplayState();
1230     if (hasMediaControls()) {
1231         mediaControls()->reset();
1232         mediaControls()->reportedError();
1233     }
1234 }
1235
1236 void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
1237 {
1238     LOG(Media, "HTMLMediaElement::setNetworkState(%d) - current state is %d", static_cast<int>(state), static_cast<int>(m_networkState));
1239
1240     if (state == MediaPlayer::Empty) {
1241         // Just update the cached state and leave, we can't do anything.
1242         m_networkState = NETWORK_EMPTY;
1243         return;
1244     }
1245
1246     if (state == MediaPlayer::FormatError || state == MediaPlayer::NetworkError || state == MediaPlayer::DecodeError) {
1247         mediaLoadingFailed(state);
1248         return;
1249     }
1250
1251     if (state == MediaPlayer::Idle) {
1252         if (m_networkState > NETWORK_IDLE) {
1253             m_progressEventTimer.stop();
1254             scheduleEvent(eventNames().suspendEvent);
1255             setShouldDelayLoadEvent(false);
1256         }
1257         m_networkState = NETWORK_IDLE;
1258     }
1259
1260     if (state == MediaPlayer::Loading) {
1261         if (m_networkState < NETWORK_LOADING || m_networkState == NETWORK_NO_SOURCE)
1262             startProgressEventTimer();
1263         m_networkState = NETWORK_LOADING;
1264     }
1265
1266     if (state == MediaPlayer::Loaded) {
1267         if (m_networkState != NETWORK_IDLE) {
1268             m_progressEventTimer.stop();
1269
1270             // Schedule one last progress event so we guarantee that at least one is fired
1271             // for files that load very quickly.
1272             scheduleEvent(eventNames().progressEvent);
1273         }
1274         m_networkState = NETWORK_IDLE;
1275         m_completelyLoaded = true;
1276     }
1277
1278     if (hasMediaControls())
1279         mediaControls()->updateStatusDisplay();
1280 }
1281
1282 void HTMLMediaElement::mediaPlayerReadyStateChanged(MediaPlayer*)
1283 {
1284     beginProcessingMediaPlayerCallback();
1285
1286     setReadyState(m_player->readyState());
1287
1288     endProcessingMediaPlayerCallback();
1289 }
1290
1291 void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
1292 {
1293     LOG(Media, "HTMLMediaElement::setReadyState(%d) - current state is %d,", static_cast<int>(state), static_cast<int>(m_readyState));
1294
1295     // Set "wasPotentiallyPlaying" BEFORE updating m_readyState, potentiallyPlaying() uses it
1296     bool wasPotentiallyPlaying = potentiallyPlaying();
1297
1298     ReadyState oldState = m_readyState;
1299     m_readyState = static_cast<ReadyState>(state);
1300
1301 #if ENABLE(VIDEO_TRACK)
1302     bool tracksAreReady = textTracksAreReady();
1303
1304     if (m_readyState == oldState && m_tracksAreReady == tracksAreReady)
1305         return;
1306
1307     m_tracksAreReady = tracksAreReady;
1308 #else
1309     if (m_readyState == oldState)
1310         return;
1311     bool tracksAreReady = true;
1312 #endif
1313     
1314     if (oldState > m_readyStateMaximum)
1315         m_readyStateMaximum = oldState;
1316
1317     if (m_networkState == NETWORK_EMPTY)
1318         return;
1319
1320     if (m_seeking) {
1321         // 4.8.10.9, step 11
1322         if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA)
1323             scheduleEvent(eventNames().waitingEvent);
1324
1325         // 4.8.10.10 step 14 & 15.
1326         if (m_readyState >= HAVE_CURRENT_DATA)
1327             finishSeek();
1328     } else {
1329         if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA) {
1330             // 4.8.10.8
1331             scheduleTimeupdateEvent(false);
1332             scheduleEvent(eventNames().waitingEvent);
1333         }
1334     }
1335
1336     if (m_readyState >= HAVE_METADATA && oldState < HAVE_METADATA && tracksAreReady) {
1337         scheduleEvent(eventNames().durationchangeEvent);
1338         scheduleEvent(eventNames().loadedmetadataEvent);
1339         if (hasMediaControls())
1340             mediaControls()->loadedMetadata();
1341         if (renderer())
1342             renderer()->updateFromElement();
1343     }
1344
1345     bool shouldUpdateDisplayState = false;
1346
1347     if (m_readyState >= HAVE_CURRENT_DATA && oldState < HAVE_CURRENT_DATA && !m_haveFiredLoadedData && tracksAreReady) {
1348         m_haveFiredLoadedData = true;
1349         shouldUpdateDisplayState = true;
1350         scheduleEvent(eventNames().loadeddataEvent);
1351         setShouldDelayLoadEvent(false);
1352     }
1353
1354     bool isPotentiallyPlaying = potentiallyPlaying();
1355     if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA && tracksAreReady) {
1356         scheduleEvent(eventNames().canplayEvent);
1357         if (isPotentiallyPlaying)
1358             scheduleEvent(eventNames().playingEvent);
1359         shouldUpdateDisplayState = true;
1360     }
1361
1362     if (m_readyState == HAVE_ENOUGH_DATA && oldState < HAVE_ENOUGH_DATA && tracksAreReady) {
1363         if (oldState <= HAVE_CURRENT_DATA)
1364             scheduleEvent(eventNames().canplayEvent);
1365
1366         scheduleEvent(eventNames().canplaythroughEvent);
1367
1368         if (isPotentiallyPlaying && oldState <= HAVE_CURRENT_DATA)
1369             scheduleEvent(eventNames().playingEvent);
1370
1371         if (m_autoplaying && m_paused && autoplay()) {
1372             m_paused = false;
1373             invalidateCachedTime();
1374             scheduleEvent(eventNames().playEvent);
1375             scheduleEvent(eventNames().playingEvent);
1376         }
1377
1378         shouldUpdateDisplayState = true;
1379     }
1380
1381     if (shouldUpdateDisplayState) {
1382         updateDisplayState();
1383         if (hasMediaControls())
1384             mediaControls()->updateStatusDisplay();
1385     }
1386
1387     updatePlayState();
1388     updateMediaController();
1389 }
1390
1391 #if ENABLE(MEDIA_SOURCE)
1392 void HTMLMediaElement::mediaPlayerSourceOpened()
1393 {
1394     beginProcessingMediaPlayerCallback();
1395
1396     setSourceState(SOURCE_OPEN);
1397
1398     endProcessingMediaPlayerCallback();
1399 }
1400
1401 String HTMLMediaElement::mediaPlayerSourceURL() const
1402 {
1403     return m_mediaSourceURL.string();
1404 }
1405 #endif
1406
1407 void HTMLMediaElement::progressEventTimerFired(Timer<HTMLMediaElement>*)
1408 {
1409     ASSERT(m_player);
1410     if (m_networkState != NETWORK_LOADING)
1411         return;
1412
1413     unsigned progress = m_player->bytesLoaded();
1414     double time = WTF::currentTime();
1415     double timedelta = time - m_previousProgressTime;
1416
1417     if (progress == m_previousProgress) {
1418         if (timedelta > 3.0 && !m_sentStalledEvent) {
1419             scheduleEvent(eventNames().stalledEvent);
1420             m_sentStalledEvent = true;
1421             setShouldDelayLoadEvent(false);
1422         }
1423     } else {
1424         scheduleEvent(eventNames().progressEvent);
1425         m_previousProgress = progress;
1426         m_previousProgressTime = time;
1427         m_sentStalledEvent = false;
1428         if (renderer())
1429             renderer()->updateFromElement();
1430     }
1431 }
1432
1433 void HTMLMediaElement::rewind(float timeDelta)
1434 {
1435     LOG(Media, "HTMLMediaElement::rewind(%f)", timeDelta);
1436
1437     ExceptionCode e;
1438     setCurrentTime(max(currentTime() - timeDelta, minTimeSeekable()), e);
1439 }
1440
1441 void HTMLMediaElement::returnToRealtime()
1442 {
1443     LOG(Media, "HTMLMediaElement::returnToRealtime");
1444     ExceptionCode e;
1445     setCurrentTime(maxTimeSeekable(), e);
1446 }  
1447
1448 void HTMLMediaElement::addPlayedRange(float start, float end)
1449 {
1450     LOG(Media, "HTMLMediaElement::addPlayedRange(%f, %f)", start, end);
1451     if (!m_playedTimeRanges)
1452         m_playedTimeRanges = TimeRanges::create();
1453     m_playedTimeRanges->add(start, end);
1454 }  
1455
1456 bool HTMLMediaElement::supportsSave() const
1457 {
1458     return m_player ? m_player->supportsSave() : false;
1459 }
1460
1461 bool HTMLMediaElement::supportsScanning() const
1462 {
1463     return m_player ? m_player->supportsScanning() : false;
1464 }
1465
1466 void HTMLMediaElement::prepareToPlay()
1467 {
1468     LOG(Media, "HTMLMediaElement::prepareToPlay(%p)", this);
1469     if (m_havePreparedToPlay)
1470         return;
1471     m_havePreparedToPlay = true;
1472     m_player->prepareToPlay();
1473 }
1474
1475 void HTMLMediaElement::seek(float time, ExceptionCode& ec)
1476 {
1477     LOG(Media, "HTMLMediaElement::seek(%f)", time);
1478
1479     // 4.8.9.9 Seeking
1480
1481     // 1 - If the media element's readyState is HAVE_NOTHING, then raise an INVALID_STATE_ERR exception.
1482     if (m_readyState == HAVE_NOTHING || !m_player) {
1483         ec = INVALID_STATE_ERR;
1484         return;
1485     }
1486
1487     // If the media engine has been told to postpone loading data, let it go ahead now.
1488     if (m_preload < MediaPlayer::Auto && m_readyState < HAVE_FUTURE_DATA)
1489         prepareToPlay();
1490
1491     // Get the current time before setting m_seeking, m_lastSeekTime is returned once it is set.
1492     refreshCachedTime();
1493     float now = currentTime();
1494
1495     // 2 - If the element's seeking IDL attribute is true, then another instance of this algorithm is
1496     // already running. Abort that other instance of the algorithm without waiting for the step that
1497     // it is running to complete.
1498     // Nothing specific to be done here.
1499
1500     // 3 - Set the seeking IDL attribute to true.
1501     // The flag will be cleared when the engine tells us the time has actually changed.
1502     m_seeking = true;
1503
1504     // 5 - If the new playback position is later than the end of the media resource, then let it be the end 
1505     // of the media resource instead.
1506     time = min(time, duration());
1507
1508     // 6 - If the new playback position is less than the earliest possible position, let it be that position instead.
1509     float earliestTime = m_player->startTime();
1510     time = max(time, earliestTime);
1511
1512     // Ask the media engine for the time value in the movie's time scale before comparing with current time. This
1513     // is necessary because if the seek time is not equal to currentTime but the delta is less than the movie's
1514     // time scale, we will ask the media engine to "seek" to the current movie time, which may be a noop and
1515     // not generate a timechanged callback. This means m_seeking will never be cleared and we will never 
1516     // fire a 'seeked' event.
1517 #if !LOG_DISABLED
1518     float mediaTime = m_player->mediaTimeForTimeValue(time);
1519     if (time != mediaTime)
1520         LOG(Media, "HTMLMediaElement::seek(%f) - media timeline equivalent is %f", time, mediaTime);
1521 #endif
1522     time = m_player->mediaTimeForTimeValue(time);
1523
1524     // 7 - If the (possibly now changed) new playback position is not in one of the ranges given in the 
1525     // seekable attribute, then let it be the position in one of the ranges given in the seekable attribute 
1526     // that is the nearest to the new playback position. ... If there are no ranges given in the seekable
1527     // attribute then set the seeking IDL attribute to false and abort these steps.
1528     RefPtr<TimeRanges> seekableRanges = seekable();
1529
1530     // Short circuit seeking to the current time by just firing the events if no seek is required.
1531     // Don't skip calling the media engine if we are in poster mode because a seek should always 
1532     // cancel poster display.
1533     bool noSeekRequired = !seekableRanges->length() || (time == now && displayMode() != Poster);
1534
1535 #if ENABLE(MEDIA_SOURCE)
1536     // Always notify the media engine of a seek if the source is not closed. This ensures that the source is
1537     // always in a flushed state when the 'seeking' event fires.
1538     if (m_sourceState != SOURCE_CLOSED)
1539       noSeekRequired = false;
1540 #endif
1541
1542     if (noSeekRequired) {
1543         if (time == now) {
1544             scheduleEvent(eventNames().seekingEvent);
1545             scheduleTimeupdateEvent(false);
1546             scheduleEvent(eventNames().seekedEvent);
1547         }
1548         m_seeking = false;
1549         return;
1550     }
1551     time = seekableRanges->nearest(time);
1552
1553     if (m_playing) {
1554         if (m_lastSeekTime < now)
1555             addPlayedRange(m_lastSeekTime, now);
1556     }
1557     m_lastSeekTime = time;
1558     m_sentEndEvent = false;
1559
1560 #if ENABLE(MEDIA_SOURCE)
1561     if (m_sourceState == SOURCE_ENDED)
1562         setSourceState(SOURCE_OPEN);
1563 #endif
1564
1565     // 8 - Set the current playback position to the given new playback position
1566     m_player->seek(time);
1567
1568     // 9 - Queue a task to fire a simple event named seeking at the element.
1569     scheduleEvent(eventNames().seekingEvent);
1570
1571     // 10 - Queue a task to fire a simple event named timeupdate at the element.
1572     scheduleTimeupdateEvent(false);
1573
1574     // 11-15 are handled, if necessary, when the engine signals a readystate change.
1575 }
1576
1577 void HTMLMediaElement::finishSeek()
1578 {
1579     LOG(Media, "HTMLMediaElement::finishSeek");
1580
1581     // 4.8.10.9 Seeking step 14
1582     m_seeking = false;
1583
1584     // 4.8.10.9 Seeking step 15
1585     scheduleEvent(eventNames().seekedEvent);
1586
1587     setDisplayMode(Video);
1588 }
1589
1590 HTMLMediaElement::ReadyState HTMLMediaElement::readyState() const
1591 {
1592     return m_readyState;
1593 }
1594
1595 MediaPlayer::MovieLoadType HTMLMediaElement::movieLoadType() const
1596 {
1597     return m_player ? m_player->movieLoadType() : MediaPlayer::Unknown;
1598 }
1599
1600 bool HTMLMediaElement::hasAudio() const
1601 {
1602     return m_player ? m_player->hasAudio() : false;
1603 }
1604
1605 bool HTMLMediaElement::seeking() const
1606 {
1607     return m_seeking;
1608 }
1609
1610 void HTMLMediaElement::refreshCachedTime() const
1611 {
1612     m_cachedTime = m_player->currentTime();
1613     m_cachedTimeWallClockUpdateTime = WTF::currentTime();
1614 }
1615
1616 void HTMLMediaElement::invalidateCachedTime()
1617 {
1618     LOG(Media, "HTMLMediaElement::invalidateCachedTime");
1619
1620     // Don't try to cache movie time when playback first starts as the time reported by the engine
1621     // sometimes fluctuates for a short amount of time, so the cached time will be off if we take it
1622     // too early.
1623     static const double minimumTimePlayingBeforeCacheSnapshot = 0.5;
1624
1625     m_minimumWallClockTimeToCacheMediaTime = WTF::currentTime() + minimumTimePlayingBeforeCacheSnapshot;
1626     m_cachedTime = invalidMediaTime;
1627 }
1628
1629 // playback state
1630 float HTMLMediaElement::currentTime() const
1631 {
1632 #if LOG_CACHED_TIME_WARNINGS
1633     static const double minCachedDeltaForWarning = 0.01;
1634 #endif
1635
1636     if (!m_player)
1637         return 0;
1638
1639     if (m_seeking) {
1640         LOG(Media, "HTMLMediaElement::currentTime - seeking, returning %f", m_lastSeekTime);
1641         return m_lastSeekTime;
1642     }
1643
1644     if (m_cachedTime != invalidMediaTime && m_paused) {
1645 #if LOG_CACHED_TIME_WARNINGS
1646         float delta = m_cachedTime - m_player->currentTime();
1647         if (delta > minCachedDeltaForWarning)
1648             LOG(Media, "HTMLMediaElement::currentTime - WARNING, cached time is %f seconds off of media time when paused", delta);
1649 #endif
1650         return m_cachedTime;
1651     }
1652
1653     // Is it too soon use a cached time?
1654     double now = WTF::currentTime();
1655     double maximumDurationToCacheMediaTime = m_player->maximumDurationToCacheMediaTime();
1656
1657     if (maximumDurationToCacheMediaTime && m_cachedTime != invalidMediaTime && !m_paused && now > m_minimumWallClockTimeToCacheMediaTime) {
1658         double wallClockDelta = now - m_cachedTimeWallClockUpdateTime;
1659
1660         // Not too soon, use the cached time only if it hasn't expired.
1661         if (wallClockDelta < maximumDurationToCacheMediaTime) {
1662             float adjustedCacheTime = static_cast<float>(m_cachedTime + (m_playbackRate * wallClockDelta));
1663
1664 #if LOG_CACHED_TIME_WARNINGS
1665             float delta = adjustedCacheTime - m_player->currentTime();
1666             if (delta > minCachedDeltaForWarning)
1667                 LOG(Media, "HTMLMediaElement::currentTime - WARNING, cached time is %f seconds off of media time when playing", delta);
1668 #endif
1669             return adjustedCacheTime;
1670         }
1671     }
1672
1673 #if LOG_CACHED_TIME_WARNINGS
1674     if (maximumDurationToCacheMediaTime && now > m_minimumWallClockTimeToCacheMediaTime && m_cachedTime != invalidMediaTime) {
1675         double wallClockDelta = now - m_cachedTimeWallClockUpdateTime;
1676         float delta = m_cachedTime + (m_playbackRate * wallClockDelta) - m_player->currentTime();
1677         LOG(Media, "HTMLMediaElement::currentTime - cached time was %f seconds off of media time when it expired", delta);
1678     }
1679 #endif
1680
1681     refreshCachedTime();
1682
1683     return m_cachedTime;
1684 }
1685
1686 void HTMLMediaElement::setCurrentTime(float time, ExceptionCode& ec)
1687 {
1688     if (m_mediaController) {
1689         ec = INVALID_STATE_ERR;
1690         return;
1691     }
1692     seek(time, ec);
1693 }
1694
1695 float HTMLMediaElement::startTime() const
1696 {
1697     if (!m_player)
1698         return 0;
1699     return m_player->startTime();
1700 }
1701
1702 double HTMLMediaElement::initialTime() const
1703 {
1704     if (!m_player)
1705         return 0;
1706     return m_player->initialTime();
1707 }
1708
1709 float HTMLMediaElement::duration() const
1710 {
1711     if (m_player && m_readyState >= HAVE_METADATA)
1712         return m_player->duration();
1713
1714     return numeric_limits<float>::quiet_NaN();
1715 }
1716
1717 bool HTMLMediaElement::paused() const
1718 {
1719     return m_paused;
1720 }
1721
1722 float HTMLMediaElement::defaultPlaybackRate() const
1723 {
1724     return m_defaultPlaybackRate;
1725 }
1726
1727 void HTMLMediaElement::setDefaultPlaybackRate(float rate)
1728 {
1729     if (m_defaultPlaybackRate != rate) {
1730         m_defaultPlaybackRate = rate;
1731         scheduleEvent(eventNames().ratechangeEvent);
1732     }
1733 }
1734
1735 float HTMLMediaElement::playbackRate() const
1736 {
1737     return m_playbackRate;
1738 }
1739
1740 void HTMLMediaElement::setPlaybackRate(float rate)
1741 {
1742     LOG(Media, "HTMLMediaElement::setPlaybackRate(%f)", rate);
1743     
1744     if (m_playbackRate != rate) {
1745         m_playbackRate = rate;
1746         invalidateCachedTime();
1747         scheduleEvent(eventNames().ratechangeEvent);
1748     }
1749
1750     if (m_player && potentiallyPlaying() && m_player->rate() != rate && !m_mediaController)
1751         m_player->setRate(rate);
1752 }
1753
1754 void HTMLMediaElement::updatePlaybackRate()
1755 {
1756     float effectiveRate = m_mediaController ? m_mediaController->playbackRate() : m_playbackRate;
1757     if (m_player && potentiallyPlaying() && m_player->rate() != effectiveRate && !m_mediaController)
1758         m_player->setRate(effectiveRate);
1759 }
1760
1761 bool HTMLMediaElement::webkitPreservesPitch() const
1762 {
1763     return m_webkitPreservesPitch;
1764 }
1765
1766 void HTMLMediaElement::setWebkitPreservesPitch(bool preservesPitch)
1767 {
1768     LOG(Media, "HTMLMediaElement::setWebkitPreservesPitch(%s)", boolString(preservesPitch));
1769
1770     m_webkitPreservesPitch = preservesPitch;
1771     
1772     if (!m_player)
1773         return;
1774
1775     m_player->setPreservesPitch(preservesPitch);
1776 }
1777
1778 bool HTMLMediaElement::ended() const
1779 {
1780     // 4.8.10.8 Playing the media resource
1781     // The ended attribute must return true if the media element has ended 
1782     // playback and the direction of playback is forwards, and false otherwise.
1783     return endedPlayback() && m_playbackRate > 0;
1784 }
1785
1786 bool HTMLMediaElement::autoplay() const
1787 {
1788     return fastHasAttribute(autoplayAttr);
1789 }
1790
1791 void HTMLMediaElement::setAutoplay(bool b)
1792 {
1793     LOG(Media, "HTMLMediaElement::setAutoplay(%s)", boolString(b));
1794     setBooleanAttribute(autoplayAttr, b);
1795 }
1796
1797 String HTMLMediaElement::preload() const
1798 {
1799     switch (m_preload) {
1800     case MediaPlayer::None:
1801         return "none";
1802         break;
1803     case MediaPlayer::MetaData:
1804         return "metadata";
1805         break;
1806     case MediaPlayer::Auto:
1807         return "auto";
1808         break;
1809     }
1810
1811     ASSERT_NOT_REACHED();
1812     return String();
1813 }
1814
1815 void HTMLMediaElement::setPreload(const String& preload)
1816 {
1817     LOG(Media, "HTMLMediaElement::setPreload(%s)", preload.utf8().data());
1818     setAttribute(preloadAttr, preload);
1819 }
1820
1821 void HTMLMediaElement::play()
1822 {
1823     LOG(Media, "HTMLMediaElement::play()");
1824
1825     if (userGestureRequiredForRateChange() && !ScriptController::processingUserGesture())
1826         return;
1827
1828     Settings* settings = document()->settings();
1829     if (settings && settings->needsSiteSpecificQuirks() && m_dispatchingCanPlayEvent && !m_loadInitiatedByUserGesture) {
1830         // It should be impossible to be processing the canplay event while handling a user gesture
1831         // since it is dispatched asynchronously.
1832         ASSERT(!ScriptController::processingUserGesture());
1833         String host = document()->baseURL().host();
1834         if (host.endsWith(".npr.org", false) || equalIgnoringCase(host, "npr.org"))
1835             return;
1836     }
1837
1838     playInternal();
1839 }
1840
1841 void HTMLMediaElement::playInternal()
1842 {
1843     LOG(Media, "HTMLMediaElement::playInternal");
1844
1845     // 4.8.10.9. Playing the media resource
1846     if (!m_player || m_networkState == NETWORK_EMPTY)
1847         scheduleLoad(MediaResource);
1848
1849     if (endedPlayback()) {
1850         ExceptionCode unused;
1851         seek(0, unused);
1852     }
1853
1854     if (m_mediaController)
1855         m_mediaController->bringElementUpToSpeed(this);
1856
1857     if (m_paused) {
1858         m_paused = false;
1859         invalidateCachedTime();
1860         scheduleEvent(eventNames().playEvent);
1861
1862         if (m_readyState <= HAVE_CURRENT_DATA)
1863             scheduleEvent(eventNames().waitingEvent);
1864         else if (m_readyState >= HAVE_FUTURE_DATA)
1865             scheduleEvent(eventNames().playingEvent);
1866     }
1867     m_autoplaying = false;
1868
1869     updatePlayState();
1870     updateMediaController();
1871 }
1872
1873 void HTMLMediaElement::pause()
1874 {
1875     LOG(Media, "HTMLMediaElement::pause()");
1876
1877     if (userGestureRequiredForRateChange() && !ScriptController::processingUserGesture())
1878         return;
1879
1880     pauseInternal();
1881 }
1882
1883
1884 void HTMLMediaElement::pauseInternal()
1885 {
1886     LOG(Media, "HTMLMediaElement::pauseInternal");
1887
1888     // 4.8.10.9. Playing the media resource
1889     if (!m_player || m_networkState == NETWORK_EMPTY)
1890         scheduleLoad(MediaResource);
1891
1892     m_autoplaying = false;
1893     
1894     if (!m_paused) {
1895         m_paused = true;
1896         scheduleTimeupdateEvent(false);
1897         scheduleEvent(eventNames().pauseEvent);
1898     }
1899
1900     updatePlayState();
1901 }
1902
1903 #if ENABLE(MEDIA_SOURCE)
1904 void HTMLMediaElement::webkitSourceAppend(PassRefPtr<Uint8Array> data, ExceptionCode& ec)
1905 {
1906     if (!m_player || m_currentSrc != m_mediaSourceURL || m_sourceState != SOURCE_OPEN) {
1907         ec = INVALID_STATE_ERR;
1908         return;
1909     }
1910
1911     if (!data.get() || !m_player->sourceAppend(data->data(), data->length())) {
1912         ec = SYNTAX_ERR;
1913         return;
1914     }
1915 }
1916
1917 void HTMLMediaElement::webkitSourceEndOfStream(unsigned short status, ExceptionCode& ec)
1918 {
1919     if (!m_player || m_currentSrc != m_mediaSourceURL || m_sourceState != SOURCE_OPEN) {
1920         ec = INVALID_STATE_ERR;
1921         return;
1922     }
1923
1924     MediaPlayer::EndOfStreamStatus eosStatus = MediaPlayer::EosNoError;
1925
1926     switch (status) {
1927     case EOS_NO_ERROR:
1928         eosStatus = MediaPlayer::EosNoError;
1929         break;
1930     case EOS_NETWORK_ERR:
1931         eosStatus = MediaPlayer::EosNetworkError;
1932         break;
1933     case EOS_DECODE_ERR:
1934         eosStatus = MediaPlayer::EosDecodeError;
1935         break;
1936     default:
1937         ec = SYNTAX_ERR;
1938         return;
1939     }
1940
1941     setSourceState(SOURCE_ENDED);
1942     m_player->sourceEndOfStream(eosStatus);
1943 }
1944
1945 HTMLMediaElement::SourceState HTMLMediaElement::webkitSourceState() const
1946 {
1947     return m_sourceState;
1948 }
1949
1950 void HTMLMediaElement::setSourceState(SourceState state)
1951 {
1952     SourceState oldState = m_sourceState;
1953     m_sourceState = static_cast<SourceState>(state);
1954
1955     if (m_sourceState == oldState)
1956         return;
1957
1958     if (m_sourceState == SOURCE_CLOSED) {
1959         scheduleEvent(eventNames().webkitsourcecloseEvent);
1960         return;
1961     }
1962
1963     if (oldState == SOURCE_OPEN && m_sourceState == SOURCE_ENDED) {
1964         scheduleEvent(eventNames().webkitsourceendedEvent);
1965         return;
1966     }
1967
1968     if (m_sourceState == SOURCE_OPEN) {
1969         scheduleEvent(eventNames().webkitsourceopenEvent);
1970         return;
1971     }
1972 }
1973 #endif
1974
1975 bool HTMLMediaElement::loop() const
1976 {
1977     return fastHasAttribute(loopAttr);
1978 }
1979
1980 void HTMLMediaElement::setLoop(bool b)
1981 {
1982     LOG(Media, "HTMLMediaElement::setLoop(%s)", boolString(b));
1983     setBooleanAttribute(loopAttr, b);
1984 }
1985
1986 bool HTMLMediaElement::controls() const
1987 {
1988     Frame* frame = document()->frame();
1989
1990     // always show controls when scripting is disabled
1991     if (frame && !frame->script()->canExecuteScripts(NotAboutToExecuteScript))
1992         return true;
1993
1994     // always show controls for video when fullscreen playback is required.
1995     if (isVideo() && document()->page() && document()->page()->chrome()->requiresFullscreenForVideoPlayback())
1996         return true;
1997
1998     // Always show controls when in full screen mode.
1999     if (isFullscreen())
2000         return true;
2001
2002     return fastHasAttribute(controlsAttr);
2003 }
2004
2005 void HTMLMediaElement::setControls(bool b)
2006 {
2007     LOG(Media, "HTMLMediaElement::setControls(%s)", boolString(b));
2008     setBooleanAttribute(controlsAttr, b);
2009 }
2010
2011 float HTMLMediaElement::volume() const
2012 {
2013     return m_volume;
2014 }
2015
2016 void HTMLMediaElement::setVolume(float vol, ExceptionCode& ec)
2017 {
2018     LOG(Media, "HTMLMediaElement::setVolume(%f)", vol);
2019
2020     if (vol < 0.0f || vol > 1.0f) {
2021         ec = INDEX_SIZE_ERR;
2022         return;
2023     }
2024     
2025     if (m_volume != vol) {
2026         m_volume = vol;
2027         updateVolume();
2028         scheduleEvent(eventNames().volumechangeEvent);
2029     }
2030 }
2031
2032 bool HTMLMediaElement::muted() const
2033 {
2034     return m_muted;
2035 }
2036
2037 void HTMLMediaElement::setMuted(bool muted)
2038 {
2039     LOG(Media, "HTMLMediaElement::setMuted(%s)", boolString(muted));
2040
2041     if (m_muted != muted) {
2042         m_muted = muted;
2043         // Avoid recursion when the player reports volume changes.
2044         if (!processingMediaPlayerCallback()) {
2045             if (m_player) {
2046                 m_player->setMuted(m_muted);
2047                 if (hasMediaControls())
2048                     mediaControls()->changedMute();
2049             }
2050         }
2051         scheduleEvent(eventNames().volumechangeEvent);
2052     }
2053 }
2054
2055 void HTMLMediaElement::togglePlayState()
2056 {
2057     LOG(Media, "HTMLMediaElement::togglePlayState - canPlay() is %s", boolString(canPlay()));
2058
2059     // We can safely call the internal play/pause methods, which don't check restrictions, because
2060     // this method is only called from the built-in media controller
2061     if (canPlay()) {
2062         updatePlaybackRate();
2063         playInternal();
2064     } else 
2065         pauseInternal();
2066 }
2067
2068 void HTMLMediaElement::beginScrubbing()
2069 {
2070     LOG(Media, "HTMLMediaElement::beginScrubbing - paused() is %s", boolString(paused()));
2071
2072     if (!paused()) {
2073         if (ended()) {
2074             // Because a media element stays in non-paused state when it reaches end, playback resumes 
2075             // when the slider is dragged from the end to another position unless we pause first. Do 
2076             // a "hard pause" so an event is generated, since we want to stay paused after scrubbing finishes.
2077             pause();
2078         } else {
2079             // Not at the end but we still want to pause playback so the media engine doesn't try to
2080             // continue playing during scrubbing. Pause without generating an event as we will 
2081             // unpause after scrubbing finishes.
2082             setPausedInternal(true);
2083         }
2084     }
2085 }
2086
2087 void HTMLMediaElement::endScrubbing()
2088 {
2089     LOG(Media, "HTMLMediaElement::endScrubbing - m_pausedInternal is %s", boolString(m_pausedInternal));
2090
2091     if (m_pausedInternal)
2092         setPausedInternal(false);
2093 }
2094
2095 // The spec says to fire periodic timeupdate events (those sent while playing) every
2096 // "15 to 250ms", we choose the slowest frequency
2097 static const double maxTimeupdateEventFrequency = 0.25;
2098
2099 static const double timeWithoutMouseMovementBeforeHidingControls = 3;
2100
2101 void HTMLMediaElement::startPlaybackProgressTimer()
2102 {
2103     if (m_playbackProgressTimer.isActive())
2104         return;
2105
2106     m_previousProgressTime = WTF::currentTime();
2107     m_previousProgress = 0;
2108     m_playbackProgressTimer.startRepeating(maxTimeupdateEventFrequency);
2109 }
2110
2111 void HTMLMediaElement::playbackProgressTimerFired(Timer<HTMLMediaElement>*)
2112 {
2113     ASSERT(m_player);
2114     if (!m_playbackRate)
2115         return;
2116
2117     scheduleTimeupdateEvent(true);
2118     if (hasMediaControls())
2119         mediaControls()->playbackProgressed();
2120     // FIXME: deal with cue ranges here
2121     
2122 #if ENABLE(VIDEO_TRACK)
2123     updateActiveTextTrackCues(currentTime());
2124 #endif
2125 }
2126
2127 void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent)
2128 {
2129     double now = WTF::currentTime();
2130     double timedelta = now - m_lastTimeUpdateEventWallTime;
2131
2132     // throttle the periodic events
2133     if (periodicEvent && timedelta < maxTimeupdateEventFrequency)
2134         return;
2135
2136     // Some media engines make multiple "time changed" callbacks at the same time, but we only want one
2137     // event at a given time so filter here
2138     float movieTime = currentTime();
2139     if (movieTime != m_lastTimeUpdateEventMovieTime) {
2140         scheduleEvent(eventNames().timeupdateEvent);
2141         m_lastTimeUpdateEventWallTime = now;
2142         m_lastTimeUpdateEventMovieTime = movieTime;
2143     }
2144 }
2145
2146 bool HTMLMediaElement::canPlay() const
2147 {
2148     return paused() || ended() || m_readyState < HAVE_METADATA;
2149 }
2150
2151 float HTMLMediaElement::percentLoaded() const
2152 {
2153     if (!m_player)
2154         return 0;
2155     float duration = m_player->duration();
2156
2157     if (!duration || isinf(duration))
2158         return 0;
2159
2160     float buffered = 0;
2161     RefPtr<TimeRanges> timeRanges = m_player->buffered();
2162     for (unsigned i = 0; i < timeRanges->length(); ++i) {
2163         ExceptionCode ignoredException;
2164         float start = timeRanges->start(i, ignoredException);
2165         float end = timeRanges->end(i, ignoredException);
2166         buffered += end - start;
2167     }
2168     return buffered / duration;
2169 }
2170
2171 #if ENABLE(VIDEO_TRACK)
2172 PassRefPtr<TextTrack> HTMLMediaElement::addTrack(const String& kind, const String& label, const String& language, ExceptionCode& ec)
2173 {
2174     if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
2175         return 0;
2176
2177     // 4.8.10.12.4 Text track API
2178     // The addTextTrack(kind, label, language) method of media elements, when invoked, must run the following steps:
2179     
2180     // 1. If kind is not one of the following strings, then throw a SyntaxError exception and abort these steps
2181     if (!TextTrack::isValidKindKeyword(kind)) {
2182         ec = SYNTAX_ERR;
2183         return 0;
2184     }
2185
2186     // 2. If the label argument was omitted, let label be the empty string.
2187     // 3. If the language argument was omitted, let language be the empty string.
2188     // 4. Create a new TextTrack object.
2189     RefPtr<TextTrack> textTrack = TextTrack::create(ActiveDOMObject::scriptExecutionContext(), this, kind, label, language);
2190
2191     // 5. Create a new text track corresponding to the new object, and set its text track kind to kind, its text 
2192     // track label to label, its text track language to language, its text track readiness state to the text track
2193     // loaded state, its text track mode to the text track hidden mode, and its text track list of cues to an empty list.
2194     
2195     // 6. Add the new text track to the media element's list of text tracks.
2196     textTracks()->append(textTrack);
2197
2198     return textTrack.release();
2199 }
2200
2201 TextTrackList* HTMLMediaElement::textTracks() 
2202 {
2203     if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
2204         return 0;
2205
2206     if (!m_textTracks)
2207         m_textTracks = TextTrackList::create(this, ActiveDOMObject::scriptExecutionContext());
2208
2209     return m_textTracks.get();
2210 }
2211
2212 HTMLTrackElement* HTMLMediaElement::showingTrackWithSameKind(HTMLTrackElement* trackElement) const
2213 {
2214     HTMLTrackElement* showingTrack = 0;
2215     
2216     for (Node* node = firstChild(); node; node = node->nextSibling()) {
2217         if (trackElement == node)
2218             continue;
2219         if (!node->hasTagName(trackTag))
2220             continue;
2221
2222         showingTrack = static_cast<HTMLTrackElement*>(node);
2223         if (showingTrack->kind() == trackElement->kind() && showingTrack->track()->mode() == TextTrack::SHOWING)
2224             return showingTrack;
2225     }
2226     
2227     return 0;
2228 }
2229
2230 void HTMLMediaElement::trackWasAdded(HTMLTrackElement* trackElement)
2231 {
2232     ASSERT(trackElement->hasTagName(trackTag));
2233
2234     if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
2235         return;
2236
2237     // 4.8.10.12.3 Sourcing out-of-band text tracks
2238     // When a track element's parent element changes and the new parent is a media element, 
2239     // then the user agent must add the track element's corresponding text track to the 
2240     // media element's list of text tracks ... [continues in TextTrackList::append]
2241     RefPtr<TextTrack> textTrack = trackElement->track();
2242     if (!textTrack)
2243         return;
2244     
2245     textTracks()->append(textTrack);
2246     
2247     // Do not schedule the track loading until parsing finishes so we don't start before all tracks
2248     // in the markup have been added.
2249     if (!m_parsingInProgress)
2250         scheduleLoad(TextTrackResource);
2251 }
2252
2253 void HTMLMediaElement::trackWillBeRemoved(HTMLTrackElement* trackElement)
2254 {
2255     ASSERT(trackElement->hasTagName(trackTag));
2256
2257     if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
2258         return;
2259
2260 #if !LOG_DISABLED
2261     if (trackElement->hasTagName(trackTag)) {
2262         KURL url = trackElement->getNonEmptyURLAttribute(srcAttr);
2263         LOG(Media, "HTMLMediaElement::trackWillBeRemoved - 'src' is %s", urlForLogging(url).utf8().data());
2264     }
2265 #endif
2266
2267     trackElement->setHasBeenConfigured(false);
2268
2269     RefPtr<TextTrack> textTrack = trackElement->track();
2270     if (!textTrack)
2271         return;
2272
2273     // 4.8.10.12.3 Sourcing out-of-band text tracks
2274     // When a track element's parent element changes and the old parent was a media element, 
2275     // then the user agent must remove the track element's corresponding text track from the 
2276     // media element's list of text tracks.
2277     m_textTracks->remove(textTrack.get());
2278     size_t index = m_textTracksWhenResourceSelectionBegan.find(textTrack.get());
2279     if (index != notFound)
2280         m_textTracksWhenResourceSelectionBegan.remove(index);
2281 }
2282
2283 bool HTMLMediaElement::userIsInterestedInThisLanguage(const String&) const
2284 {
2285     // FIXME: check the user's language preference - bugs.webkit.org/show_bug.cgi?id=74121
2286     return true;
2287 }
2288
2289 bool HTMLMediaElement::userIsInterestedInThisTrack(HTMLTrackElement* trackElement) const
2290 {
2291     RefPtr<TextTrack> textTrack = trackElement->track();
2292     if (!textTrack)
2293         return false;
2294
2295     String kind = textTrack->kind();
2296     if (!TextTrack::isValidKindKeyword(kind))
2297         return false;
2298
2299     // If ... the user has indicated an interest in having a track with this text track kind, text track language, ... 
2300     Settings* settings = document()->settings();
2301     if (!settings)
2302         return false;
2303
2304     if (kind == TextTrack::subtitlesKeyword() || kind == TextTrack::captionsKeyword()) {
2305         if (kind == TextTrack::subtitlesKeyword() && !settings->shouldDisplaySubtitles())
2306             return false;
2307         if (kind == TextTrack::captionsKeyword() && !settings->shouldDisplayCaptions())
2308             return false;
2309         return userIsInterestedInThisLanguage(trackElement->srclang());
2310     }
2311
2312     if (kind == TextTrack::descriptionsKeyword()) {
2313         if (!settings->shouldDisplayTextDescriptions())
2314             return false;
2315         return userIsInterestedInThisLanguage(trackElement->srclang());
2316     }
2317     
2318     return false;
2319 }
2320
2321 void HTMLMediaElement::configureTextTrack(HTMLTrackElement* trackElement)
2322 {
2323 #if !LOG_DISABLED
2324     if (trackElement->hasTagName(trackTag)) {
2325         KURL url = trackElement->getNonEmptyURLAttribute(srcAttr);
2326         LOG(Media, "HTMLMediaElement::configureTextTrack - 'src' is %s", urlForLogging(url).utf8().data());
2327     }
2328 #endif
2329
2330     // 4.8.10.12.3 Sourcing out-of-band text tracks
2331     
2332     // When a text track corresponding to a track element is added to a media element's list of text tracks,
2333     // the user agent must set the text track mode appropriately, as determined by the following conditions:
2334     RefPtr<TextTrack> textTrack = trackElement->track();
2335     if (!textTrack)
2336         return;
2337     
2338     TextTrack::Mode mode = TextTrack::HIDDEN;
2339     HTMLTrackElement* trackElementCurrentlyShowing = showingTrackWithSameKind(trackElement);
2340     String kind = textTrack->kind();
2341     bool hideDefaultTrack = false;
2342
2343     if (userIsInterestedInThisTrack(trackElement)) {
2344         if (kind == TextTrack::subtitlesKeyword() || kind == TextTrack::captionsKeyword()) {
2345             // * If the text track kind is subtitles or captions and the user has indicated an interest in having a
2346             // track with this text track kind, text track language, and text track label enabled, and there is no
2347             // other text track in the media element's list of text tracks with a text track kind of either subtitles
2348             // or captions whose text track mode is showing
2349             hideDefaultTrack = trackElementCurrentlyShowing && trackElementCurrentlyShowing->track()->showingByDefault();
2350             if (!trackElementCurrentlyShowing || hideDefaultTrack) {
2351                 //    Let the text track mode be showing.
2352                 //    If there is a text track in the media element's list of text tracks whose text track mode is showing 
2353                 //    by default, the user agent must furthermore change that text track's text track mode to hidden.
2354                 mode = TextTrack::SHOWING;
2355             }
2356         } else if (kind == TextTrack::descriptionsKeyword()) {
2357             // * If the text track kind is descriptions and the user has indicated an interest in having text 
2358             // descriptions with this text track language and text track label enabled, and there is no other text 
2359             // track in the media element's list of text tracks with a text track kind of descriptions whose text 
2360             // track mode is showing
2361             hideDefaultTrack = trackElementCurrentlyShowing && trackElementCurrentlyShowing->track()->showingByDefault();
2362             if (!trackElementCurrentlyShowing || hideDefaultTrack) {
2363                 //    Let the text track mode be showing.
2364                 //    If there is a text track in the media element's list of text tracks whose text track mode is showing 
2365                 //    by default, the user agent must furthermore change that text track's text track mode to hidden.
2366                 mode = TextTrack::SHOWING;
2367             }
2368         } else if (kind == TextTrack::chaptersKeyword()) {
2369             // * If the text track kind is chapters and the text track language is one that the user agent has reason
2370             // to believe is appropriate for the user, and there is no other text track in the media element's list of
2371             // text tracks with a text track kind of chapters whose text track mode is showing
2372             //    Let the text track mode be showing.
2373             if (!trackElementCurrentlyShowing)
2374                 mode = TextTrack::SHOWING;
2375         }
2376     } else if (!trackElementCurrentlyShowing && trackElement->isDefault()) {
2377         // * If the track element has a default attribute specified, and there is no other text track in the media
2378         // element's list of text tracks whose text track mode is showing or showing by default
2379         //    Let the text track mode be showing by default.
2380         mode = TextTrack::SHOWING;
2381         textTrack->setShowingByDefault(false);
2382     } else {
2383         // Otherwise
2384         //    Let the text track mode be disabled.
2385         mode = TextTrack::DISABLED;
2386     }
2387
2388     ExceptionCode unusedException;
2389     if (hideDefaultTrack) {
2390         trackElementCurrentlyShowing->track()->setMode(TextTrack::HIDDEN, unusedException);
2391         trackElementCurrentlyShowing->track()->setShowingByDefault(false);
2392     }
2393
2394     textTrack->setMode(mode, unusedException);
2395 }
2396  
2397 void HTMLMediaElement::configureTextTracks()
2398 {
2399     for (Node* node = firstChild(); node; node = node->nextSibling()) {
2400         if (!node->hasTagName(trackTag))
2401             continue;
2402         HTMLTrackElement* trackElement = static_cast<HTMLTrackElement*>(node);
2403         
2404         // Only call configureTextTrack once per track so that adding another track after
2405         // the initial configuration doesn't reconfigure every track, only those that should
2406         // be changed by the new addition. For example all metadata tracks are disabled by 
2407         // default, and we don't want a track that has been enabled by script to be disabled
2408         // automatically when a new track element is added later.
2409         if (!trackElement->hasBeenConfigured())
2410             configureTextTrack(trackElement);
2411     }
2412 }
2413
2414 #endif
2415
2416 bool HTMLMediaElement::havePotentialSourceChild()
2417 {
2418     // Stash the current <source> node and next nodes so we can restore them after checking
2419     // to see there is another potential.
2420     HTMLSourceElement* currentSourceNode = m_currentSourceNode;
2421     Node* nextNode = m_nextChildNodeToConsider;
2422
2423     KURL nextURL = selectNextSourceChild(0, DoNothing);
2424
2425     m_currentSourceNode = currentSourceNode;
2426     m_nextChildNodeToConsider = nextNode;
2427
2428     return nextURL.isValid();
2429 }
2430
2431 KURL HTMLMediaElement::selectNextSourceChild(ContentType *contentType, InvalidURLAction actionIfInvalid)
2432 {
2433 #if !LOG_DISABLED
2434     // Don't log if this was just called to find out if there are any valid <source> elements.
2435     bool shouldLog = actionIfInvalid != DoNothing;
2436     if (shouldLog)
2437         LOG(Media, "HTMLMediaElement::selectNextSourceChild");
2438 #endif
2439
2440     if (m_nextChildNodeToConsider == sourceChildEndOfListValue()) {
2441 #if !LOG_DISABLED
2442         if (shouldLog)
2443             LOG(Media, "HTMLMediaElement::selectNextSourceChild -> 0x0000, \"\"");
2444 #endif
2445         return KURL();
2446     }
2447
2448     KURL mediaURL;
2449     Node* node;
2450     HTMLSourceElement* source = 0;
2451     bool lookingForStartNode = m_nextChildNodeToConsider;
2452     bool canUse = false;
2453
2454     for (node = firstChild(); !canUse && node; node = node->nextSibling()) {
2455         if (lookingForStartNode && m_nextChildNodeToConsider != node)
2456             continue;
2457         lookingForStartNode = false;
2458         
2459         if (!node->hasTagName(sourceTag))
2460             continue;
2461
2462         source = static_cast<HTMLSourceElement*>(node);
2463
2464         // 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
2465         mediaURL = source->getNonEmptyURLAttribute(srcAttr);
2466 #if !LOG_DISABLED
2467         if (shouldLog)
2468             LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'src' is %s", urlForLogging(mediaURL).utf8().data());
2469 #endif
2470         if (mediaURL.isEmpty())
2471             goto check_again;
2472         
2473         if (source->fastHasAttribute(mediaAttr)) {
2474             MediaQueryEvaluator screenEval("screen", document()->frame(), renderer() ? renderer()->style() : 0);
2475             RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(source->media());
2476 #if !LOG_DISABLED
2477             if (shouldLog)
2478                 LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'media' is %s", source->media().utf8().data());
2479 #endif
2480             if (!screenEval.eval(media.get())) 
2481                 goto check_again;
2482         }
2483
2484         if (source->fastHasAttribute(typeAttr)) {
2485 #if !LOG_DISABLED
2486             if (shouldLog)
2487                 LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'type' is %s", source->type().utf8().data());
2488 #endif
2489             if (!MediaPlayer::supportsType(ContentType(source->type())))
2490                 goto check_again;
2491         }
2492
2493         // Is it safe to load this url?
2494         if (!isSafeToLoadURL(mediaURL, actionIfInvalid) || !dispatchBeforeLoadEvent(mediaURL.string()))
2495             goto check_again;
2496
2497         // Making it this far means the <source> looks reasonable.
2498         canUse = true;
2499
2500 check_again:
2501         if (!canUse && actionIfInvalid == Complain)
2502             source->scheduleErrorEvent();
2503     }
2504
2505     if (canUse) {
2506         if (contentType)
2507             *contentType = ContentType(source->type());
2508         m_currentSourceNode = source;
2509         m_nextChildNodeToConsider = source->nextSibling();
2510         if (!m_nextChildNodeToConsider)
2511             m_nextChildNodeToConsider = sourceChildEndOfListValue();
2512     } else {
2513         m_currentSourceNode = 0;
2514         m_nextChildNodeToConsider = sourceChildEndOfListValue();
2515     }
2516
2517 #if !LOG_DISABLED
2518     if (shouldLog)
2519         LOG(Media, "HTMLMediaElement::selectNextSourceChild -> %p, %s", m_currentSourceNode, canUse ? urlForLogging(mediaURL).utf8().data() : "");
2520 #endif
2521     return canUse ? mediaURL : KURL();
2522 }
2523
2524 void HTMLMediaElement::sourceWasAdded(HTMLSourceElement* source)
2525 {
2526     LOG(Media, "HTMLMediaElement::sourceWasAdded(%p)", source);
2527
2528 #if !LOG_DISABLED
2529     if (source->hasTagName(sourceTag)) {
2530         KURL url = source->getNonEmptyURLAttribute(srcAttr);
2531         LOG(Media, "HTMLMediaElement::sourceWasAdded - 'src' is %s", urlForLogging(url).utf8().data());
2532     }
2533 #endif
2534     
2535     // We should only consider a <source> element when there is not src attribute at all.
2536     if (fastHasAttribute(srcAttr))
2537         return;
2538
2539     // 4.8.8 - If a source element is inserted as a child of a media element that has no src 
2540     // attribute and whose networkState has the value NETWORK_EMPTY, the user agent must invoke 
2541     // the media element's resource selection algorithm.
2542     if (networkState() == HTMLMediaElement::NETWORK_EMPTY) {
2543         scheduleLoad(MediaResource);
2544         return;
2545     }
2546
2547     if (m_currentSourceNode && source == m_currentSourceNode->nextSibling()) {
2548         LOG(Media, "HTMLMediaElement::sourceWasAdded - <source> inserted immediately after current source");
2549         m_nextChildNodeToConsider = source;
2550         return;
2551     }
2552
2553     if (m_nextChildNodeToConsider != sourceChildEndOfListValue())
2554         return;
2555     
2556     // 4.8.9.5, resource selection algorithm, source elements section:
2557     // 20 - Wait until the node after pointer is a node other than the end of the list. (This step might wait forever.)
2558     // 21 - Asynchronously await a stable state...
2559     // 22 - Set the element's delaying-the-load-event flag back to true (this delays the load event again, in case 
2560     // it hasn't been fired yet).
2561     setShouldDelayLoadEvent(true);
2562
2563     // 23 - Set the networkState back to NETWORK_LOADING.
2564     m_networkState = NETWORK_LOADING;
2565     
2566     // 24 - Jump back to the find next candidate step above.
2567     m_nextChildNodeToConsider = source;
2568     scheduleNextSourceChild();
2569 }
2570
2571 void HTMLMediaElement::sourceWillBeRemoved(HTMLSourceElement* source)
2572 {
2573     LOG(Media, "HTMLMediaElement::sourceWillBeRemoved(%p)", source);
2574
2575 #if !LOG_DISABLED
2576     if (source->hasTagName(sourceTag)) {
2577         KURL url = source->getNonEmptyURLAttribute(srcAttr);
2578         LOG(Media, "HTMLMediaElement::sourceWillBeRemoved - 'src' is %s", urlForLogging(url).utf8().data());
2579     }
2580 #endif
2581
2582     if (source != m_currentSourceNode && source != m_nextChildNodeToConsider)
2583         return;
2584
2585     if (source == m_nextChildNodeToConsider) {
2586         m_nextChildNodeToConsider = m_nextChildNodeToConsider->nextSibling();
2587         if (!m_nextChildNodeToConsider)
2588             m_nextChildNodeToConsider = sourceChildEndOfListValue();
2589         LOG(Media, "HTMLMediaElement::sourceRemoved - m_nextChildNodeToConsider set to %p", m_nextChildNodeToConsider);
2590     } else if (source == m_currentSourceNode) {
2591         // Clear the current source node pointer, but don't change the movie as the spec says:
2592         // 4.8.8 - Dynamically modifying a source element and its attribute when the element is already 
2593         // inserted in a video or audio element will have no effect.
2594         m_currentSourceNode = 0;
2595         LOG(Media, "HTMLMediaElement::sourceRemoved - m_currentSourceNode set to 0");
2596     }
2597 }
2598
2599 void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
2600 {
2601     LOG(Media, "HTMLMediaElement::mediaPlayerTimeChanged");
2602
2603     beginProcessingMediaPlayerCallback();
2604
2605     invalidateCachedTime();
2606
2607     // 4.8.10.9 step 14 & 15.  Needed if no ReadyState change is associated with the seek.
2608     if (m_seeking && m_readyState >= HAVE_CURRENT_DATA)
2609         finishSeek();
2610     
2611     // Always call scheduleTimeupdateEvent when the media engine reports a time discontinuity, 
2612     // it will only queue a 'timeupdate' event if we haven't already posted one at the current
2613     // movie time.
2614     scheduleTimeupdateEvent(false);
2615
2616     float now = currentTime();
2617     float dur = duration();
2618     
2619     // When the current playback position reaches the end of the media resource when the direction of
2620     // playback is forwards, then the user agent must follow these steps:
2621     if (!isnan(dur) && dur && now >= dur && m_playbackRate > 0) {
2622         // If the media element has a loop attribute specified and does not have a current media controller,
2623         if (loop() && !m_mediaController) {
2624             ExceptionCode ignoredException;
2625             m_sentEndEvent = false;
2626             //  then seek to the earliest possible position of the media resource and abort these steps.
2627             seek(startTime(), ignoredException);
2628         } else {
2629             // If the media element does not have a current media controller, and the media element
2630             // has still ended playback, and the direction of playback is still forwards, and paused
2631             // is false,
2632             if (!m_mediaController && !m_paused) {
2633                 // changes paused to true and fires a simple event named pause at the media element.
2634                 m_paused = true;
2635                 scheduleEvent(eventNames().pauseEvent);
2636             }
2637             // Queue a task to fire a simple event named ended at the media element.
2638             if (!m_sentEndEvent) {
2639                 m_sentEndEvent = true;
2640                 scheduleEvent(eventNames().endedEvent);
2641             }
2642             // If the media element has a current media controller, then report the controller state
2643             // for the media element's current media controller.
2644             updateMediaController();
2645         }
2646     }
2647     else
2648         m_sentEndEvent = false;
2649
2650     updatePlayState();
2651 #if ENABLE(VIDEO_TRACK)
2652     updateActiveTextTrackCues(now);
2653 #endif
2654     endProcessingMediaPlayerCallback();
2655 }
2656
2657 void HTMLMediaElement::mediaPlayerVolumeChanged(MediaPlayer*)
2658 {
2659     LOG(Media, "HTMLMediaElement::mediaPlayerVolumeChanged");
2660
2661     beginProcessingMediaPlayerCallback();
2662     if (m_player) {
2663         float vol = m_player->volume();
2664         if (vol != m_volume) {
2665             m_volume = vol;
2666             updateVolume();
2667             scheduleEvent(eventNames().volumechangeEvent);
2668         }
2669     }
2670     endProcessingMediaPlayerCallback();
2671 }
2672
2673 void HTMLMediaElement::mediaPlayerMuteChanged(MediaPlayer*)
2674 {
2675     LOG(Media, "HTMLMediaElement::mediaPlayerMuteChanged");
2676
2677     beginProcessingMediaPlayerCallback();
2678     if (m_player)
2679         setMuted(m_player->muted());
2680     endProcessingMediaPlayerCallback();
2681 }
2682
2683 void HTMLMediaElement::mediaPlayerDurationChanged(MediaPlayer* player)
2684 {
2685     LOG(Media, "HTMLMediaElement::mediaPlayerDurationChanged");
2686
2687     beginProcessingMediaPlayerCallback();
2688     scheduleEvent(eventNames().durationchangeEvent);
2689     mediaPlayerCharacteristicChanged(player);
2690     endProcessingMediaPlayerCallback();
2691 }
2692
2693 void HTMLMediaElement::mediaPlayerRateChanged(MediaPlayer*)
2694 {
2695     LOG(Media, "HTMLMediaElement::mediaPlayerRateChanged");
2696
2697     beginProcessingMediaPlayerCallback();
2698
2699     // Stash the rate in case the one we tried to set isn't what the engine is
2700     // using (eg. it can't handle the rate we set)
2701     m_playbackRate = m_player->rate();
2702     if (m_playing)
2703         invalidateCachedTime();
2704
2705 #if PLATFORM(MAC)
2706     if (m_player->paused() && m_sleepDisabler)
2707         m_sleepDisabler = nullptr;
2708     else if (!m_player->paused() && !m_sleepDisabler)
2709         m_sleepDisabler = DisplaySleepDisabler::create("com.apple.WebCore: HTMLMediaElement playback");
2710 #endif
2711
2712     endProcessingMediaPlayerCallback();
2713 }
2714
2715 void HTMLMediaElement::mediaPlayerPlaybackStateChanged(MediaPlayer*)
2716 {
2717     LOG(Media, "HTMLMediaElement::mediaPlayerPlaybackStateChanged");
2718
2719     if (!m_player || m_pausedInternal)
2720         return;
2721
2722     beginProcessingMediaPlayerCallback();
2723     if (m_player->paused())
2724         pauseInternal();
2725     else
2726         playInternal();
2727     endProcessingMediaPlayerCallback();
2728 }
2729
2730 void HTMLMediaElement::mediaPlayerSawUnsupportedTracks(MediaPlayer*)
2731 {
2732     LOG(Media, "HTMLMediaElement::mediaPlayerSawUnsupportedTracks");
2733
2734     // The MediaPlayer came across content it cannot completely handle.
2735     // This is normally acceptable except when we are in a standalone
2736     // MediaDocument. If so, tell the document what has happened.
2737     if (ownerDocument()->isMediaDocument()) {
2738         MediaDocument* mediaDocument = static_cast<MediaDocument*>(ownerDocument());
2739         mediaDocument->mediaElementSawUnsupportedTracks();
2740     }
2741 }
2742
2743 // MediaPlayerPresentation methods
2744 void HTMLMediaElement::mediaPlayerRepaint(MediaPlayer*)
2745 {
2746     beginProcessingMediaPlayerCallback();
2747     updateDisplayState();
2748     if (renderer())
2749         renderer()->repaint();
2750     endProcessingMediaPlayerCallback();
2751 }
2752
2753 void HTMLMediaElement::mediaPlayerSizeChanged(MediaPlayer*)
2754 {
2755     LOG(Media, "HTMLMediaElement::mediaPlayerSizeChanged");
2756
2757     beginProcessingMediaPlayerCallback();
2758     if (renderer())
2759         renderer()->updateFromElement();
2760     endProcessingMediaPlayerCallback();
2761 }
2762
2763 #if USE(ACCELERATED_COMPOSITING)
2764 bool HTMLMediaElement::mediaPlayerRenderingCanBeAccelerated(MediaPlayer*)
2765 {
2766     if (renderer() && renderer()->isVideo()) {
2767         ASSERT(renderer()->view());
2768         return renderer()->view()->compositor()->canAccelerateVideoRendering(toRenderVideo(renderer()));
2769     }
2770     return false;
2771 }
2772
2773 void HTMLMediaElement::mediaPlayerRenderingModeChanged(MediaPlayer*)
2774 {
2775     LOG(Media, "HTMLMediaElement::mediaPlayerRenderingModeChanged");
2776
2777     // Kick off a fake recalcStyle that will update the compositing tree.
2778     setNeedsStyleRecalc(SyntheticStyleChange);
2779 }
2780 #endif
2781
2782 void HTMLMediaElement::mediaPlayerEngineUpdated(MediaPlayer*)
2783 {
2784     LOG(Media, "HTMLMediaElement::mediaPlayerEngineUpdated");
2785     beginProcessingMediaPlayerCallback();
2786     if (renderer())
2787         renderer()->updateFromElement();
2788     endProcessingMediaPlayerCallback();
2789 }
2790
2791 void HTMLMediaElement::mediaPlayerFirstVideoFrameAvailable(MediaPlayer*)
2792 {
2793     LOG(Media, "HTMLMediaElement::mediaPlayerFirstVideoFrameAvailable");
2794     beginProcessingMediaPlayerCallback();
2795     if (displayMode() == PosterWaitingForVideo) {
2796         setDisplayMode(Video);
2797 #if USE(ACCELERATED_COMPOSITING)
2798         mediaPlayerRenderingModeChanged(m_player.get());
2799 #endif
2800     }
2801     endProcessingMediaPlayerCallback();
2802 }
2803
2804 void HTMLMediaElement::mediaPlayerCharacteristicChanged(MediaPlayer*)
2805 {
2806     LOG(Media, "HTMLMediaElement::mediaPlayerCharacteristicChanged");
2807     
2808     beginProcessingMediaPlayerCallback();
2809     if (hasMediaControls())
2810         mediaControls()->reset();
2811     if (renderer())
2812         renderer()->updateFromElement();
2813     endProcessingMediaPlayerCallback();
2814 }
2815
2816 PassRefPtr<TimeRanges> HTMLMediaElement::buffered() const
2817 {
2818     if (!m_player)
2819         return TimeRanges::create();
2820     return m_player->buffered();
2821 }
2822
2823 PassRefPtr<TimeRanges> HTMLMediaElement::played()
2824 {
2825     if (m_playing) {
2826         float time = currentTime();
2827         if (time > m_lastSeekTime)
2828             addPlayedRange(m_lastSeekTime, time);
2829     }
2830
2831     if (!m_playedTimeRanges)
2832         m_playedTimeRanges = TimeRanges::create();
2833
2834     return m_playedTimeRanges->copy();
2835 }
2836
2837 PassRefPtr<TimeRanges> HTMLMediaElement::seekable() const
2838 {
2839     return m_player ? m_player->seekable() : TimeRanges::create();
2840 }
2841
2842 bool HTMLMediaElement::potentiallyPlaying() const
2843 {
2844     // "pausedToBuffer" means the media engine's rate is 0, but only because it had to stop playing
2845     // when it ran out of buffered data. A movie is this state is "potentially playing", modulo the
2846     // checks in couldPlayIfEnoughData().
2847     bool pausedToBuffer = m_readyStateMaximum >= HAVE_FUTURE_DATA && m_readyState < HAVE_FUTURE_DATA;
2848     return (pausedToBuffer || m_readyState >= HAVE_FUTURE_DATA) && couldPlayIfEnoughData() && !isBlockedOnMediaController();
2849 }
2850
2851 bool HTMLMediaElement::couldPlayIfEnoughData() const
2852 {
2853     return !paused() && !endedPlayback() && !stoppedDueToErrors() && !pausedForUserInteraction();
2854 }
2855
2856 bool HTMLMediaElement::endedPlayback() const
2857 {
2858     float dur = duration();
2859     if (!m_player || isnan(dur))
2860         return false;
2861
2862     // 4.8.10.8 Playing the media resource
2863
2864     // A media element is said to have ended playback when the element's 
2865     // readyState attribute is HAVE_METADATA or greater, 
2866     if (m_readyState < HAVE_METADATA)
2867         return false;
2868
2869     // and the current playback position is the end of the media resource and the direction
2870     // of playback is forwards, Either the media element does not have a loop attribute specified,
2871     // or the media element has a current media controller.
2872     float now = currentTime();
2873     if (m_playbackRate > 0)
2874         return dur > 0 && now >= dur && (!loop() || m_mediaController);
2875
2876     // or the current playback position is the earliest possible position and the direction 
2877     // of playback is backwards
2878     if (m_playbackRate < 0)
2879         return now <= 0;
2880
2881     return false;
2882 }
2883
2884 bool HTMLMediaElement::stoppedDueToErrors() const
2885 {
2886     if (m_readyState >= HAVE_METADATA && m_error) {
2887         RefPtr<TimeRanges> seekableRanges = seekable();
2888         if (!seekableRanges->contain(currentTime()))
2889             return true;
2890     }
2891     
2892     return false;
2893 }
2894
2895 bool HTMLMediaElement::pausedForUserInteraction() const
2896 {
2897 //    return !paused() && m_readyState >= HAVE_FUTURE_DATA && [UA requires a decitions from the user]
2898     return false;
2899 }
2900
2901 float HTMLMediaElement::minTimeSeekable() const
2902 {
2903     return 0;
2904 }
2905
2906 float HTMLMediaElement::maxTimeSeekable() const
2907 {
2908     return m_player ? m_player->maxTimeSeekable() : 0;
2909 }
2910     
2911 void HTMLMediaElement::updateVolume()
2912 {
2913     if (!m_player)
2914         return;
2915
2916     // Avoid recursion when the player reports volume changes.
2917     if (!processingMediaPlayerCallback()) {
2918         Page* page = document()->page();
2919         float volumeMultiplier = page ? page->mediaVolume() : 1;
2920         bool shouldMute = m_muted;
2921
2922         if (m_mediaController) {
2923             volumeMultiplier *= m_mediaController->volume();
2924             shouldMute = m_mediaController->muted();
2925         }
2926
2927         m_player->setMuted(shouldMute);
2928         m_player->setVolume(m_volume * volumeMultiplier);
2929     }
2930
2931     if (hasMediaControls())
2932         mediaControls()->changedVolume();
2933 }
2934
2935 void HTMLMediaElement::updatePlayState()
2936 {
2937     if (!m_player)
2938         return;
2939
2940     if (m_pausedInternal) {
2941         if (!m_player->paused())
2942             m_player->pause();
2943         refreshCachedTime();
2944         m_playbackProgressTimer.stop();
2945         if (hasMediaControls())
2946             mediaControls()->playbackStopped();
2947         return;
2948     }
2949     
2950     bool shouldBePlaying = potentiallyPlaying();
2951     bool playerPaused = m_player->paused();
2952
2953     LOG(Media, "HTMLMediaElement::updatePlayState - shouldBePlaying = %s, playerPaused = %s", 
2954         boolString(shouldBePlaying), boolString(playerPaused));
2955
2956     if (shouldBePlaying) {
2957         setDisplayMode(Video);
2958         invalidateCachedTime();
2959
2960         if (playerPaused) {
2961             if (!m_isFullscreen && isVideo() && document() && document()->page() && document()->page()->chrome()->requiresFullscreenForVideoPlayback())
2962                 enterFullscreen();
2963
2964             // Set rate, muted before calling play in case they were set before the media engine was setup.
2965             // The media engine should just stash the rate and muted values since it isn't already playing.
2966             m_player->setRate(m_playbackRate);
2967             m_player->setMuted(m_muted);
2968
2969             m_player->play();
2970         }
2971
2972         if (hasMediaControls())
2973             mediaControls()->playbackStarted();
2974         startPlaybackProgressTimer();
2975         m_playing = true;
2976
2977     } else { // Should not be playing right now
2978         if (!playerPaused)
2979             m_player->pause();
2980         refreshCachedTime();
2981
2982         m_playbackProgressTimer.stop();
2983         m_playing = false;
2984         float time = currentTime();
2985         if (time > m_lastSeekTime)
2986             addPlayedRange(m_lastSeekTime, time);
2987
2988         if (couldPlayIfEnoughData())
2989             prepareToPlay();
2990
2991         if (hasMediaControls())
2992             mediaControls()->playbackStopped();
2993     }
2994
2995     updateMediaController();
2996
2997     if (renderer())
2998         renderer()->updateFromElement();
2999 }
3000
3001 void HTMLMediaElement::setPausedInternal(bool b)
3002 {
3003     m_pausedInternal = b;
3004     updatePlayState();
3005 }
3006
3007 void HTMLMediaElement::stopPeriodicTimers()
3008 {
3009     m_progressEventTimer.stop();
3010     m_playbackProgressTimer.stop();
3011 }
3012
3013 void HTMLMediaElement::userCancelledLoad()
3014 {
3015     LOG(Media, "HTMLMediaElement::userCancelledLoad");
3016
3017     if (m_networkState == NETWORK_EMPTY || m_completelyLoaded)
3018         return;
3019
3020     // If the media data fetching process is aborted by the user:
3021
3022     // 1 - The user agent should cancel the fetching process.
3023 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
3024     m_player.clear();
3025 #endif
3026     stopPeriodicTimers();
3027     m_loadTimer.stop();
3028     m_loadState = WaitingForSource;
3029
3030     // 2 - Set the error attribute to a new MediaError object whose code attribute is set to MEDIA_ERR_ABORTED.
3031     m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
3032
3033     // 3 - Queue a task to fire a simple event named error at the media element.
3034     scheduleEvent(eventNames().abortEvent);
3035
3036 #if ENABLE(MEDIA_SOURCE)
3037     if (m_sourceState != SOURCE_CLOSED)
3038         setSourceState(SOURCE_CLOSED);
3039 #endif
3040
3041     // 4 - If the media element's readyState attribute has a value equal to HAVE_NOTHING, set the 
3042     // element's networkState attribute to the NETWORK_EMPTY value and queue a task to fire a 
3043     // simple event named emptied at the element. Otherwise, set the element's networkState 
3044     // attribute to the NETWORK_IDLE value.
3045     if (m_readyState == HAVE_NOTHING) {
3046         m_networkState = NETWORK_EMPTY;
3047         scheduleEvent(eventNames().emptiedEvent);
3048     }
3049     else
3050         m_networkState = NETWORK_IDLE;
3051
3052     // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
3053     setShouldDelayLoadEvent(false);
3054
3055     // 6 - Abort the overall resource selection algorithm.
3056     m_currentSourceNode = 0;
3057
3058     // Reset m_readyState since m_player is gone.
3059     m_readyState = HAVE_NOTHING;
3060     updateMediaController();
3061 }
3062
3063 bool HTMLMediaElement::canSuspend() const
3064 {
3065     return true; 
3066 }
3067
3068 void HTMLMediaElement::stop()
3069 {
3070     LOG(Media, "HTMLMediaElement::stop");
3071     if (m_isFullscreen)
3072         exitFullscreen();
3073     
3074     m_inActiveDocument = false;
3075     userCancelledLoad();
3076     
3077     // Stop the playback without generating events
3078     setPausedInternal(true);
3079     
3080     if (renderer())
3081         renderer()->updateFromElement();
3082     
3083     stopPeriodicTimers();
3084     cancelPendingEventsAndCallbacks();
3085 }
3086
3087 void HTMLMediaElement::suspend(ReasonForSuspension why)
3088 {
3089     LOG(Media, "HTMLMediaElement::suspend");
3090     
3091     switch (why)
3092     {
3093         case DocumentWillBecomeInactive:
3094             stop();
3095             break;
3096         case JavaScriptDebuggerPaused:
3097         case WillShowDialog:
3098             // Do nothing, we don't pause media playback in these cases.
3099             break;
3100     }
3101 }
3102
3103 void HTMLMediaElement::resume()
3104 {
3105     LOG(Media, "HTMLMediaElement::resume");
3106
3107     m_inActiveDocument = true;
3108     setPausedInternal(false);
3109
3110     if (m_error && m_error->code() == MediaError::MEDIA_ERR_ABORTED) {
3111         // Restart the load if it was aborted in the middle by moving the document to the page cache.
3112         // m_error is only left at MEDIA_ERR_ABORTED when the document becomes inactive (it is set to
3113         //  MEDIA_ERR_ABORTED while the abortEvent is being sent, but cleared immediately afterwards).
3114         // This behavior is not specified but it seems like a sensible thing to do.
3115         ExceptionCode ec;
3116         load(ec);
3117     }
3118
3119     if (renderer())
3120         renderer()->updateFromElement();
3121 }
3122
3123 bool HTMLMediaElement::hasPendingActivity() const
3124 {
3125     // Return true when we have pending events so we can't fire events after the JS 
3126     // object gets collected.
3127     bool pending = m_pendingEvents.size();
3128     LOG(Media, "HTMLMediaElement::hasPendingActivity -> %s", boolString(pending));
3129     return pending;
3130 }
3131
3132 void HTMLMediaElement::mediaVolumeDidChange()
3133 {
3134     LOG(Media, "HTMLMediaElement::mediaVolumeDidChange");
3135     updateVolume();
3136 }
3137
3138 void HTMLMediaElement::defaultEventHandler(Event* event)
3139 {
3140 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
3141     RenderObject* r = renderer();
3142     if (!r || !r->isWidget())
3143         return;
3144
3145     Widget* widget = toRenderWidget(r)->widget();
3146     if (widget)
3147         widget->handleEvent(event);
3148 #else
3149     HTMLElement::defaultEventHandler(event);
3150 #endif
3151 }
3152
3153 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
3154
3155 void HTMLMediaElement::ensureMediaPlayer()
3156 {
3157     if (!m_player)
3158         createMediaPlayer();
3159 }
3160
3161 void HTMLMediaElement::deliverNotification(MediaPlayerProxyNotificationType notification)
3162 {
3163     if (notification == MediaPlayerNotificationPlayPauseButtonPressed) {
3164         togglePlayState();
3165         return;
3166     }
3167
3168     if (m_player)
3169         m_player->deliverNotification(notification);
3170 }
3171
3172 void HTMLMediaElement::setMediaPlayerProxy(WebMediaPlayerProxy* proxy)
3173 {
3174     ensureMediaPlayer();
3175     m_player->setMediaPlayerProxy(proxy);
3176 }
3177
3178 void HTMLMediaElement::getPluginProxyParams(KURL& url, Vector<String>& names, Vector<String>& values)
3179 {
3180     Frame* frame = document()->frame();
3181
3182     if (isVideo()) {
3183         KURL posterURL = getNonEmptyURLAttribute(posterAttr);
3184         if (!posterURL.isEmpty() && frame && frame->loader()->willLoadMediaElementURL(posterURL)) {
3185             names.append("_media_element_poster_");
3186             values.append(posterURL.string());
3187         }
3188     }
3189
3190     if (controls()) {
3191         names.append("_media_element_controls_");
3192         values.append("true");
3193     }
3194
3195     url = src();
3196     if (!isSafeToLoadURL(url, Complain))
3197         url = selectNextSourceChild(0, DoNothing);
3198
3199     m_currentSrc = url;
3200     if (url.isValid() && frame && frame->loader()->willLoadMediaElementURL(url)) {
3201         names.append("_media_element_src_");
3202         values.append(m_currentSrc.string());
3203     }
3204 }
3205
3206 void HTMLMediaElement::createMediaPlayerProxy()
3207 {
3208     ensureMediaPlayer();
3209
3210     if (m_proxyWidget || (inDocument() && !m_needWidgetUpdate))
3211         return;
3212
3213     Frame* frame = document()->frame();
3214     if (!frame)
3215         return;
3216
3217     LOG(Media, "HTMLMediaElement::createMediaPlayerProxy");
3218
3219     KURL url;
3220     Vector<String> paramNames;
3221     Vector<String> paramValues;
3222
3223     getPluginProxyParams(url, paramNames, paramValues);
3224     
3225     // Hang onto the proxy widget so it won't be destroyed if the plug-in is set to
3226     // display:none
3227     m_proxyWidget = frame->loader()->subframeLoader()->loadMediaPlayerProxyPlugin(this, url, paramNames, paramValues);
3228     if (m_proxyWidget)
3229         m_needWidgetUpdate = false;
3230 }
3231
3232 void HTMLMediaElement::updateWidget(PluginCreationOption)
3233 {
3234     mediaElement->setNeedWidgetUpdate(false);
3235
3236     Vector<String> paramNames;
3237     Vector<String> paramValues;
3238     // FIXME: Rename kurl to something more sensible.
3239     KURL kurl;
3240
3241     mediaElement->getPluginProxyParams(kurl, paramNames, paramValues);
3242     // FIXME: What if document()->frame() is 0?
3243     SubframeLoader* loader = document()->frame()->loader()->subframeLoader();
3244     loader->loadMediaPlayerProxyPlugin(mediaElement, kurl, paramNames, paramValues);
3245 }
3246
3247 #endif // ENABLE(PLUGIN_PROXY_FOR_VIDEO)
3248
3249 bool HTMLMediaElement::isFullscreen() const
3250 {
3251     if (m_isFullscreen)
3252         return true;
3253     
3254 #if ENABLE(FULLSCREEN_API)
3255     if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == this)
3256         return true;
3257 #endif
3258     
3259     return false;
3260 }
3261
3262 void HTMLMediaElement::enterFullscreen()
3263 {
3264     LOG(Media, "HTMLMediaElement::enterFullscreen");
3265
3266 #if ENABLE(FULLSCREEN_API)
3267     if (document() && document()->settings() && document()->settings()->fullScreenEnabled()) {
3268         document()->requestFullScreenForElement(this, 0, Document::ExemptIFrameAllowFulScreenRequirement);
3269         return;
3270     }
3271 #endif
3272     ASSERT(!m_isFullscreen);
3273     m_isFullscreen = true;
3274     if (hasMediaControls())
3275         mediaControls()->enteredFullscreen();
3276     if (document() && document()->page()) {
3277         document()->page()->chrome()->client()->enterFullscreenForNode(this);
3278         scheduleEvent(eventNames().webkitbeginfullscreenEvent);
3279     }
3280 }
3281
3282 void HTMLMediaElement::exitFullscreen()
3283 {
3284     LOG(Media, "HTMLMediaElement::exitFullscreen");
3285
3286 #if ENABLE(FULLSCREEN_API)
3287     if (document() && document()->settings() && document()->settings()->fullScreenEnabled()) {
3288         if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == this)
3289             document()->webkitCancelFullScreen();
3290         return;
3291     }
3292 #endif
3293     ASSERT(m_isFullscreen);
3294     m_isFullscreen = false;
3295     if (hasMediaControls())
3296         mediaControls()->exitedFullscreen();
3297     if (document() && document()->page()) {
3298         if (document()->page()->chrome()->requiresFullscreenForVideoPlayback())
3299             pauseInternal();
3300         document()->page()->chrome()->client()->exitFullscreenForNode(this);
3301         scheduleEvent(eventNames().webkitendfullscreenEvent);
3302     }
3303 }
3304
3305 void HTMLMediaElement::didBecomeFullscreenElement()
3306 {
3307     if (hasMediaControls())
3308         mediaControls()->enteredFullscreen();
3309 }
3310
3311 void HTMLMediaElement::willStopBeingFullscreenElement()
3312 {
3313     if (hasMediaControls())
3314         mediaControls()->exitedFullscreen();
3315 }
3316
3317 PlatformMedia HTMLMediaElement::platformMedia() const
3318 {
3319     return m_player ? m_player->platformMedia() : NoPlatformMedia;
3320 }
3321
3322 #if USE(ACCELERATED_COMPOSITING)
3323 PlatformLayer* HTMLMediaElement::platformLayer() const
3324 {
3325     return m_player ? m_player->platformLayer() : 0;
3326 }
3327 #endif
3328
3329 bool HTMLMediaElement::hasClosedCaptions() const
3330 {
3331     return m_player && m_player->hasClosedCaptions();
3332 }
3333
3334 bool HTMLMediaElement::closedCaptionsVisible() const
3335 {
3336     return m_closedCaptionsVisible;
3337 }
3338
3339 void HTMLMediaElement::setClosedCaptionsVisible(bool closedCaptionVisible)
3340 {
3341     LOG(Media, "HTMLMediaElement::setClosedCaptionsVisible(%s)", boolString(closedCaptionVisible));
3342
3343     if (!m_player ||!hasClosedCaptions())
3344         return;
3345
3346     m_closedCaptionsVisible = closedCaptionVisible;
3347     m_player->setClosedCaptionsVisible(closedCaptionVisible);
3348     if (hasMediaControls())
3349         mediaControls()->changedClosedCaptionsVisibility();
3350 }
3351
3352 void HTMLMediaElement::setWebkitClosedCaptionsVisible(bool visible)
3353 {
3354     setClosedCaptionsVisible(visible);
3355 }
3356
3357 bool HTMLMediaElement::webkitClosedCaptionsVisible() const
3358 {
3359     return closedCaptionsVisible();
3360 }
3361
3362
3363 bool HTMLMediaElement::webkitHasClosedCaptions() const
3364 {
3365     return hasClosedCaptions();
3366 }
3367
3368 #if ENABLE(MEDIA_STATISTICS)
3369 unsigned HTMLMediaElement::webkitAudioDecodedByteCount() const
3370 {
3371     if (!m_player)
3372         return 0;
3373     return m_player->audioDecodedByteCount();
3374 }
3375
3376 unsigned HTMLMediaElement::webkitVideoDecodedByteCount() const
3377 {
3378     if (!m_player)
3379         return 0;
3380     return m_player->videoDecodedByteCount();
3381 }
3382 #endif
3383
3384 void HTMLMediaElement::mediaCanStart()
3385 {
3386     LOG(Media, "HTMLMediaElement::mediaCanStart");
3387
3388     ASSERT(m_isWaitingUntilMediaCanStart);
3389     m_isWaitingUntilMediaCanStart = false;
3390     loadInternal();
3391 }
3392
3393 bool HTMLMediaElement::isURLAttribute(Attribute* attribute) const
3394 {
3395     return attribute->name() == srcAttr || HTMLElement::isURLAttribute(attribute);
3396 }
3397
3398 void HTMLMediaElement::setShouldDelayLoadEvent(bool shouldDelay)
3399 {
3400     if (m_shouldDelayLoadEvent == shouldDelay)
3401         return;
3402
3403     LOG(Media, "HTMLMediaElement::setShouldDelayLoadEvent(%s)", boolString(shouldDelay));
3404
3405     m_shouldDelayLoadEvent = shouldDelay;
3406     if (shouldDelay)
3407         document()->incrementLoadEventDelayCount();
3408     else
3409         document()->decrementLoadEventDelayCount();
3410 }
3411     
3412
3413 void HTMLMediaElement::getSitesInMediaCache(Vector<String>& sites)
3414 {
3415     MediaPlayer::getSitesInMediaCache(sites);
3416 }
3417
3418 void HTMLMediaElement::clearMediaCache()
3419 {
3420     MediaPlayer::clearMediaCache();
3421 }
3422
3423 void HTMLMediaElement::clearMediaCacheForSite(const String& site)
3424 {
3425     MediaPlayer::clearMediaCacheForSite(site);
3426 }
3427
3428 void HTMLMediaElement::privateBrowsingStateDidChange()
3429 {
3430     if (!m_player)
3431         return;
3432
3433     Settings* settings = document()->settings();
3434     bool privateMode = !settings || settings->privateBrowsingEnabled();
3435     LOG(Media, "HTMLMediaElement::privateBrowsingStateDidChange(%s)", boolString(privateMode));
3436     m_player->setPrivateBrowsingMode(privateMode);
3437 }
3438
3439 MediaControls* HTMLMediaElement::mediaControls()
3440 {
3441     return toMediaControls(shadowRoot()->firstChild());
3442 }
3443
3444 bool HTMLMediaElement::hasMediaControls()
3445 {
3446     if (!shadowRoot())
3447         return false;
3448
3449     Node* node = shadowRoot()->firstChild();
3450     return node && node->isMediaControls();
3451 }
3452
3453 bool HTMLMediaElement::createMediaControls()
3454 {
3455     if (hasMediaControls())
3456         return true;
3457
3458     ExceptionCode ec;
3459     RefPtr<MediaControls> controls = MediaControls::create(document());
3460     if (!controls)
3461         return false;
3462
3463     controls->setMediaController(m_mediaController ? m_mediaController.get() : static_cast<MediaControllerInterface*>(this));
3464     controls->reset();
3465
3466     ensureShadowRoot()->appendChild(controls, ec);
3467     return true;
3468 }
3469
3470 void HTMLMediaElement::configureMediaControls()
3471 {
3472 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
3473     if (!controls()) {
3474         if (hasMediaControls())
3475             mediaControls()->hide();
3476         return;
3477     }
3478
3479     if (!hasMediaControls() && !createMediaControls())
3480         return;
3481
3482     mediaControls()->show();
3483 #else
3484     if (m_player)
3485         m_player->setControls(controls());
3486 #endif
3487 }
3488
3489 #if ENABLE(VIDEO_TRACK)
3490 void HTMLMediaElement::configureTextTrackDisplay()
3491 {
3492     ASSERT(m_textTracks);
3493
3494     bool haveVisibleTextTrack = false;
3495     for (unsigned i = 0; i < m_textTracks->length(); ++i) {
3496         if (m_textTracks->item(i)->mode() == TextTrack::SHOWING) {
3497             haveVisibleTextTrack = true;
3498             break;
3499         }
3500     }
3501
3502     if (m_haveVisibleTextTrack == haveVisibleTextTrack)
3503         return;
3504     m_haveVisibleTextTrack = haveVisibleTextTrack;
3505
3506     if (!m_haveVisibleTextTrack) {
3507         if (hasMediaControls())
3508             mediaControls()->hideTextTrackDisplay();
3509         return;
3510     }
3511
3512     if (!hasMediaControls() && !createMediaControls())
3513         return;
3514     mediaControls()->showTextTrackDisplay();
3515 }
3516 #endif
3517
3518 void* HTMLMediaElement::preDispatchEventHandler(Event* event)
3519 {
3520     if (event && event->type() == eventNames().webkitfullscreenchangeEvent)
3521         configureMediaControls();
3522
3523     return 0;
3524 }
3525
3526 void HTMLMediaElement::createMediaPlayer()
3527 {
3528 #if ENABLE(WEB_AUDIO)
3529     if (m_audioSourceNode)
3530         m_audioSourceNode->lock();
3531 #endif
3532         
3533     m_player = MediaPlayer::create(this);
3534
3535 #if ENABLE(WEB_AUDIO)
3536     if (m_audioSourceNode) {
3537         // When creating the player, make sure its AudioSourceProvider knows about the MediaElementAudioSourceNode.
3538         if (audioSourceProvider())
3539             audioSourceProvider()->setClient(m_audioSourceNode);
3540
3541         m_audioSourceNode->unlock();
3542     }
3543 #endif
3544 }
3545
3546 #if ENABLE(WEB_AUDIO)
3547 void HTMLMediaElement::setAudioSourceNode(MediaElementAudioSourceNode* sourceNode)
3548 {
3549 &nb