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