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