2011-05-24 Adam Barth <abarth@webkit.org>
[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 "Attribute.h"
32 #include "Chrome.h"
33 #include "ChromeClient.h"
34 #include "ClientRect.h"
35 #include "ClientRectList.h"
36 #include "ContentSecurityPolicy.h"
37 #include "ContentType.h"
38 #include "CSSPropertyNames.h"
39 #include "CSSValueKeywords.h"
40 #include "Event.h"
41 #include "EventNames.h"
42 #include "ExceptionCode.h"
43 #include "Frame.h"
44 #include "FrameLoader.h"
45 #include "FrameLoaderClient.h"
46 #include "FrameView.h"
47 #include "HTMLDocument.h"
48 #include "HTMLNames.h"
49 #include "HTMLSourceElement.h"
50 #include "HTMLVideoElement.h"
51 #include "Logging.h"
52 #include "MediaControls.h"
53 #include "MediaDocument.h"
54 #include "MediaError.h"
55 #include "MediaList.h"
56 #include "MediaPlayer.h"
57 #include "MediaQueryEvaluator.h"
58 #include "MouseEvent.h"
59 #include "MIMETypeRegistry.h"
60 #include "Page.h"
61 #include "RenderVideo.h"
62 #include "RenderView.h"
63 #include "ScriptEventListener.h"
64 #include "SecurityOrigin.h"
65 #include "Settings.h"
66 #include "ShadowRoot.h"
67 #include "TimeRanges.h"
68 #include <limits>
69 #include <wtf/CurrentTime.h>
70 #include <wtf/MathExtras.h>
71 #include <wtf/text/CString.h>
72
73 #if USE(ACCELERATED_COMPOSITING)
74 #include "RenderView.h"
75 #include "RenderLayerCompositor.h"
76 #endif
77
78 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
79 #include "RenderEmbeddedObject.h"
80 #include "Widget.h"
81 #endif
82
83 using namespace std;
84
85 namespace WebCore {
86
87 #if !LOG_DISABLED
88 static String urlForLogging(const String& url)
89 {
90     static const unsigned maximumURLLengthForLogging = 128;
91
92     if (url.length() < maximumURLLengthForLogging)
93         return url;
94     return url.substring(0, maximumURLLengthForLogging) + "...";
95 }
96
97 static const char *boolString(bool val)
98 {
99     return val ? "true" : "false";
100 }
101 #endif
102
103 #ifndef LOG_MEDIA_EVENTS
104 // Default to not logging events because so many are generated they can overwhelm the rest of 
105 // the logging.
106 #define LOG_MEDIA_EVENTS 0
107 #endif
108
109 #ifndef LOG_CACHED_TIME_WARNINGS
110 // Default to not logging warnings about excessive drift in the cached media time because it adds a
111 // fair amount of overhead and logging.
112 #define LOG_CACHED_TIME_WARNINGS 0
113 #endif
114
115 static const float invalidMediaTime = -1;
116
117 using namespace HTMLNames;
118
119 HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* document)
120     : HTMLElement(tagName, document)
121     , ActiveDOMObject(document, this)
122     , m_loadTimer(this, &HTMLMediaElement::loadTimerFired)
123     , m_asyncEventTimer(this, &HTMLMediaElement::asyncEventTimerFired)
124     , m_progressEventTimer(this, &HTMLMediaElement::progressEventTimerFired)
125     , m_playbackProgressTimer(this, &HTMLMediaElement::playbackProgressTimerFired)
126     , m_playedTimeRanges()
127     , m_playbackRate(1.0f)
128     , m_defaultPlaybackRate(1.0f)
129     , m_webkitPreservesPitch(true)
130     , m_networkState(NETWORK_EMPTY)
131     , m_readyState(HAVE_NOTHING)
132     , m_readyStateMaximum(HAVE_NOTHING)
133     , m_volume(1.0f)
134     , m_lastSeekTime(0)
135     , m_previousProgress(0)
136     , m_previousProgressTime(numeric_limits<double>::max())
137     , m_lastTimeUpdateEventWallTime(0)
138     , m_lastTimeUpdateEventMovieTime(numeric_limits<float>::max())
139     , m_loadState(WaitingForSource)
140     , m_currentSourceNode(0)
141     , m_nextChildNodeToConsider(0)
142 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
143     , m_proxyWidget(0)
144 #endif
145     , m_restrictions(RequireUserGestureForFullScreenRestriction)
146     , m_preload(MediaPlayer::Auto)
147     , m_displayMode(Unknown)
148     , m_processingMediaPlayerCallback(0)
149     , m_cachedTime(invalidMediaTime)
150     , m_cachedTimeWallClockUpdateTime(0)
151     , m_minimumWallClockTimeToCacheMediaTime(0)
152     , m_playing(false)
153     , m_isWaitingUntilMediaCanStart(false)
154     , m_shouldDelayLoadEvent(false)
155     , m_haveFiredLoadedData(false)
156     , m_inActiveDocument(true)
157     , m_autoplaying(true)
158     , m_muted(false)
159     , m_paused(true)
160     , m_seeking(false)
161     , m_sentStalledEvent(false)
162     , m_sentEndEvent(false)
163     , m_pausedInternal(false)
164     , m_sendProgressEvents(true)
165     , m_isFullscreen(false)
166     , m_closedCaptionsVisible(false)
167     , m_mouseOver(false)
168 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
169     , m_needWidgetUpdate(false)
170 #endif
171     , m_dispatchingCanPlayEvent(false)
172     , m_loadInitiatedByUserGesture(false)
173     , m_completelyLoaded(false)
174     , m_havePreparedToPlay(false)
175 {
176     LOG(Media, "HTMLMediaElement::HTMLMediaElement");
177     document->registerForDocumentActivationCallbacks(this);
178     document->registerForMediaVolumeCallbacks(this);
179     document->registerForPrivateBrowsingStateChangedCallbacks(this);
180 }
181
182 HTMLMediaElement::~HTMLMediaElement()
183 {
184     LOG(Media, "HTMLMediaElement::~HTMLMediaElement");
185     if (m_isWaitingUntilMediaCanStart)
186         document()->removeMediaCanStartListener(this);
187     setShouldDelayLoadEvent(false);
188     document()->unregisterForDocumentActivationCallbacks(this);
189     document()->unregisterForMediaVolumeCallbacks(this);
190     document()->unregisterForPrivateBrowsingStateChangedCallbacks(this);
191 }
192
193 void HTMLMediaElement::willMoveToNewOwnerDocument()
194 {
195     if (m_isWaitingUntilMediaCanStart)
196         document()->removeMediaCanStartListener(this);
197     setShouldDelayLoadEvent(false);
198     document()->unregisterForDocumentActivationCallbacks(this);
199     document()->unregisterForMediaVolumeCallbacks(this);
200     HTMLElement::willMoveToNewOwnerDocument();
201 }
202
203 void HTMLMediaElement::didMoveToNewOwnerDocument()
204 {
205     if (m_isWaitingUntilMediaCanStart)
206         document()->addMediaCanStartListener(this);
207     if (m_readyState < HAVE_CURRENT_DATA)
208         setShouldDelayLoadEvent(true);
209     document()->registerForDocumentActivationCallbacks(this);
210     document()->registerForMediaVolumeCallbacks(this);
211     HTMLElement::didMoveToNewOwnerDocument();
212 }
213
214 void HTMLMediaElement::attributeChanged(Attribute* attr, bool preserveDecls)
215 {
216     HTMLElement::attributeChanged(attr, preserveDecls);
217
218     const QualifiedName& attrName = attr->name();
219     if (attrName == srcAttr) {
220         // Trigger a reload, as long as the 'src' attribute is present.
221         if (!getAttribute(srcAttr).isEmpty())
222             scheduleLoad();
223     }
224     else if (attrName == controlsAttr) {
225 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
226         if (controls()) {
227             if (!hasMediaControls()) {
228                 ensureMediaControls();
229                 mediaControls()->reset();
230             }
231             mediaControls()->show();
232         } else if (hasMediaControls())
233             mediaControls()->hide();
234 #else
235         if (m_player)
236             m_player->setControls(controls());
237 #endif
238     }
239 }
240
241 void HTMLMediaElement::parseMappedAttribute(Attribute* attr)
242 {
243     const QualifiedName& attrName = attr->name();
244
245     if (attrName == preloadAttr) {
246         String value = attr->value();
247
248         if (equalIgnoringCase(value, "none"))
249             m_preload = MediaPlayer::None;
250         else if (equalIgnoringCase(value, "metadata"))
251             m_preload = MediaPlayer::MetaData;
252         else {
253             // The spec does not define an "invalid value default" but "auto" is suggested as the
254             // "missing value default", so use it for everything except "none" and "metadata"
255             m_preload = MediaPlayer::Auto;
256         }
257
258         // The attribute must be ignored if the autoplay attribute is present
259         if (!autoplay() && m_player)
260             m_player->setPreload(m_preload);
261
262     } else if (attrName == onabortAttr)
263         setAttributeEventListener(eventNames().abortEvent, createAttributeEventListener(this, attr));
264     else if (attrName == onbeforeloadAttr)
265         setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, attr));
266     else if (attrName == oncanplayAttr)
267         setAttributeEventListener(eventNames().canplayEvent, createAttributeEventListener(this, attr));
268     else if (attrName == oncanplaythroughAttr)
269         setAttributeEventListener(eventNames().canplaythroughEvent, createAttributeEventListener(this, attr));
270     else if (attrName == ondurationchangeAttr)
271         setAttributeEventListener(eventNames().durationchangeEvent, createAttributeEventListener(this, attr));
272     else if (attrName == onemptiedAttr)
273         setAttributeEventListener(eventNames().emptiedEvent, createAttributeEventListener(this, attr));
274     else if (attrName == onendedAttr)
275         setAttributeEventListener(eventNames().endedEvent, createAttributeEventListener(this, attr));
276     else if (attrName == onerrorAttr)
277         setAttributeEventListener(eventNames().errorEvent, createAttributeEventListener(this, attr));
278     else if (attrName == onloadeddataAttr)
279         setAttributeEventListener(eventNames().loadeddataEvent, createAttributeEventListener(this, attr));
280     else if (attrName == onloadedmetadataAttr)
281         setAttributeEventListener(eventNames().loadedmetadataEvent, createAttributeEventListener(this, attr));
282     else if (attrName == onloadstartAttr)
283         setAttributeEventListener(eventNames().loadstartEvent, createAttributeEventListener(this, attr));
284     else if (attrName == onpauseAttr)
285         setAttributeEventListener(eventNames().pauseEvent, createAttributeEventListener(this, attr));
286     else if (attrName == onplayAttr)
287         setAttributeEventListener(eventNames().playEvent, createAttributeEventListener(this, attr));
288     else if (attrName == onplayingAttr)
289         setAttributeEventListener(eventNames().playingEvent, createAttributeEventListener(this, attr));
290     else if (attrName == onprogressAttr)
291         setAttributeEventListener(eventNames().progressEvent, createAttributeEventListener(this, attr));
292     else if (attrName == onratechangeAttr)
293         setAttributeEventListener(eventNames().ratechangeEvent, createAttributeEventListener(this, attr));
294     else if (attrName == onseekedAttr)
295         setAttributeEventListener(eventNames().seekedEvent, createAttributeEventListener(this, attr));
296     else if (attrName == onseekingAttr)
297         setAttributeEventListener(eventNames().seekingEvent, createAttributeEventListener(this, attr));
298     else if (attrName == onstalledAttr)
299         setAttributeEventListener(eventNames().stalledEvent, createAttributeEventListener(this, attr));
300     else if (attrName == onsuspendAttr)
301         setAttributeEventListener(eventNames().suspendEvent, createAttributeEventListener(this, attr));
302     else if (attrName == ontimeupdateAttr)
303         setAttributeEventListener(eventNames().timeupdateEvent, createAttributeEventListener(this, attr));
304     else if (attrName == onvolumechangeAttr)
305         setAttributeEventListener(eventNames().volumechangeEvent, createAttributeEventListener(this, attr));
306     else if (attrName == onwaitingAttr)
307         setAttributeEventListener(eventNames().waitingEvent, createAttributeEventListener(this, attr));
308     else if (attrName == onwebkitbeginfullscreenAttr)
309         setAttributeEventListener(eventNames().webkitbeginfullscreenEvent, createAttributeEventListener(this, attr));
310     else if (attrName == onwebkitendfullscreenAttr)
311         setAttributeEventListener(eventNames().webkitendfullscreenEvent, createAttributeEventListener(this, attr));
312     else
313         HTMLElement::parseMappedAttribute(attr);
314 }
315
316 bool HTMLMediaElement::rendererIsNeeded(const NodeRenderingContext& context)
317 {
318 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
319     UNUSED_PARAM(context);
320     Frame* frame = document()->frame();
321     if (!frame)
322         return false;
323
324     return true;
325 #else
326     return controls() ? HTMLElement::rendererIsNeeded(context) : false;
327 #endif
328 }
329
330 RenderObject* HTMLMediaElement::createRenderer(RenderArena* arena, RenderStyle*)
331 {
332 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
333     // Setup the renderer if we already have a proxy widget.
334     RenderEmbeddedObject* mediaRenderer = new (arena) RenderEmbeddedObject(this);
335     if (m_proxyWidget) {
336         mediaRenderer->setWidget(m_proxyWidget);
337
338         Frame* frame = document()->frame();
339         FrameLoader* loader = frame ? frame->loader() : 0;
340         if (loader)
341             loader->showMediaPlayerProxyPlugin(m_proxyWidget.get());
342     }
343     return mediaRenderer;
344 #else
345     return new (arena) RenderMedia(this);
346 #endif
347 }
348  
349 void HTMLMediaElement::insertedIntoDocument()
350 {
351     LOG(Media, "HTMLMediaElement::removedFromDocument");
352     HTMLElement::insertedIntoDocument();
353     if (!getAttribute(srcAttr).isEmpty() && m_networkState == NETWORK_EMPTY)
354         scheduleLoad();
355 }
356
357 void HTMLMediaElement::removedFromDocument()
358 {
359     LOG(Media, "HTMLMediaElement::removedFromDocument");
360     if (m_networkState > NETWORK_EMPTY)
361         pause(processingUserGesture());
362     if (m_isFullscreen)
363         exitFullscreen();
364     HTMLElement::removedFromDocument();
365 }
366
367 void HTMLMediaElement::attach()
368 {
369     ASSERT(!attached());
370
371 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
372     m_needWidgetUpdate = true;
373 #endif
374
375     HTMLElement::attach();
376
377     if (renderer())
378         renderer()->updateFromElement();
379 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
380     else if (m_proxyWidget) {
381         Frame* frame = document()->frame();
382         FrameLoader* loader = frame ? frame->loader() : 0;
383         if (loader)
384             loader->hideMediaPlayerProxyPlugin(m_proxyWidget.get());
385     }
386 #endif
387 }
388
389 void HTMLMediaElement::recalcStyle(StyleChange change)
390 {
391     HTMLElement::recalcStyle(change);
392
393     if (renderer())
394         renderer()->updateFromElement();
395 }
396
397 void HTMLMediaElement::scheduleLoad()
398 {
399     LOG(Media, "HTMLMediaElement::scheduleLoad");
400 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
401     createMediaPlayerProxy();
402 #endif
403
404     if (m_loadTimer.isActive())
405         return;
406     prepareForLoad();
407     m_loadTimer.startOneShot(0);
408 }
409
410 void HTMLMediaElement::scheduleNextSourceChild()
411 {
412     // Schedule the timer to try the next <source> element WITHOUT resetting state ala prepareForLoad.
413     m_loadTimer.startOneShot(0);
414 }
415
416 void HTMLMediaElement::scheduleEvent(const AtomicString& eventName)
417 {
418 #if LOG_MEDIA_EVENTS
419     LOG(Media, "HTMLMediaElement::scheduleEvent - scheduling '%s'", eventName.string().ascii().data());
420 #endif
421     m_pendingEvents.append(Event::create(eventName, false, true));
422     if (!m_asyncEventTimer.isActive())
423         m_asyncEventTimer.startOneShot(0);
424 }
425
426 void HTMLMediaElement::asyncEventTimerFired(Timer<HTMLMediaElement>*)
427 {
428     Vector<RefPtr<Event> > pendingEvents;
429     ExceptionCode ec = 0;
430
431     m_pendingEvents.swap(pendingEvents);
432     unsigned count = pendingEvents.size();
433     for (unsigned ndx = 0; ndx < count; ++ndx) {
434 #if LOG_MEDIA_EVENTS
435         LOG(Media, "HTMLMediaElement::asyncEventTimerFired - dispatching '%s'", pendingEvents[ndx]->type().string().ascii().data());
436 #endif
437         if (pendingEvents[ndx]->type() == eventNames().canplayEvent) {
438             m_dispatchingCanPlayEvent = true;
439             dispatchEvent(pendingEvents[ndx].release(), ec);
440             m_dispatchingCanPlayEvent = false;
441         } else
442             dispatchEvent(pendingEvents[ndx].release(), ec);
443     }
444 }
445
446 void HTMLMediaElement::loadTimerFired(Timer<HTMLMediaElement>*)
447 {
448     if (m_loadState == LoadingFromSourceElement)
449         loadNextSourceChild();
450     else
451         loadInternal();
452 }
453
454 PassRefPtr<MediaError> HTMLMediaElement::error() const 
455 {
456     return m_error;
457 }
458
459 void HTMLMediaElement::setSrc(const String& url)
460 {
461     setAttribute(srcAttr, url);
462 }
463
464 String HTMLMediaElement::currentSrc() const
465 {
466     return m_currentSrc;
467 }
468
469 HTMLMediaElement::NetworkState HTMLMediaElement::networkState() const
470 {
471     return m_networkState;
472 }
473
474 String HTMLMediaElement::canPlayType(const String& mimeType) const
475 {
476     MediaPlayer::SupportsType support = MediaPlayer::supportsType(ContentType(mimeType));
477     String canPlay;
478
479     // 4.8.10.3
480     switch (support)
481     {
482         case MediaPlayer::IsNotSupported:
483             canPlay = "";
484             break;
485         case MediaPlayer::MayBeSupported:
486             canPlay = "maybe";
487             break;
488         case MediaPlayer::IsSupported:
489             canPlay = "probably";
490             break;
491     }
492     
493     LOG(Media, "HTMLMediaElement::canPlayType(%s) -> %s", mimeType.utf8().data(), canPlay.utf8().data());
494
495     return canPlay;
496 }
497
498 void HTMLMediaElement::load(bool isUserGesture, ExceptionCode& ec)
499 {
500     LOG(Media, "HTMLMediaElement::load(isUserGesture : %s)", boolString(isUserGesture));
501
502     if (m_restrictions & RequireUserGestureForLoadRestriction && !isUserGesture)
503         ec = INVALID_STATE_ERR;
504     else {
505         m_loadInitiatedByUserGesture = isUserGesture;
506         prepareForLoad();
507         loadInternal();
508     }
509 }
510
511 void HTMLMediaElement::prepareForLoad()
512 {
513     LOG(Media, "HTMLMediaElement::prepareForLoad");
514
515     // Perform the cleanup required for the resource load algorithm to run.
516     stopPeriodicTimers();
517     m_loadTimer.stop();
518     m_sentStalledEvent = false;
519     m_haveFiredLoadedData = false;
520     m_completelyLoaded = false;
521     m_havePreparedToPlay = false;
522     m_displayMode = Unknown;
523
524     // 1 - Abort any already-running instance of the resource selection algorithm for this element.
525     m_loadState = WaitingForSource;
526     m_currentSourceNode = 0;
527
528     // 2 - If there are any tasks from the media element's media element event task source in 
529     // one of the task queues, then remove those tasks.
530     cancelPendingEventsAndCallbacks();
531
532     // 3 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, queue
533     // a task to fire a simple event named abort at the media element.
534     if (m_networkState == NETWORK_LOADING || m_networkState == NETWORK_IDLE)
535         scheduleEvent(eventNames().abortEvent);
536
537 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
538     m_player = MediaPlayer::create(this);
539 #else
540     if (m_player)
541         m_player->cancelLoad();
542     else
543         createMediaPlayerProxy();
544 #endif
545
546     // 4 - If the media element's networkState is not set to NETWORK_EMPTY, then run these substeps
547     if (m_networkState != NETWORK_EMPTY) {
548         m_networkState = NETWORK_EMPTY;
549         m_readyState = HAVE_NOTHING;
550         m_readyStateMaximum = HAVE_NOTHING;
551         refreshCachedTime();
552         m_paused = true;
553         m_seeking = false;
554         invalidateCachedTime();
555         scheduleEvent(eventNames().emptiedEvent);
556     }
557
558     // 5 - Set the playbackRate attribute to the value of the defaultPlaybackRate attribute.
559     setPlaybackRate(defaultPlaybackRate());
560
561     // 6 - Set the error attribute to null and the autoplaying flag to true.
562     m_error = 0;
563     m_autoplaying = true;
564
565     // 7 - Invoke the media element's resource selection algorithm.
566
567     // 8 - Note: Playback of any previously playing media resource for this element stops.
568
569     // The resource selection algorithm
570     // 1 - Set the networkState to NETWORK_NO_SOURCE
571     m_networkState = NETWORK_NO_SOURCE;
572
573     // 2 - Asynchronously await a stable state.
574
575     m_playedTimeRanges = TimeRanges::create();
576     m_lastSeekTime = 0;
577     m_closedCaptionsVisible = false;
578
579     // The spec doesn't say to block the load event until we actually run the asynchronous section
580     // algorithm, but do it now because we won't start that until after the timer fires and the 
581     // event may have already fired by then.
582     setShouldDelayLoadEvent(true);
583 }
584
585 void HTMLMediaElement::loadInternal()
586 {
587     // If we can't start a load right away, start it later.
588     Page* page = document()->page();
589     if (page && !page->canStartMedia()) {
590         if (m_isWaitingUntilMediaCanStart)
591             return;
592         document()->addMediaCanStartListener(this);
593         m_isWaitingUntilMediaCanStart = true;
594         return;
595     }
596
597     selectMediaResource();
598 }
599
600 void HTMLMediaElement::selectMediaResource()
601 {
602     LOG(Media, "HTMLMediaElement::selectMediaResource");
603
604     enum Mode { attribute, children };
605     Mode mode = attribute;
606
607     // 3 - ... the media element has neither a src attribute ...
608     if (!hasAttribute(srcAttr)) {
609         // ... nor a source element child: ...
610         Node* node;
611         for (node = firstChild(); node; node = node->nextSibling()) {
612             if (node->hasTagName(sourceTag))
613                 break;
614         }
615
616         if (!node) {
617             m_loadState = WaitingForSource;
618             setShouldDelayLoadEvent(false);
619
620             // ... set the networkState to NETWORK_EMPTY, and abort these steps
621             m_networkState = NETWORK_EMPTY;
622
623             LOG(Media, "HTMLMediaElement::selectMediaResource, nothing to load");
624             return;
625         }
626
627         mode = children;
628     }
629
630     // 4 - Set the media element's delaying-the-load-event flag to true (this delays the load event), 
631     // and set its networkState to NETWORK_LOADING.
632     setShouldDelayLoadEvent(true);
633     m_networkState = NETWORK_LOADING;
634
635     // 5
636     scheduleEvent(eventNames().loadstartEvent);
637
638     // 6 - If mode is attribute, then run these substeps
639     if (mode == attribute) {
640         // If the src attribute's value is the empty string ... jump down to the failed step below
641         KURL mediaURL = getNonEmptyURLAttribute(srcAttr);
642         if (mediaURL.isEmpty()) {
643             noneSupported();
644             LOG(Media, "HTMLMediaElement::selectMediaResource, empty 'src'");
645             return;
646         }
647
648         if (isSafeToLoadURL(mediaURL, Complain) && dispatchBeforeLoadEvent(mediaURL.string())) {
649             ContentType contentType("");
650             m_loadState = LoadingFromSrcAttr;
651             loadResource(mediaURL, contentType);
652         } else 
653             noneSupported();
654
655         LOG(Media, "HTMLMediaElement::selectMediaResource, 'src' not used");
656         return;
657     }
658
659     // Otherwise, the source elements will be used
660     m_currentSourceNode = 0;
661     loadNextSourceChild();
662 }
663
664 void HTMLMediaElement::loadNextSourceChild()
665 {
666     ContentType contentType("");
667     KURL mediaURL = selectNextSourceChild(&contentType, Complain);
668     if (!mediaURL.isValid()) {
669         waitForSourceChange();
670         return;
671     }
672
673 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
674     // Recreate the media player for the new url
675     m_player = MediaPlayer::create(this);
676 #endif
677
678     m_loadState = LoadingFromSourceElement;
679     loadResource(mediaURL, contentType);
680 }
681
682 void HTMLMediaElement::loadResource(const KURL& initialURL, ContentType& contentType)
683 {
684     ASSERT(isSafeToLoadURL(initialURL, Complain));
685
686     LOG(Media, "HTMLMediaElement::loadResource(%s, %s)", urlForLogging(initialURL.string()).utf8().data(), contentType.raw().utf8().data());
687
688     Frame* frame = document()->frame();
689     if (!frame)
690         return;
691     FrameLoader* loader = frame->loader();
692     if (!loader)
693         return;
694
695     KURL url(initialURL);
696     if (!loader->willLoadMediaElementURL(url))
697         return;
698
699     // The resource fetch algorithm 
700     m_networkState = NETWORK_LOADING;
701
702     m_currentSrc = url;
703
704     LOG(Media, "HTMLMediaElement::loadResource - m_currentSrc -> %s", urlForLogging(m_currentSrc).utf8().data());
705
706     if (m_sendProgressEvents) 
707         startProgressEventTimer();
708
709     Settings* settings = document()->settings();
710     bool privateMode = !settings || settings->privateBrowsingEnabled();
711     m_player->setPrivateBrowsingMode(privateMode);
712
713     // Reset display mode to force a recalculation of what to show because we are resetting the player.
714     setDisplayMode(Unknown);
715
716     if (!autoplay())
717         m_player->setPreload(m_preload);
718     m_player->setPreservesPitch(m_webkitPreservesPitch);
719     updateVolume();
720
721     m_player->load(m_currentSrc, contentType);
722
723     // If there is no poster to display, allow the media engine to render video frames as soon as
724     // they are available.
725     updateDisplayState();
726
727     if (renderer())
728         renderer()->updateFromElement();
729 }
730
731 bool HTMLMediaElement::isSafeToLoadURL(const KURL& url, InvalidSourceAction actionIfInvalid)
732 {
733     if (!url.isValid()) {
734         LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%s) -> FALSE because url is invalid", urlForLogging(url.string()).utf8().data());
735         return false;
736     }
737
738     Frame* frame = document()->frame();
739     if (!frame || !document()->securityOrigin()->canDisplay(url)) {
740         if (actionIfInvalid == Complain)
741             FrameLoader::reportLocalLoadFailed(frame, url.string());
742         LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%s) -> FALSE rejected by SecurityOrigin", urlForLogging(url.string()).utf8().data());
743         return false;
744     }
745
746     if (!document()->contentSecurityPolicy()->allowMediaFromSource(url))
747         return false;
748
749     return true;
750 }
751
752 void HTMLMediaElement::startProgressEventTimer()
753 {
754     if (m_progressEventTimer.isActive())
755         return;
756
757     m_previousProgressTime = WTF::currentTime();
758     m_previousProgress = 0;
759     // 350ms is not magic, it is in the spec!
760     m_progressEventTimer.startRepeating(0.350);
761 }
762
763 void HTMLMediaElement::waitForSourceChange()
764 {
765     LOG(Media, "HTMLMediaElement::waitForSourceChange");
766
767     stopPeriodicTimers();
768     m_loadState = WaitingForSource;
769
770     // 6.17 - Waiting: Set the element's networkState attribute to the NETWORK_NO_SOURCE value
771     m_networkState = NETWORK_NO_SOURCE;
772
773     // 6.18 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
774     setShouldDelayLoadEvent(false);
775
776     updateDisplayState();
777
778     if (renderer())
779         renderer()->updateFromElement();
780 }
781
782 void HTMLMediaElement::noneSupported()
783 {
784     LOG(Media, "HTMLMediaElement::noneSupported");
785
786     stopPeriodicTimers();
787     m_loadState = WaitingForSource;
788     m_currentSourceNode = 0;
789
790     // 5 - Reaching this step indicates that either the URL failed to resolve, or the media
791     // resource failed to load. Set the error attribute to a new MediaError object whose
792     // code attribute is set to MEDIA_ERR_SRC_NOT_SUPPORTED.
793     m_error = MediaError::create(MediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
794
795     // 6 - Set the element's networkState attribute to the NETWORK_NO_SOURCE value.
796     m_networkState = NETWORK_NO_SOURCE;
797
798     // 7 - Queue a task to fire a progress event called error at the media element, in
799     // the context of the fetching process that was used to try to obtain the media
800     // resource in the resource fetch algorithm.
801     scheduleEvent(eventNames().errorEvent);
802
803     // 8 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
804     setShouldDelayLoadEvent(false);
805
806     // 9 -Abort these steps. Until the load() method is invoked, the element won't attempt to load another resource.
807
808     updateDisplayState();
809
810     if (renderer())
811         renderer()->updateFromElement();
812 }
813
814 void HTMLMediaElement::mediaEngineError(PassRefPtr<MediaError> err)
815 {
816     LOG(Media, "HTMLMediaElement::mediaEngineError(%d)", static_cast<int>(err->code()));
817
818     // 1 - The user agent should cancel the fetching process.
819     stopPeriodicTimers();
820     m_loadState = WaitingForSource;
821
822     // 2 - Set the error attribute to a new MediaError object whose code attribute is 
823     // set to MEDIA_ERR_NETWORK/MEDIA_ERR_DECODE.
824     m_error = err;
825
826     // 3 - Queue a task to fire a simple event named error at the media element.
827     scheduleEvent(eventNames().errorEvent);
828
829     // 4 - Set the element's networkState attribute to the NETWORK_EMPTY value and queue a
830     // task to fire a simple event called emptied at the element.
831     m_networkState = NETWORK_EMPTY;
832     scheduleEvent(eventNames().emptiedEvent);
833
834     // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
835     setShouldDelayLoadEvent(false);
836
837     // 6 - Abort the overall resource selection algorithm.
838     m_currentSourceNode = 0;
839 }
840
841 void HTMLMediaElement::cancelPendingEventsAndCallbacks()
842 {
843     LOG(Media, "HTMLMediaElement::cancelPendingEventsAndCallbacks");
844
845     m_pendingEvents.clear();
846
847     for (Node* node = firstChild(); node; node = node->nextSibling()) {
848         if (node->hasTagName(sourceTag))
849             static_cast<HTMLSourceElement*>(node)->cancelPendingErrorEvent();
850     }
851 }
852
853 Document* HTMLMediaElement::mediaPlayerOwningDocument()
854 {
855     Document* d = document();
856     
857     if (!d)
858         d = ownerDocument();
859     
860     return d;
861 }
862
863 void HTMLMediaElement::mediaPlayerNetworkStateChanged(MediaPlayer*)
864 {
865     beginProcessingMediaPlayerCallback();
866     setNetworkState(m_player->networkState());
867     endProcessingMediaPlayerCallback();
868 }
869
870 void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
871 {
872     LOG(Media, "HTMLMediaElement::setNetworkState(%d) - current state is %d", static_cast<int>(state), static_cast<int>(m_networkState));
873
874     if (state == MediaPlayer::Empty) {
875         // Just update the cached state and leave, we can't do anything.
876         m_networkState = NETWORK_EMPTY;
877         return;
878     }
879
880     if (state == MediaPlayer::FormatError || state == MediaPlayer::NetworkError || state == MediaPlayer::DecodeError) {
881         stopPeriodicTimers();
882
883         // If we failed while trying to load a <source> element, the movie was never parsed, and there are more
884         // <source> children, schedule the next one
885         if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement) {
886
887             if (m_currentSourceNode)
888                 m_currentSourceNode->scheduleErrorEvent();
889             else
890                 LOG(Media, "HTMLMediaElement::setNetworkState - error event not sent, <source> was removed");
891
892             if (havePotentialSourceChild()) {
893                 LOG(Media, "HTMLMediaElement::setNetworkState - scheduling next <source>");
894                 scheduleNextSourceChild();
895             } else {
896                 LOG(Media, "HTMLMediaElement::setNetworkState - no more <source> elements, waiting");
897                 waitForSourceChange();
898             }
899
900             return;
901         }
902
903         if (state == MediaPlayer::NetworkError)
904             mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_NETWORK));
905         else if (state == MediaPlayer::DecodeError)
906             mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_DECODE));
907         else if (state == MediaPlayer::FormatError && m_loadState == LoadingFromSrcAttr)
908             noneSupported();
909
910         updateDisplayState();
911         if (hasMediaControls())
912             mediaControls()->reportedError();
913         return;
914     }
915
916     if (state == MediaPlayer::Idle) {
917         if (m_networkState > NETWORK_IDLE) {
918             m_progressEventTimer.stop();
919             scheduleEvent(eventNames().suspendEvent);
920             setShouldDelayLoadEvent(false);
921         }
922         m_networkState = NETWORK_IDLE;
923     }
924
925     if (state == MediaPlayer::Loading) {
926         if (m_networkState < NETWORK_LOADING || m_networkState == NETWORK_NO_SOURCE)
927             startProgressEventTimer();
928         m_networkState = NETWORK_LOADING;
929     }
930
931     if (state == MediaPlayer::Loaded) {
932         if (m_networkState != NETWORK_IDLE) {
933             m_progressEventTimer.stop();
934
935             // Schedule one last progress event so we guarantee that at least one is fired
936             // for files that load very quickly.
937             scheduleEvent(eventNames().progressEvent);
938         }
939         m_networkState = NETWORK_IDLE;
940         m_completelyLoaded = true;
941     }
942
943     if (hasMediaControls())
944         mediaControls()->updateStatusDisplay();
945 }
946
947 void HTMLMediaElement::mediaPlayerReadyStateChanged(MediaPlayer*)
948 {
949     beginProcessingMediaPlayerCallback();
950
951     setReadyState(m_player->readyState());
952
953     endProcessingMediaPlayerCallback();
954 }
955
956 void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
957 {
958     LOG(Media, "HTMLMediaElement::setReadyState(%d) - current state is %d,", static_cast<int>(state), static_cast<int>(m_readyState));
959
960     // Set "wasPotentiallyPlaying" BEFORE updating m_readyState, potentiallyPlaying() uses it
961     bool wasPotentiallyPlaying = potentiallyPlaying();
962
963     ReadyState oldState = m_readyState;
964     m_readyState = static_cast<ReadyState>(state);
965
966     if (m_readyState == oldState)
967         return;
968     
969     if (oldState > m_readyStateMaximum)
970         m_readyStateMaximum = oldState;
971
972     if (m_networkState == NETWORK_EMPTY)
973         return;
974
975     if (m_seeking) {
976         // 4.8.10.9, step 11
977         if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA)
978             scheduleEvent(eventNames().waitingEvent);
979
980         // 4.8.10.10 step 14 & 15.
981         if (m_readyState >= HAVE_CURRENT_DATA)
982             finishSeek();
983     } else {
984         if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA) {
985             // 4.8.10.8
986             scheduleTimeupdateEvent(false);
987             scheduleEvent(eventNames().waitingEvent);
988         }
989     }
990
991     if (m_readyState >= HAVE_METADATA && oldState < HAVE_METADATA) {
992         scheduleEvent(eventNames().durationchangeEvent);
993         scheduleEvent(eventNames().loadedmetadataEvent);
994         if (hasMediaControls())
995             mediaControls()->loadedMetadata();
996         if (renderer())
997             renderer()->updateFromElement();
998     }
999
1000     bool shouldUpdateDisplayState = false;
1001
1002     if (m_readyState >= HAVE_CURRENT_DATA && oldState < HAVE_CURRENT_DATA && !m_haveFiredLoadedData) {
1003         m_haveFiredLoadedData = true;
1004         shouldUpdateDisplayState = true;
1005         scheduleEvent(eventNames().loadeddataEvent);
1006         setShouldDelayLoadEvent(false);
1007     }
1008
1009     bool isPotentiallyPlaying = potentiallyPlaying();
1010     if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA) {
1011         scheduleEvent(eventNames().canplayEvent);
1012         if (isPotentiallyPlaying)
1013             scheduleEvent(eventNames().playingEvent);
1014         shouldUpdateDisplayState = true;
1015     }
1016
1017     if (m_readyState == HAVE_ENOUGH_DATA && oldState < HAVE_ENOUGH_DATA) {
1018         if (oldState <= HAVE_CURRENT_DATA)
1019             scheduleEvent(eventNames().canplayEvent);
1020
1021         scheduleEvent(eventNames().canplaythroughEvent);
1022
1023         if (isPotentiallyPlaying && oldState <= HAVE_CURRENT_DATA)
1024             scheduleEvent(eventNames().playingEvent);
1025
1026         if (m_autoplaying && m_paused && autoplay()) {
1027             m_paused = false;
1028             invalidateCachedTime();
1029             scheduleEvent(eventNames().playEvent);
1030             scheduleEvent(eventNames().playingEvent);
1031         }
1032
1033         shouldUpdateDisplayState = true;
1034     }
1035
1036     if (shouldUpdateDisplayState) {
1037         updateDisplayState();
1038         if (hasMediaControls())
1039             mediaControls()->updateStatusDisplay();
1040     }
1041
1042     updatePlayState();
1043 }
1044
1045 void HTMLMediaElement::progressEventTimerFired(Timer<HTMLMediaElement>*)
1046 {
1047     ASSERT(m_player);
1048     if (m_networkState != NETWORK_LOADING)
1049         return;
1050
1051     unsigned progress = m_player->bytesLoaded();
1052     double time = WTF::currentTime();
1053     double timedelta = time - m_previousProgressTime;
1054
1055     if (progress == m_previousProgress) {
1056         if (timedelta > 3.0 && !m_sentStalledEvent) {
1057             scheduleEvent(eventNames().stalledEvent);
1058             m_sentStalledEvent = true;
1059             setShouldDelayLoadEvent(false);
1060         }
1061     } else {
1062         scheduleEvent(eventNames().progressEvent);
1063         m_previousProgress = progress;
1064         m_previousProgressTime = time;
1065         m_sentStalledEvent = false;
1066         if (renderer())
1067             renderer()->updateFromElement();
1068     }
1069 }
1070
1071 void HTMLMediaElement::rewind(float timeDelta)
1072 {
1073     LOG(Media, "HTMLMediaElement::rewind(%f)", timeDelta);
1074
1075     ExceptionCode e;
1076     setCurrentTime(max(currentTime() - timeDelta, minTimeSeekable()), e);
1077 }
1078
1079 void HTMLMediaElement::returnToRealtime()
1080 {
1081     LOG(Media, "HTMLMediaElement::returnToRealtime");
1082     ExceptionCode e;
1083     setCurrentTime(maxTimeSeekable(), e);
1084 }  
1085
1086 void HTMLMediaElement::addPlayedRange(float start, float end)
1087 {
1088     LOG(Media, "HTMLMediaElement::addPlayedRange(%f, %f)", start, end);
1089     if (!m_playedTimeRanges)
1090         m_playedTimeRanges = TimeRanges::create();
1091     m_playedTimeRanges->add(start, end);
1092 }  
1093
1094 bool HTMLMediaElement::supportsSave() const
1095 {
1096     return m_player ? m_player->supportsSave() : false;
1097 }
1098
1099 void HTMLMediaElement::prepareToPlay()
1100 {
1101     if (m_havePreparedToPlay)
1102         return;
1103     m_havePreparedToPlay = true;
1104     m_player->prepareToPlay();
1105 }
1106
1107 void HTMLMediaElement::seek(float time, ExceptionCode& ec)
1108 {
1109     LOG(Media, "HTMLMediaElement::seek(%f)", time);
1110
1111     // 4.8.9.9 Seeking
1112
1113     // 1 - If the media element's readyState is HAVE_NOTHING, then raise an INVALID_STATE_ERR exception.
1114     if (m_readyState == HAVE_NOTHING || !m_player) {
1115         ec = INVALID_STATE_ERR;
1116         return;
1117     }
1118
1119     // If the media engine has been told to postpone loading data, let it go ahead now.
1120     if (m_preload < MediaPlayer::Auto && m_readyState < HAVE_FUTURE_DATA)
1121         prepareToPlay();
1122
1123     // Get the current time before setting m_seeking, m_lastSeekTime is returned once it is set.
1124     refreshCachedTime();
1125     float now = currentTime();
1126
1127     // 2 - If the element's seeking IDL attribute is true, then another instance of this algorithm is
1128     // already running. Abort that other instance of the algorithm without waiting for the step that
1129     // it is running to complete.
1130     // Nothing specific to be done here.
1131
1132     // 3 - Set the seeking IDL attribute to true.
1133     // The flag will be cleared when the engine tells us the time has actually changed.
1134     m_seeking = true;
1135
1136     // 5 - If the new playback position is later than the end of the media resource, then let it be the end 
1137     // of the media resource instead.
1138     time = min(time, duration());
1139
1140     // 6 - If the new playback position is less than the earliest possible position, let it be that position instead.
1141     float earliestTime = m_player->startTime();
1142     time = max(time, earliestTime);
1143
1144     // Ask the media engine for the time value in the movie's time scale before comparing with current time. This
1145     // is necessary because if the seek time is not equal to currentTime but the delta is less than the movie's
1146     // time scale, we will ask the media engine to "seek" to the current movie time, which may be a noop and
1147     // not generate a timechanged callback. This means m_seeking will never be cleared and we will never 
1148     // fire a 'seeked' event.
1149 #if !LOG_DISABLED
1150     float mediaTime = m_player->mediaTimeForTimeValue(time);
1151     if (time != mediaTime)
1152         LOG(Media, "HTMLMediaElement::seek(%f) - media timeline equivalent is %f", time, mediaTime);
1153 #endif
1154     time = m_player->mediaTimeForTimeValue(time);
1155
1156     // 7 - If the (possibly now changed) new playback position is not in one of the ranges given in the 
1157     // seekable attribute, then let it be the position in one of the ranges given in the seekable attribute 
1158     // that is the nearest to the new playback position. ... If there are no ranges given in the seekable
1159     // attribute then set the seeking IDL attribute to false and abort these steps.
1160     RefPtr<TimeRanges> seekableRanges = seekable();
1161
1162     // Short circuit seeking to the current time by just firing the events if no seek is required.
1163     // Don't skip calling the media engine if we are in poster mode because a seek should always 
1164     // cancel poster display.
1165     bool noSeekRequired = !seekableRanges->length() || (time == now && displayMode() != Poster);
1166     if (noSeekRequired) {
1167         if (time == now) {
1168             scheduleEvent(eventNames().seekingEvent);
1169             scheduleTimeupdateEvent(false);
1170             scheduleEvent(eventNames().seekedEvent);
1171         }
1172         m_seeking = false;
1173         return;
1174     }
1175     time = seekableRanges->nearest(time);
1176
1177     if (m_playing) {
1178         if (m_lastSeekTime < now)
1179             addPlayedRange(m_lastSeekTime, now);
1180     }
1181     m_lastSeekTime = time;
1182     m_sentEndEvent = false;
1183
1184     // 8 - Set the current playback position to the given new playback position
1185     m_player->seek(time);
1186
1187     // 9 - Queue a task to fire a simple event named seeking at the element.
1188     scheduleEvent(eventNames().seekingEvent);
1189
1190     // 10 - Queue a task to fire a simple event named timeupdate at the element.
1191     scheduleTimeupdateEvent(false);
1192
1193     // 11-15 are handled, if necessary, when the engine signals a readystate change.
1194 }
1195
1196 void HTMLMediaElement::finishSeek()
1197 {
1198     LOG(Media, "HTMLMediaElement::finishSeek");
1199
1200     // 4.8.10.9 Seeking step 14
1201     m_seeking = false;
1202
1203     // 4.8.10.9 Seeking step 15
1204     scheduleEvent(eventNames().seekedEvent);
1205
1206     setDisplayMode(Video);
1207 }
1208
1209 HTMLMediaElement::ReadyState HTMLMediaElement::readyState() const
1210 {
1211     return m_readyState;
1212 }
1213
1214 MediaPlayer::MovieLoadType HTMLMediaElement::movieLoadType() const
1215 {
1216     return m_player ? m_player->movieLoadType() : MediaPlayer::Unknown;
1217 }
1218
1219 bool HTMLMediaElement::hasAudio() const
1220 {
1221     return m_player ? m_player->hasAudio() : false;
1222 }
1223
1224 bool HTMLMediaElement::seeking() const
1225 {
1226     return m_seeking;
1227 }
1228
1229 void HTMLMediaElement::refreshCachedTime() const
1230 {
1231     m_cachedTime = m_player->currentTime();
1232     m_cachedTimeWallClockUpdateTime = WTF::currentTime();
1233 }
1234
1235 void HTMLMediaElement::invalidateCachedTime()
1236 {
1237     LOG(Media, "HTMLMediaElement::invalidateCachedTime");
1238
1239     // Don't try to cache movie time when playback first starts as the time reported by the engine
1240     // sometimes fluctuates for a short amount of time, so the cached time will be off if we take it
1241     // too early.
1242     static const double minimumTimePlayingBeforeCacheSnapshot = 0.5;
1243
1244     m_minimumWallClockTimeToCacheMediaTime = WTF::currentTime() + minimumTimePlayingBeforeCacheSnapshot;
1245     m_cachedTime = invalidMediaTime;
1246 }
1247
1248 // playback state
1249 float HTMLMediaElement::currentTime() const
1250 {
1251 #if LOG_CACHED_TIME_WARNINGS
1252     static const double minCachedDeltaForWarning = 0.01;
1253 #endif
1254
1255     if (!m_player)
1256         return 0;
1257
1258     if (m_seeking) {
1259         LOG(Media, "HTMLMediaElement::currentTime - seeking, returning %f", m_lastSeekTime);
1260         return m_lastSeekTime;
1261     }
1262
1263     if (m_cachedTime != invalidMediaTime && m_paused) {
1264 #if LOG_CACHED_TIME_WARNINGS
1265         float delta = m_cachedTime - m_player->currentTime();
1266         if (delta > minCachedDeltaForWarning)
1267             LOG(Media, "HTMLMediaElement::currentTime - WARNING, cached time is %f seconds off of media time when paused", delta);
1268 #endif
1269         return m_cachedTime;
1270     }
1271
1272     // Is it too soon use a cached time?
1273     double now = WTF::currentTime();
1274     double maximumDurationToCacheMediaTime = m_player->maximumDurationToCacheMediaTime();
1275
1276     if (maximumDurationToCacheMediaTime && m_cachedTime != invalidMediaTime && !m_paused && now > m_minimumWallClockTimeToCacheMediaTime) {
1277         double wallClockDelta = now - m_cachedTimeWallClockUpdateTime;
1278
1279         // Not too soon, use the cached time only if it hasn't expired.
1280         if (wallClockDelta < maximumDurationToCacheMediaTime) {
1281             float adjustedCacheTime = static_cast<float>(m_cachedTime + (m_playbackRate * wallClockDelta));
1282
1283 #if LOG_CACHED_TIME_WARNINGS
1284             float delta = adjustedCacheTime - m_player->currentTime();
1285             if (delta > minCachedDeltaForWarning)
1286                 LOG(Media, "HTMLMediaElement::currentTime - WARNING, cached time is %f seconds off of media time when playing", delta);
1287 #endif
1288             return adjustedCacheTime;
1289         }
1290     }
1291
1292 #if LOG_CACHED_TIME_WARNINGS
1293     if (maximumDurationToCacheMediaTime && now > m_minimumWallClockTimeToCacheMediaTime && m_cachedTime != invalidMediaTime) {
1294         double wallClockDelta = now - m_cachedTimeWallClockUpdateTime;
1295         float delta = m_cachedTime + (m_playbackRate * wallClockDelta) - m_player->currentTime();
1296         LOG(Media, "HTMLMediaElement::currentTime - cached time was %f seconds off of media time when it expired", delta);
1297     }
1298 #endif
1299
1300     refreshCachedTime();
1301
1302     return m_cachedTime;
1303 }
1304
1305 void HTMLMediaElement::setCurrentTime(float time, ExceptionCode& ec)
1306 {
1307     seek(time, ec);
1308 }
1309
1310 float HTMLMediaElement::startTime() const
1311 {
1312     if (!m_player)
1313         return 0;
1314     return m_player->startTime();
1315 }
1316
1317 float HTMLMediaElement::duration() const
1318 {
1319     if (m_player && m_readyState >= HAVE_METADATA)
1320         return m_player->duration();
1321
1322     return numeric_limits<float>::quiet_NaN();
1323 }
1324
1325 bool HTMLMediaElement::paused() const
1326 {
1327     return m_paused;
1328 }
1329
1330 float HTMLMediaElement::defaultPlaybackRate() const
1331 {
1332     return m_defaultPlaybackRate;
1333 }
1334
1335 void HTMLMediaElement::setDefaultPlaybackRate(float rate)
1336 {
1337     if (m_defaultPlaybackRate != rate) {
1338         m_defaultPlaybackRate = rate;
1339         scheduleEvent(eventNames().ratechangeEvent);
1340     }
1341 }
1342
1343 float HTMLMediaElement::playbackRate() const
1344 {
1345     return m_playbackRate;
1346 }
1347
1348 void HTMLMediaElement::setPlaybackRate(float rate)
1349 {
1350     LOG(Media, "HTMLMediaElement::setPlaybackRate(%f)", rate);
1351
1352     if (m_playbackRate != rate) {
1353         m_playbackRate = rate;
1354         invalidateCachedTime();
1355         scheduleEvent(eventNames().ratechangeEvent);
1356     }
1357     if (m_player && potentiallyPlaying() && m_player->rate() != rate)
1358         m_player->setRate(rate);
1359 }
1360
1361 bool HTMLMediaElement::webkitPreservesPitch() const
1362 {
1363     return m_webkitPreservesPitch;
1364 }
1365
1366 void HTMLMediaElement::setWebkitPreservesPitch(bool preservesPitch)
1367 {
1368     LOG(Media, "HTMLMediaElement::setWebkitPreservesPitch(%s)", boolString(preservesPitch));
1369
1370     m_webkitPreservesPitch = preservesPitch;
1371     
1372     if (!m_player)
1373         return;
1374
1375     m_player->setPreservesPitch(preservesPitch);
1376 }
1377
1378 bool HTMLMediaElement::ended() const
1379 {
1380     // 4.8.10.8 Playing the media resource
1381     // The ended attribute must return true if the media element has ended 
1382     // playback and the direction of playback is forwards, and false otherwise.
1383     return endedPlayback() && m_playbackRate > 0;
1384 }
1385
1386 bool HTMLMediaElement::autoplay() const
1387 {
1388     return hasAttribute(autoplayAttr);
1389 }
1390
1391 void HTMLMediaElement::setAutoplay(bool b)
1392 {
1393     LOG(Media, "HTMLMediaElement::setAutoplay(%s)", boolString(b));
1394     setBooleanAttribute(autoplayAttr, b);
1395 }
1396
1397 String HTMLMediaElement::preload() const
1398 {
1399     switch (m_preload) {
1400     case MediaPlayer::None:
1401         return "none";
1402         break;
1403     case MediaPlayer::MetaData:
1404         return "metadata";
1405         break;
1406     case MediaPlayer::Auto:
1407         return "auto";
1408         break;
1409     }
1410
1411     ASSERT_NOT_REACHED();
1412     return String();
1413 }
1414
1415 void HTMLMediaElement::setPreload(const String& preload)
1416 {
1417     LOG(Media, "HTMLMediaElement::setPreload(%s)", preload.utf8().data());
1418     setAttribute(preloadAttr, preload);
1419 }
1420
1421 void HTMLMediaElement::play(bool isUserGesture)
1422 {
1423     LOG(Media, "HTMLMediaElement::play(isUserGesture : %s)", boolString(isUserGesture));
1424
1425     if (m_restrictions & RequireUserGestureForRateChangeRestriction && !isUserGesture)
1426         return;
1427
1428     Document* doc = document();
1429     Settings* settings = doc->settings();
1430     if (settings && settings->needsSiteSpecificQuirks() && m_dispatchingCanPlayEvent && !m_loadInitiatedByUserGesture) {
1431         // It should be impossible to be processing the canplay event while handling a user gesture
1432         // since it is dispatched asynchronously.
1433         ASSERT(!isUserGesture);
1434         String host = doc->baseURL().host();
1435         if (host.endsWith(".npr.org", false) || equalIgnoringCase(host, "npr.org"))
1436             return;
1437     }
1438     
1439     playInternal();
1440 }
1441
1442 void HTMLMediaElement::playInternal()
1443 {
1444     LOG(Media, "HTMLMediaElement::playInternal");
1445
1446     // 4.8.10.9. Playing the media resource
1447     if (!m_player || m_networkState == NETWORK_EMPTY)
1448         scheduleLoad();
1449
1450     if (endedPlayback()) {
1451         ExceptionCode unused;
1452         seek(0, unused);
1453     }
1454     
1455     if (m_paused) {
1456         m_paused = false;
1457         invalidateCachedTime();
1458         scheduleEvent(eventNames().playEvent);
1459
1460         if (m_readyState <= HAVE_CURRENT_DATA)
1461             scheduleEvent(eventNames().waitingEvent);
1462         else if (m_readyState >= HAVE_FUTURE_DATA)
1463             scheduleEvent(eventNames().playingEvent);
1464     }
1465     m_autoplaying = false;
1466
1467     updatePlayState();
1468 }
1469
1470 void HTMLMediaElement::pause(bool isUserGesture)
1471 {
1472     LOG(Media, "HTMLMediaElement::pause(isUserGesture : %s)", boolString(isUserGesture));
1473
1474     if (m_restrictions & RequireUserGestureForRateChangeRestriction && !isUserGesture)
1475         return;
1476
1477     pauseInternal();
1478 }
1479
1480
1481 void HTMLMediaElement::pauseInternal()
1482 {
1483     LOG(Media, "HTMLMediaElement::pauseInternal");
1484
1485     // 4.8.10.9. Playing the media resource
1486     if (!m_player || m_networkState == NETWORK_EMPTY)
1487         scheduleLoad();
1488
1489     m_autoplaying = false;
1490     
1491     if (!m_paused) {
1492         m_paused = true;
1493         scheduleTimeupdateEvent(false);
1494         scheduleEvent(eventNames().pauseEvent);
1495     }
1496
1497     updatePlayState();
1498 }
1499
1500 bool HTMLMediaElement::loop() const
1501 {
1502     return hasAttribute(loopAttr);
1503 }
1504
1505 void HTMLMediaElement::setLoop(bool b)
1506 {
1507     LOG(Media, "HTMLMediaElement::setLoop(%s)", boolString(b));
1508     setBooleanAttribute(loopAttr, b);
1509 }
1510
1511 bool HTMLMediaElement::controls() const
1512 {
1513     Frame* frame = document()->frame();
1514
1515     // always show controls when scripting is disabled
1516     if (frame && !frame->script()->canExecuteScripts(NotAboutToExecuteScript))
1517         return true;
1518
1519     // always show controls for video when fullscreen playback is required.
1520     if (isVideo() && document()->page() && document()->page()->chrome()->requiresFullscreenForVideoPlayback())
1521         return true;
1522
1523     // Always show controls when in full screen mode.
1524     if (isFullscreen())
1525         return true;
1526
1527     return hasAttribute(controlsAttr);
1528 }
1529
1530 void HTMLMediaElement::setControls(bool b)
1531 {
1532     LOG(Media, "HTMLMediaElement::setControls(%s)", boolString(b));
1533     setBooleanAttribute(controlsAttr, b);
1534 }
1535
1536 float HTMLMediaElement::volume() const
1537 {
1538     return m_volume;
1539 }
1540
1541 void HTMLMediaElement::setVolume(float vol, ExceptionCode& ec)
1542 {
1543     LOG(Media, "HTMLMediaElement::setVolume(%f)", vol);
1544
1545     if (vol < 0.0f || vol > 1.0f) {
1546         ec = INDEX_SIZE_ERR;
1547         return;
1548     }
1549     
1550     if (m_volume != vol) {
1551         m_volume = vol;
1552         updateVolume();
1553         scheduleEvent(eventNames().volumechangeEvent);
1554     }
1555 }
1556
1557 bool HTMLMediaElement::muted() const
1558 {
1559     return m_muted;
1560 }
1561
1562 void HTMLMediaElement::setMuted(bool muted)
1563 {
1564     LOG(Media, "HTMLMediaElement::setMuted(%s)", boolString(muted));
1565
1566     if (m_muted != muted) {
1567         m_muted = muted;
1568         // Avoid recursion when the player reports volume changes.
1569         if (!processingMediaPlayerCallback()) {
1570             if (m_player) {
1571                 m_player->setMuted(m_muted);
1572                 if (hasMediaControls())
1573                     mediaControls()->changedMute();
1574             }
1575         }
1576         scheduleEvent(eventNames().volumechangeEvent);
1577     }
1578 }
1579
1580 void HTMLMediaElement::togglePlayState()
1581 {
1582     LOG(Media, "HTMLMediaElement::togglePlayState - canPlay() is %s", boolString(canPlay()));
1583
1584     // We can safely call the internal play/pause methods, which don't check restrictions, because
1585     // this method is only called from the built-in media controller
1586     if (canPlay()) {
1587         setPlaybackRate(defaultPlaybackRate());
1588         playInternal();
1589     } else 
1590         pauseInternal();
1591 }
1592
1593 void HTMLMediaElement::beginScrubbing()
1594 {
1595     LOG(Media, "HTMLMediaElement::beginScrubbing - paused() is %s", boolString(paused()));
1596
1597     if (!paused()) {
1598         if (ended()) {
1599             // Because a media element stays in non-paused state when it reaches end, playback resumes 
1600             // when the slider is dragged from the end to another position unless we pause first. Do 
1601             // a "hard pause" so an event is generated, since we want to stay paused after scrubbing finishes.
1602             pause(processingUserGesture());
1603         } else {
1604             // Not at the end but we still want to pause playback so the media engine doesn't try to
1605             // continue playing during scrubbing. Pause without generating an event as we will 
1606             // unpause after scrubbing finishes.
1607             setPausedInternal(true);
1608         }
1609     }
1610 }
1611
1612 void HTMLMediaElement::endScrubbing()
1613 {
1614     LOG(Media, "HTMLMediaElement::endScrubbing - m_pausedInternal is %s", boolString(m_pausedInternal));
1615
1616     if (m_pausedInternal)
1617         setPausedInternal(false);
1618 }
1619
1620 // The spec says to fire periodic timeupdate events (those sent while playing) every
1621 // "15 to 250ms", we choose the slowest frequency
1622 static const double maxTimeupdateEventFrequency = 0.25;
1623
1624 void HTMLMediaElement::startPlaybackProgressTimer()
1625 {
1626     if (m_playbackProgressTimer.isActive())
1627         return;
1628
1629     m_previousProgressTime = WTF::currentTime();
1630     m_previousProgress = 0;
1631     m_playbackProgressTimer.startRepeating(maxTimeupdateEventFrequency);
1632 }
1633
1634 void HTMLMediaElement::playbackProgressTimerFired(Timer<HTMLMediaElement>*)
1635 {
1636     ASSERT(m_player);
1637     if (!m_playbackRate)
1638         return;
1639
1640     scheduleTimeupdateEvent(true);
1641     if (hasMediaControls()) {
1642         if (!m_mouseOver && controls() && hasVideo())
1643             mediaControls()->makeTransparent();
1644         mediaControls()->playbackProgressed();
1645     }
1646     // FIXME: deal with cue ranges here
1647 }
1648
1649 void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent)
1650 {
1651     double now = WTF::currentTime();
1652     double timedelta = now - m_lastTimeUpdateEventWallTime;
1653
1654     // throttle the periodic events
1655     if (periodicEvent && timedelta < maxTimeupdateEventFrequency)
1656         return;
1657
1658     // Some media engines make multiple "time changed" callbacks at the same time, but we only want one
1659     // event at a given time so filter here
1660     float movieTime = currentTime();
1661     if (movieTime != m_lastTimeUpdateEventMovieTime) {
1662         scheduleEvent(eventNames().timeupdateEvent);
1663         m_lastTimeUpdateEventWallTime = now;
1664         m_lastTimeUpdateEventMovieTime = movieTime;
1665     }
1666 }
1667
1668 bool HTMLMediaElement::canPlay() const
1669 {
1670     return paused() || ended() || m_readyState < HAVE_METADATA;
1671 }
1672
1673 float HTMLMediaElement::percentLoaded() const
1674 {
1675     if (!m_player)
1676         return 0;
1677     float duration = m_player->duration();
1678
1679     if (!duration || isinf(duration))
1680         return 0;
1681
1682     float buffered = 0;
1683     RefPtr<TimeRanges> timeRanges = m_player->buffered();
1684     for (unsigned i = 0; i < timeRanges->length(); ++i) {
1685         ExceptionCode ignoredException;
1686         float start = timeRanges->start(i, ignoredException);
1687         float end = timeRanges->end(i, ignoredException);
1688         buffered += end - start;
1689     }
1690     return buffered / duration;
1691 }
1692
1693 bool HTMLMediaElement::havePotentialSourceChild()
1694 {
1695     // Stash the current <source> node and next nodes so we can restore them after checking
1696     // to see there is another potential.
1697     HTMLSourceElement* currentSourceNode = m_currentSourceNode;
1698     Node* nextNode = m_nextChildNodeToConsider;
1699
1700     KURL nextURL = selectNextSourceChild(0, DoNothing);
1701
1702     m_currentSourceNode = currentSourceNode;
1703     m_nextChildNodeToConsider = nextNode;
1704
1705     return nextURL.isValid();
1706 }
1707
1708 KURL HTMLMediaElement::selectNextSourceChild(ContentType *contentType, InvalidSourceAction actionIfInvalid)
1709 {
1710 #if !LOG_DISABLED
1711     // Don't log if this was just called to find out if there are any valid <source> elements.
1712     bool shouldLog = actionIfInvalid != DoNothing;
1713     if (shouldLog)
1714         LOG(Media, "HTMLMediaElement::selectNextSourceChild(contentType : \"%s\")", contentType ? contentType->raw().utf8().data() : "");
1715 #endif
1716
1717     if (m_nextChildNodeToConsider == sourceChildEndOfListValue()) {
1718 #if !LOG_DISABLED
1719         if (shouldLog)
1720             LOG(Media, "HTMLMediaElement::selectNextSourceChild -> 0x0000, \"\"");
1721 #endif
1722         return KURL();
1723     }
1724
1725     KURL mediaURL;
1726     Node* node;
1727     HTMLSourceElement* source = 0;
1728     bool lookingForStartNode = m_nextChildNodeToConsider;
1729     bool canUse = false;
1730
1731     for (node = firstChild(); !canUse && node; node = node->nextSibling()) {
1732         if (lookingForStartNode && m_nextChildNodeToConsider != node)
1733             continue;
1734         lookingForStartNode = false;
1735         
1736         if (!node->hasTagName(sourceTag))
1737             continue;
1738
1739         source = static_cast<HTMLSourceElement*>(node);
1740
1741         // 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
1742         mediaURL = source->getNonEmptyURLAttribute(srcAttr);
1743 #if !LOG_DISABLED
1744         if (shouldLog)
1745             LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'src' is %s", urlForLogging(mediaURL).utf8().data());
1746 #endif
1747         if (mediaURL.isEmpty())
1748             goto check_again;
1749         
1750         if (source->hasAttribute(mediaAttr)) {
1751             MediaQueryEvaluator screenEval("screen", document()->frame(), renderer() ? renderer()->style() : 0);
1752             RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(source->media());
1753 #if !LOG_DISABLED
1754             if (shouldLog)
1755                 LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'media' is %s", source->media().utf8().data());
1756 #endif
1757             if (!screenEval.eval(media.get())) 
1758                 goto check_again;
1759         }
1760
1761         if (source->hasAttribute(typeAttr)) {
1762 #if !LOG_DISABLED
1763             if (shouldLog)
1764                 LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'type' is %s", source->type().utf8().data());
1765 #endif
1766             if (!MediaPlayer::supportsType(ContentType(source->type())))
1767                 goto check_again;
1768         }
1769
1770         // Is it safe to load this url?
1771         if (!isSafeToLoadURL(mediaURL, actionIfInvalid) || !dispatchBeforeLoadEvent(mediaURL.string()))
1772             goto check_again;
1773
1774         // Making it this far means the <source> looks reasonable.
1775         canUse = true;
1776
1777 check_again:
1778         if (!canUse && actionIfInvalid == Complain)
1779             source->scheduleErrorEvent();
1780     }
1781
1782     if (canUse) {
1783         if (contentType)
1784             *contentType = ContentType(source->type());
1785         m_currentSourceNode = source;
1786         m_nextChildNodeToConsider = source->nextSibling();
1787         if (!m_nextChildNodeToConsider)
1788             m_nextChildNodeToConsider = sourceChildEndOfListValue();
1789     } else {
1790         m_currentSourceNode = 0;
1791         m_nextChildNodeToConsider = sourceChildEndOfListValue();
1792     }
1793
1794 #if !LOG_DISABLED
1795     if (shouldLog)
1796         LOG(Media, "HTMLMediaElement::selectNextSourceChild -> %p, %s", m_currentSourceNode, canUse ? urlForLogging(mediaURL.string()).utf8().data() : "");
1797 #endif
1798     return canUse ? mediaURL : KURL();
1799 }
1800
1801 void HTMLMediaElement::sourceWasAdded(HTMLSourceElement* source)
1802 {
1803     LOG(Media, "HTMLMediaElement::sourceWasAdded(%p)", source);
1804
1805 #if !LOG_DISABLED
1806     if (source->hasTagName(sourceTag)) {
1807         KURL url = source->getNonEmptyURLAttribute(srcAttr);
1808         LOG(Media, "HTMLMediaElement::sourceWasAdded - 'src' is %s", urlForLogging(url).utf8().data());
1809     }
1810 #endif
1811     
1812     // We should only consider a <source> element when there is not src attribute at all.
1813     if (hasAttribute(srcAttr))
1814         return;
1815
1816     // 4.8.8 - If a source element is inserted as a child of a media element that has no src 
1817     // attribute and whose networkState has the value NETWORK_EMPTY, the user agent must invoke 
1818     // the media element's resource selection algorithm.
1819     if (networkState() == HTMLMediaElement::NETWORK_EMPTY) {
1820         scheduleLoad();
1821         return;
1822     }
1823
1824     if (m_currentSourceNode && source == m_currentSourceNode->nextSibling()) {
1825         LOG(Media, "HTMLMediaElement::sourceWasAdded - <source> inserted immediately after current source");
1826         m_nextChildNodeToConsider = source;
1827         return;
1828     }
1829
1830     if (m_nextChildNodeToConsider != sourceChildEndOfListValue())
1831         return;
1832     
1833     // 4.8.9.5, resource selection algorithm, source elements section:
1834     // 20 - Wait until the node after pointer is a node other than the end of the list. (This step might wait forever.)
1835     // 21 - Asynchronously await a stable state...
1836     // 22 - Set the element's delaying-the-load-event flag back to true (this delays the load event again, in case 
1837     // it hasn't been fired yet).
1838     setShouldDelayLoadEvent(true);
1839
1840     // 23 - Set the networkState back to NETWORK_LOADING.
1841     m_networkState = NETWORK_LOADING;
1842     
1843     // 24 - Jump back to the find next candidate step above.
1844     m_nextChildNodeToConsider = source;
1845     scheduleNextSourceChild();
1846 }
1847
1848 void HTMLMediaElement::sourceWillBeRemoved(HTMLSourceElement* source)
1849 {
1850     LOG(Media, "HTMLMediaElement::sourceWillBeRemoved(%p)", source);
1851
1852 #if !LOG_DISABLED
1853     if (source->hasTagName(sourceTag)) {
1854         KURL url = source->getNonEmptyURLAttribute(srcAttr);
1855         LOG(Media, "HTMLMediaElement::sourceWillBeRemoved - 'src' is %s", urlForLogging(url).utf8().data());
1856     }
1857 #endif
1858
1859     if (source != m_currentSourceNode && source != m_nextChildNodeToConsider)
1860         return;
1861
1862     if (source == m_nextChildNodeToConsider) {
1863         m_nextChildNodeToConsider = m_nextChildNodeToConsider->nextSibling();
1864         if (!m_nextChildNodeToConsider)
1865             m_nextChildNodeToConsider = sourceChildEndOfListValue();
1866         LOG(Media, "HTMLMediaElement::sourceRemoved - m_nextChildNodeToConsider set to %p", m_nextChildNodeToConsider);
1867     } else if (source == m_currentSourceNode) {
1868         // Clear the current source node pointer, but don't change the movie as the spec says:
1869         // 4.8.8 - Dynamically modifying a source element and its attribute when the element is already 
1870         // inserted in a video or audio element will have no effect.
1871         m_currentSourceNode = 0;
1872         LOG(Media, "HTMLMediaElement::sourceRemoved - m_currentSourceNode set to 0");
1873     }
1874 }
1875
1876 void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
1877 {
1878     LOG(Media, "HTMLMediaElement::mediaPlayerTimeChanged");
1879
1880     beginProcessingMediaPlayerCallback();
1881
1882     invalidateCachedTime();
1883
1884     // 4.8.10.9 step 14 & 15.  Needed if no ReadyState change is associated with the seek.
1885     if (m_seeking && m_readyState >= HAVE_CURRENT_DATA)
1886         finishSeek();
1887     
1888     // Always call scheduleTimeupdateEvent when the media engine reports a time discontinuity, 
1889     // it will only queue a 'timeupdate' event if we haven't already posted one at the current
1890     // movie time.
1891     scheduleTimeupdateEvent(false);
1892
1893     float now = currentTime();
1894     float dur = duration();
1895     if (!isnan(dur) && dur && now >= dur) {
1896         if (loop()) {
1897             ExceptionCode ignoredException;
1898             m_sentEndEvent = false;
1899             seek(0, ignoredException);
1900         } else {
1901             if (!m_sentEndEvent) {
1902                 m_sentEndEvent = true;
1903                 scheduleEvent(eventNames().endedEvent);
1904             }
1905         }
1906     }
1907     else
1908         m_sentEndEvent = false;
1909
1910     updatePlayState();
1911     endProcessingMediaPlayerCallback();
1912 }
1913
1914 void HTMLMediaElement::mediaPlayerVolumeChanged(MediaPlayer*)
1915 {
1916     LOG(Media, "HTMLMediaElement::mediaPlayerVolumeChanged");
1917
1918     beginProcessingMediaPlayerCallback();
1919     if (m_player) {
1920         float vol = m_player->volume();
1921         if (vol != m_volume) {
1922             m_volume = vol;
1923             updateVolume();
1924             scheduleEvent(eventNames().volumechangeEvent);
1925         }
1926     }
1927     endProcessingMediaPlayerCallback();
1928 }
1929
1930 void HTMLMediaElement::mediaPlayerMuteChanged(MediaPlayer*)
1931 {
1932     LOG(Media, "HTMLMediaElement::mediaPlayerMuteChanged");
1933
1934     beginProcessingMediaPlayerCallback();
1935     if (m_player)
1936         setMuted(m_player->muted());
1937     endProcessingMediaPlayerCallback();
1938 }
1939
1940 void HTMLMediaElement::mediaPlayerDurationChanged(MediaPlayer* player)
1941 {
1942     LOG(Media, "HTMLMediaElement::mediaPlayerDurationChanged");
1943
1944     beginProcessingMediaPlayerCallback();
1945     scheduleEvent(eventNames().durationchangeEvent);
1946     mediaPlayerCharacteristicChanged(player);
1947     endProcessingMediaPlayerCallback();
1948 }
1949
1950 void HTMLMediaElement::mediaPlayerRateChanged(MediaPlayer*)
1951 {
1952     LOG(Media, "HTMLMediaElement::mediaPlayerRateChanged");
1953
1954     beginProcessingMediaPlayerCallback();
1955
1956     invalidateCachedTime();
1957
1958     // Stash the rate in case the one we tried to set isn't what the engine is
1959     // using (eg. it can't handle the rate we set)
1960     m_playbackRate = m_player->rate();
1961     invalidateCachedTime();
1962     endProcessingMediaPlayerCallback();
1963 }
1964
1965 void HTMLMediaElement::mediaPlayerPlaybackStateChanged(MediaPlayer*)
1966 {
1967     LOG(Media, "HTMLMediaElement::mediaPlayerPlaybackStateChanged");
1968
1969     if (!m_player || m_pausedInternal)
1970         return;
1971
1972     beginProcessingMediaPlayerCallback();
1973     if (m_player->paused())
1974         pauseInternal();
1975     else
1976         playInternal();
1977     endProcessingMediaPlayerCallback();
1978 }
1979
1980 void HTMLMediaElement::mediaPlayerSawUnsupportedTracks(MediaPlayer*)
1981 {
1982     LOG(Media, "HTMLMediaElement::mediaPlayerSawUnsupportedTracks");
1983
1984     // The MediaPlayer came across content it cannot completely handle.
1985     // This is normally acceptable except when we are in a standalone
1986     // MediaDocument. If so, tell the document what has happened.
1987     if (ownerDocument()->isMediaDocument()) {
1988         MediaDocument* mediaDocument = static_cast<MediaDocument*>(ownerDocument());
1989         mediaDocument->mediaElementSawUnsupportedTracks();
1990     }
1991 }
1992
1993 // MediaPlayerPresentation methods
1994 void HTMLMediaElement::mediaPlayerRepaint(MediaPlayer*)
1995 {
1996     beginProcessingMediaPlayerCallback();
1997     updateDisplayState();
1998     if (renderer())
1999         renderer()->repaint();
2000     endProcessingMediaPlayerCallback();
2001 }
2002
2003 void HTMLMediaElement::mediaPlayerSizeChanged(MediaPlayer*)
2004 {
2005     LOG(Media, "HTMLMediaElement::mediaPlayerSizeChanged");
2006
2007     beginProcessingMediaPlayerCallback();
2008     if (renderer())
2009         renderer()->updateFromElement();
2010     endProcessingMediaPlayerCallback();
2011 }
2012
2013 #if USE(ACCELERATED_COMPOSITING)
2014 bool HTMLMediaElement::mediaPlayerRenderingCanBeAccelerated(MediaPlayer*)
2015 {
2016     if (renderer() && renderer()->isVideo()) {
2017         ASSERT(renderer()->view());
2018         return renderer()->view()->compositor()->canAccelerateVideoRendering(toRenderVideo(renderer()));
2019     }
2020     return false;
2021 }
2022
2023 void HTMLMediaElement::mediaPlayerRenderingModeChanged(MediaPlayer*)
2024 {
2025     LOG(Media, "HTMLMediaElement::mediaPlayerRenderingModeChanged");
2026
2027     // Kick off a fake recalcStyle that will update the compositing tree.
2028     setNeedsStyleRecalc(SyntheticStyleChange);
2029 }
2030 #endif
2031
2032 void HTMLMediaElement::mediaPlayerEngineUpdated(MediaPlayer*)
2033 {
2034     LOG(Media, "HTMLMediaElement::mediaPlayerEngineUpdated");
2035     beginProcessingMediaPlayerCallback();
2036     if (renderer())
2037         renderer()->updateFromElement();
2038     endProcessingMediaPlayerCallback();
2039 }
2040
2041 void HTMLMediaElement::mediaPlayerFirstVideoFrameAvailable(MediaPlayer*)
2042 {
2043     LOG(Media, "HTMLMediaElement::mediaPlayerFirstVideoFrameAvailable");
2044     beginProcessingMediaPlayerCallback();
2045     if (displayMode() == PosterWaitingForVideo) {
2046         setDisplayMode(Video);
2047 #if USE(ACCELERATED_COMPOSITING)
2048         mediaPlayerRenderingModeChanged(m_player.get());
2049 #endif
2050     }
2051     endProcessingMediaPlayerCallback();
2052 }
2053
2054 void HTMLMediaElement::mediaPlayerCharacteristicChanged(MediaPlayer*)
2055 {
2056     LOG(Media, "HTMLMediaElement::mediaPlayerCharacteristicChanged");
2057     
2058     beginProcessingMediaPlayerCallback();
2059     if (hasMediaControls())
2060         mediaControls()->reset();
2061     if (renderer())
2062         renderer()->updateFromElement();
2063     endProcessingMediaPlayerCallback();
2064 }
2065
2066 PassRefPtr<TimeRanges> HTMLMediaElement::buffered() const
2067 {
2068     if (!m_player)
2069         return TimeRanges::create();
2070     return m_player->buffered();
2071 }
2072
2073 PassRefPtr<TimeRanges> HTMLMediaElement::played()
2074 {
2075     if (m_playing) {
2076         float time = currentTime();
2077         if (time > m_lastSeekTime)
2078             addPlayedRange(m_lastSeekTime, time);
2079     }
2080
2081     if (!m_playedTimeRanges)
2082         m_playedTimeRanges = TimeRanges::create();
2083
2084     return m_playedTimeRanges->copy();
2085 }
2086
2087 PassRefPtr<TimeRanges> HTMLMediaElement::seekable() const
2088 {
2089     // FIXME real ranges support
2090     if (!maxTimeSeekable())
2091         return TimeRanges::create();
2092     return TimeRanges::create(minTimeSeekable(), maxTimeSeekable());
2093 }
2094
2095 bool HTMLMediaElement::potentiallyPlaying() const
2096 {
2097     // "pausedToBuffer" means the media engine's rate is 0, but only because it had to stop playing
2098     // when it ran out of buffered data. A movie is this state is "potentially playing", modulo the
2099     // checks in couldPlayIfEnoughData().
2100     bool pausedToBuffer = m_readyStateMaximum >= HAVE_FUTURE_DATA && m_readyState < HAVE_FUTURE_DATA;
2101     return (pausedToBuffer || m_readyState >= HAVE_FUTURE_DATA) && couldPlayIfEnoughData();
2102 }
2103
2104 bool HTMLMediaElement::couldPlayIfEnoughData() const
2105 {
2106     return !paused() && !endedPlayback() && !stoppedDueToErrors() && !pausedForUserInteraction();
2107 }
2108
2109 bool HTMLMediaElement::endedPlayback() const
2110 {
2111     float dur = duration();
2112     if (!m_player || isnan(dur))
2113         return false;
2114
2115     // 4.8.10.8 Playing the media resource
2116
2117     // A media element is said to have ended playback when the element's 
2118     // readyState attribute is HAVE_METADATA or greater, 
2119     if (m_readyState < HAVE_METADATA)
2120         return false;
2121
2122     // and the current playback position is the end of the media resource and the direction
2123     // of playback is forwards and the media element does not have a loop attribute specified,
2124     float now = currentTime();
2125     if (m_playbackRate > 0)
2126         return dur > 0 && now >= dur && !loop();
2127
2128     // or the current playback position is the earliest possible position and the direction 
2129     // of playback is backwards
2130     if (m_playbackRate < 0)
2131         return now <= 0;
2132
2133     return false;
2134 }
2135
2136 bool HTMLMediaElement::stoppedDueToErrors() const
2137 {
2138     if (m_readyState >= HAVE_METADATA && m_error) {
2139         RefPtr<TimeRanges> seekableRanges = seekable();
2140         if (!seekableRanges->contain(currentTime()))
2141             return true;
2142     }
2143     
2144     return false;
2145 }
2146
2147 bool HTMLMediaElement::pausedForUserInteraction() const
2148 {
2149 //    return !paused() && m_readyState >= HAVE_FUTURE_DATA && [UA requires a decitions from the user]
2150     return false;
2151 }
2152
2153 float HTMLMediaElement::minTimeSeekable() const
2154 {
2155     return 0;
2156 }
2157
2158 float HTMLMediaElement::maxTimeSeekable() const
2159 {
2160     return m_player ? m_player->maxTimeSeekable() : 0;
2161 }
2162     
2163 void HTMLMediaElement::updateVolume()
2164 {
2165     if (!m_player)
2166         return;
2167
2168     // Avoid recursion when the player reports volume changes.
2169     if (!processingMediaPlayerCallback()) {
2170         Page* page = document()->page();
2171         float volumeMultiplier = page ? page->mediaVolume() : 1;
2172     
2173         m_player->setMuted(m_muted);
2174         m_player->setVolume(m_volume * volumeMultiplier);
2175     }
2176
2177     if (hasMediaControls())
2178         mediaControls()->changedVolume();
2179 }
2180
2181 void HTMLMediaElement::updatePlayState()
2182 {
2183     if (!m_player)
2184         return;
2185
2186     if (m_pausedInternal) {
2187         if (!m_player->paused())
2188             m_player->pause();
2189         refreshCachedTime();
2190         m_playbackProgressTimer.stop();
2191         if (hasMediaControls())
2192             mediaControls()->playbackStopped();
2193         return;
2194     }
2195     
2196     bool shouldBePlaying = potentiallyPlaying();
2197     bool playerPaused = m_player->paused();
2198
2199     LOG(Media, "HTMLMediaElement::updatePlayState - shouldBePlaying = %s, playerPaused = %s", 
2200         boolString(shouldBePlaying), boolString(playerPaused));
2201
2202     if (shouldBePlaying) {
2203         setDisplayMode(Video);
2204         invalidateCachedTime();
2205
2206         if (playerPaused) {
2207             if (!m_isFullscreen && isVideo() && document() && document()->page() && document()->page()->chrome()->requiresFullscreenForVideoPlayback())
2208                 enterFullscreen();
2209
2210             // Set rate, muted before calling play in case they were set before the media engine was setup.
2211             // The media engine should just stash the rate and muted values since it isn't already playing.
2212             m_player->setRate(m_playbackRate);
2213             m_player->setMuted(m_muted);
2214
2215             m_player->play();
2216         }
2217
2218         if (hasMediaControls())
2219             mediaControls()->playbackStarted();
2220         startPlaybackProgressTimer();
2221         m_playing = true;
2222
2223     } else { // Should not be playing right now
2224         if (!playerPaused)
2225             m_player->pause();
2226         refreshCachedTime();
2227
2228         m_playbackProgressTimer.stop();
2229         m_playing = false;
2230         float time = currentTime();
2231         if (time > m_lastSeekTime)
2232             addPlayedRange(m_lastSeekTime, time);
2233
2234         if (couldPlayIfEnoughData())
2235             prepareToPlay();
2236
2237         if (hasMediaControls())
2238             mediaControls()->playbackStopped();
2239     }
2240     
2241     if (renderer())
2242         renderer()->updateFromElement();
2243 }
2244     
2245 void HTMLMediaElement::setPausedInternal(bool b)
2246 {
2247     m_pausedInternal = b;
2248     updatePlayState();
2249 }
2250
2251 void HTMLMediaElement::stopPeriodicTimers()
2252 {
2253     m_progressEventTimer.stop();
2254     m_playbackProgressTimer.stop();
2255 }
2256
2257 void HTMLMediaElement::userCancelledLoad()
2258 {
2259     LOG(Media, "HTMLMediaElement::userCancelledLoad");
2260
2261     if (m_networkState == NETWORK_EMPTY || m_completelyLoaded)
2262         return;
2263
2264     // If the media data fetching process is aborted by the user:
2265
2266     // 1 - The user agent should cancel the fetching process.
2267 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
2268     m_player.clear();
2269 #endif
2270     stopPeriodicTimers();
2271     m_loadTimer.stop();
2272     m_loadState = WaitingForSource;
2273
2274     // 2 - Set the error attribute to a new MediaError object whose code attribute is set to MEDIA_ERR_ABORTED.
2275     m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
2276
2277     // 3 - Queue a task to fire a simple event named error at the media element.
2278     scheduleEvent(eventNames().abortEvent);
2279
2280     // 4 - If the media element's readyState attribute has a value equal to HAVE_NOTHING, set the 
2281     // element's networkState attribute to the NETWORK_EMPTY value and queue a task to fire a 
2282     // simple event named emptied at the element. Otherwise, set the element's networkState 
2283     // attribute to the NETWORK_IDLE value.
2284     if (m_readyState == HAVE_NOTHING) {
2285         m_networkState = NETWORK_EMPTY;
2286         scheduleEvent(eventNames().emptiedEvent);
2287     }
2288     else
2289         m_networkState = NETWORK_IDLE;
2290
2291     // 5 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
2292     setShouldDelayLoadEvent(false);
2293
2294     // 6 - Abort the overall resource selection algorithm.
2295     m_currentSourceNode = 0;
2296
2297     // Reset m_readyState since m_player is gone.
2298     m_readyState = HAVE_NOTHING;
2299 }
2300
2301 bool HTMLMediaElement::canSuspend() const
2302 {
2303     return true; 
2304 }
2305
2306 void HTMLMediaElement::stop()
2307 {
2308     LOG(Media, "HTMLMediaElement::stop");
2309     if (m_isFullscreen)
2310         exitFullscreen();
2311     
2312     m_inActiveDocument = false;
2313     userCancelledLoad();
2314     
2315     // Stop the playback without generating events
2316     setPausedInternal(true);
2317     
2318     if (renderer())
2319         renderer()->updateFromElement();
2320     
2321     stopPeriodicTimers();
2322     cancelPendingEventsAndCallbacks();
2323 }
2324
2325 void HTMLMediaElement::suspend(ReasonForSuspension why)
2326 {
2327     LOG(Media, "HTMLMediaElement::suspend");
2328     
2329     switch (why)
2330     {
2331         case DocumentWillBecomeInactive:
2332             stop();
2333             break;
2334         case JavaScriptDebuggerPaused:
2335         case WillShowDialog:
2336             // Do nothing, we don't pause media playback in these cases.
2337             break;
2338     }
2339 }
2340
2341 void HTMLMediaElement::resume()
2342 {
2343     LOG(Media, "HTMLMediaElement::resume");
2344
2345     m_inActiveDocument = true;
2346     setPausedInternal(false);
2347
2348     if (m_error && m_error->code() == MediaError::MEDIA_ERR_ABORTED) {
2349         // Restart the load if it was aborted in the middle by moving the document to the page cache.
2350         // m_error is only left at MEDIA_ERR_ABORTED when the document becomes inactive (it is set to
2351         //  MEDIA_ERR_ABORTED while the abortEvent is being sent, but cleared immediately afterwards).
2352         // This behavior is not specified but it seems like a sensible thing to do.
2353         ExceptionCode ec;
2354         load(processingUserGesture(), ec);
2355     }
2356
2357     if (renderer())
2358         renderer()->updateFromElement();
2359 }
2360
2361 bool HTMLMediaElement::hasPendingActivity() const
2362 {
2363     // Return true when we have pending events so we can't fire events after the JS 
2364     // object gets collected.
2365     bool pending = m_pendingEvents.size();
2366     LOG(Media, "HTMLMediaElement::hasPendingActivity -> %s", boolString(pending));
2367     return pending;
2368 }
2369
2370 void HTMLMediaElement::mediaVolumeDidChange()
2371 {
2372     LOG(Media, "HTMLMediaElement::mediaVolumeDidChange");
2373     updateVolume();
2374 }
2375
2376 void HTMLMediaElement::defaultEventHandler(Event* event)
2377 {
2378 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
2379     RenderObject* r = renderer();
2380     if (!r || !r->isWidget())
2381         return;
2382
2383     Widget* widget = toRenderWidget(r)->widget();
2384     if (widget)
2385         widget->handleEvent(event);
2386 #else
2387     if (event->isMouseEvent()) {
2388         MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
2389         if (mouseEvent->relatedTarget() != this) {
2390             if (event->type() == eventNames().mouseoverEvent) {
2391                 m_mouseOver = true;
2392                 if (hasMediaControls() && controls() && !canPlay())
2393                     mediaControls()->makeOpaque();
2394             } else if (event->type() == eventNames().mouseoutEvent)
2395                 m_mouseOver = false;
2396         }
2397     }
2398
2399     HTMLElement::defaultEventHandler(event);
2400 #endif
2401 }
2402
2403 bool HTMLMediaElement::processingUserGesture() const
2404 {
2405     // FIXME: We should call ScriptController::processingUserGesture() so
2406     // we know what to do without a Frame.
2407     Frame* frame = document()->frame();
2408     if (!frame)
2409         return true;
2410     return frame->loader()->isProcessingUserGesture();
2411 }
2412
2413 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
2414
2415 void HTMLMediaElement::ensureMediaPlayer()
2416 {
2417     if (!m_player)
2418         m_player = MediaPlayer::create(this);
2419 }
2420
2421 void HTMLMediaElement::deliverNotification(MediaPlayerProxyNotificationType notification)
2422 {
2423     if (notification == MediaPlayerNotificationPlayPauseButtonPressed) {
2424         togglePlayState();
2425         return;
2426     }
2427
2428     if (m_player)
2429         m_player->deliverNotification(notification);
2430 }
2431
2432 void HTMLMediaElement::setMediaPlayerProxy(WebMediaPlayerProxy* proxy)
2433 {
2434     ensureMediaPlayer();
2435     m_player->setMediaPlayerProxy(proxy);
2436 }
2437
2438 void HTMLMediaElement::getPluginProxyParams(KURL& url, Vector<String>& names, Vector<String>& values)
2439 {
2440     Frame* frame = document()->frame();
2441     FrameLoader* loader = frame ? frame->loader() : 0;
2442
2443     if (isVideo()) {
2444         KURL posterURL = getNonEmptyURLAttribute(posterAttr);
2445         if (!posterURL.isEmpty() && loader && loader->willLoadMediaElementURL(posterURL)) {
2446             names.append("_media_element_poster_");
2447             values.append(posterURL.string());
2448         }
2449     }
2450
2451     if (controls()) {
2452         names.append("_media_element_controls_");
2453         values.append("true");
2454     }
2455
2456     url = src();
2457     if (!isSafeToLoadURL(url, Complain))
2458         url = selectNextSourceChild(0, DoNothing);
2459
2460     m_currentSrc = url.string();
2461     if (url.isValid() && loader && loader->willLoadMediaElementURL(url)) {
2462         names.append("_media_element_src_");
2463         values.append(m_currentSrc);
2464     }
2465 }
2466
2467 void HTMLMediaElement::finishParsingChildren()
2468 {
2469     HTMLElement::finishParsingChildren();
2470     document()->updateStyleIfNeeded();
2471     createMediaPlayerProxy();
2472 }
2473
2474 void HTMLMediaElement::createMediaPlayerProxy()
2475 {
2476     ensureMediaPlayer();
2477
2478     if (m_proxyWidget || (inDocument() && !m_needWidgetUpdate))
2479         return;
2480
2481     Frame* frame = document()->frame();
2482     FrameLoader* loader = frame ? frame->loader() : 0;
2483     if (!loader)
2484         return;
2485
2486     LOG(Media, "HTMLMediaElement::createMediaPlayerProxy");
2487
2488     KURL url;
2489     Vector<String> paramNames;
2490     Vector<String> paramValues;
2491
2492     getPluginProxyParams(url, paramNames, paramValues);
2493     
2494     // Hang onto the proxy widget so it won't be destroyed if the plug-in is set to
2495     // display:none
2496     m_proxyWidget = loader->subframeLoader()->loadMediaPlayerProxyPlugin(this, url, paramNames, paramValues);
2497     if (m_proxyWidget)
2498         m_needWidgetUpdate = false;
2499 }
2500
2501 void HTMLMediaElement::updateWidget(PluginCreationOption)
2502 {
2503     mediaElement->setNeedWidgetUpdate(false);
2504
2505     Vector<String> paramNames;
2506     Vector<String> paramValues;
2507     KURL kurl;
2508     
2509     mediaElement->getPluginProxyParams(kurl, paramNames, paramValues);
2510     SubframeLoader* loader = document()->frame()->loader()->subframeLoader();
2511     loader->loadMediaPlayerProxyPlugin(mediaElement, kurl, paramNames, paramValues);
2512 }
2513
2514 #endif // ENABLE(PLUGIN_PROXY_FOR_VIDEO)
2515
2516 bool HTMLMediaElement::isFullscreen() const
2517 {
2518     if (m_isFullscreen)
2519         return true;
2520     
2521 #if ENABLE(FULLSCREEN_API)
2522     if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == this)
2523         return true;
2524 #endif
2525     
2526     return false;
2527 }
2528
2529 void HTMLMediaElement::enterFullscreen()
2530 {
2531     LOG(Media, "HTMLMediaElement::enterFullscreen");
2532 #if ENABLE(FULLSCREEN_API)
2533     if (document() && document()->settings() && document()->settings()->fullScreenEnabled()) {
2534         webkitRequestFullScreen(0);
2535         return;
2536     }
2537 #endif
2538     ASSERT(!m_isFullscreen);
2539     m_isFullscreen = true;
2540     if (hasMediaControls())
2541         mediaControls()->enteredFullscreen();
2542     if (document() && document()->page()) {
2543         document()->page()->chrome()->client()->enterFullscreenForNode(this);
2544         scheduleEvent(eventNames().webkitbeginfullscreenEvent);
2545     }
2546 }
2547
2548 void HTMLMediaElement::exitFullscreen()
2549 {
2550     LOG(Media, "HTMLMediaElement::exitFullscreen");
2551 #if ENABLE(FULLSCREEN_API)
2552     if (document() && document()->settings() && document()->settings()->fullScreenEnabled()) {
2553         if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == this)
2554             document()->webkitCancelFullScreen();
2555         return;
2556     }
2557 #endif
2558     ASSERT(m_isFullscreen);
2559     m_isFullscreen = false;
2560     if (hasMediaControls())
2561         mediaControls()->exitedFullscreen();
2562     if (document() && document()->page()) {
2563         if (document()->page()->chrome()->requiresFullscreenForVideoPlayback())
2564             pauseInternal();
2565         document()->page()->chrome()->client()->exitFullscreenForNode(this);
2566         scheduleEvent(eventNames().webkitendfullscreenEvent);
2567     }
2568 }
2569
2570 PlatformMedia HTMLMediaElement::platformMedia() const
2571 {
2572     return m_player ? m_player->platformMedia() : NoPlatformMedia;
2573 }
2574
2575 #if USE(ACCELERATED_COMPOSITING)
2576 PlatformLayer* HTMLMediaElement::platformLayer() const
2577 {
2578     return m_player ? m_player->platformLayer() : 0;
2579 }
2580 #endif
2581
2582 bool HTMLMediaElement::hasClosedCaptions() const
2583 {
2584     return m_player && m_player->hasClosedCaptions();
2585 }
2586
2587 bool HTMLMediaElement::closedCaptionsVisible() const
2588 {
2589     return m_closedCaptionsVisible;
2590 }
2591
2592 void HTMLMediaElement::setClosedCaptionsVisible(bool closedCaptionVisible)
2593 {
2594     LOG(Media, "HTMLMediaElement::setClosedCaptionsVisible(%s)", boolString(closedCaptionVisible));
2595
2596     if (!m_player ||!hasClosedCaptions())
2597         return;
2598
2599     m_closedCaptionsVisible = closedCaptionVisible;
2600     m_player->setClosedCaptionsVisible(closedCaptionVisible);
2601     if (hasMediaControls())
2602         mediaControls()->changedClosedCaptionsVisibility();
2603 }
2604
2605 void HTMLMediaElement::setWebkitClosedCaptionsVisible(bool visible)
2606 {
2607     setClosedCaptionsVisible(visible);
2608 }
2609
2610 bool HTMLMediaElement::webkitClosedCaptionsVisible() const
2611 {
2612     return closedCaptionsVisible();
2613 }
2614
2615
2616 bool HTMLMediaElement::webkitHasClosedCaptions() const
2617 {
2618     return hasClosedCaptions();
2619 }
2620
2621 #if ENABLE(MEDIA_STATISTICS)
2622 unsigned HTMLMediaElement::webkitAudioDecodedByteCount() const
2623 {
2624     if (!m_player)
2625         return 0;
2626     return m_player->audioDecodedByteCount();
2627 }
2628
2629 unsigned HTMLMediaElement::webkitVideoDecodedByteCount() const
2630 {
2631     if (!m_player)
2632         return 0;
2633     return m_player->videoDecodedByteCount();
2634 }
2635 #endif
2636
2637 void HTMLMediaElement::mediaCanStart()
2638 {
2639     LOG(Media, "HTMLMediaElement::mediaCanStart");
2640
2641     ASSERT(m_isWaitingUntilMediaCanStart);
2642     m_isWaitingUntilMediaCanStart = false;
2643     loadInternal();
2644 }
2645
2646 bool HTMLMediaElement::isURLAttribute(Attribute* attribute) const
2647 {
2648     return attribute->name() == srcAttr;
2649 }
2650
2651 void HTMLMediaElement::setShouldDelayLoadEvent(bool shouldDelay)
2652 {
2653     if (m_shouldDelayLoadEvent == shouldDelay)
2654         return;
2655
2656     LOG(Media, "HTMLMediaElement::setShouldDelayLoadEvent(%s)", boolString(shouldDelay));
2657
2658     m_shouldDelayLoadEvent = shouldDelay;
2659     if (shouldDelay)
2660         document()->incrementLoadEventDelayCount();
2661     else
2662         document()->decrementLoadEventDelayCount();
2663 }
2664     
2665
2666 void HTMLMediaElement::getSitesInMediaCache(Vector<String>& sites)
2667 {
2668     MediaPlayer::getSitesInMediaCache(sites);
2669 }
2670
2671 void HTMLMediaElement::clearMediaCache()
2672 {
2673     MediaPlayer::clearMediaCache();
2674 }
2675
2676 void HTMLMediaElement::clearMediaCacheForSite(const String& site)
2677 {
2678     MediaPlayer::clearMediaCacheForSite(site);
2679 }
2680
2681 void HTMLMediaElement::privateBrowsingStateDidChange()
2682 {
2683     if (!m_player)
2684         return;
2685
2686     Settings* settings = document()->settings();
2687     bool privateMode = !settings || settings->privateBrowsingEnabled();
2688     LOG(Media, "HTMLMediaElement::privateBrowsingStateDidChange(%s)", boolString(privateMode));
2689     m_player->setPrivateBrowsingMode(privateMode);
2690 }
2691
2692 MediaControls* HTMLMediaElement::mediaControls()
2693 {
2694     if (!shadowRoot())
2695         return 0;
2696
2697     Node* node = shadowRoot()->firstChild();
2698     ASSERT(node->isHTMLElement());
2699     return static_cast<MediaControls*>(node);
2700 }
2701
2702 bool HTMLMediaElement::hasMediaControls()
2703 {
2704     return shadowRoot();
2705 }
2706
2707 void HTMLMediaElement::ensureMediaControls()
2708 {
2709     if (hasMediaControls())
2710         return;
2711
2712     ExceptionCode ec;
2713     ensureShadowRoot()->appendChild(MediaControls::create(this), ec);
2714 }
2715
2716 void* HTMLMediaElement::preDispatchEventHandler(Event* event)
2717 {
2718     if (event && event->type() == eventNames().webkitfullscreenchangeEvent) {
2719         if (controls()) {
2720             if (!hasMediaControls()) {
2721                 ensureMediaControls();
2722                 mediaControls()->reset();
2723             }
2724             mediaControls()->show();
2725         } else if (hasMediaControls())
2726             mediaControls()->hide();
2727     }
2728     return 0;
2729 }
2730
2731
2732 }
2733
2734 #endif