63a8c974fc90f8f15e34ffe4602a49e0575377e4
[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 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
2142     if (m_player->currentTime() > 0.0f || m_cachedTime == MediaPlayer::invalidTime())
2143 #endif
2144     m_cachedTime = m_player->currentTime();
2145     m_cachedTimeWallClockUpdateTime = WTF::currentTime();
2146 }
2147
2148 void HTMLMediaElement::invalidateCachedTime()
2149 {
2150     LOG(Media, "HTMLMediaElement::invalidateCachedTime");
2151
2152     // Don't try to cache movie time when playback first starts as the time reported by the engine
2153     // sometimes fluctuates for a short amount of time, so the cached time will be off if we take it
2154     // too early.
2155     static const double minimumTimePlayingBeforeCacheSnapshot = 0.5;
2156
2157     m_minimumWallClockTimeToCacheMediaTime = WTF::currentTime() + minimumTimePlayingBeforeCacheSnapshot;
2158 #if !ENABLE(TIZEN_GSTREAMER_VIDEO)
2159     m_cachedTime = MediaPlayer::invalidTime();
2160 #endif
2161 }
2162
2163 // playback state
2164 float HTMLMediaElement::currentTime() const
2165 {
2166 #if LOG_CACHED_TIME_WARNINGS
2167     static const double minCachedDeltaForWarning = 0.01;
2168 #endif
2169
2170     if (!m_player)
2171         return 0;
2172
2173     if (m_seeking) {
2174         LOG(Media, "HTMLMediaElement::currentTime - seeking, returning %f", m_lastSeekTime);
2175         return m_lastSeekTime;
2176     }
2177
2178     if (m_cachedTime != MediaPlayer::invalidTime() && m_paused) {
2179 #if LOG_CACHED_TIME_WARNINGS
2180         float delta = m_cachedTime - m_player->currentTime();
2181         if (delta > minCachedDeltaForWarning)
2182             LOG(Media, "HTMLMediaElement::currentTime - WARNING, cached time is %f seconds off of media time when paused", delta);
2183 #endif
2184         return m_cachedTime;
2185     }
2186
2187     // Is it too soon use a cached time?
2188     double now = WTF::currentTime();
2189     double maximumDurationToCacheMediaTime = m_player->maximumDurationToCacheMediaTime();
2190
2191     if (maximumDurationToCacheMediaTime && m_cachedTime != MediaPlayer::invalidTime() && !m_paused && now > m_minimumWallClockTimeToCacheMediaTime) {
2192         double wallClockDelta = now - m_cachedTimeWallClockUpdateTime;
2193
2194         // Not too soon, use the cached time only if it hasn't expired.
2195         if (wallClockDelta < maximumDurationToCacheMediaTime) {
2196             float adjustedCacheTime = static_cast<float>(m_cachedTime + (m_playbackRate * wallClockDelta));
2197
2198 #if LOG_CACHED_TIME_WARNINGS
2199             float delta = adjustedCacheTime - m_player->currentTime();
2200             if (delta > minCachedDeltaForWarning)
2201                 LOG(Media, "HTMLMediaElement::currentTime - WARNING, cached time is %f seconds off of media time when playing", delta);
2202 #endif
2203             return adjustedCacheTime;
2204         }
2205     }
2206
2207 #if LOG_CACHED_TIME_WARNINGS
2208     if (maximumDurationToCacheMediaTime && now > m_minimumWallClockTimeToCacheMediaTime && m_cachedTime != MediaPlayer::invalidTime()) {
2209         double wallClockDelta = now - m_cachedTimeWallClockUpdateTime;
2210         float delta = m_cachedTime + (m_playbackRate * wallClockDelta) - m_player->currentTime();
2211         LOG(Media, "HTMLMediaElement::currentTime - cached time was %f seconds off of media time when it expired", delta);
2212     }
2213 #endif
2214
2215     refreshCachedTime();
2216
2217     return m_cachedTime;
2218 }
2219
2220 void HTMLMediaElement::setCurrentTime(float time, ExceptionCode& ec)
2221 {
2222     if (m_mediaController) {
2223         ec = INVALID_STATE_ERR;
2224         return;
2225     }
2226     seek(time, ec);
2227 }
2228
2229 float HTMLMediaElement::startTime() const
2230 {
2231     if (!m_player)
2232         return 0;
2233     return m_player->startTime();
2234 }
2235
2236 double HTMLMediaElement::initialTime() const
2237 {
2238     if (m_fragmentStartTime != MediaPlayer::invalidTime())
2239         return m_fragmentStartTime;
2240
2241     if (!m_player)
2242         return 0;
2243
2244     return m_player->initialTime();
2245 }
2246
2247 float HTMLMediaElement::duration() const
2248 {
2249     if (m_player && m_readyState >= HAVE_METADATA)
2250         return m_player->duration();
2251
2252     return numeric_limits<float>::quiet_NaN();
2253 }
2254
2255 bool HTMLMediaElement::paused() const
2256 {
2257     return m_paused;
2258 }
2259
2260 float HTMLMediaElement::defaultPlaybackRate() const
2261 {
2262     return m_defaultPlaybackRate;
2263 }
2264
2265 void HTMLMediaElement::setDefaultPlaybackRate(float rate)
2266 {
2267     if (m_defaultPlaybackRate != rate) {
2268         m_defaultPlaybackRate = rate;
2269         scheduleEvent(eventNames().ratechangeEvent);
2270     }
2271 }
2272
2273 float HTMLMediaElement::playbackRate() const
2274 {
2275     return m_playbackRate;
2276 }
2277
2278 void HTMLMediaElement::setPlaybackRate(float rate)
2279 {
2280     LOG(Media, "HTMLMediaElement::setPlaybackRate(%f)", rate);
2281
2282     if (m_playbackRate != rate) {
2283         m_playbackRate = rate;
2284         invalidateCachedTime();
2285         scheduleEvent(eventNames().ratechangeEvent);
2286     }
2287
2288     if (m_player && potentiallyPlaying() && m_player->rate() != rate && !m_mediaController)
2289         m_player->setRate(rate);
2290 }
2291
2292 void HTMLMediaElement::updatePlaybackRate()
2293 {
2294     float effectiveRate = m_mediaController ? m_mediaController->playbackRate() : m_playbackRate;
2295     if (m_player && potentiallyPlaying() && m_player->rate() != effectiveRate)
2296         m_player->setRate(effectiveRate);
2297 }
2298
2299 bool HTMLMediaElement::webkitPreservesPitch() const
2300 {
2301     return m_webkitPreservesPitch;
2302 }
2303
2304 void HTMLMediaElement::setWebkitPreservesPitch(bool preservesPitch)
2305 {
2306     LOG(Media, "HTMLMediaElement::setWebkitPreservesPitch(%s)", boolString(preservesPitch));
2307
2308     m_webkitPreservesPitch = preservesPitch;
2309
2310     if (!m_player)
2311         return;
2312
2313     m_player->setPreservesPitch(preservesPitch);
2314 }
2315
2316 bool HTMLMediaElement::ended() const
2317 {
2318     // 4.8.10.8 Playing the media resource
2319     // The ended attribute must return true if the media element has ended
2320     // playback and the direction of playback is forwards, and false otherwise.
2321     return endedPlayback() && m_playbackRate > 0;
2322 }
2323
2324 bool HTMLMediaElement::autoplay() const
2325 {
2326     return fastHasAttribute(autoplayAttr);
2327 }
2328
2329 void HTMLMediaElement::setAutoplay(bool b)
2330 {
2331     LOG(Media, "HTMLMediaElement::setAutoplay(%s)", boolString(b));
2332     setBooleanAttribute(autoplayAttr, b);
2333 }
2334
2335 String HTMLMediaElement::preload() const
2336 {
2337     switch (m_preload) {
2338     case MediaPlayer::None:
2339         return "none";
2340         break;
2341     case MediaPlayer::MetaData:
2342         return "metadata";
2343         break;
2344     case MediaPlayer::Auto:
2345         return "auto";
2346         break;
2347     }
2348
2349     ASSERT_NOT_REACHED();
2350     return String();
2351 }
2352
2353 void HTMLMediaElement::setPreload(const String& preload)
2354 {
2355     LOG(Media, "HTMLMediaElement::setPreload(%s)", preload.utf8().data());
2356     setAttribute(preloadAttr, preload);
2357 }
2358
2359 void HTMLMediaElement::play()
2360 {
2361     LOG(Media, "HTMLMediaElement::play()");
2362
2363     if (userGestureRequiredForRateChange() && !ScriptController::processingUserGesture())
2364         return;
2365     if (ScriptController::processingUserGesture())
2366         removeBehaviorsRestrictionsAfterFirstUserGesture();
2367
2368     Settings* settings = document()->settings();
2369     if (settings && settings->needsSiteSpecificQuirks() && m_dispatchingCanPlayEvent && !m_loadInitiatedByUserGesture) {
2370         // It should be impossible to be processing the canplay event while handling a user gesture
2371         // since it is dispatched asynchronously.
2372         ASSERT(!ScriptController::processingUserGesture());
2373         String host = document()->baseURL().host();
2374         if (host.endsWith(".npr.org", false) || equalIgnoringCase(host, "npr.org"))
2375             return;
2376     }
2377
2378 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
2379     if (isVideo())
2380         power_lock_state(POWER_STATE_NORMAL, 0);
2381 #endif
2382     playInternal();
2383 }
2384
2385 void HTMLMediaElement::playInternal()
2386 {
2387     LOG(Media, "HTMLMediaElement::playInternal");
2388
2389     // 4.8.10.9. Playing the media resource
2390     if (!m_player || m_networkState == NETWORK_EMPTY)
2391         scheduleLoad(MediaResource);
2392
2393     if (endedPlayback()) {
2394         ExceptionCode unused;
2395         seek(0, unused);
2396     }
2397
2398     if (m_mediaController)
2399         m_mediaController->bringElementUpToSpeed(this);
2400
2401     if (m_paused) {
2402         m_paused = false;
2403         invalidateCachedTime();
2404         scheduleEvent(eventNames().playEvent);
2405
2406         if (m_readyState <= HAVE_CURRENT_DATA)
2407             scheduleEvent(eventNames().waitingEvent);
2408         else if (m_readyState >= HAVE_FUTURE_DATA)
2409             scheduleEvent(eventNames().playingEvent);
2410     }
2411     m_autoplaying = false;
2412
2413     updatePlayState();
2414     updateMediaController();
2415 }
2416
2417 void HTMLMediaElement::pause()
2418 {
2419     LOG(Media, "HTMLMediaElement::pause()");
2420
2421     if (userGestureRequiredForRateChange() && !ScriptController::processingUserGesture())
2422         return;
2423
2424 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
2425     if (isVideo())
2426         power_unlock_state(POWER_STATE_NORMAL);
2427 #endif
2428     pauseInternal();
2429 }
2430
2431
2432 void HTMLMediaElement::pauseInternal()
2433 {
2434     LOG(Media, "HTMLMediaElement::pauseInternal");
2435
2436     // 4.8.10.9. Playing the media resource
2437     if (!m_player || m_networkState == NETWORK_EMPTY)
2438         scheduleLoad(MediaResource);
2439
2440     m_autoplaying = false;
2441
2442     if (!m_paused) {
2443         m_paused = true;
2444         scheduleTimeupdateEvent(false);
2445         scheduleEvent(eventNames().pauseEvent);
2446     }
2447
2448     updatePlayState();
2449 }
2450
2451 #if ENABLE(MEDIA_SOURCE)
2452
2453 void HTMLMediaElement::webkitSourceAddId(const String& id, const String& type, ExceptionCode& ec)
2454 {
2455     if (id.isNull() || id.isEmpty()) {
2456         ec = INVALID_ACCESS_ERR;
2457         return;
2458     }
2459
2460     if (m_sourceIDs.contains(id)) {
2461         ec = INVALID_STATE_ERR;
2462         return;
2463     }
2464
2465     if (type.isNull() || type.isEmpty()) {
2466         ec = INVALID_ACCESS_ERR;
2467         return;
2468     }
2469
2470     if (!m_player || m_currentSrc != m_mediaSourceURL || m_sourceState != SOURCE_OPEN) {
2471         ec = INVALID_STATE_ERR;
2472         return;
2473     }
2474
2475     ContentType contentType(type);
2476     Vector<String> codecs = contentType.codecs();
2477
2478     if (!codecs.size()) {
2479         ec = NOT_SUPPORTED_ERR;
2480         return;
2481     }
2482
2483     switch (m_player->sourceAddId(id, contentType.type(), codecs)) {
2484     case MediaPlayer::Ok:
2485         m_sourceIDs.add(id);
2486         return;
2487     case MediaPlayer::NotSupported:
2488         ec = NOT_SUPPORTED_ERR;
2489         return;
2490     case MediaPlayer::ReachedIdLimit:
2491         ec = QUOTA_EXCEEDED_ERR;
2492         return;
2493     }
2494
2495     ASSERT_NOT_REACHED();
2496 }
2497
2498 void HTMLMediaElement::webkitSourceRemoveId(const String& id, ExceptionCode& ec)
2499 {
2500     if (!isValidSourceId(id, ec))
2501         return;
2502
2503     if (!m_player || m_currentSrc != m_mediaSourceURL || m_sourceState == SOURCE_CLOSED) {
2504         ec = INVALID_STATE_ERR;
2505         return;
2506     }
2507
2508     if (!m_player->sourceRemoveId(id))
2509         ASSERT_NOT_REACHED();
2510
2511     m_sourceIDs.remove(id);
2512 }
2513
2514 PassRefPtr<TimeRanges> HTMLMediaElement::webkitSourceBuffered(const String& id, ExceptionCode& ec)
2515 {
2516     if (!isValidSourceId(id, ec))
2517         return 0;
2518
2519     if (!m_player || m_currentSrc != m_mediaSourceURL || m_sourceState == SOURCE_CLOSED) {
2520         ec = INVALID_STATE_ERR;
2521         return 0;
2522     }
2523
2524     return m_player->sourceBuffered(id);
2525 }
2526
2527 void HTMLMediaElement::webkitSourceAppend(const String& id, PassRefPtr<Uint8Array> data, ExceptionCode& ec)
2528 {
2529     if (!isValidSourceId(id, ec))
2530         return;
2531
2532     if (!m_player || m_currentSrc != m_mediaSourceURL || m_sourceState != SOURCE_OPEN) {
2533         ec = INVALID_STATE_ERR;
2534         return;
2535     }
2536
2537     if (!data.get()) {
2538         ec = INVALID_ACCESS_ERR;
2539         return;
2540     }
2541
2542     if (!data->length())
2543         return;
2544
2545     if (!m_player->sourceAppend(id, data->data(), data->length())) {
2546         ec = SYNTAX_ERR;
2547         return;
2548     }
2549 }
2550
2551 void HTMLMediaElement::webkitSourceAbort(const String& id, ExceptionCode& ec)
2552 {
2553     if (!isValidSourceId(id, ec))
2554         return;
2555
2556     if (!m_player || m_currentSrc != m_mediaSourceURL || m_sourceState != SOURCE_OPEN) {
2557         ec = INVALID_STATE_ERR;
2558         return;
2559     }
2560
2561     if (!m_player->sourceAbort(id))
2562         ASSERT_NOT_REACHED();
2563 }
2564
2565 void HTMLMediaElement::webkitSourceEndOfStream(unsigned short status, ExceptionCode& ec)
2566 {
2567     if (!m_player || m_currentSrc != m_mediaSourceURL || m_sourceState != SOURCE_OPEN) {
2568         ec = INVALID_STATE_ERR;
2569         return;
2570     }
2571
2572     MediaPlayer::EndOfStreamStatus eosStatus = MediaPlayer::EosNoError;
2573
2574     switch (status) {
2575     case EOS_NO_ERROR:
2576         eosStatus = MediaPlayer::EosNoError;
2577         break;
2578     case EOS_NETWORK_ERR:
2579         eosStatus = MediaPlayer::EosNetworkError;
2580         break;
2581     case EOS_DECODE_ERR:
2582         eosStatus = MediaPlayer::EosDecodeError;
2583         break;
2584     default:
2585         ec = SYNTAX_ERR;
2586         return;
2587     }
2588
2589     setSourceState(SOURCE_ENDED);
2590     m_player->sourceEndOfStream(eosStatus);
2591 }
2592
2593 HTMLMediaElement::SourceState HTMLMediaElement::webkitSourceState() const
2594 {
2595     return m_sourceState;
2596 }
2597
2598 void HTMLMediaElement::setSourceState(SourceState state)
2599 {
2600     SourceState oldState = m_sourceState;
2601     m_sourceState = static_cast<SourceState>(state);
2602
2603     if (m_sourceState == oldState)
2604         return;
2605
2606     if (m_sourceState == SOURCE_CLOSED) {
2607         m_sourceIDs.clear();
2608         scheduleEvent(eventNames().webkitsourcecloseEvent);
2609         return;
2610     }
2611
2612     if (oldState == SOURCE_OPEN && m_sourceState == SOURCE_ENDED) {
2613         scheduleEvent(eventNames().webkitsourceendedEvent);
2614         return;
2615     }
2616
2617     if (m_sourceState == SOURCE_OPEN) {
2618         scheduleEvent(eventNames().webkitsourceopenEvent);
2619         return;
2620     }
2621 }
2622 #endif
2623
2624 #if ENABLE(ENCRYPTED_MEDIA)
2625 void HTMLMediaElement::webkitGenerateKeyRequest(const String& keySystem, PassRefPtr<Uint8Array> initData, ExceptionCode& ec)
2626 {
2627     if (keySystem.isEmpty()) {
2628         ec = SYNTAX_ERR;
2629         return;
2630     }
2631
2632     if (!m_player) {
2633         ec = INVALID_STATE_ERR;
2634         return;
2635     }
2636
2637     const unsigned char* initDataPointer = 0;
2638     unsigned initDataLength = 0;
2639     if (initData) {
2640         initDataPointer = initData->data();
2641         initDataLength = initData->length();
2642     }
2643
2644     MediaPlayer::MediaKeyException result = m_player->generateKeyRequest(keySystem, initDataPointer, initDataLength);
2645     ec = exceptionCodeForMediaKeyException(result);
2646 }
2647
2648 void HTMLMediaElement::webkitGenerateKeyRequest(const String& keySystem, ExceptionCode& ec)
2649 {
2650     webkitGenerateKeyRequest(keySystem, Uint8Array::create(0), ec);
2651 }
2652
2653 void HTMLMediaElement::webkitAddKey(const String& keySystem, PassRefPtr<Uint8Array> key, PassRefPtr<Uint8Array> initData, const String& sessionId, ExceptionCode& ec)
2654 {
2655     if (keySystem.isEmpty()) {
2656         ec = SYNTAX_ERR;
2657         return;
2658     }
2659
2660     if (!key) {
2661         ec = SYNTAX_ERR;
2662         return;
2663     }
2664
2665     if (!key->length()) {
2666         ec = TYPE_MISMATCH_ERR;
2667         return;
2668     }
2669
2670     if (!m_player) {
2671         ec = INVALID_STATE_ERR;
2672         return;
2673     }
2674
2675     const unsigned char* initDataPointer = 0;
2676     unsigned initDataLength = 0;
2677     if (initData) {
2678         initDataPointer = initData->data();
2679         initDataLength = initData->length();
2680     }
2681
2682     MediaPlayer::MediaKeyException result = m_player->addKey(keySystem, key->data(), key->length(), initDataPointer, initDataLength, sessionId);
2683     ec = exceptionCodeForMediaKeyException(result);
2684 }
2685
2686 void HTMLMediaElement::webkitAddKey(const String& keySystem, PassRefPtr<Uint8Array> key, ExceptionCode& ec)
2687 {
2688     webkitAddKey(keySystem, key, Uint8Array::create(0), String(), ec);
2689 }
2690
2691 void HTMLMediaElement::webkitCancelKeyRequest(const String& keySystem, const String& sessionId, ExceptionCode& ec)
2692 {
2693     if (keySystem.isEmpty()) {
2694         ec = SYNTAX_ERR;
2695         return;
2696     }
2697
2698     if (!m_player) {
2699         ec = INVALID_STATE_ERR;
2700         return;
2701     }
2702
2703     MediaPlayer::MediaKeyException result = m_player->cancelKeyRequest(keySystem, sessionId);
2704     ec = exceptionCodeForMediaKeyException(result);
2705 }
2706
2707 #endif
2708
2709 bool HTMLMediaElement::loop() const
2710 {
2711     return fastHasAttribute(loopAttr);
2712 }
2713
2714 void HTMLMediaElement::setLoop(bool b)
2715 {
2716     LOG(Media, "HTMLMediaElement::setLoop(%s)", boolString(b));
2717     setBooleanAttribute(loopAttr, b);
2718 #if PLATFORM(MAC)
2719     updateDisableSleep();
2720 #endif
2721 }
2722
2723 bool HTMLMediaElement::controls() const
2724 {
2725     Frame* frame = document()->frame();
2726
2727     // always show controls when scripting is disabled
2728     if (frame && !frame->script()->canExecuteScripts(NotAboutToExecuteScript))
2729         return true;
2730
2731     // always show controls for video when fullscreen playback is required.
2732     if (isVideo() && document()->page() && document()->page()->chrome()->requiresFullscreenForVideoPlayback())
2733         return true;
2734
2735     // Always show controls when in full screen mode.
2736     if (isFullscreen())
2737         return true;
2738
2739     return fastHasAttribute(controlsAttr);
2740 }
2741
2742 void HTMLMediaElement::setControls(bool b)
2743 {
2744     LOG(Media, "HTMLMediaElement::setControls(%s)", boolString(b));
2745     setBooleanAttribute(controlsAttr, b);
2746 }
2747
2748 float HTMLMediaElement::volume() const
2749 {
2750     return m_volume;
2751 }
2752
2753 void HTMLMediaElement::setVolume(float vol, ExceptionCode& ec)
2754 {
2755     LOG(Media, "HTMLMediaElement::setVolume(%f)", vol);
2756
2757     if (vol < 0.0f || vol > 1.0f) {
2758         ec = INDEX_SIZE_ERR;
2759         return;
2760     }
2761
2762     if (m_volume != vol) {
2763         m_volume = vol;
2764         updateVolume();
2765         scheduleEvent(eventNames().volumechangeEvent);
2766     }
2767 }
2768
2769 bool HTMLMediaElement::muted() const
2770 {
2771     return m_muted;
2772 }
2773
2774 void HTMLMediaElement::setMuted(bool muted)
2775 {
2776     LOG(Media, "HTMLMediaElement::setMuted(%s)", boolString(muted));
2777
2778     if (m_muted != muted) {
2779         m_muted = muted;
2780         // Avoid recursion when the player reports volume changes.
2781         if (!processingMediaPlayerCallback()) {
2782             if (m_player) {
2783                 m_player->setMuted(m_muted);
2784                 if (hasMediaControls())
2785                     mediaControls()->changedMute();
2786             }
2787         }
2788         scheduleEvent(eventNames().volumechangeEvent);
2789     }
2790 }
2791
2792 void HTMLMediaElement::togglePlayState()
2793 {
2794     LOG(Media, "HTMLMediaElement::togglePlayState - canPlay() is %s", boolString(canPlay()));
2795
2796     // We can safely call the internal play/pause methods, which don't check restrictions, because
2797     // this method is only called from the built-in media controller
2798     if (canPlay()) {
2799         updatePlaybackRate();
2800         playInternal();
2801     } else
2802         pauseInternal();
2803 }
2804
2805 void HTMLMediaElement::beginScrubbing()
2806 {
2807     LOG(Media, "HTMLMediaElement::beginScrubbing - paused() is %s", boolString(paused()));
2808
2809     if (!paused()) {
2810         if (ended()) {
2811             // Because a media element stays in non-paused state when it reaches end, playback resumes
2812             // when the slider is dragged from the end to another position unless we pause first. Do
2813             // a "hard pause" so an event is generated, since we want to stay paused after scrubbing finishes.
2814             pause();
2815         } else {
2816             // Not at the end but we still want to pause playback so the media engine doesn't try to
2817             // continue playing during scrubbing. Pause without generating an event as we will
2818             // unpause after scrubbing finishes.
2819             setPausedInternal(true);
2820         }
2821     }
2822 }
2823
2824 void HTMLMediaElement::endScrubbing()
2825 {
2826     LOG(Media, "HTMLMediaElement::endScrubbing - m_pausedInternal is %s", boolString(m_pausedInternal));
2827
2828     if (m_pausedInternal)
2829         setPausedInternal(false);
2830 }
2831
2832 // The spec says to fire periodic timeupdate events (those sent while playing) every
2833 // "15 to 250ms", we choose the slowest frequency
2834 static const double maxTimeupdateEventFrequency = 0.25;
2835
2836 void HTMLMediaElement::startPlaybackProgressTimer()
2837 {
2838     if (m_playbackProgressTimer.isActive())
2839         return;
2840
2841     m_previousProgressTime = WTF::currentTime();
2842     m_playbackProgressTimer.startRepeating(maxTimeupdateEventFrequency);
2843 }
2844
2845 void HTMLMediaElement::playbackProgressTimerFired(Timer<HTMLMediaElement>*)
2846 {
2847     ASSERT(m_player);
2848
2849     if (m_fragmentEndTime != MediaPlayer::invalidTime() && currentTime() >= m_fragmentEndTime && m_playbackRate > 0) {
2850         m_fragmentEndTime = MediaPlayer::invalidTime();
2851         if (!m_mediaController && !m_paused) {
2852             // changes paused to true and fires a simple event named pause at the media element.
2853             pauseInternal();
2854         }
2855     }
2856
2857     scheduleTimeupdateEvent(true);
2858
2859     if (!m_playbackRate)
2860         return;
2861
2862     if (!m_paused && hasMediaControls())
2863         mediaControls()->playbackProgressed();
2864
2865 #if ENABLE(VIDEO_TRACK)
2866     if (RuntimeEnabledFeatures::webkitVideoTrackEnabled())
2867         updateActiveTextTrackCues(currentTime());
2868 #endif
2869 }
2870
2871 void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent)
2872 {
2873     double now = WTF::currentTime();
2874     double timedelta = now - m_lastTimeUpdateEventWallTime;
2875
2876     // throttle the periodic events
2877     if (periodicEvent && timedelta < maxTimeupdateEventFrequency)
2878         return;
2879
2880     // Some media engines make multiple "time changed" callbacks at the same time, but we only want one
2881     // event at a given time so filter here
2882     float movieTime = currentTime();
2883     if (movieTime != m_lastTimeUpdateEventMovieTime) {
2884         scheduleEvent(eventNames().timeupdateEvent);
2885         m_lastTimeUpdateEventWallTime = now;
2886         m_lastTimeUpdateEventMovieTime = movieTime;
2887     }
2888 }
2889
2890 bool HTMLMediaElement::canPlay() const
2891 {
2892     return paused() || ended() || m_readyState < HAVE_METADATA;
2893 }
2894
2895 float HTMLMediaElement::percentLoaded() const
2896 {
2897     if (!m_player)
2898         return 0;
2899     float duration = m_player->duration();
2900
2901     if (!duration || isinf(duration))
2902         return 0;
2903
2904     float buffered = 0;
2905     RefPtr<TimeRanges> timeRanges = m_player->buffered();
2906     for (unsigned i = 0; i < timeRanges->length(); ++i) {
2907         ExceptionCode ignoredException;
2908         float start = timeRanges->start(i, ignoredException);
2909         float end = timeRanges->end(i, ignoredException);
2910         buffered += end - start;
2911     }
2912     return buffered / duration;
2913 }
2914
2915 #if ENABLE(VIDEO_TRACK)
2916 PassRefPtr<TextTrack> HTMLMediaElement::addTextTrack(const String& kind, const String& label, const String& language, ExceptionCode& ec)
2917 {
2918     if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
2919         return 0;
2920
2921     // 4.8.10.12.4 Text track API
2922     // The addTextTrack(kind, label, language) method of media elements, when invoked, must run the following steps:
2923
2924     // 1. If kind is not one of the following strings, then throw a SyntaxError exception and abort these steps
2925     if (!TextTrack::isValidKindKeyword(kind)) {
2926         ec = SYNTAX_ERR;
2927         return 0;
2928     }
2929
2930     // 2. If the label argument was omitted, let label be the empty string.
2931     // 3. If the language argument was omitted, let language be the empty string.
2932     // 4. Create a new TextTrack object.
2933
2934     // 5. Create a new text track corresponding to the new object, and set its text track kind to kind, its text
2935     // track label to label, its text track language to language...
2936     RefPtr<TextTrack> textTrack = TextTrack::create(ActiveDOMObject::scriptExecutionContext(), this, kind, label, language);
2937
2938     // Note, due to side effects when changing track parameters, we have to
2939     // first append the track to the text track list.
2940
2941     // 6. Add the new text track to the media element's list of text tracks.
2942     textTracks()->append(textTrack);
2943
2944     // ... its text track readiness state to the text track loaded state ...
2945     textTrack->setReadinessState(TextTrack::Loaded);
2946
2947     // ... its text track mode to the text track hidden mode, and its text track list of cues to an empty list ...
2948     textTrack->setMode(TextTrack::hiddenKeyword());
2949
2950     return textTrack.release();
2951 }
2952
2953 TextTrackList* HTMLMediaElement::textTracks()
2954 {
2955     if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
2956         return 0;
2957
2958     if (!m_textTracks)
2959         m_textTracks = TextTrackList::create(this, ActiveDOMObject::scriptExecutionContext());
2960
2961     return m_textTracks.get();
2962 }
2963
2964 HTMLTrackElement* HTMLMediaElement::showingTrackWithSameKind(HTMLTrackElement* trackElement) const
2965 {
2966     for (Node* node = firstChild(); node; node = node->nextSibling()) {
2967         if (trackElement == node)
2968             continue;
2969         if (!node->hasTagName(trackTag))
2970             continue;
2971
2972         HTMLTrackElement* showingTrack = static_cast<HTMLTrackElement*>(node);
2973         if (showingTrack->kind() == trackElement->kind() && showingTrack->track()->mode() == TextTrack::showingKeyword())
2974             return showingTrack;
2975     }
2976
2977     return 0;
2978 }
2979
2980 void HTMLMediaElement::didAddTrack(HTMLTrackElement* trackElement)
2981 {
2982     ASSERT(trackElement->hasTagName(trackTag));
2983
2984     if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
2985         return;
2986
2987     // 4.8.10.12.3 Sourcing out-of-band text tracks
2988     // When a track element's parent element changes and the new parent is a media element,
2989     // then the user agent must add the track element's corresponding text track to the
2990     // media element's list of text tracks ... [continues in TextTrackList::append]
2991     RefPtr<TextTrack> textTrack = trackElement->track();
2992     if (!textTrack)
2993         return;
2994
2995     textTracks()->append(textTrack);
2996
2997     // Do not schedule the track loading until parsing finishes so we don't start before all tracks
2998     // in the markup have been added.
2999     if (!m_parsingInProgress)
3000         scheduleLoad(TextTrackResource);
3001 }
3002
3003 void HTMLMediaElement::willRemoveTrack(HTMLTrackElement* trackElement)
3004 {
3005     ASSERT(trackElement->hasTagName(trackTag));
3006
3007     if (!RuntimeEnabledFeatures::webkitVideoTrackEnabled())
3008         return;
3009
3010 #if !LOG_DISABLED
3011     if (trackElement->hasTagName(trackTag)) {
3012         KURL url = trackElement->getNonEmptyURLAttribute(srcAttr);
3013         LOG(Media, "HTMLMediaElement::willRemoveTrack - 'src' is %s", urlForLogging(url).utf8().data());
3014     }
3015 #endif
3016
3017     trackElement->setHasBeenConfigured(false);
3018
3019     if (!m_textTracks)
3020         return;
3021
3022     RefPtr<TextTrack> textTrack = trackElement->track();
3023     if (!textTrack)
3024         return;
3025
3026     // 4.8.10.12.3 Sourcing out-of-band text tracks
3027     // When a track element's parent element changes and the old parent was a media element,
3028     // then the user agent must remove the track element's corresponding text track from the
3029     // media element's list of text tracks.
3030     m_textTracks->remove(textTrack.get());
3031     size_t index = m_textTracksWhenResourceSelectionBegan.find(textTrack.get());
3032     if (index != notFound)
3033         m_textTracksWhenResourceSelectionBegan.remove(index);
3034 }
3035
3036 bool HTMLMediaElement::userIsInterestedInThisLanguage(const String&) const
3037 {
3038     // FIXME: check the user's language preference - bugs.webkit.org/show_bug.cgi?id=74121
3039     return true;
3040 }
3041
3042 bool HTMLMediaElement::userIsInterestedInThisTrackKind(String kind) const
3043 {
3044     // If ... the user has indicated an interest in having a track with this text track kind, text track language, ...
3045     if (m_disableCaptions)
3046         return false;
3047
3048     Settings* settings = document()->settings();
3049     if (!settings)
3050         return false;
3051
3052     if (kind == TextTrack::subtitlesKeyword())
3053         return settings->shouldDisplaySubtitles() || m_closedCaptionsVisible;
3054     if (kind == TextTrack::captionsKeyword())
3055         return settings->shouldDisplayCaptions() || m_closedCaptionsVisible;
3056     if (kind == TextTrack::descriptionsKeyword())
3057         return settings->shouldDisplayTextDescriptions() || m_closedCaptionsVisible;
3058
3059     return false;
3060 }
3061
3062 void HTMLMediaElement::configureTextTrackGroup(const TrackGroup& group) const
3063 {
3064     ASSERT(group.tracks.size());
3065
3066     String bestMatchingLanguage;
3067     if (group.hasSrcLang) {
3068         Vector<String> languages;
3069         languages.reserveInitialCapacity(group.tracks.size());
3070         for (size_t i = 0; i < group.tracks.size(); ++i) {
3071             String srcLanguage = group.tracks[i]->track()->language();
3072             if (srcLanguage.length())
3073                 languages.append(srcLanguage);
3074         }
3075         bestMatchingLanguage = preferredLanguageFromList(languages);
3076     }
3077
3078     // First, find the track in the group that should be enabled (if any).
3079     HTMLTrackElement* trackElementToEnable = 0;
3080     HTMLTrackElement* defaultTrack = 0;
3081     HTMLTrackElement* fallbackTrack = 0;
3082     for (size_t i = 0; !trackElementToEnable && i < group.tracks.size(); ++i) {
3083         HTMLTrackElement* trackElement = group.tracks[i];
3084         RefPtr<TextTrack> textTrack = trackElement->track();
3085
3086         if (userIsInterestedInThisTrackKind(textTrack->kind())) {
3087             // * If the text track kind is { [subtitles or captions] [descriptions] } and the user has indicated an interest in having a
3088             // track with this text track kind, text track language, and text track label enabled, and there is no
3089             // other text track in the media element's list of text tracks with a text track kind of either subtitles
3090             // or captions whose text track mode is showing
3091             // ...
3092             // * If the text track kind is chapters and the text track language is one that the user agent has reason
3093             // to believe is appropriate for the user, and there is no other text track in the media element's list of
3094             // text tracks with a text track kind of chapters whose text track mode is showing
3095             //    Let the text track mode be showing.
3096             if (bestMatchingLanguage.length()) {
3097                 if (textTrack->language() == bestMatchingLanguage)
3098                     trackElementToEnable = trackElement;
3099             } else if (trackElement->isDefault()) {
3100                 // The user is interested in this type of track, but their language preference doesn't match any track so we will
3101                 // enable the 'default' track.
3102                 defaultTrack = trackElement;
3103             }
3104
3105             // Remember the first track that doesn't match language or have 'default' to potentially use as fallback.
3106             if (!fallbackTrack)
3107                 fallbackTrack = trackElement;
3108         } else if (!group.visibleTrack && !defaultTrack && trackElement->isDefault()) {
3109             // * If the track element has a default attribute specified, and there is no other text track in the media
3110             // element's list of text tracks whose text track mode is showing or showing by default
3111             //    Let the text track mode be showing by default.
3112             defaultTrack = trackElement;
3113         }
3114     }
3115
3116     if (!trackElementToEnable && defaultTrack)
3117         trackElementToEnable = defaultTrack;
3118
3119     // If no track matches the user's preferred language and non was marked 'default', enable the first track
3120     // because the user has explicitly stated a preference for this kind of track.
3121     if (!trackElementToEnable && fallbackTrack)
3122         trackElementToEnable = fallbackTrack;
3123
3124     for (size_t i = 0; i < group.tracks.size(); ++i) {
3125         HTMLTrackElement* trackElement = group.tracks[i];
3126         RefPtr<TextTrack> textTrack = trackElement->track();
3127
3128         if (trackElementToEnable == trackElement) {
3129             textTrack->setMode(TextTrack::showingKeyword());
3130             if (defaultTrack == trackElement)
3131                 textTrack->setShowingByDefault(true);
3132         } else {
3133             if (textTrack->showingByDefault()) {
3134                 // If there is a text track in the media element's list of text tracks whose text track
3135                 // mode is showing by default, the user agent must furthermore change that text track's
3136                 // text track mode to hidden.
3137                 textTrack->setShowingByDefault(false);
3138                 textTrack->setMode(TextTrack::hiddenKeyword());
3139             } else
3140                 textTrack->setMode(TextTrack::disabledKeyword());
3141         }
3142     }
3143
3144     if (trackElementToEnable && group.defaultTrack && group.defaultTrack != trackElementToEnable) {
3145         RefPtr<TextTrack> textTrack = group.defaultTrack->track();
3146         if (textTrack && textTrack->showingByDefault()) {
3147             textTrack->setShowingByDefault(false);
3148             textTrack->setMode(TextTrack::hiddenKeyword());
3149         }
3150     }
3151 }
3152
3153 void HTMLMediaElement::configureTextTracks()
3154 {
3155     TrackGroup captionAndSubtitleTracks(TrackGroup::CaptionsAndSubtitles);
3156     TrackGroup descriptionTracks(TrackGroup::Description);
3157     TrackGroup chapterTracks(TrackGroup::Chapter);
3158     TrackGroup metadataTracks(TrackGroup::Metadata);
3159     TrackGroup otherTracks(TrackGroup::Other);
3160
3161     for (Node* node = firstChild(); node; node = node->nextSibling()) {
3162         if (!node->hasTagName(trackTag))
3163             continue;
3164
3165         HTMLTrackElement* trackElement = static_cast<HTMLTrackElement*>(node);
3166         RefPtr<TextTrack> textTrack = trackElement->track();
3167         if (!textTrack)
3168             continue;
3169
3170         String kind = textTrack->kind();
3171         TrackGroup* currentGroup;
3172         if (kind == TextTrack::subtitlesKeyword() || kind == TextTrack::captionsKeyword())
3173             currentGroup = &captionAndSubtitleTracks;
3174         else if (kind == TextTrack::descriptionsKeyword())
3175             currentGroup = &descriptionTracks;
3176         else if (kind == TextTrack::chaptersKeyword())
3177             currentGroup = &chapterTracks;
3178         else if (kind == TextTrack::metadataKeyword())
3179             currentGroup = &metadataTracks;
3180         else
3181             currentGroup = &otherTracks;
3182
3183         if (!currentGroup->visibleTrack && textTrack->mode() == TextTrack::showingKeyword())
3184             currentGroup->visibleTrack = trackElement;
3185         if (!currentGroup->defaultTrack && trackElement->isDefault())
3186             currentGroup->defaultTrack = trackElement;
3187
3188         // Do not add this track to the group if it has already been automatically configured
3189         // as we only want to call configureTextTrack once per track so that adding another
3190         // track after the initial configuration doesn't reconfigure every track - only those
3191         // that should be changed by the new addition. For example all metadata tracks are
3192         // disabled by default, and we don't want a track that has been enabled by script
3193         // to be disabled automatically when a new metadata track is added later.
3194         if (trackElement->hasBeenConfigured())
3195             continue;
3196
3197         if (textTrack->language().length())
3198             currentGroup->hasSrcLang = true;
3199         currentGroup->tracks.append(trackElement);
3200     }
3201
3202     if (captionAndSubtitleTracks.tracks.size())
3203         configureTextTrackGroup(captionAndSubtitleTracks);
3204     if (descriptionTracks.tracks.size())
3205         configureTextTrackGroup(descriptionTracks);
3206     if (chapterTracks.tracks.size())
3207         configureTextTrackGroup(chapterTracks);
3208     if (metadataTracks.tracks.size())
3209         configureTextTrackGroup(metadataTracks);
3210     if (otherTracks.tracks.size())
3211         configureTextTrackGroup(otherTracks);
3212 }
3213 #endif
3214
3215 bool HTMLMediaElement::havePotentialSourceChild()
3216 {
3217     // Stash the current <source> node and next nodes so we can restore them after checking
3218     // to see there is another potential.
3219     RefPtr<HTMLSourceElement> currentSourceNode = m_currentSourceNode;
3220     RefPtr<Node> nextNode = m_nextChildNodeToConsider;
3221
3222     KURL nextURL = selectNextSourceChild(0, 0, DoNothing);
3223
3224     m_currentSourceNode = currentSourceNode;
3225     m_nextChildNodeToConsider = nextNode;
3226
3227     return nextURL.isValid();
3228 }
3229
3230 KURL HTMLMediaElement::selectNextSourceChild(ContentType* contentType, String* keySystem, InvalidURLAction actionIfInvalid)
3231 {
3232 #if !LOG_DISABLED
3233     // Don't log if this was just called to find out if there are any valid <source> elements.
3234     bool shouldLog = actionIfInvalid != DoNothing;
3235     if (shouldLog)
3236         LOG(Media, "HTMLMediaElement::selectNextSourceChild");
3237 #endif
3238
3239     if (!m_nextChildNodeToConsider) {
3240 #if !LOG_DISABLED
3241         if (shouldLog)
3242             LOG(Media, "HTMLMediaElement::selectNextSourceChild -> 0x0000, \"\"");
3243 #endif
3244         return KURL();
3245     }
3246
3247     KURL mediaURL;
3248     Node* node;
3249     HTMLSourceElement* source = 0;
3250     String type;
3251     String system;
3252     bool lookingForStartNode = m_nextChildNodeToConsider;
3253     bool canUseSourceElement = false;
3254     bool okToLoadSourceURL;
3255
3256     NodeVector potentialSourceNodes;
3257     getChildNodes(this, potentialSourceNodes);
3258
3259     for (unsigned i = 0; !canUseSourceElement && i < potentialSourceNodes.size(); ++i) {
3260         node = potentialSourceNodes[i].get();
3261         if (lookingForStartNode && m_nextChildNodeToConsider != node)
3262             continue;
3263         lookingForStartNode = false;
3264
3265         if (!node->hasTagName(sourceTag))
3266             continue;
3267         if (node->parentNode() != this)
3268             continue;
3269
3270         source = static_cast<HTMLSourceElement*>(node);
3271
3272         // 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
3273         mediaURL = source->getNonEmptyURLAttribute(srcAttr);
3274 #if !LOG_DISABLED
3275         if (shouldLog)
3276             LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'src' is %s", urlForLogging(mediaURL).utf8().data());
3277 #endif
3278         if (mediaURL.isEmpty())
3279             goto check_again;
3280
3281         if (source->fastHasAttribute(mediaAttr)) {
3282             MediaQueryEvaluator screenEval("screen", document()->frame(), renderer() ? renderer()->style() : 0);
3283             RefPtr<MediaQuerySet> media = MediaQuerySet::createAllowingDescriptionSyntax(source->media());
3284 #if !LOG_DISABLED
3285             if (shouldLog)
3286                 LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'media' is %s", source->media().utf8().data());
3287 #endif
3288             if (!screenEval.eval(media.get()))
3289                 goto check_again;
3290         }
3291
3292         type = source->type();
3293         // FIXME(82965): Add support for keySystem in <source> and set system from source.
3294         if (type.isEmpty() && mediaURL.protocolIsData())
3295             type = mimeTypeFromDataURL(mediaURL);
3296         if (!type.isEmpty() || !system.isEmpty()) {
3297 #if !LOG_DISABLED
3298             if (shouldLog)
3299                 LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'type' is '%s' - key system is '%s'", type.utf8().data(), system.utf8().data());
3300 #endif
3301             if (!MediaPlayer::supportsType(ContentType(type), system, mediaURL, this))
3302                 goto check_again;
3303         }
3304
3305         // Is it safe to load this url?
3306         okToLoadSourceURL = isSafeToLoadURL(mediaURL, actionIfInvalid) && dispatchBeforeLoadEvent(mediaURL.string());
3307
3308         // A 'beforeload' event handler can mutate the DOM, so check to see if the source element is still a child node.
3309         if (node->parentNode() != this) {
3310             LOG(Media, "HTMLMediaElement::selectNextSourceChild : 'beforeload' removed current element");
3311             source = 0;
3312             goto check_again;
3313         }
3314
3315         if (!okToLoadSourceURL)
3316             goto check_again;
3317
3318         // Making it this far means the <source> looks reasonable.
3319         canUseSourceElement = true;
3320
3321 check_again:
3322         if (!canUseSourceElement && actionIfInvalid == Complain && source)
3323             source->scheduleErrorEvent();
3324     }
3325
3326     if (canUseSourceElement) {
3327         if (contentType)
3328             *contentType = ContentType(type);
3329         if (keySystem)
3330             *keySystem = system;
3331         m_currentSourceNode = source;
3332         m_nextChildNodeToConsider = source->nextSibling();
3333     } else {
3334         m_currentSourceNode = 0;
3335         m_nextChildNodeToConsider = 0;
3336     }
3337
3338 #if !LOG_DISABLED
3339     if (shouldLog)
3340         LOG(Media, "HTMLMediaElement::selectNextSourceChild -> %p, %s", m_currentSourceNode.get(), canUseSourceElement ? urlForLogging(mediaURL).utf8().data() : "");
3341 #endif
3342     return canUseSourceElement ? mediaURL : KURL();
3343 }
3344
3345 void HTMLMediaElement::sourceWasAdded(HTMLSourceElement* source)
3346 {
3347     LOG(Media, "HTMLMediaElement::sourceWasAdded(%p)", source);
3348
3349 #if !LOG_DISABLED
3350     if (source->hasTagName(sourceTag)) {
3351         KURL url = source->getNonEmptyURLAttribute(srcAttr);
3352         LOG(Media, "HTMLMediaElement::sourceWasAdded - 'src' is %s", urlForLogging(url).utf8().data());
3353     }
3354 #endif
3355
3356     // We should only consider a <source> element when there is not src attribute at all.
3357     if (fastHasAttribute(srcAttr))
3358         return;
3359
3360     // 4.8.8 - If a source element is inserted as a child of a media element that has no src
3361     // attribute and whose networkState has the value NETWORK_EMPTY, the user agent must invoke
3362     // the media element's resource selection algorithm.
3363     if (networkState() == HTMLMediaElement::NETWORK_EMPTY) {
3364         scheduleLoad(MediaResource);
3365         m_nextChildNodeToConsider = source;
3366         return;
3367     }
3368
3369     if (m_currentSourceNode && source == m_currentSourceNode->nextSibling()) {
3370         LOG(Media, "HTMLMediaElement::sourceWasAdded - <source> inserted immediately after current source");
3371         m_nextChildNodeToConsider = source;
3372         return;
3373     }
3374
3375     if (m_nextChildNodeToConsider)
3376         return;
3377
3378     // 4.8.9.5, resource selection algorithm, source elements section:
3379     // 21. Wait until the node after pointer is a node other than the end of the list. (This step might wait forever.)
3380     // 22. Asynchronously await a stable state...
3381     // 23. Set the element's delaying-the-load-event flag back to true (this delays the load event again, in case
3382     // it hasn't been fired yet).
3383     setShouldDelayLoadEvent(true);
3384
3385     // 24. Set the networkState back to NETWORK_LOADING.
3386     m_networkState = NETWORK_LOADING;
3387
3388     // 25. Jump back to the find next candidate step above.
3389     m_nextChildNodeToConsider = source;
3390     scheduleNextSourceChild();
3391 }
3392
3393 void HTMLMediaElement::sourceWasRemoved(HTMLSourceElement* source)
3394 {
3395     LOG(Media, "HTMLMediaElement::sourceWasRemoved(%p)", source);
3396
3397 #if !LOG_DISABLED
3398     if (source->hasTagName(sourceTag)) {
3399         KURL url = source->getNonEmptyURLAttribute(srcAttr);
3400         LOG(Media, "HTMLMediaElement::sourceWasRemoved - 'src' is %s", urlForLogging(url).utf8().data());
3401     }
3402 #endif
3403
3404     if (source != m_currentSourceNode && source != m_nextChildNodeToConsider)
3405         return;
3406
3407     if (source == m_nextChildNodeToConsider) {
3408         if (m_currentSourceNode)
3409             m_nextChildNodeToConsider = m_currentSourceNode->nextSibling();
3410         LOG(Media, "HTMLMediaElement::sourceRemoved - m_nextChildNodeToConsider set to %p", m_nextChildNodeToConsider.get());
3411     } else if (source == m_currentSourceNode) {
3412         // Clear the current source node pointer, but don't change the movie as the spec says:
3413         // 4.8.8 - Dynamically modifying a source element and its attribute when the element is already
3414         // inserted in a video or audio element will have no effect.
3415         m_currentSourceNode = 0;
3416         LOG(Media, "HTMLMediaElement::sourceRemoved - m_currentSourceNode set to 0");
3417     }
3418 }
3419
3420 void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
3421 {
3422     LOG(Media, "HTMLMediaElement::mediaPlayerTimeChanged");
3423
3424 #if ENABLE(VIDEO_TRACK)
3425     if (RuntimeEnabledFeatures::webkitVideoTrackEnabled())
3426         updateActiveTextTrackCues(currentTime());
3427 #endif
3428
3429     beginProcessingMediaPlayerCallback();
3430
3431     invalidateCachedTime();
3432
3433     // 4.8.10.9 step 14 & 15.  Needed if no ReadyState change is associated with the seek.
3434     if (m_seeking && m_readyState >= HAVE_CURRENT_DATA)
3435         finishSeek();
3436
3437     // Always call scheduleTimeupdateEvent when the media engine reports a time discontinuity,
3438     // it will only queue a 'timeupdate' event if we haven't already posted one at the current
3439     // movie time.
3440     scheduleTimeupdateEvent(false);
3441
3442     float now = currentTime();
3443     float dur = duration();
3444
3445     // When the current playback position reaches the end of the media resource when the direction of
3446     // playback is forwards, then the user agent must follow these steps:
3447     if (!isnan(dur) && dur && now >= dur && m_playbackRate > 0) {
3448         // If the media element has a loop attribute specified and does not have a current media controller,
3449         if (loop() && !m_mediaController) {
3450             ExceptionCode ignoredException;
3451             m_sentEndEvent = false;
3452             //  then seek to the earliest possible position of the media resource and abort these steps.
3453             seek(startTime(), ignoredException);
3454         } else {
3455             // If the media element does not have a current media controller, and the media element
3456             // has still ended playback, and the direction of playback is still forwards, and paused
3457             // is false,
3458             if (!m_mediaController && !m_paused) {
3459                 // changes paused to true and fires a simple event named pause at the media element.
3460                 m_paused = true;
3461                 scheduleEvent(eventNames().pauseEvent);
3462             }
3463             // Queue a task to fire a simple event named ended at the media element.
3464             if (!m_sentEndEvent) {
3465                 m_sentEndEvent = true;
3466                 scheduleEvent(eventNames().endedEvent);
3467             }
3468             // If the media element has a current media controller, then report the controller state
3469             // for the media element's current media controller.
3470             updateMediaController();
3471         }
3472     }
3473     else
3474         m_sentEndEvent = false;
3475
3476     updatePlayState();
3477     endProcessingMediaPlayerCallback();
3478 }
3479
3480 void HTMLMediaElement::mediaPlayerVolumeChanged(MediaPlayer*)
3481 {
3482     LOG(Media, "HTMLMediaElement::mediaPlayerVolumeChanged");
3483
3484     beginProcessingMediaPlayerCallback();
3485     if (m_player) {
3486         float vol = m_player->volume();
3487         if (vol != m_volume) {
3488             m_volume = vol;
3489             updateVolume();
3490             scheduleEvent(eventNames().volumechangeEvent);
3491         }
3492     }
3493     endProcessingMediaPlayerCallback();
3494 }
3495
3496 void HTMLMediaElement::mediaPlayerMuteChanged(MediaPlayer*)
3497 {
3498     LOG(Media, "HTMLMediaElement::mediaPlayerMuteChanged");
3499
3500     beginProcessingMediaPlayerCallback();
3501     if (m_player)
3502         setMuted(m_player->muted());
3503     endProcessingMediaPlayerCallback();
3504 }
3505
3506 void HTMLMediaElement::mediaPlayerDurationChanged(MediaPlayer* player)
3507 {
3508     LOG(Media, "HTMLMediaElement::mediaPlayerDurationChanged");
3509
3510     beginProcessingMediaPlayerCallback();
3511     scheduleEvent(eventNames().durationchangeEvent);
3512     mediaPlayerCharacteristicChanged(player);
3513     endProcessingMediaPlayerCallback();
3514 }
3515
3516 void HTMLMediaElement::mediaPlayerRateChanged(MediaPlayer*)
3517 {
3518     LOG(Media, "HTMLMediaElement::mediaPlayerRateChanged");
3519
3520     beginProcessingMediaPlayerCallback();
3521
3522     // Stash the rate in case the one we tried to set isn't what the engine is
3523     // using (eg. it can't handle the rate we set)
3524     m_playbackRate = m_player->rate();
3525     if (m_playing)
3526         invalidateCachedTime();
3527
3528 #if PLATFORM(MAC)
3529     updateDisableSleep();
3530 #endif
3531
3532     endProcessingMediaPlayerCallback();
3533 }
3534
3535 void HTMLMediaElement::mediaPlayerPlaybackStateChanged(MediaPlayer*)
3536 {
3537     LOG(Media, "HTMLMediaElement::mediaPlayerPlaybackStateChanged");
3538
3539     if (!m_player || m_pausedInternal)
3540         return;
3541
3542     beginProcessingMediaPlayerCallback();
3543     if (m_player->paused())
3544         pauseInternal();
3545     else
3546         playInternal();
3547     endProcessingMediaPlayerCallback();
3548 }
3549
3550 void HTMLMediaElement::mediaPlayerSawUnsupportedTracks(MediaPlayer*)
3551 {
3552     LOG(Media, "HTMLMediaElement::mediaPlayerSawUnsupportedTracks");
3553
3554     // The MediaPlayer came across content it cannot completely handle.
3555     // This is normally acceptable except when we are in a standalone
3556     // MediaDocument. If so, tell the document what has happened.
3557     if (ownerDocument()->isMediaDocument()) {
3558         MediaDocument* mediaDocument = static_cast<MediaDocument*>(ownerDocument());
3559         mediaDocument->mediaElementSawUnsupportedTracks();
3560     }
3561 }
3562
3563 void HTMLMediaElement::mediaPlayerResourceNotSupported(MediaPlayer*)
3564 {
3565     LOG(Media, "HTMLMediaElement::mediaPlayerResourceNotSupported");
3566
3567     // The MediaPlayer came across content which no installed engine supports.
3568     mediaLoadingFailed(MediaPlayer::FormatError);
3569 }
3570
3571 // MediaPlayerPresentation methods
3572 void HTMLMediaElement::mediaPlayerRepaint(MediaPlayer*)
3573 {
3574     beginProcessingMediaPlayerCallback();
3575     updateDisplayState();
3576     if (renderer())
3577         renderer()->repaint();
3578     endProcessingMediaPlayerCallback();
3579 }
3580
3581 void HTMLMediaElement::mediaPlayerSizeChanged(MediaPlayer*)
3582 {
3583     LOG(Media, "HTMLMediaElement::mediaPlayerSizeChanged");
3584
3585     beginProcessingMediaPlayerCallback();
3586     if (renderer())
3587         renderer()->updateFromElement();
3588     endProcessingMediaPlayerCallback();
3589 }
3590
3591 #if USE(ACCELERATED_COMPOSITING)
3592 bool HTMLMediaElement::mediaPlayerRenderingCanBeAccelerated(MediaPlayer*)
3593 {
3594     if (renderer() && renderer()->isVideo()) {
3595         ASSERT(renderer()->view());
3596         return renderer()->view()->compositor()->canAccelerateVideoRendering(toRenderVideo(renderer()));
3597     }
3598     return false;
3599 }
3600
3601 void HTMLMediaElement::mediaPlayerRenderingModeChanged(MediaPlayer*)
3602 {
3603     LOG(Media, "HTMLMediaElement::mediaPlayerRenderingModeChanged");
3604
3605     // Kick off a fake recalcStyle that will update the compositing tree.
3606     setNeedsStyleRecalc(SyntheticStyleChange);
3607 }
3608 #endif
3609
3610 #if PLATFORM(WIN) && USE(AVFOUNDATION)
3611 GraphicsDeviceAdapter* HTMLMediaElement::mediaPlayerGraphicsDeviceAdapter(const MediaPlayer*) const
3612 {
3613     if (!document() || !document()->page())
3614         return 0;
3615
3616     return document()->page()->chrome()->client()->graphicsDeviceAdapter();
3617 }
3618 #endif
3619
3620 void HTMLMediaElement::mediaPlayerEngineUpdated(MediaPlayer*)
3621 {
3622     LOG(Media, "HTMLMediaElement::mediaPlayerEngineUpdated");
3623     beginProcessingMediaPlayerCallback();
3624     if (renderer())
3625         renderer()->updateFromElement();
3626     endProcessingMediaPlayerCallback();
3627 }
3628
3629 void HTMLMediaElement::mediaPlayerFirstVideoFrameAvailable(MediaPlayer*)
3630 {
3631     LOG(Media, "HTMLMediaElement::mediaPlayerFirstVideoFrameAvailable");
3632     beginProcessingMediaPlayerCallback();
3633     if (displayMode() == PosterWaitingForVideo) {
3634         setDisplayMode(Video);
3635 #if USE(ACCELERATED_COMPOSITING)
3636         mediaPlayerRenderingModeChanged(m_player.get());
3637 #endif
3638     }
3639     endProcessingMediaPlayerCallback();
3640 }
3641
3642 void HTMLMediaElement::mediaPlayerCharacteristicChanged(MediaPlayer*)
3643 {
3644     LOG(Media, "HTMLMediaElement::mediaPlayerCharacteristicChanged");
3645
3646     beginProcessingMediaPlayerCallback();
3647     if (hasMediaControls())
3648         mediaControls()->reset();
3649     if (renderer())
3650         renderer()->updateFromElement();
3651     endProcessingMediaPlayerCallback();
3652 }
3653
3654 PassRefPtr<TimeRanges> HTMLMediaElement::buffered() const
3655 {
3656     if (!m_player)
3657         return TimeRanges::create();
3658     return m_player->buffered();
3659 }
3660
3661 PassRefPtr<TimeRanges> HTMLMediaElement::played()
3662 {
3663     if (m_playing) {
3664         float time = currentTime();
3665         if (time > m_lastSeekTime)
3666             addPlayedRange(m_lastSeekTime, time);
3667     }
3668
3669     if (!m_playedTimeRanges)
3670         m_playedTimeRanges = TimeRanges::create();
3671
3672     return m_playedTimeRanges->copy();
3673 }
3674
3675 PassRefPtr<TimeRanges> HTMLMediaElement::seekable() const
3676 {
3677     return m_player ? m_player->seekable() : TimeRanges::create();
3678 }
3679
3680 bool HTMLMediaElement::potentiallyPlaying() const
3681 {
3682     // "pausedToBuffer" means the media engine's rate is 0, but only because it had to stop playing
3683     // when it ran out of buffered data. A movie is this state is "potentially playing", modulo the
3684     // checks in couldPlayIfEnoughData().
3685     bool pausedToBuffer = m_readyStateMaximum >= HAVE_FUTURE_DATA && m_readyState < HAVE_FUTURE_DATA;
3686     return (pausedToBuffer || m_readyState >= HAVE_FUTURE_DATA) && couldPlayIfEnoughData() && !isBlockedOnMediaController();
3687 }
3688
3689 bool HTMLMediaElement::couldPlayIfEnoughData() const
3690 {
3691     return !paused() && !endedPlayback() && !stoppedDueToErrors() && !pausedForUserInteraction();
3692 }
3693
3694 bool HTMLMediaElement::endedPlayback() const
3695 {
3696     float dur = duration();
3697     if (!m_player || isnan(dur))
3698         return false;
3699
3700     // 4.8.10.8 Playing the media resource
3701
3702     // A media element is said to have ended playback when the element's
3703     // readyState attribute is HAVE_METADATA or greater,
3704     if (m_readyState < HAVE_METADATA)
3705         return false;
3706
3707     // and the current playback position is the end of the media resource and the direction
3708     // of playback is forwards, Either the media element does not have a loop attribute specified,
3709     // or the media element has a current media controller.
3710     float now = currentTime();
3711     if (m_playbackRate > 0)
3712         return dur > 0 && now >= dur && (!loop() || m_mediaController);
3713
3714     // or the current playback position is the earliest possible position and the direction
3715     // of playback is backwards
3716     if (m_playbackRate < 0)
3717         return now <= 0;
3718
3719     return false;
3720 }
3721
3722 bool HTMLMediaElement::stoppedDueToErrors() const
3723 {
3724     if (m_readyState >= HAVE_METADATA && m_error) {
3725         RefPtr<TimeRanges> seekableRanges = seekable();
3726         if (!seekableRanges->contain(currentTime()))
3727             return true;
3728     }
3729
3730     return false;
3731 }
3732
3733 bool HTMLMediaElement::pausedForUserInteraction() const
3734 {
3735 //    return !paused() && m_readyState >= HAVE_FUTURE_DATA && [UA requires a decitions from the user]
3736     return false;
3737 }
3738
3739 float HTMLMediaElement::minTimeSeekable() const
3740 {
3741     return 0;
3742 }
3743
3744 float HTMLMediaElement::maxTimeSeekable() const
3745 {
3746     return m_player ? m_player->maxTimeSeekable() : 0;
3747 }
3748
3749 void HTMLMediaElement::updateVolume()
3750 {
3751     if (!m_player)
3752         return;
3753
3754     // Avoid recursion when the player reports volume changes.
3755     if (!processingMediaPlayerCallback()) {
3756         Page* page = document()->page();
3757         float volumeMultiplier = page ? page->mediaVolume() : 1;
3758         bool shouldMute = m_muted;
3759
3760         if (m_mediaController) {
3761             volumeMultiplier *= m_mediaController->volume();
3762             shouldMute = m_mediaController->muted();
3763         }
3764
3765         m_player->setMuted(shouldMute);
3766         m_player->setVolume(m_volume * volumeMultiplier);
3767     }
3768
3769     if (hasMediaControls())
3770         mediaControls()->changedVolume();
3771 }
3772
3773 void HTMLMediaElement::updatePlayState()
3774 {
3775     if (!m_player)
3776         return;
3777
3778     if (m_pausedInternal) {
3779         if (!m_player->paused())
3780             m_player->pause();
3781         refreshCachedTime();
3782         m_playbackProgressTimer.stop();
3783         if (hasMediaControls())
3784             mediaControls()->playbackStopped();
3785         return;
3786     }
3787
3788     bool shouldBePlaying = potentiallyPlaying();
3789     bool playerPaused = m_player->paused();
3790
3791     LOG(Media, "HTMLMediaElement::updatePlayState - shouldBePlaying = %s, playerPaused = %s",
3792         boolString(shouldBePlaying), boolString(playerPaused));
3793
3794     if (shouldBePlaying) {
3795         setDisplayMode(Video);
3796         invalidateCachedTime();
3797
3798         if (playerPaused) {
3799             if (!m_isFullscreen && isVideo() && document() && document()->page() && document()->page()->chrome()->requiresFullscreenForVideoPlayback())
3800                 enterFullscreen();
3801
3802             // Set rate, muted before calling play in case they were set before the media engine was setup.
3803             // The media engine should just stash the rate and muted values since it isn't already playing.
3804             m_player->setRate(m_playbackRate);
3805             m_player->setMuted(m_muted);
3806
3807             m_player->play();
3808         }
3809
3810         if (hasMediaControls())
3811             mediaControls()->playbackStarted();
3812         startPlaybackProgressTimer();
3813         m_playing = true;
3814     } else { // Should not be playing right now
3815         if (!playerPaused)
3816             m_player->pause();
3817         refreshCachedTime();
3818
3819         m_playbackProgressTimer.stop();
3820         m_playing = false;
3821         float time = currentTime();
3822         if (time > m_lastSeekTime)
3823             addPlayedRange(m_lastSeekTime, time);
3824
3825         if (couldPlayIfEnoughData())
3826             prepareToPlay();
3827
3828         if (hasMediaControls())
3829             mediaControls()->playbackStopped();
3830     }
3831
3832     updateMediaController();
3833
3834     if (renderer())
3835         renderer()->updateFromElement();
3836 }
3837
3838 void HTMLMediaElement::setPausedInternal(bool b)
3839 {
3840     m_pausedInternal = b;
3841     updatePlayState();
3842 }
3843
3844 void HTMLMediaElement::stopPeriodicTimers()
3845 {
3846     m_progressEventTimer.stop();
3847     m_playbackProgressTimer.stop();
3848 }
3849
3850 void HTMLMediaElement::userCancelledLoad()
3851 {
3852     LOG(Media, "HTMLMediaElement::userCancelledLoad");
3853
3854     if (m_networkState == NETWORK_EMPTY || m_completelyLoaded)
3855         return;
3856
3857     // If the media data fetching process is aborted by the user:
3858
3859     // 1 - The user agent should cancel the fetching process.
3860 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
3861     m_player.clear();
3862 #endif
3863     stopPeriodicTimers();
3864     m_loadTimer.stop();
3865     m_loadState = WaitingForSource;
3866     m_pendingLoadFlags = 0;
3867
3868     // 2 - Set the error attribute to a new MediaError object whose code attribute is set to MEDIA_ERR_ABORTED.
3869     m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
3870
3871     // 3 - Queue a task to fire a simple event named error at the media element.
3872     scheduleEvent(eventNames().abortEvent);
3873
3874 #if ENABLE(MEDIA_SOURCE)
3875     if (m_sourceState != SOURCE_CLOSED)
3876         setSourceState(SOURCE_CLOSED);
3877 #endif
3878
3879     // 4 - If the media element's readyState attribute has a value equal to HAVE_NOTHING, set the
3880     // element's networkState attribute to the NETWORK_EMPTY value and queue a task to fire a
3881     // simple event named emptied at the element. Otherwise, set the element's networkState
3882     // attribute to the NETWORK_IDLE value.
3883     if (m_readyState == HAVE_NOTHING) {
3884         m_networkState = NETWORK_EMPTY;
3885         scheduleEvent(eventNames().emptiedEvent);
3886     }
3887     else
3888         m_networkState = NETWORK_IDLE;
3889
3890     // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
3891     setShouldDelayLoadEvent(false);
3892
3893     // 6 - Abort the overall resource selection algorithm.
3894     m_currentSourceNode = 0;
3895
3896     // Reset m_readyState since m_player is gone.
3897     m_readyState = HAVE_NOTHING;
3898     updateMediaController();
3899 #if ENABLE(VIDEO_TRACK)
3900     if (RuntimeEnabledFeatures::webkitVideoTrackEnabled())
3901         updateActiveTextTrackCues(0);
3902 #endif
3903 }
3904
3905 bool HTMLMediaElement::canSuspend() const
3906 {
3907     return true;
3908 }
3909
3910 void HTMLMediaElement::stop()
3911 {
3912     LOG(Media, "HTMLMediaElement::stop");
3913     if (m_isFullscreen)
3914         exitFullscreen();
3915
3916     m_inActiveDocument = false;
3917     userCancelledLoad();
3918
3919     // Stop the playback without generating events
3920     setPausedInternal(true);
3921
3922     if (renderer())
3923         renderer()->updateFromElement();
3924
3925     stopPeriodicTimers();
3926     cancelPendingEventsAndCallbacks();
3927 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
3928     if (isVideo())
3929         power_unlock_state(POWER_STATE_NORMAL);
3930 #endif
3931 }
3932
3933 void HTMLMediaElement::suspend(ReasonForSuspension why)
3934 {
3935     LOG(Media, "HTMLMediaElement::suspend");
3936 #if ENABLE(TIZEN_DLOG_SUPPORT)
3937     TIZEN_LOGI("Why: %d", why);
3938 #endif
3939
3940     switch (why)
3941     {
3942         case DocumentWillBecomeInactive:
3943             stop();
3944             break;
3945         case PageWillBeSuspended:
3946         case JavaScriptDebuggerPaused:
3947         case WillDeferLoading:
3948             // Do nothing, we don't pause media playback in these cases.
3949 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
3950             if (shouldSuspendMedia()) {
3951                 pause();
3952                 m_player->suspend();
3953                 m_suspended = true;
3954             }
3955 #endif
3956             break;
3957     }
3958 }
3959
3960 void HTMLMediaElement::resume()
3961 {
3962     LOG(Media, "HTMLMediaElement::resume");
3963
3964     m_inActiveDocument = true;
3965     setPausedInternal(false);
3966
3967     if (m_error && m_error->code() == MediaError::MEDIA_ERR_ABORTED) {
3968         // Restart the load if it was aborted in the middle by moving the document to the page cache.
3969         // m_error is only left at MEDIA_ERR_ABORTED when the document becomes inactive (it is set to
3970         //  MEDIA_ERR_ABORTED while the abortEvent is being sent, but cleared immediately afterwards).
3971         // This behavior is not specified but it seems like a sensible thing to do.
3972         // As it is not safe to immedately start loading now, let's schedule a load.
3973         scheduleLoad(MediaResource);
3974     }
3975
3976     if (renderer())
3977         renderer()->updateFromElement();
3978
3979 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
3980     // Player will resume asynchronously.
3981     // Set m_suspended to false in setSuspended().
3982     if (m_suspended)
3983         m_player->resume();
3984 #endif
3985 }
3986
3987 bool HTMLMediaElement::hasPendingActivity() const
3988 {
3989     return m_asyncEventQueue->hasPendingEvents();
3990 }
3991
3992 void HTMLMediaElement::mediaVolumeDidChange()
3993 {
3994     LOG(Media, "HTMLMediaElement::mediaVolumeDidChange");
3995     updateVolume();
3996 }
3997
3998 void HTMLMediaElement::defaultEventHandler(Event* event)
3999 {
4000 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
4001     RenderObject* r = renderer();
4002     if (!r || !r->isWidget())
4003         return;
4004
4005     Widget* widget = toRenderWidget(r)->widget();
4006     if (widget)
4007         widget->handleEvent(event);
4008 #else
4009     HTMLElement::defaultEventHandler(event);
4010 #endif
4011 }
4012
4013 bool HTMLMediaElement::willRespondToMouseClickEvents()
4014 {
4015 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
4016     return true;
4017 #else
4018     return HTMLElement::willRespondToMouseClickEvents();
4019 #endif
4020 }
4021
4022 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
4023
4024 void HTMLMediaElement::ensureMediaPlayer()
4025 {
4026     if (!m_player)
4027         createMediaPlayer();
4028 }
4029
4030 void HTMLMediaElement::deliverNotification(MediaPlayerProxyNotificationType notification)
4031 {
4032     if (notification == MediaPlayerNotificationPlayPauseButtonPressed) {
4033         togglePlayState();
4034         return;
4035     }
4036
4037     if (m_player)
4038         m_player->deliverNotification(notification);
4039 }
4040
4041 void HTMLMediaElement::setMediaPlayerProxy(WebMediaPlayerProxy* proxy)
4042 {
4043     ensureMediaPlayer();
4044     m_player->setMediaPlayerProxy(proxy);
4045 }
4046
4047 void HTMLMediaElement::getPluginProxyParams(KURL& url, Vector<String>& names, Vector<String>& values)
4048 {
4049     RefPtr<HTMLMediaElement> protect(this); // selectNextSourceChild may fire 'beforeload', which can make arbitrary DOM mutations.
4050
4051     Frame* frame = document()->frame();
4052
4053     if (isVideo()) {
4054         KURL posterURL = getNonEmptyURLAttribute(posterAttr);
4055         if (!posterURL.isEmpty() && frame && frame->loader()->willLoadMediaElementURL(posterURL)) {
4056             names.append("_media_element_poster_");
4057             values.append(posterURL.string());
4058         }
4059     }
4060
4061     if (controls()) {
4062         names.append("_media_element_controls_");
4063         values.append("true");
4064     }
4065
4066     url = src();
4067     if (!isSafeToLoadURL(url, Complain))
4068         url = selectNextSourceChild(0, 0, DoNothing);
4069
4070     m_currentSrc = url;
4071     if (url.isValid() && frame && frame->loader()->willLoadMediaElementURL(url)) {
4072         names.append("_media_element_src_");
4073         values.append(m_currentSrc.string());
4074     }
4075 }
4076
4077 void HTMLMediaElement::createMediaPlayerProxy()
4078 {
4079     ensureMediaPlayer();
4080
4081     if (m_proxyWidget || (inDocument() && !m_needWidgetUpdate))
4082         return;
4083
4084     Frame* frame = document()->frame();
4085     if (!frame)
4086         return;
4087
4088     LOG(Media, "HTMLMediaElement::createMediaPlayerProxy");
4089
4090     KURL url;
4091     Vector<String> paramNames;
4092     Vector<String> paramValues;
4093
4094     getPluginProxyParams(url, paramNames, paramValues);
4095
4096     // Hang onto the proxy widget so it won't be destroyed if the plug-in is set to
4097     // display:none
4098     m_proxyWidget = frame->loader()->subframeLoader()->loadMediaPlayerProxyPlugin(this, url, paramNames, paramValues);
4099     if (m_proxyWidget)
4100         m_needWidgetUpdate = false;
4101 }
4102
4103 void HTMLMediaElement::updateWidget(PluginCreationOption)
4104 {
4105     mediaElement->setNeedWidgetUpdate(false);
4106
4107     Vector<String> paramNames;
4108     Vector<String> paramValues;
4109     // FIXME: Rename kurl to something more sensible.
4110     KURL kurl;
4111
4112     mediaElement->getPluginProxyParams(kurl, paramNames, paramValues);
4113     // FIXME: What if document()->frame() is 0?
4114     SubframeLoader* loader = document()->frame()->loader()->subframeLoader();
4115     loader->loadMediaPlayerProxyPlugin(mediaElement, kurl, paramNames, paramValues);
4116 }
4117
4118 #endif // ENABLE(PLUGIN_PROXY_FOR_VIDEO)
4119
4120 bool HTMLMediaElement::isFullscreen() const
4121 {
4122     if (m_isFullscreen)
4123         return true;
4124
4125 #if ENABLE(FULLSCREEN_API)
4126     if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == this)
4127         return true;
4128 #endif
4129
4130     return false;
4131 }
4132
4133 void HTMLMediaElement::enterFullscreen()
4134 {
4135     LOG(Media, "HTMLMediaElement::enterFullscreen");
4136
4137 #if ENABLE(FULLSCREEN_API)
4138     if (document() && document()->settings() && document()->settings()->fullScreenEnabled()) {
4139         document()->requestFullScreenForElement(this, 0, Document::ExemptIFrameAllowFullScreenRequirement);
4140 #if ENABLE(TIZEN_FULLSCREEN_API)
4141         if (hasMediaControls())
4142             mediaControls()->updateMediaControlScale();
4143 #endif
4144         return;
4145     }
4146 #endif
4147     ASSERT(!m_isFullscreen);
4148     m_isFullscreen = true;
4149     if (hasMediaControls())
4150         mediaControls()->enteredFullscreen();
4151     if (document() && document()->page()) {
4152         document()->page()->chrome()->client()->enterFullscreenForNode(this);
4153         scheduleEvent(eventNames().webkitbeginfullscreenEvent);
4154     }
4155
4156 }
4157
4158 void HTMLMediaElement::exitFullscreen()
4159 {
4160     LOG(Media, "HTMLMediaElement::exitFullscreen");
4161
4162 #if ENABLE(FULLSCREEN_API)
4163     if (document() && document()->settings() && document()->settings()->fullScreenEnabled()) {
4164         if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == this)
4165             document()->webkitCancelFullScreen();
4166         return;
4167     }
4168 #endif
4169     ASSERT(m_isFullscreen);
4170     m_isFullscreen = false;
4171     if (hasMediaControls())
4172         mediaControls()->exitedFullscreen();
4173     if (document() && document()->page()) {
4174         if (document()->page()->chrome()->requiresFullscreenForVideoPlayback())
4175             pauseInternal();
4176         document()->page()->chrome()->client()->exitFullscreenForNode(this);
4177         scheduleEvent(eventNames().webkitendfullscreenEvent);
4178     }
4179 }
4180
4181 #if ENABLE(TIZEN_FULLSCREEN_API)
4182 void HTMLMediaElement::updateMediaControlsStyle(bool needsRecalc)
4183 {
4184     if (hasMediaControls())
4185         mediaControls()->updateMediaControlScale();
4186
4187     if (needsRecalc)
4188         recalcStyle(Node::Force);
4189 }
4190 #endif
4191
4192 void HTMLMediaElement::didBecomeFullscreenElement()
4193 {
4194     if (hasMediaControls())
4195         mediaControls()->enteredFullscreen();
4196 }
4197
4198 void HTMLMediaElement::willStopBeingFullscreenElement()
4199 {
4200     if (hasMediaControls())
4201         mediaControls()->exitedFullscreen();
4202 }
4203
4204 PlatformMedia HTMLMediaElement::platformMedia() const
4205 {
4206     return m_player ? m_player->platformMedia() : NoPlatformMedia;
4207 }
4208
4209 #if USE(ACCELERATED_COMPOSITING)
4210 PlatformLayer* HTMLMediaElement::platformLayer() const
4211 {
4212     return m_player ? m_player->platformLayer() : 0;
4213 }
4214 #endif
4215
4216 bool HTMLMediaElement::hasClosedCaptions() const
4217 {
4218     if (m_player && m_player->hasClosedCaptions())
4219         return true;
4220
4221 #if ENABLE(VIDEO_TRACK)
4222     if (RuntimeEnabledFeatures::webkitVideoTrackEnabled() && m_textTracks)
4223     for (unsigned i = 0; i < m_textTracks->length(); ++i) {
4224         if (m_textTracks->item(i)->kind() == TextTrack::captionsKeyword()
4225             || m_textTracks->item(i)->kind() == TextTrack::subtitlesKeyword())
4226             return true;
4227     }
4228 #endif
4229     return false;
4230 }
4231
4232 bool HTMLMediaElement::closedCaptionsVisible() const
4233 {
4234     return m_closedCaptionsVisible;
4235 }
4236
4237 void HTMLMediaElement::setClosedCaptionsVisible(bool closedCaptionVisible)
4238 {
4239     LOG(Media, "HTMLMediaElement::setClosedCaptionsVisible(%s)", boolString(closedCaptionVisible));
4240
4241     if (!m_player || !hasClosedCaptions())
4242         return;
4243
4244     m_closedCaptionsVisible = closedCaptionVisible;
4245     m_player->setClosedCaptionsVisible(closedCaptionVisible);
4246
4247 #if ENABLE(VIDEO_TRACK)
4248     if (RuntimeEnabledFeatures::webkitVideoTrackEnabled()) {
4249         m_disableCaptions = !m_closedCaptionsVisible;
4250         
4251         // Mark all track elements as not "configured" so that configureTextTracks()
4252         // will reconsider which tracks to display in light of new user preferences
4253         // (e.g. default tracks should not be displayed if the user has turned off
4254         // captions and non-default tracks should be displayed based on language
4255         // preferences if the user has turned captions on).
4256         for (Node* node = firstChild(); node; node = node->nextSibling()) {
4257             if (!node->hasTagName(trackTag))
4258                 continue;
4259             HTMLTrackElement* trackElement = static_cast<HTMLTrackElement*>(node);
4260             if (trackElement->kind() == TextTrack::captionsKeyword()
4261                 || trackElement->kind() == TextTrack::subtitlesKeyword())
4262                 trackElement->setHasBeenConfigured(false);
4263         }
4264
4265         configureTextTracks();
4266     }
4267 #else
4268     if (hasMediaControls())
4269         mediaControls()->changedClosedCaptionsVisibility();
4270 #endif
4271 }
4272
4273 void HTMLMediaElement::setWebkitClosedCaptionsVisible(bool visible)
4274 {
4275     setClosedCaptionsVisible(visible);
4276 }
4277
4278 bool HTMLMediaElement::webkitClosedCaptionsVisible() const
4279 {
4280     return closedCaptionsVisible();
4281 }
4282
4283
4284 bool HTMLMediaElement::webkitHasClosedCaptions() const
4285 {
4286     return hasClosedCaptions();
4287 }
4288
4289 #if ENABLE(MEDIA_STATISTICS)
4290 unsigned HTMLMediaElement::webkitAudioDecodedByteCount() const
4291 {
4292     if (!m_player)
4293         return 0;
4294     return m_player->audioDecodedByteCount();
4295 }
4296
4297 unsigned HTMLMediaElement::webkitVideoDecodedByteCount() const
4298 {
4299     if (!m_player)
4300         return 0;
4301     return m_player->videoDecodedByteCount();
4302 }
4303 #endif
4304
4305 void HTMLMediaElement::mediaCanStart()
4306 {
4307     LOG(Media, "HTMLMediaElement::mediaCanStart");
4308
4309     ASSERT(m_isWaitingUntilMediaCanStart);
4310     m_isWaitingUntilMediaCanStart = false;
4311     loadInternal();
4312 }
4313
4314 bool HTMLMediaElement::isURLAttribute(const Attribute& attribute) const
4315 {
4316     return attribute.name() == srcAttr || HTMLElement::isURLAttribute(attribute);
4317 }
4318
4319 void HTMLMediaElement::setShouldDelayLoadEvent(bool shouldDelay)
4320 {
4321     if (m_shouldDelayLoadEvent == shouldDelay)
4322         return;
4323
4324     LOG(Media, "HTMLMediaElement::setShouldDelayLoadEvent(%s)", boolString(shouldDelay));
4325
4326     m_shouldDelayLoadEvent = shouldDelay;
4327     if (shouldDelay)
4328         document()->incrementLoadEventDelayCount();
4329     else
4330         document()->decrementLoadEventDelayCount();
4331 }
4332
4333
4334 void HTMLMediaElement::getSitesInMediaCache(Vector<String>& sites)
4335 {
4336     MediaPlayer::getSitesInMediaCache(sites);
4337 }
4338
4339 void HTMLMediaElement::clearMediaCache()
4340 {
4341     MediaPlayer::clearMediaCache();
4342 }
4343
4344 void HTMLMediaElement::clearMediaCacheForSite(const String& site)
4345 {
4346     MediaPlayer::clearMediaCacheForSite(site);
4347 }
4348
4349 void HTMLMediaElement::privateBrowsingStateDidChange()
4350 {
4351     if (!m_player)
4352         return;
4353
4354     Settings* settings = document()->settings();
4355     bool privateMode = !settings || settings->privateBrowsingEnabled();
4356     LOG(Media, "HTMLMediaElement::privateBrowsingStateDidChange(%s)", boolString(privateMode));
4357     m_player->setPrivateBrowsingMode(privateMode);
4358 }
4359
4360 MediaControls* HTMLMediaElement::mediaControls() const
4361 {
4362     return toMediaControls(userAgentShadowRoot()->firstChild());
4363 }
4364
4365 bool HTMLMediaElement::hasMediaControls() const
4366 {
4367     if (ShadowRoot* userAgent = userAgentShadowRoot()) {
4368         Node* node = userAgent->firstChild();
4369         ASSERT(!node || node->isMediaControls());
4370         return node;
4371     }
4372
4373     return false;
4374 }
4375
4376 bool HTMLMediaElement::createMediaControls()
4377 {
4378     if (hasMediaControls())
4379         return true;
4380
4381     ExceptionCode ec;
4382     RefPtr<MediaControls> controls = MediaControls::create(document());
4383     if (!controls)
4384         return false;
4385
4386     controls->setMediaController(m_mediaController ? m_mediaController.get() : static_cast<MediaControllerInterface*>(this));
4387     controls->reset();
4388 #if ENABLE(TIZEN_FULLSCREEN_API)
4389     if (isFullscreen())
4390         controls->updateMediaControlScale();
4391 #endif
4392     if (isFullscreen())
4393         controls->enteredFullscreen();
4394
4395     if (!shadow())
4396         createShadowSubtree();
4397
4398     ASSERT(userAgentShadowRoot());
4399     userAgentShadowRoot()->appendChild(controls, ec);
4400     return true;
4401 }
4402
4403 void HTMLMediaElement::configureMediaControls()
4404 {
4405 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
4406     if (!controls() || !inDocument()) {
4407         if (hasMediaControls())
4408             mediaControls()->hide();
4409         return;
4410     }
4411
4412     if (!hasMediaControls() && !createMediaControls())
4413         return;
4414
4415     mediaControls()->show();
4416 #else
4417     if (m_player)
4418         m_player->setControls(controls());
4419 #endif
4420 }
4421
4422 #if ENABLE(VIDEO_TRACK)
4423 void HTMLMediaElement::configureTextTrackDisplay()
4424 {
4425     ASSERT(m_textTracks);
4426
4427     bool haveVisibleTextTrack = false;
4428     for (unsigned i = 0; i < m_textTracks->length(); ++i) {
4429         if (m_textTracks->item(i)->mode() == TextTrack::showingKeyword()) {
4430             haveVisibleTextTrack = true;
4431             break;
4432         }
4433     }
4434
4435     if (m_haveVisibleTextTrack == haveVisibleTextTrack)
4436         return;
4437     m_haveVisibleTextTrack = haveVisibleTextTrack;
4438     m_closedCaptionsVisible = m_haveVisibleTextTrack;
4439
4440     if (!m_haveVisibleTextTrack && !hasMediaControls())
4441         return;
4442     if (!hasMediaControls() && !createMediaControls())
4443         return;
4444
4445     updateClosedCaptionsControls();
4446 }
4447
4448 void HTMLMediaElement::updateClosedCaptionsControls()
4449 {
4450     if (hasMediaControls()) {
4451         mediaControls()->changedClosedCaptionsVisibility();
4452
4453         if (RuntimeEnabledFeatures::webkitVideoTrackEnabled())
4454             mediaControls()->updateTextTrackDisplay();
4455     }
4456 }
4457 #endif
4458
4459 void* HTMLMediaElement::preDispatchEventHandler(Event* event)
4460 {
4461     if (event && event->type() == eventNames().webkitfullscreenchangeEvent) {
4462         configureMediaControls();
4463 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
4464         if (!isFullscreen())
4465             scheduleEvent(eventNames().webkitendfullscreenEvent);
4466 #endif
4467     }
4468
4469     return 0;
4470 }
4471
4472 void HTMLMediaElement::createMediaPlayer()
4473 {
4474 #if ENABLE(WEB_AUDIO)
4475     if (m_audioSourceNode)
4476         m_audioSourceNode->lock();
4477 #endif
4478
4479     m_player = MediaPlayer::create(this);
4480
4481 #if ENABLE(WEB_AUDIO)
4482     if (m_audioSourceNode) {
4483         // When creating the player, make sure its AudioSourceProvider knows about the MediaElementAudioSourceNode.
4484         if (audioSourceProvider())
4485             audioSourceProvider()->setClient(m_audioSourceNode);
4486
4487         m_audioSourceNode->unlock();
4488     }
4489 #endif
4490 }
4491
4492 #if ENABLE(WEB_AUDIO)
4493 void HTMLMediaElement::setAudioSourceNode(MediaElementAudioSourceNode* sourceNode)
4494 {
4495     m_audioSourceNode = sourceNode;
4496
4497     if (audioSourceProvider())
4498         audioSourceProvider()->setClient(m_audioSourceNode);
4499 }
4500
4501 AudioSourceProvider* HTMLMediaElement::audioSourceProvider()
4502 {
4503     if (m_player)
4504         return m_player->audioSourceProvider();
4505
4506     return 0;
4507 }
4508 #endif
4509
4510 #if ENABLE(MICRODATA)
4511 String HTMLMediaElement::itemValueText() const
4512 {
4513     return getURLAttribute(srcAttr);
4514 }
4515
4516 void HTMLMediaElement::setItemValueText(const String& value, ExceptionCode&)
4517 {
4518     setAttribute(srcAttr, value);
4519 }
4520 #endif
4521
4522 const String& HTMLMediaElement::mediaGroup() const
4523 {
4524     return m_mediaGroup;
4525 }
4526
4527 void HTMLMediaElement::setMediaGroup(const String& group)
4528 {
4529     if (m_mediaGroup == group)
4530         return;
4531     m_mediaGroup = group;
4532
4533     // When a media element is created with a mediagroup attribute, and when a media element's mediagroup
4534     // attribute is set, changed, or removed, the user agent must run the following steps:
4535     // 1. Let m [this] be the media element in question.
4536     // 2. Let m have no current media controller, if it currently has one.
4537     setController(0);
4538
4539     // 3. If m's mediagroup attribute is being removed, then abort these steps.
4540     if (group.isNull() || group.isEmpty())
4541         return;
4542
4543     // 4. If there is another media element whose Document is the same as m's Document (even if one or both
4544     // of these elements are not actually in the Document),
4545     HashSet<HTMLMediaElement*> elements = documentToElementSetMap().get(document());
4546     for (HashSet<HTMLMediaElement*>::iterator i = elements.begin(); i != elements.end(); ++i) {
4547         if (*i == this)
4548             continue;
4549
4550         // and which also has a mediagroup attribute, and whose mediagroup attribute has the same value as
4551         // the new value of m's mediagroup attribute,
4552         if ((*i)->mediaGroup() == group) {
4553             //  then let controller be that media element's current media controller.
4554             setController((*i)->controller());
4555             return;
4556         }
4557     }
4558
4559     // Otherwise, let controller be a newly created MediaController.
4560     setController(MediaController::create(Node::scriptExecutionContext()));
4561 }
4562
4563 MediaController* HTMLMediaElement::controller() const
4564 {
4565     return m_mediaController.get();
4566 }
4567
4568 void HTMLMediaElement::setController(PassRefPtr<MediaController> controller)
4569 {
4570     if (m_mediaController)
4571         m_mediaController->removeMediaElement(this);
4572
4573     m_mediaController = controller;
4574
4575     if (m_mediaController)
4576         m_mediaController->addMediaElement(this);
4577
4578     if (hasMediaControls())
4579         mediaControls()->setMediaController(m_mediaController ? m_mediaController.get() : static_cast<MediaControllerInterface*>(this));
4580 }
4581
4582 void HTMLMediaElement::updateMediaController()
4583 {
4584     if (m_mediaController)
4585         m_mediaController->reportControllerState();
4586 }
4587
4588 bool HTMLMediaElement::dispatchEvent(PassRefPtr<Event> event)
4589 {
4590     bool dispatchResult;
4591     bool isCanPlayEvent;
4592
4593     isCanPlayEvent = (event->type() == eventNames().canplayEvent);
4594
4595     if (isCanPlayEvent)
4596         m_dispatchingCanPlayEvent = true;
4597
4598     dispatchResult = HTMLElement::dispatchEvent(event);
4599
4600     if (isCanPlayEvent)
4601         m_dispatchingCanPlayEvent = false;
4602
4603     return dispatchResult;
4604 }
4605
4606 bool HTMLMediaElement::isBlocked() const
4607 {
4608     // A media element is a blocked media element if its readyState attribute is in the
4609     // HAVE_NOTHING state, the HAVE_METADATA state, or the HAVE_CURRENT_DATA state,
4610     if (m_readyState <= HAVE_CURRENT_DATA)
4611         return true;
4612
4613     // or if the element has paused for user interaction.
4614     return pausedForUserInteraction();
4615 }
4616
4617 bool HTMLMediaElement::isBlockedOnMediaController() const
4618 {
4619     if (!m_mediaController)
4620         return false;
4621
4622     // A media element is blocked on its media controller if the MediaController is a blocked
4623     // media controller,
4624     if (m_mediaController->isBlocked())
4625         return true;
4626
4627     // or if its media controller position is either before the media resource's earliest possible
4628     // position relative to the MediaController's timeline or after the end of the media resource
4629     // relative to the MediaController's timeline.
4630     float mediaControllerPosition = m_mediaController->currentTime();
4631     if (mediaControllerPosition < startTime() || mediaControllerPosition > startTime() + duration())
4632         return true;
4633
4634     return false;
4635 }
4636
4637 void HTMLMediaElement::prepareMediaFragmentURI()
4638 {
4639     MediaFragmentURIParser fragmentParser(m_currentSrc);
4640     float dur = duration();
4641
4642     double start = fragmentParser.startTime();
4643     if (start != MediaFragmentURIParser::invalidTimeValue() && start > 0) {
4644         m_fragmentStartTime = start;
4645         if (m_fragmentStartTime > dur)
4646             m_fragmentStartTime = dur;
4647     } else
4648         m_fragmentStartTime = MediaPlayer::invalidTime();
4649
4650     double end = fragmentParser.endTime();
4651     if (end != MediaFragmentURIParser::invalidTimeValue() && end > 0 && end > m_fragmentStartTime) {
4652         m_fragmentEndTime = end;
4653         if (m_fragmentEndTime > dur)
4654             m_fragmentEndTime = dur;
4655     } else
4656         m_fragmentEndTime = MediaPlayer::invalidTime();
4657
4658     if (m_fragmentStartTime != MediaPlayer::invalidTime() && m_readyState < HAVE_FUTURE_DATA)
4659         prepareToPlay();
4660 }
4661
4662 void HTMLMediaElement::applyMediaFragmentURI()
4663 {
4664     if (m_fragmentStartTime != MediaPlayer::invalidTime()) {
4665         ExceptionCode ignoredException;
4666         m_sentEndEvent = false;
4667         seek(m_fragmentStartTime, ignoredException);
4668     }
4669 }
4670
4671 #if PLATFORM(MAC)
4672 void HTMLMediaElement::updateDisableSleep()
4673 {
4674     if (!shouldDisableSleep() && m_sleepDisabler)
4675         m_sleepDisabler = nullptr;
4676     else if (shouldDisableSleep() && !m_sleepDisabler)
4677         m_sleepDisabler = DisplaySleepDisabler::create("com.apple.WebCore: HTMLMediaElement playback");
4678 }
4679
4680 bool HTMLMediaElement::shouldDisableSleep() const
4681 {
4682     return m_player && !m_player->paused() && hasVideo() && hasAudio() && !loop();
4683 }
4684 #endif
4685
4686 String HTMLMediaElement::mediaPlayerReferrer() const
4687 {
4688     Frame* frame = document()->frame();
4689     if (!frame)
4690         return String();
4691
4692     return SecurityPolicy::generateReferrerHeader(document()->referrerPolicy(), m_currentSrc, frame->loader()->outgoingReferrer());
4693 }
4694
4695 String HTMLMediaElement::mediaPlayerUserAgent() const
4696 {
4697     Frame* frame = document()->frame();
4698     if (!frame)
4699         return String();
4700
4701     return frame->loader()->userAgent(m_currentSrc);
4702
4703 }
4704
4705 MediaPlayerClient::CORSMode HTMLMediaElement::mediaPlayerCORSMode() const
4706 {
4707     if (!fastHasAttribute(HTMLNames::crossoriginAttr))
4708         return Unspecified;
4709     if (equalIgnoringCase(fastGetAttribute(HTMLNames::crossoriginAttr), "use-credentials"))
4710         return UseCredentials;
4711     return Anonymous;
4712 }
4713
4714 bool HTMLMediaElement::mediaPlayerNeedsSiteSpecificHacks() const
4715 {
4716     Settings* settings = document()->settings();
4717     return settings && settings->needsSiteSpecificQuirks();
4718 }
4719
4720 String HTMLMediaElement::mediaPlayerDocumentHost() const
4721 {
4722     return document()->url().host();
4723 }
4724
4725 void HTMLMediaElement::mediaPlayerExitFullscreen()
4726 {
4727     exitFullscreen();
4728 }
4729
4730 bool HTMLMediaElement::mediaPlayerIsVideo() const
4731 {
4732     return isVideo();
4733 }
4734
4735 LayoutRect HTMLMediaElement::mediaPlayerContentBoxRect() const
4736 {
4737     if (renderer())
4738         return renderer()->enclosingBox()->contentBoxRect();
4739     return LayoutRect();
4740 }
4741
4742 void HTMLMediaElement::mediaPlayerSetSize(const IntSize& size)
4743 {
4744     setAttribute(widthAttr, String::number(size.width()));
4745     setAttribute(heightAttr, String::number(size.height()));
4746 }
4747
4748 void HTMLMediaElement::mediaPlayerPause()
4749 {
4750     pause();
4751 }
4752
4753 void HTMLMediaElement::mediaPlayerPlay()
4754 {
4755     play();
4756 }
4757
4758 bool HTMLMediaElement::mediaPlayerIsPaused() const
4759 {
4760     return paused();
4761 }
4762
4763 bool HTMLMediaElement::mediaPlayerIsLooping() const
4764 {
4765     return loop();
4766 }
4767
4768 HostWindow* HTMLMediaElement::mediaPlayerHostWindow()
4769 {
4770     return mediaPlayerOwningDocument()->view()->hostWindow();
4771 }
4772
4773 IntRect HTMLMediaElement::mediaPlayerWindowClipRect()
4774 {
4775     return mediaPlayerOwningDocument()->view()->windowClipRect();
4776 }
4777
4778 void HTMLMediaElement::removeBehaviorsRestrictionsAfterFirstUserGesture()
4779 {
4780     m_restrictions = NoRestrictions;
4781 }
4782
4783 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
4784 bool HTMLMediaElement::shouldSuspendMedia()
4785 {
4786     if (!m_player)
4787         return false;
4788
4789     if (isVideo())
4790         return true;
4791
4792 #if ENABLE(TIZEN_EXTENSIBLE_API)
4793     if (!TizenExtensibleAPI::extensibleAPI().backgroundMusic())
4794         return true;
4795 #endif
4796
4797     return false;
4798 }
4799
4800 void HTMLMediaElement::setSuspended(bool suspended)
4801 {
4802     m_suspended = suspended;
4803 }
4804 #endif
4805
4806 }
4807 #endif