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