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