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