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