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