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