2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #include <wtf/Platform.h>
28 #include "HTMLMediaElement.h"
29 #include "HTMLDocument.h"
30 #include <misc/htmlhashes.h>
31 #include <rendering/render_object.h>
32 #include "MediaError.h"
33 #include "TimeRanges.h"
35 const double doubleMax
= 999999999.8; // ### numeric_limits<double>::max()
36 const double doubleInf
= 999999999.0; // ### numeric_limits<double>::infinity()
42 HTMLMediaElement::HTMLMediaElement(Document
* doc
)
44 , m_defaultPlaybackRate(1.0f
)
45 , m_networkState(EMPTY
)
46 , m_readyState(DATA_UNAVAILABLE
)
48 , m_loadedFirstFrame(false)
55 , m_currentTimeDuringSeek(0)
56 , m_previousProgress(0)
57 , m_previousProgressTime(doubleMax
)
58 , m_sentStalledEvent(false)
64 HTMLMediaElement::~HTMLMediaElement()
68 void HTMLMediaElement::attributeChanged(NodeImpl::Id attrId
)
70 HTMLElement::attributeChanged(attrId
);
72 if (attrId
== ATTR_SRC
) {
74 // change to src attribute triggers load()
75 if (inDocument() && m_networkState
== EMPTY
)
77 } if (attrId
== ATTR_CONTROLS
) {
78 if (!isVideo() && attached() && (controls() != (renderer() != 0))) {
83 renderer()->updateFromElement();
87 void HTMLMediaElement::scheduleLoad()
92 String
serializeTimeOffset(float time
)
94 QString timeString
= QString::number(time
);
95 // FIXME serialize time offset values properly (format not specified yet)
96 timeString
.append("s");
100 float parseTimeOffset(const String
& timeString
, bool* ok
= 0)
103 const UChar
* characters
= timeString
.characters();
104 unsigned length
= timeString
.length();
106 if (length
&& characters
[length
- 1] == 's')
109 // FIXME parse time offset values (format not specified yet)
110 float val
= charactersToFloat(characters
, length
, ok
);
113 return timeString
.string().toFloat(ok
);
117 float HTMLMediaElement::getTimeOffsetAttribute(NodeImpl::Id name
, float valueOnError
) const
120 String timeString
= getAttribute(name
);
121 float result
= parseTimeOffset(timeString
, &ok
);
127 void HTMLMediaElement::setTimeOffsetAttribute(NodeImpl::Id name
, float value
)
129 setAttribute(name
, serializeTimeOffset(value
));
132 PassRefPtr
<MediaError
> HTMLMediaElement::error() const
137 String
HTMLMediaElement::src() const
139 return document()->completeURL(getAttribute(ATTR_SRC
).string());
142 void HTMLMediaElement::setSrc(const String
& url
)
144 setAttribute(ATTR_SRC
, url
);
147 String
HTMLMediaElement::currentSrc() const
152 HTMLMediaElement::NetworkState
HTMLMediaElement::networkState() const
154 return m_networkState
;
157 float HTMLMediaElement::bufferingRate()
161 return m_bufferingRate
;
164 void HTMLMediaElement::load(ExceptionCode
&)
169 void HTMLMediaElement::setReadyState(ReadyState state
)
171 // 3.14.9.6. The ready states
172 if (m_readyState
== state
)
180 HTMLMediaElement::ReadyState
HTMLMediaElement::readyState() const
185 bool HTMLMediaElement::seeking() const
191 float HTMLMediaElement::currentTime() const
196 return m_currentTimeDuringSeek
;
197 return m_player
->currentTime();
200 void HTMLMediaElement::setCurrentTime(float time
, ExceptionCode
& ec
)
205 float HTMLMediaElement::duration() const
207 return m_player
? m_player
->duration() : 0;
210 bool HTMLMediaElement::paused() const
215 float HTMLMediaElement::defaultPlaybackRate() const
217 return m_defaultPlaybackRate
;
220 void HTMLMediaElement::setDefaultPlaybackRate(float rate
, ExceptionCode
& ec
)
223 ec
= DOMException::NOT_SUPPORTED_ERR
;
226 if (m_defaultPlaybackRate
!= rate
) {
227 m_defaultPlaybackRate
= rate
;
228 // ### dispatchEventAsync(ratechangeEvent);
232 float HTMLMediaElement::playbackRate() const
234 return m_player
? m_player
->rate() : 0;
237 void HTMLMediaElement::setPlaybackRate(float rate
, ExceptionCode
& ec
)
240 ec
= DOMException::NOT_SUPPORTED_ERR
;
243 if (m_player
&& m_player
->rate() != rate
) {
244 m_player
->setRate(rate
);
245 // ### dispatchEventAsync(ratechangeEvent);
249 bool HTMLMediaElement::ended() const
251 return endedPlayback();
254 bool HTMLMediaElement::autoplay() const
256 return hasAttribute(ATTR_AUTOPLAY
);
259 void HTMLMediaElement::setAutoplay(bool b
)
261 // setBooleanAttribute(ATTR_AUTOPLAY, b);
264 void HTMLMediaElement::play(ExceptionCode
& ec
)
266 // 3.14.9.7. Playing the media resource
267 if (!m_player
|| networkState() == EMPTY
) {
273 ExceptionCode unused
;
274 if (endedPlayback()) {
276 // ### seek(effectiveStart(), unused);
278 setPlaybackRate(defaultPlaybackRate(), unused
);
282 // ### dispatchEventAsync(playEvent);
285 m_autoplaying
= false;
290 void HTMLMediaElement::pause(ExceptionCode
& ec
)
292 // 3.14.9.7. Playing the media resource
293 if (!m_player
|| networkState() == EMPTY
) {
302 // ### dispatchEventAsync(timeupdateEvent);
303 // ### dispatchEventAsync(pauseEvent);
306 m_autoplaying
= false;
311 unsigned HTMLMediaElement::playCount() const
313 String val
= getAttribute(ATTR_PLAYCOUNT
);
314 int count
= val
.toInt();
315 return qMax(count
, 1);
318 void HTMLMediaElement::setPlayCount(unsigned count
, ExceptionCode
& ec
)
321 ec
= DOMException::INDEX_SIZE_ERR
;
324 setAttribute(ATTR_PLAYCOUNT
, QString::number(count
));
328 float HTMLMediaElement::start() const
330 return getTimeOffsetAttribute(ATTR_START
, 0);
333 void HTMLMediaElement::setStart(float time
)
335 setTimeOffsetAttribute(ATTR_START
, time
);
339 float HTMLMediaElement::end() const
341 return getTimeOffsetAttribute(ATTR_END
, doubleInf
);
344 void HTMLMediaElement::setEnd(float time
)
346 setTimeOffsetAttribute(ATTR_END
, time
);
350 float HTMLMediaElement::loopStart() const
352 return getTimeOffsetAttribute(ATTR_LOOPSTART
, 0);
355 void HTMLMediaElement::setLoopStart(float time
)
357 setTimeOffsetAttribute(ATTR_LOOPSTART
, time
);
361 float HTMLMediaElement::loopEnd() const
363 return getTimeOffsetAttribute(ATTR_LOOPEND
, doubleInf
);
366 void HTMLMediaElement::setLoopEnd(float time
)
368 setTimeOffsetAttribute(ATTR_LOOPEND
, time
);
372 unsigned HTMLMediaElement::currentLoop() const
374 return m_currentLoop
;
377 void HTMLMediaElement::setCurrentLoop(unsigned currentLoop
)
379 m_currentLoop
= currentLoop
;
382 bool HTMLMediaElement::controls() const
384 return hasAttribute(ATTR_CONTROLS
);
387 void HTMLMediaElement::setControls(bool b
)
389 // setBooleanAttribute(ATTR_CONTROLS, b);
392 float HTMLMediaElement::volume() const
397 void HTMLMediaElement::setVolume(float vol
, ExceptionCode
& ec
)
399 if (vol
< 0.0f
|| vol
> 1.0f
) {
400 ec
= DOMException::INDEX_SIZE_ERR
;
404 if (m_volume
!= vol
) {
407 // ### dispatchEventAsync(volumechangeEvent);
411 bool HTMLMediaElement::muted() const
416 void HTMLMediaElement::setMuted(bool muted
)
418 if (m_muted
!= muted
) {
421 // ### dispatchEventAsync(volumechangeEvent);
425 void HTMLMediaElement::checkIfSeekNeeded()
430 PassRefPtr
<TimeRanges
> HTMLMediaElement::buffered() const
432 // FIXME real ranges support
433 if (!m_player
|| !m_player
->maxTimeBuffered())
434 return new TimeRanges
;
435 return new TimeRanges(0, m_player
->maxTimeBuffered());
438 PassRefPtr
<TimeRanges
> HTMLMediaElement::played() const
440 // FIXME track played
441 return new TimeRanges
;
444 PassRefPtr
<TimeRanges
> HTMLMediaElement::seekable() const
446 // FIXME real ranges support
447 if (!m_player
|| !m_player
->maxTimeSeekable())
448 return new TimeRanges
;
449 return new TimeRanges(0, m_player
->maxTimeSeekable());
452 bool HTMLMediaElement::endedPlayback() const
455 return networkState() >= LOADED_METADATA
&& currentTime() >= effectiveEnd() && currentLoop() == playCount() - 1;
460 void HTMLMediaElement::updateVolume()
465 m_player
->setVolume(m_muted
? 0 : m_volume
);
468 renderer()->updateFromElement();
471 void HTMLMediaElement::updatePlayState()