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