~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/3rdparty/webkit/WebCore/html/HTMLMediaElement.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
 
2
 * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
3
3
 *
4
4
 * Redistribution and use in source and binary forms, with or without
5
5
 * modification, are permitted provided that the following conditions
31
31
#include "CSSHelper.h"
32
32
#include "CSSPropertyNames.h"
33
33
#include "CSSValueKeywords.h"
 
34
#include "ContentType.h"
34
35
#include "DocLoader.h"
35
36
#include "Event.h"
36
37
#include "EventNames.h"
37
38
#include "ExceptionCode.h"
38
39
#include "Frame.h"
39
40
#include "FrameLoader.h"
 
41
#include "FrameLoaderClient.h"
40
42
#include "HTMLDocument.h"
41
43
#include "HTMLNames.h"
42
44
#include "HTMLSourceElement.h"
43
45
#include "HTMLVideoElement.h"
44
 
#include <limits>
 
46
#include "MIMETypeRegistry.h"
 
47
#include "MappedAttribute.h"
 
48
#include "MediaDocument.h"
45
49
#include "MediaError.h"
46
50
#include "MediaList.h"
 
51
#include "MediaPlayer.h"
47
52
#include "MediaQueryEvaluator.h"
48
 
#include "MIMETypeRegistry.h"
49
 
#include "MediaPlayer.h"
50
53
#include "Page.h"
 
54
#include "ProgressEvent.h"
51
55
#include "RenderVideo.h"
52
 
#include "SystemTime.h"
 
56
#include "ScriptEventListener.h"
53
57
#include "TimeRanges.h"
 
58
#include <limits>
 
59
#include <wtf/CurrentTime.h>
54
60
#include <wtf/MathExtras.h>
55
61
 
 
62
#if USE(ACCELERATED_COMPOSITING)
 
63
#include "RenderView.h"
 
64
#include "RenderLayerCompositor.h"
 
65
#endif
 
66
 
 
67
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
 
68
#include "RenderPartObject.h"
 
69
#include "Widget.h"
 
70
#endif
 
71
 
56
72
using namespace std;
57
73
 
58
74
namespace WebCore {
64
80
    , m_loadTimer(this, &HTMLMediaElement::loadTimerFired)
65
81
    , m_asyncEventTimer(this, &HTMLMediaElement::asyncEventTimerFired)
66
82
    , m_progressEventTimer(this, &HTMLMediaElement::progressEventTimerFired)
 
83
    , m_playbackProgressTimer(this, &HTMLMediaElement::playbackProgressTimerFired)
 
84
    , m_playedTimeRanges()
 
85
    , m_playbackRate(1.0f)
67
86
    , m_defaultPlaybackRate(1.0f)
68
 
    , m_networkState(EMPTY)
69
 
    , m_readyState(DATA_UNAVAILABLE)
70
 
    , m_begun(false)
71
 
    , m_loadedFirstFrame(false)
 
87
    , m_webkitPreservesPitch(true)
 
88
    , m_networkState(NETWORK_EMPTY)
 
89
    , m_readyState(HAVE_NOTHING)
 
90
    , m_volume(1.0f)
 
91
    , m_lastSeekTime(0)
 
92
    , m_previousProgress(0)
 
93
    , m_previousProgressTime(numeric_limits<double>::max())
 
94
    , m_lastTimeUpdateEventWallTime(0)
 
95
    , m_lastTimeUpdateEventMovieTime(numeric_limits<float>::max())
 
96
    , m_loadState(WaitingForSource)
 
97
    , m_currentSourceNode(0)
 
98
    , m_player(0)
 
99
    , m_restrictions(NoRestrictions)
 
100
    , m_playing(false)
 
101
    , m_processingMediaPlayerCallback(0)
 
102
    , m_processingLoad(false)
 
103
    , m_delayingTheLoadEvent(false)
 
104
    , m_haveFiredLoadedData(false)
 
105
    , m_inActiveDocument(true)
72
106
    , m_autoplaying(true)
73
 
    , m_currentLoop(0)
74
 
    , m_volume(1.0f)
75
107
    , m_muted(false)
76
108
    , m_paused(true)
77
109
    , m_seeking(false)
78
 
    , m_currentTimeDuringSeek(0)
79
 
    , m_previousProgress(0)
80
 
    , m_previousProgressTime(numeric_limits<double>::max())
81
110
    , m_sentStalledEvent(false)
82
 
    , m_bufferingRate(0)
83
 
    , m_loadNestingLevel(0)
84
 
    , m_terminateLoadBelowNestingLevel(0)
 
111
    , m_sentEndEvent(false)
85
112
    , m_pausedInternal(false)
86
 
    , m_inActiveDocument(true)
87
 
    , m_player(0)
 
113
    , m_sendProgressEvents(true)
 
114
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
 
115
    , m_needWidgetUpdate(false)
 
116
#endif
88
117
{
89
118
    document()->registerForDocumentActivationCallbacks(this);
90
119
    document()->registerForMediaVolumeCallbacks(this);
107
136
 
108
137
    const QualifiedName& attrName = attr->name();
109
138
    if (attrName == srcAttr) {
110
 
        // 3.14.9.2.
111
 
        // change to src attribute triggers load()
112
 
        if (inDocument() && m_networkState == EMPTY)
 
139
        // don't have a src or any <source> children, trigger load
 
140
        if (inDocument() && m_loadState == WaitingForSource)
113
141
            scheduleLoad();
114
 
    } if (attrName == controlsAttr) {
 
142
    } 
 
143
#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
 
144
    else if (attrName == controlsAttr) {
115
145
        if (!isVideo() && attached() && (controls() != (renderer() != 0))) {
116
146
            detach();
117
147
            attach();
119
149
        if (renderer())
120
150
            renderer()->updateFromElement();
121
151
    }
122
 
}
123
 
    
 
152
#endif
 
153
}
 
154
 
 
155
void HTMLMediaElement::parseMappedAttribute(MappedAttribute* attr)
 
156
{
 
157
    const QualifiedName& attrName = attr->name();
 
158
 
 
159
    if (attrName == autobufferAttr) {
 
160
        if (m_player)
 
161
            m_player->setAutobuffer(!attr->isNull());
 
162
    } else if (attrName == onabortAttr)
 
163
        setAttributeEventListener(eventNames().abortEvent, createAttributeEventListener(this, attr));
 
164
    else if (attrName == oncanplayAttr)
 
165
        setAttributeEventListener(eventNames().canplayEvent, createAttributeEventListener(this, attr));
 
166
    else if (attrName == oncanplaythroughAttr)
 
167
        setAttributeEventListener(eventNames().canplaythroughEvent, createAttributeEventListener(this, attr));
 
168
    else if (attrName == ondurationchangeAttr)
 
169
        setAttributeEventListener(eventNames().durationchangeEvent, createAttributeEventListener(this, attr));
 
170
    else if (attrName == onemptiedAttr)
 
171
        setAttributeEventListener(eventNames().emptiedEvent, createAttributeEventListener(this, attr));
 
172
    else if (attrName == onendedAttr)
 
173
        setAttributeEventListener(eventNames().endedEvent, createAttributeEventListener(this, attr));
 
174
    else if (attrName == onerrorAttr)
 
175
        setAttributeEventListener(eventNames().errorEvent, createAttributeEventListener(this, attr));
 
176
    else if (attrName == onloadAttr)
 
177
        setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr));
 
178
    else if (attrName == onloadeddataAttr)
 
179
        setAttributeEventListener(eventNames().loadeddataEvent, createAttributeEventListener(this, attr));
 
180
    else if (attrName == onloadedmetadataAttr)
 
181
        setAttributeEventListener(eventNames().loadedmetadataEvent, createAttributeEventListener(this, attr));
 
182
    else if (attrName == onloadendAttr)
 
183
        setAttributeEventListener(eventNames().loadendEvent, createAttributeEventListener(this, attr));
 
184
    else if (attrName == onloadstartAttr)
 
185
        setAttributeEventListener(eventNames().loadstartEvent, createAttributeEventListener(this, attr));
 
186
    else if (attrName == onpauseAttr)
 
187
        setAttributeEventListener(eventNames().pauseEvent, createAttributeEventListener(this, attr));
 
188
    else if (attrName == onplayAttr)
 
189
        setAttributeEventListener(eventNames().playEvent, createAttributeEventListener(this, attr));
 
190
    else if (attrName == onplayingAttr)
 
191
        setAttributeEventListener(eventNames().playingEvent, createAttributeEventListener(this, attr));
 
192
    else if (attrName == onprogressAttr)
 
193
        setAttributeEventListener(eventNames().progressEvent, createAttributeEventListener(this, attr));
 
194
    else if (attrName == onratechangeAttr)
 
195
        setAttributeEventListener(eventNames().ratechangeEvent, createAttributeEventListener(this, attr));
 
196
    else if (attrName == onseekedAttr)
 
197
        setAttributeEventListener(eventNames().seekedEvent, createAttributeEventListener(this, attr));
 
198
    else if (attrName == onseekingAttr)
 
199
        setAttributeEventListener(eventNames().seekingEvent, createAttributeEventListener(this, attr));
 
200
    else if (attrName == onstalledAttr)
 
201
        setAttributeEventListener(eventNames().stalledEvent, createAttributeEventListener(this, attr));
 
202
    else if (attrName == onsuspendAttr)
 
203
        setAttributeEventListener(eventNames().suspendEvent, createAttributeEventListener(this, attr));
 
204
    else if (attrName == ontimeupdateAttr)
 
205
        setAttributeEventListener(eventNames().timeupdateEvent, createAttributeEventListener(this, attr));
 
206
    else if (attrName == onvolumechangeAttr)
 
207
        setAttributeEventListener(eventNames().volumechangeEvent, createAttributeEventListener(this, attr));
 
208
    else if (attrName == onwaitingAttr)
 
209
        setAttributeEventListener(eventNames().waitingEvent, createAttributeEventListener(this, attr));
 
210
    else
 
211
        HTMLElement::parseMappedAttribute(attr);
 
212
}
 
213
 
124
214
bool HTMLMediaElement::rendererIsNeeded(RenderStyle* style)
125
215
{
 
216
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
 
217
    UNUSED_PARAM(style);
 
218
    Frame* frame = document()->frame();
 
219
    if (!frame)
 
220
        return false;
 
221
 
 
222
    return true;
 
223
#else
126
224
    return controls() ? HTMLElement::rendererIsNeeded(style) : false;
 
225
#endif
127
226
}
128
227
 
129
228
RenderObject* HTMLMediaElement::createRenderer(RenderArena* arena, RenderStyle*)
130
229
{
 
230
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
 
231
    return new (arena) RenderPartObject(this);
 
232
#else
131
233
    return new (arena) RenderMedia(this);
 
234
#endif
132
235
}
133
236
 
134
237
void HTMLMediaElement::insertedIntoDocument()
135
238
{
136
239
    HTMLElement::insertedIntoDocument();
137
 
    if (!src().isEmpty())
 
240
    if (!src().isEmpty() && m_networkState == NETWORK_EMPTY)
138
241
        scheduleLoad();
139
242
}
140
243
 
141
244
void HTMLMediaElement::removedFromDocument()
142
245
{
143
 
    // FIXME: pause() may invoke load() which seem like a strange thing to do as a side effect
144
 
    // of removing an element. This might need to be fixed in the spec.
145
 
    ExceptionCode ec;
146
 
    pause(ec);
 
246
    if (m_networkState > NETWORK_EMPTY)
 
247
        pause();
147
248
    HTMLElement::removedFromDocument();
148
249
}
149
250
 
151
252
{
152
253
    ASSERT(!attached());
153
254
 
 
255
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
 
256
    m_needWidgetUpdate = true;
 
257
#endif
 
258
 
154
259
    HTMLElement::attach();
155
260
 
156
261
    if (renderer())
167
272
 
168
273
void HTMLMediaElement::scheduleLoad()
169
274
{
170
 
    m_loadTimer.startOneShot(0);
171
 
}
172
 
 
173
 
void HTMLMediaElement::initAndDispatchProgressEvent(const AtomicString& eventName)
174
 
{
 
275
    if (m_loadTimer.isActive())
 
276
        return;
 
277
    prepareForLoad();
 
278
    m_loadTimer.startOneShot(0);
 
279
}
 
280
 
 
281
void HTMLMediaElement::scheduleNextSourceChild()
 
282
{
 
283
    // Schedule the timer to try the next <source> element WITHOUT resetting state ala prepareForLoad.
 
284
    m_loadTimer.startOneShot(0);
 
285
}
 
286
 
 
287
void HTMLMediaElement::scheduleProgressEvent(const AtomicString& eventName)
 
288
{
 
289
    if (!m_sendProgressEvents)
 
290
        return;
 
291
 
 
292
    // FIXME: don't schedule timeupdate or progress events unless there are registered listeners
 
293
 
175
294
    bool totalKnown = m_player && m_player->totalBytesKnown();
176
295
    unsigned loaded = m_player ? m_player->bytesLoaded() : 0;
177
296
    unsigned total = m_player ? m_player->totalBytes() : 0;
178
 
    dispatchProgressEvent(eventName, totalKnown, loaded, total);
 
297
 
 
298
    RefPtr<ProgressEvent> evt = ProgressEvent::create(eventName, totalKnown, loaded, total);
 
299
    enqueueEvent(evt);
 
300
 
179
301
    if (renderer())
180
302
        renderer()->updateFromElement();
181
303
}
182
304
 
183
 
void HTMLMediaElement::dispatchEventAsync(const AtomicString& eventName)
184
 
{
185
 
    m_asyncEventsToDispatch.append(eventName);
186
 
    if (!m_asyncEventTimer.isActive())                            
 
305
void HTMLMediaElement::scheduleEvent(const AtomicString& eventName)
 
306
{
 
307
    enqueueEvent(Event::create(eventName, false, true));
 
308
}
 
309
 
 
310
void HTMLMediaElement::enqueueEvent(RefPtr<Event> event)
 
311
{
 
312
    m_pendingEvents.append(event);
 
313
    if (!m_asyncEventTimer.isActive())
187
314
        m_asyncEventTimer.startOneShot(0);
188
315
}
189
316
 
 
317
void HTMLMediaElement::asyncEventTimerFired(Timer<HTMLMediaElement>*)
 
318
{
 
319
    Vector<RefPtr<Event> > pendingEvents;
 
320
    ExceptionCode ec = 0;
 
321
 
 
322
    m_pendingEvents.swap(pendingEvents);
 
323
    unsigned count = pendingEvents.size();
 
324
    for (unsigned ndx = 0; ndx < count; ++ndx) 
 
325
        dispatchEvent(pendingEvents[ndx].release(), ec);
 
326
}
 
327
 
190
328
void HTMLMediaElement::loadTimerFired(Timer<HTMLMediaElement>*)
191
329
{
192
 
    ExceptionCode ec;
193
 
    load(ec);
194
 
}
195
 
 
196
 
void HTMLMediaElement::asyncEventTimerFired(Timer<HTMLMediaElement>*)
197
 
{
198
 
    Vector<AtomicString> asyncEventsToDispatch;
199
 
    m_asyncEventsToDispatch.swap(asyncEventsToDispatch);
200
 
    unsigned count = asyncEventsToDispatch.size();
201
 
    for (unsigned n = 0; n < count; ++n)
202
 
        dispatchEventForType(asyncEventsToDispatch[n], false, true);
203
 
}
204
 
 
205
 
String serializeTimeOffset(float time)
 
330
    if (m_loadState == LoadingFromSourceElement)
 
331
        loadNextSourceChild();
 
332
    else
 
333
        loadInternal();
 
334
}
 
335
 
 
336
static String serializeTimeOffset(float time)
206
337
{
207
338
    String timeString = String::number(time);
208
339
    // FIXME serialize time offset values properly (format not specified yet)
210
341
    return timeString;
211
342
}
212
343
 
213
 
float parseTimeOffset(const String& timeString, bool* ok = 0)
 
344
static float parseTimeOffset(const String& timeString, bool* ok = 0)
214
345
{
215
346
    const UChar* characters = timeString.characters();
216
347
    unsigned length = timeString.length();
263
394
    return m_networkState;
264
395
}
265
396
 
266
 
float HTMLMediaElement::bufferingRate()
 
397
String HTMLMediaElement::canPlayType(const String& mimeType) const
267
398
{
268
 
    if (!m_player)
269
 
        return 0;
270
 
    return m_bufferingRate;
271
 
    //return m_player->dataRate();
 
399
    MediaPlayer::SupportsType support = MediaPlayer::supportsType(ContentType(mimeType));
 
400
    String canPlay;
 
401
 
 
402
    // 4.8.10.3
 
403
    switch (support)
 
404
    {
 
405
        case MediaPlayer::IsNotSupported:
 
406
            canPlay = "";
 
407
            break;
 
408
        case MediaPlayer::MayBeSupported:
 
409
            canPlay = "maybe";
 
410
            break;
 
411
        case MediaPlayer::IsSupported:
 
412
            canPlay = "probably";
 
413
            break;
 
414
    }
 
415
    
 
416
    return canPlay;
272
417
}
273
418
 
274
419
void HTMLMediaElement::load(ExceptionCode& ec)
275
420
{
276
 
    String mediaSrc;
277
 
    Frame* frame = document()->frame();
278
 
    FrameLoader* loader = frame ? frame->loader() : 0;
279
 
    
280
 
    // 3.14.9.4. Loading the media resource
281
 
    // 1
282
 
    // if an event generated during load() ends up re-entering load(), terminate previous instances
283
 
    m_loadNestingLevel++;
284
 
    m_terminateLoadBelowNestingLevel = m_loadNestingLevel;
285
 
    
286
 
    m_progressEventTimer.stop();
 
421
    if (m_restrictions & RequireUserGestureForLoadRestriction && !processingUserGesture())
 
422
        ec = INVALID_STATE_ERR;
 
423
    else {
 
424
        prepareForLoad();
 
425
        loadInternal();
 
426
    }
 
427
}
 
428
 
 
429
void HTMLMediaElement::prepareForLoad()
 
430
{
 
431
    // Perform the cleanup required for the resource load algorithm to run.
 
432
    stopPeriodicTimers();
 
433
    m_loadTimer.stop();
287
434
    m_sentStalledEvent = false;
288
 
    m_bufferingRate = 0;
289
 
    
290
 
    m_loadTimer.stop();
291
 
    
292
 
    // 2
293
 
    if (m_begun) {
294
 
        m_begun = false;
 
435
    m_haveFiredLoadedData = false;
 
436
 
 
437
    // 2 - Abort any already-running instance of the resource selection algorithm for this element.
 
438
    m_currentSourceNode = 0;
 
439
 
 
440
    // 3 - If there are any tasks from the media element's media element event task source in 
 
441
    // one of the task queues, then remove those tasks.
 
442
    cancelPendingEventsAndCallbacks();
 
443
}
 
444
 
 
445
void HTMLMediaElement::loadInternal()
 
446
{
 
447
    // 1 - If the load() method for this element is already being invoked, then abort these steps.
 
448
    if (m_processingLoad)
 
449
        return;
 
450
    m_processingLoad = true;
 
451
    
 
452
    // Steps 2 and 3 were done in prepareForLoad()
 
453
    
 
454
    // 4 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, set
 
455
    // the error attribute to a new MediaError object whose code attribute is set to
 
456
    // MEDIA_ERR_ABORTED, fire a progress event called abort at the media element, in the
 
457
    // context of the fetching process that is in progress for the element, and fire a progress
 
458
    // event called loadend at the media element, in the context of the same fetching process.
 
459
    if (m_networkState == NETWORK_LOADING || m_networkState == NETWORK_IDLE) {
295
460
        m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
296
 
        initAndDispatchProgressEvent(eventNames().abortEvent);
297
 
        if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
298
 
            goto end;
 
461
 
 
462
        // fire synchronous 'abort' and 'loadend'
 
463
        bool totalKnown = m_player && m_player->totalBytesKnown();
 
464
        unsigned loaded = m_player ? m_player->bytesLoaded() : 0;
 
465
        unsigned total = m_player ? m_player->totalBytes() : 0;
 
466
        dispatchEvent(ProgressEvent::create(eventNames().abortEvent, totalKnown, loaded, total));
 
467
        dispatchEvent(ProgressEvent::create(eventNames().loadendEvent, totalKnown, loaded, total));
299
468
    }
300
 
    
301
 
    // 3
 
469
 
 
470
    // 5
302
471
    m_error = 0;
303
 
    m_loadedFirstFrame = false;
304
472
    m_autoplaying = true;
305
 
    
306
 
    // 4
307
 
    setPlaybackRate(defaultPlaybackRate(), ec);
308
 
    
309
 
    // 5
310
 
    if (networkState() != EMPTY) {
311
 
        m_networkState = EMPTY;
312
 
        m_readyState = DATA_UNAVAILABLE;
 
473
    m_playedTimeRanges = TimeRanges::create();
 
474
    m_lastSeekTime = 0;
 
475
 
 
476
    // 6
 
477
    setPlaybackRate(defaultPlaybackRate());
 
478
 
 
479
    // 7
 
480
    if (m_networkState != NETWORK_EMPTY) {
 
481
        m_networkState = NETWORK_EMPTY;
 
482
        m_readyState = HAVE_NOTHING;
313
483
        m_paused = true;
314
484
        m_seeking = false;
315
485
        if (m_player) {
316
486
            m_player->pause();
 
487
            m_playing = false;
317
488
            m_player->seek(0);
318
489
        }
319
 
        m_currentLoop = 0;
320
 
        dispatchEventForType(eventNames().emptiedEvent, false, true);
321
 
        if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
322
 
            goto end;
323
 
    }
324
 
    
325
 
    // 6
326
 
    mediaSrc = pickMedia();
327
 
    if (mediaSrc.isEmpty()) {
328
 
        ec = INVALID_STATE_ERR;
329
 
        goto end;
330
 
    }
331
 
 
332
 
    // don't allow remote to local urls
333
 
    if (!loader || !loader->canLoad(KURL(KURL(), mediaSrc), String(), document())) {
334
 
        FrameLoader::reportLocalLoadFailed(frame, mediaSrc);
335
 
 
336
 
        ec = INVALID_STATE_ERR;
337
 
        goto end;
338
 
    }
339
 
    
340
 
    // 7
341
 
    m_networkState = LOADING;
342
 
    
343
 
    // 8
344
 
    m_currentSrc = mediaSrc;
345
 
    
346
 
    // 9
347
 
    m_begun = true;        
348
 
    dispatchProgressEvent(eventNames().loadstartEvent, false, 0, 0);
349
 
    if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
350
 
        goto end;
351
 
    
352
 
    // 10, 11, 12, 13
 
490
        dispatchEvent(Event::create(eventNames().emptiedEvent, false, true));
 
491
    }
 
492
 
 
493
    selectMediaResource();
 
494
    m_processingLoad = false;
 
495
}
 
496
 
 
497
void HTMLMediaElement::selectMediaResource()
 
498
{
 
499
    // 1 - If the media element has neither a src attribute nor any source element children, run these substeps
 
500
    String mediaSrc = getAttribute(srcAttr);
 
501
    if (!mediaSrc && !havePotentialSourceChild()) {
 
502
        m_loadState = WaitingForSource;
 
503
 
 
504
        // 1 -  Set the networkState to NETWORK_NO_SOURCE
 
505
        m_networkState = NETWORK_NO_SOURCE;
 
506
        
 
507
        // 2 - While the media element has neither a src attribute nor any source element children, 
 
508
        // wait. (This steps might wait forever.)
 
509
 
 
510
        m_delayingTheLoadEvent = false;
 
511
        return;
 
512
    }
 
513
 
 
514
    // 2
 
515
    m_delayingTheLoadEvent = true;
 
516
 
 
517
    // 3
 
518
    m_networkState = NETWORK_LOADING;
 
519
 
 
520
    // 4
 
521
    scheduleProgressEvent(eventNames().loadstartEvent);
 
522
 
 
523
    // 5 - If the media element has a src attribute, then run these substeps
 
524
    ContentType contentType("");
 
525
    if (!mediaSrc.isEmpty()) {
 
526
        KURL mediaURL = document()->completeURL(mediaSrc);
 
527
        if (isSafeToLoadURL(mediaURL, Complain)) {
 
528
            m_loadState = LoadingFromSrcAttr;
 
529
            loadResource(mediaURL, contentType);
 
530
        } else 
 
531
            noneSupported();
 
532
 
 
533
        return;
 
534
    }
 
535
 
 
536
    // Otherwise, the source elements will be used
 
537
    m_currentSourceNode = 0;
 
538
    loadNextSourceChild();
 
539
}
 
540
 
 
541
void HTMLMediaElement::loadNextSourceChild()
 
542
{
 
543
    ContentType contentType("");
 
544
    KURL mediaURL = selectNextSourceChild(&contentType, Complain);
 
545
    if (!mediaURL.isValid()) {
 
546
        // It seems wrong to fail silently when we give up because no suitable <source>
 
547
        // element can be found and set the error attribute if the element's 'src' attribute
 
548
        // fails, but that is what the spec says.
 
549
        return;
 
550
    }
 
551
 
 
552
    m_loadState = LoadingFromSourceElement;
 
553
    loadResource(mediaURL, contentType);
 
554
}
 
555
 
 
556
void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType)
 
557
{
 
558
    ASSERT(isSafeToLoadURL(url, Complain));
 
559
 
 
560
    // The resource fetch algorithm 
 
561
    m_networkState = NETWORK_LOADING;
 
562
 
 
563
    m_currentSrc = url;
 
564
 
 
565
    if (m_sendProgressEvents) 
 
566
        startProgressEventTimer();
 
567
 
 
568
#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
353
569
    m_player.clear();
354
570
    m_player.set(new MediaPlayer(this));
 
571
#else
 
572
    if (!m_player)
 
573
        m_player.set(new MediaPlayer(this));
 
574
#endif
 
575
 
 
576
    m_player->setPreservesPitch(m_webkitPreservesPitch);
355
577
    updateVolume();
356
 
    m_player->load(m_currentSrc);
357
 
    if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
358
 
        goto end;
 
578
 
 
579
    m_player->load(m_currentSrc, contentType);
359
580
    
360
581
    if (renderer())
361
582
        renderer()->updateFromElement();
 
583
}
 
584
 
 
585
bool HTMLMediaElement::isSafeToLoadURL(const KURL& url, InvalidSourceAction actionIfInvalid)
 
586
{
 
587
    Frame* frame = document()->frame();
 
588
    FrameLoader* loader = frame ? frame->loader() : 0;
 
589
 
 
590
    // don't allow remote to local urls, and check with the frame loader client.
 
591
    if (!loader || !loader->canLoad(url, String(), document()) || !loader->client()->shouldLoadMediaElementURL(url)) {
 
592
        if (actionIfInvalid == Complain)
 
593
            FrameLoader::reportLocalLoadFailed(frame, url.string());
 
594
        return false;
 
595
    }
362
596
    
363
 
    // 14
364
 
    m_previousProgressTime = WebCore::currentTime();
 
597
    return true;
 
598
}
 
599
 
 
600
void HTMLMediaElement::startProgressEventTimer()
 
601
{
 
602
    if (m_progressEventTimer.isActive())
 
603
        return;
 
604
 
 
605
    m_previousProgressTime = WTF::currentTime();
365
606
    m_previousProgress = 0;
366
 
    if (m_begun)
367
 
        // 350ms is not magic, it is in the spec!
368
 
        m_progressEventTimer.startRepeating(0.350);
369
 
end:
370
 
    ASSERT(m_loadNestingLevel);
371
 
    m_loadNestingLevel--;
 
607
    // 350ms is not magic, it is in the spec!
 
608
    m_progressEventTimer.startRepeating(0.350);
 
609
}
 
610
 
 
611
void HTMLMediaElement::noneSupported()
 
612
{
 
613
    stopPeriodicTimers();
 
614
    m_loadState = WaitingForSource;
 
615
    m_currentSourceNode = 0;
 
616
 
 
617
    // 4 - Reaching this step indicates that either the URL failed to resolve, or the media
 
618
    // resource failed to load. Set the error attribute to a new MediaError object whose
 
619
    // code attribute is set to MEDIA_ERR_SRC_NOT_SUPPORTED.
 
620
    m_error = MediaError::create(MediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
 
621
 
 
622
    // 5 - Set the element's networkState attribute to the NETWORK_NO_SOURCE value.
 
623
    m_networkState = NETWORK_NO_SOURCE;
 
624
 
 
625
    // 6 - Queue a task to fire a progress event called error at the media element, in
 
626
    // the context of the fetching process that was used to try to obtain the media
 
627
    // resource in the resource fetch algorithm.
 
628
    scheduleProgressEvent(eventNames().errorEvent);
 
629
 
 
630
    // 7 - Queue a task to fire a progress event called loadend at the media element, in
 
631
    // the context of the fetching process that was used to try to obtain the media
 
632
    // resource in the resource fetch algorithm.
 
633
    scheduleProgressEvent(eventNames().loadendEvent);
 
634
 
 
635
    // 8 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
 
636
    m_delayingTheLoadEvent = false;
 
637
 
 
638
    // 9 -Abort these steps. Until the load() method is invoked, the element won't attempt to load another resource.
 
639
 
 
640
    if (isVideo())
 
641
        static_cast<HTMLVideoElement*>(this)->updatePosterImage();
 
642
    if (renderer())
 
643
        renderer()->updateFromElement();
 
644
}
 
645
 
 
646
void HTMLMediaElement::mediaEngineError(PassRefPtr<MediaError> err)
 
647
{
 
648
    // 1 - The user agent should cancel the fetching process.
 
649
    stopPeriodicTimers();
 
650
    m_loadState = WaitingForSource;
 
651
 
 
652
    // 2 - Set the error attribute to a new MediaError object whose code attribute is 
 
653
    // set to MEDIA_ERR_NETWORK/MEDIA_ERR_DECODE.
 
654
    m_error = err;
 
655
 
 
656
    // 3 - Queue a task to fire a progress event called error at the media element, in
 
657
    // the context of the fetching process started by this instance of this algorithm.
 
658
    scheduleProgressEvent(eventNames().errorEvent);
 
659
 
 
660
    // 4 - Queue a task to fire a progress event called loadend at the media element, in
 
661
    // the context of the fetching process started by this instance of this algorithm.
 
662
    scheduleProgressEvent(eventNames().loadendEvent);
 
663
 
 
664
    // 5 - Set the element's networkState attribute to the NETWORK_EMPTY value and queue a
 
665
    // task to fire a simple event called emptied at the element.
 
666
    m_networkState = NETWORK_EMPTY;
 
667
    scheduleEvent(eventNames().emptiedEvent);
 
668
 
 
669
    // 6 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
 
670
    m_delayingTheLoadEvent = false;
 
671
 
 
672
    // 7 - Abort the overall resource selection algorithm.
 
673
    m_currentSourceNode = 0;
 
674
}
 
675
 
 
676
void HTMLMediaElement::cancelPendingEventsAndCallbacks()
 
677
{
 
678
    m_pendingEvents.clear();
 
679
 
 
680
    for (Node* node = firstChild(); node; node = node->nextSibling()) {
 
681
        if (node->hasTagName(sourceTag))
 
682
            static_cast<HTMLSourceElement*>(node)->cancelPendingErrorEvent();
 
683
    }
372
684
}
373
685
 
374
686
void HTMLMediaElement::mediaPlayerNetworkStateChanged(MediaPlayer*)
375
687
{
376
 
    if (!m_begun || m_networkState == EMPTY)
377
 
        return;
378
 
    
379
 
    m_terminateLoadBelowNestingLevel = m_loadNestingLevel;
380
 
 
381
 
    MediaPlayer::NetworkState state = m_player->networkState();
382
 
    
383
 
    // 3.14.9.4. Loading the media resource
384
 
    // 14
385
 
    if (state == MediaPlayer::LoadFailed) {
386
 
        //delete m_player;
387
 
        //m_player = 0;
388
 
        // FIXME better error handling
389
 
        m_error = MediaError::create(MediaError::MEDIA_ERR_NETWORK);
390
 
        m_begun = false;
391
 
        m_progressEventTimer.stop();
392
 
        m_bufferingRate = 0;
393
 
        
394
 
        initAndDispatchProgressEvent(eventNames().errorEvent); 
395
 
        if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
396
 
            return;
397
 
        
398
 
        m_networkState = EMPTY;
399
 
        
400
 
        if (isVideo())
401
 
            static_cast<HTMLVideoElement*>(this)->updatePosterImage();
402
 
 
403
 
        dispatchEventForType(eventNames().emptiedEvent, false, true);
404
 
        return;
405
 
    }
406
 
    
407
 
    if (state >= MediaPlayer::Loading && m_networkState < LOADING)
408
 
        m_networkState = LOADING;
409
 
    
410
 
    if (state >= MediaPlayer::LoadedMetaData && m_networkState < LOADED_METADATA) {
411
 
        m_player->seek(effectiveStart());
412
 
        m_networkState = LOADED_METADATA;
413
 
        
414
 
        dispatchEventForType(eventNames().durationchangeEvent, false, true);
415
 
        if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
416
 
            return;
417
 
        
418
 
        dispatchEventForType(eventNames().loadedmetadataEvent, false, true);
419
 
        if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
420
 
            return;
421
 
    }
422
 
    
423
 
    if (state >= MediaPlayer::LoadedFirstFrame && m_networkState < LOADED_FIRST_FRAME) {
424
 
        m_networkState = LOADED_FIRST_FRAME;
425
 
        
426
 
        setReadyState(CAN_SHOW_CURRENT_FRAME);
427
 
        
428
 
        if (isVideo())
429
 
            static_cast<HTMLVideoElement*>(this)->updatePosterImage();
430
 
        
431
 
        if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
432
 
            return;
433
 
        
434
 
        m_loadedFirstFrame = true;
435
 
        if (renderer()) {
436
 
            ASSERT(!renderer()->isImage());
437
 
            static_cast<RenderVideo*>(renderer())->videoSizeChanged();
438
 
        }
439
 
        
440
 
        dispatchEventForType(eventNames().loadedfirstframeEvent, false, true);
441
 
        if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
442
 
            return;
443
 
        
444
 
        dispatchEventForType(eventNames().canshowcurrentframeEvent, false, true);
445
 
        if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel)
446
 
            return;
447
 
    }
448
 
    
449
 
    // 15
450
 
    if (state == MediaPlayer::Loaded && m_networkState < LOADED) {
451
 
        m_begun = false;
452
 
        m_networkState = LOADED;
453
 
        m_progressEventTimer.stop();
454
 
        m_bufferingRate = 0;
455
 
        initAndDispatchProgressEvent(eventNames().loadEvent); 
 
688
    beginProcessingMediaPlayerCallback();
 
689
    setNetworkState(m_player->networkState());
 
690
    endProcessingMediaPlayerCallback();
 
691
}
 
692
 
 
693
void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
 
694
{
 
695
    if (state == MediaPlayer::Empty) {
 
696
        // just update the cached state and leave, we can't do anything 
 
697
        m_networkState = NETWORK_EMPTY;
 
698
        return;
 
699
    }
 
700
 
 
701
    if (state == MediaPlayer::FormatError || state == MediaPlayer::NetworkError || state == MediaPlayer::DecodeError) {
 
702
        stopPeriodicTimers();
 
703
 
 
704
        // If we failed while trying to load a <source> element, the movie was never parsed, and there are more
 
705
        // <source> children, schedule the next one
 
706
        if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement) {
 
707
            m_currentSourceNode->scheduleErrorEvent();
 
708
            if (havePotentialSourceChild())
 
709
                scheduleNextSourceChild();
 
710
            return;
 
711
        }
 
712
 
 
713
        if (state == MediaPlayer::NetworkError)
 
714
            mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_NETWORK));
 
715
        else if (state == MediaPlayer::DecodeError)
 
716
            mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_DECODE));
 
717
        else if (state == MediaPlayer::FormatError && m_loadState == LoadingFromSrcAttr)
 
718
            noneSupported();
 
719
 
 
720
        if (isVideo())
 
721
            static_cast<HTMLVideoElement*>(this)->updatePosterImage();
 
722
 
 
723
        return;
 
724
    }
 
725
 
 
726
    if (state == MediaPlayer::Idle) {
 
727
        if (m_networkState > NETWORK_IDLE) {
 
728
            stopPeriodicTimers();
 
729
            scheduleProgressEvent(eventNames().suspendEvent);
 
730
        }
 
731
        m_networkState = NETWORK_IDLE;
 
732
    }
 
733
 
 
734
    if (state == MediaPlayer::Loading) {
 
735
        if (m_networkState < NETWORK_LOADING || m_networkState == NETWORK_NO_SOURCE)
 
736
            startProgressEventTimer();
 
737
        m_networkState = NETWORK_LOADING;
 
738
    }
 
739
 
 
740
    if (state == MediaPlayer::Loaded) {
 
741
        NetworkState oldState = m_networkState;
 
742
 
 
743
        m_networkState = NETWORK_LOADED;
 
744
        if (oldState < NETWORK_LOADED || oldState == NETWORK_NO_SOURCE) {
 
745
            m_progressEventTimer.stop();
 
746
 
 
747
            // Schedule one last progress event so we guarantee that at least one is fired
 
748
            // for files that load very quickly.
 
749
            scheduleProgressEvent(eventNames().progressEvent);
 
750
 
 
751
            // Check to see if readyState changes need to be dealt with before sending the 
 
752
            // 'load' event so we report 'canplaythrough' first. This is necessary because a
 
753
            //  media engine reports readyState and networkState changes separately
 
754
            MediaPlayer::ReadyState currentState = m_player->readyState();
 
755
            if (static_cast<ReadyState>(currentState) != m_readyState)
 
756
                setReadyState(currentState);
 
757
 
 
758
            scheduleProgressEvent(eventNames().loadEvent);
 
759
            scheduleProgressEvent(eventNames().loadendEvent);
 
760
        }
456
761
    }
457
762
}
458
763
 
459
764
void HTMLMediaElement::mediaPlayerReadyStateChanged(MediaPlayer*)
460
765
{
461
 
    MediaPlayer::ReadyState state = m_player->readyState();
462
 
    setReadyState((ReadyState)state);
 
766
    beginProcessingMediaPlayerCallback();
 
767
 
 
768
    setReadyState(m_player->readyState());
 
769
 
 
770
    endProcessingMediaPlayerCallback();
463
771
}
464
772
 
465
 
void HTMLMediaElement::setReadyState(ReadyState state)
 
773
void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
466
774
{
467
 
    // 3.14.9.6. The ready states
468
 
    if (m_readyState == state)
469
 
        return;
470
 
    
471
 
    bool wasActivelyPlaying = activelyPlaying();
472
 
    m_readyState = state;
473
 
    
474
 
    if (state >= CAN_PLAY)
475
 
        m_seeking = false;
476
 
    
477
 
    if (networkState() == EMPTY)
478
 
        return;
479
 
    
480
 
    if (state == DATA_UNAVAILABLE) {
481
 
        dispatchEventForType(eventNames().dataunavailableEvent, false, true);
482
 
        if (wasActivelyPlaying) {
483
 
            dispatchEventForType(eventNames().timeupdateEvent, false, true);
484
 
            dispatchEventForType(eventNames().waitingEvent, false, true);
485
 
        }
486
 
    } else if (state == CAN_SHOW_CURRENT_FRAME) {
487
 
        if (m_loadedFirstFrame)
488
 
            dispatchEventForType(eventNames().canshowcurrentframeEvent, false, true);
489
 
        if (wasActivelyPlaying) {
490
 
            dispatchEventForType(eventNames().timeupdateEvent, false, true);
491
 
            dispatchEventForType(eventNames().waitingEvent, false, true);
492
 
        }
493
 
    } else if (state == CAN_PLAY) {
494
 
        dispatchEventForType(eventNames().canplayEvent, false, true);
495
 
    } else if (state == CAN_PLAY_THROUGH) {
496
 
        dispatchEventForType(eventNames().canplaythroughEvent, false, true);
 
775
    // Set "wasPotentiallyPlaying" BEFORE updating m_readyState, potentiallyPlaying() uses it
 
776
    bool wasPotentiallyPlaying = potentiallyPlaying();
 
777
 
 
778
    ReadyState oldState = m_readyState;
 
779
    m_readyState = static_cast<ReadyState>(state);
 
780
 
 
781
    if (m_readyState == oldState)
 
782
        return;
 
783
    
 
784
    if (m_networkState == NETWORK_EMPTY)
 
785
        return;
 
786
 
 
787
    if (m_seeking) {
 
788
        // 4.8.10.10, step 8
 
789
        if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA)
 
790
            scheduleEvent(eventNames().waitingEvent);
 
791
 
 
792
        // 4.8.10.10, step 9
 
793
        if (m_readyState < HAVE_CURRENT_DATA) {
 
794
            if (oldState >= HAVE_CURRENT_DATA)
 
795
                scheduleEvent(eventNames().seekingEvent);
 
796
        } else {
 
797
            // 4.8.10.10 step 12 & 13.
 
798
            finishSeek();
 
799
        }
 
800
 
 
801
    } else {
 
802
        if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA) {
 
803
            // 4.8.10.9
 
804
            scheduleTimeupdateEvent(false);
 
805
            scheduleEvent(eventNames().waitingEvent);
 
806
        }
 
807
    }
 
808
 
 
809
    if (m_readyState >= HAVE_METADATA && oldState < HAVE_METADATA) {
 
810
        scheduleEvent(eventNames().durationchangeEvent);
 
811
        scheduleEvent(eventNames().loadedmetadataEvent);
 
812
 
 
813
#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
 
814
        if (renderer() && renderer()->isVideo()) {
 
815
            toRenderVideo(renderer())->videoSizeChanged();
 
816
        }
 
817
#endif        
 
818
        m_delayingTheLoadEvent = false;
 
819
        m_player->seek(0);
 
820
    }
 
821
 
 
822
    // 4.8.10.7 says loadeddata is sent only when the new state *is* HAVE_CURRENT_DATA: "If the
 
823
    // previous ready state was HAVE_METADATA and the new ready state is HAVE_CURRENT_DATA", 
 
824
    // but the event table at the end of the spec says it is sent when: "readyState newly 
 
825
    // increased to HAVE_CURRENT_DATA  or greater for the first time"
 
826
    // We go with the later because it seems useful to count on getting this event
 
827
    if (m_readyState >= HAVE_CURRENT_DATA && oldState < HAVE_CURRENT_DATA && !m_haveFiredLoadedData) {
 
828
        m_haveFiredLoadedData = true;
 
829
        scheduleEvent(eventNames().loadeddataEvent);
 
830
    }
 
831
 
 
832
    bool isPotentiallyPlaying = potentiallyPlaying();
 
833
    if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA) {
 
834
        scheduleEvent(eventNames().canplayEvent);
 
835
        if (isPotentiallyPlaying)
 
836
            scheduleEvent(eventNames().playingEvent);
 
837
 
 
838
        if (isVideo())
 
839
            static_cast<HTMLVideoElement*>(this)->updatePosterImage();
 
840
    }
 
841
 
 
842
    if (m_readyState == HAVE_ENOUGH_DATA && oldState < HAVE_ENOUGH_DATA) {
 
843
        if (oldState <= HAVE_CURRENT_DATA)
 
844
            scheduleEvent(eventNames().canplayEvent);
 
845
 
 
846
        scheduleEvent(eventNames().canplaythroughEvent);
 
847
 
 
848
        if (isPotentiallyPlaying && oldState <= HAVE_CURRENT_DATA)
 
849
            scheduleEvent(eventNames().playingEvent);
 
850
 
497
851
        if (m_autoplaying && m_paused && autoplay()) {
498
852
            m_paused = false;
499
 
            dispatchEventForType(eventNames().playEvent, false, true);
 
853
            scheduleEvent(eventNames().playEvent);
 
854
            scheduleEvent(eventNames().playingEvent);
500
855
        }
 
856
 
 
857
        if (isVideo())
 
858
            static_cast<HTMLVideoElement*>(this)->updatePosterImage();
501
859
    }
 
860
 
502
861
    updatePlayState();
503
862
}
504
863
 
505
864
void HTMLMediaElement::progressEventTimerFired(Timer<HTMLMediaElement>*)
506
865
{
507
866
    ASSERT(m_player);
 
867
    if (m_networkState == NETWORK_EMPTY || m_networkState >= NETWORK_LOADED)
 
868
        return;
 
869
 
508
870
    unsigned progress = m_player->bytesLoaded();
509
 
    double time = WebCore::currentTime();
 
871
    double time = WTF::currentTime();
510
872
    double timedelta = time - m_previousProgressTime;
511
 
    if (timedelta)
512
 
        m_bufferingRate = (float)(0.8 * m_bufferingRate + 0.2 * ((float)(progress - m_previousProgress)) / timedelta);
513
 
    
 
873
 
514
874
    if (progress == m_previousProgress) {
515
875
        if (timedelta > 3.0 && !m_sentStalledEvent) {
516
 
            m_bufferingRate = 0;
517
 
            initAndDispatchProgressEvent(eventNames().stalledEvent);
 
876
            scheduleProgressEvent(eventNames().stalledEvent);
518
877
            m_sentStalledEvent = true;
519
878
        }
520
879
    } else {
521
 
        initAndDispatchProgressEvent(eventNames().progressEvent);
 
880
        scheduleProgressEvent(eventNames().progressEvent);
522
881
        m_previousProgress = progress;
523
882
        m_previousProgressTime = time;
524
883
        m_sentStalledEvent = false;
525
884
    }
526
885
}
527
886
 
 
887
void HTMLMediaElement::rewind(float timeDelta)
 
888
{
 
889
    ExceptionCode e;
 
890
    setCurrentTime(max(currentTime() - timeDelta, minTimeSeekable()), e);
 
891
}
 
892
 
 
893
void HTMLMediaElement::returnToRealtime()
 
894
{
 
895
    ExceptionCode e;
 
896
    setCurrentTime(maxTimeSeekable(), e);
 
897
}  
 
898
 
 
899
void HTMLMediaElement::addPlayedRange(float start, float end)
 
900
{
 
901
    if (!m_playedTimeRanges)
 
902
        m_playedTimeRanges = TimeRanges::create();
 
903
    m_playedTimeRanges->add(start, end);
 
904
}  
 
905
 
 
906
bool HTMLMediaElement::supportsSave() const
 
907
{
 
908
    return m_player ? m_player->supportsSave() : false;
 
909
}
 
910
    
528
911
void HTMLMediaElement::seek(float time, ExceptionCode& ec)
529
912
{
530
 
    // 3.14.9.8. Seeking
 
913
    // 4.8.10.10. Seeking
531
914
    // 1
532
 
    if (networkState() < LOADED_METADATA) {
 
915
    if (m_readyState == HAVE_NOTHING || !m_player) {
533
916
        ec = INVALID_STATE_ERR;
534
917
        return;
535
918
    }
536
 
    
 
919
 
537
920
    // 2
538
 
    float minTime;
539
 
    if (currentLoop() == 0)
540
 
        minTime = effectiveStart();
541
 
    else
542
 
        minTime = effectiveLoopStart();
543
 
 
 
921
    time = min(time, duration());
 
922
 
544
923
    // 3
545
 
    float maxTime = currentLoop() == playCount() - 1 ? effectiveEnd() : effectiveLoopEnd();
546
 
    
 
924
    time = max(time, 0.0f);
 
925
 
547
926
    // 4
548
 
    time = min(time, maxTime);
549
 
    
550
 
    // 5
551
 
    time = max(time, minTime);
552
 
    
553
 
    // 6
554
927
    RefPtr<TimeRanges> seekableRanges = seekable();
555
928
    if (!seekableRanges->contain(time)) {
556
929
        ec = INDEX_SIZE_ERR;
557
930
        return;
558
931
    }
559
932
    
560
 
    // 7
561
 
    m_currentTimeDuringSeek = time;
562
 
 
563
 
    // 8
 
933
    // avoid generating events when the time won't actually change
 
934
    float now = currentTime();
 
935
    if (time == now)
 
936
        return;
 
937
 
 
938
    // 5
 
939
    if (m_playing) {
 
940
        if (m_lastSeekTime < now)
 
941
            addPlayedRange(m_lastSeekTime, now);
 
942
    }
 
943
    m_lastSeekTime = time;
 
944
 
 
945
    // 6 - set the seeking flag, it will be cleared when the engine tells is the time has actually changed
564
946
    m_seeking = true;
565
 
    
566
 
    // 9
567
 
    dispatchEventForType(eventNames().timeupdateEvent, false, true);
568
 
    
 
947
 
 
948
    // 7
 
949
    scheduleTimeupdateEvent(false);
 
950
 
 
951
    // 8 - this is covered, if necessary, when the engine signals a readystate change
 
952
 
569
953
    // 10
570
 
    // As soon as the user agent has established whether or not the media data for the new playback position is available, 
571
 
    // and, if it is, decoded enough data to play back that position, the seeking DOM attribute must be set to false.
572
 
    if (m_player) {
573
 
        m_player->setEndTime(maxTime);
574
 
        m_player->seek(time);
575
 
    }
 
954
    m_player->seek(time);
 
955
    m_sentEndEvent = false;
 
956
}
 
957
 
 
958
void HTMLMediaElement::finishSeek()
 
959
{
 
960
    // 4.8.10.10 Seeking step 12
 
961
    m_seeking = false;
 
962
 
 
963
    // 4.8.10.10 Seeking step 13
 
964
    scheduleEvent(eventNames().seekedEvent);
576
965
}
577
966
 
578
967
HTMLMediaElement::ReadyState HTMLMediaElement::readyState() const
580
969
    return m_readyState;
581
970
}
582
971
 
 
972
MediaPlayer::MovieLoadType HTMLMediaElement::movieLoadType() const
 
973
{
 
974
    return m_player ? m_player->movieLoadType() : MediaPlayer::Unknown;
 
975
}
 
976
 
 
977
bool HTMLMediaElement::hasAudio() const
 
978
{
 
979
    return m_player ? m_player->hasAudio() : false;
 
980
}
 
981
 
583
982
bool HTMLMediaElement::seeking() const
584
983
{
585
984
    return m_seeking;
591
990
    if (!m_player)
592
991
        return 0;
593
992
    if (m_seeking)
594
 
        return m_currentTimeDuringSeek;
 
993
        return m_lastSeekTime;
595
994
    return m_player->currentTime();
596
995
}
597
996
 
600
999
    seek(time, ec);
601
1000
}
602
1001
 
 
1002
float HTMLMediaElement::startTime() const
 
1003
{
 
1004
    if (!m_player)
 
1005
        return 0;
 
1006
    return m_player->startTime();
 
1007
}
 
1008
 
603
1009
float HTMLMediaElement::duration() const
604
1010
{
605
 
    return m_player ? m_player->duration() : 0;
 
1011
    if (m_readyState >= HAVE_METADATA)
 
1012
        return m_player->duration();
 
1013
 
 
1014
    return numeric_limits<float>::quiet_NaN();
606
1015
}
607
1016
 
608
1017
bool HTMLMediaElement::paused() const
615
1024
    return m_defaultPlaybackRate;
616
1025
}
617
1026
 
618
 
void HTMLMediaElement::setDefaultPlaybackRate(float rate, ExceptionCode& ec)
 
1027
void HTMLMediaElement::setDefaultPlaybackRate(float rate)
619
1028
{
620
 
    if (rate == 0.0f) {
621
 
        ec = NOT_SUPPORTED_ERR;
622
 
        return;
623
 
    }
624
1029
    if (m_defaultPlaybackRate != rate) {
625
1030
        m_defaultPlaybackRate = rate;
626
 
        dispatchEventAsync(eventNames().ratechangeEvent);
 
1031
        scheduleEvent(eventNames().ratechangeEvent);
627
1032
    }
628
1033
}
629
1034
 
632
1037
    return m_player ? m_player->rate() : 0;
633
1038
}
634
1039
 
635
 
void HTMLMediaElement::setPlaybackRate(float rate, ExceptionCode& ec)
 
1040
void HTMLMediaElement::setPlaybackRate(float rate)
636
1041
{
637
 
    if (rate == 0.0f) {
638
 
        ec = NOT_SUPPORTED_ERR;
639
 
        return;
 
1042
    if (m_playbackRate != rate) {
 
1043
        m_playbackRate = rate;
 
1044
        scheduleEvent(eventNames().ratechangeEvent);
640
1045
    }
641
 
    if (m_player && m_player->rate() != rate) {
 
1046
    if (m_player && potentiallyPlaying() && m_player->rate() != rate)
642
1047
        m_player->setRate(rate);
643
 
        dispatchEventAsync(eventNames().ratechangeEvent);
644
 
    }
 
1048
}
 
1049
 
 
1050
bool HTMLMediaElement::webkitPreservesPitch() const
 
1051
{
 
1052
    return m_webkitPreservesPitch;
 
1053
}
 
1054
 
 
1055
void HTMLMediaElement::setWebkitPreservesPitch(bool preservesPitch)
 
1056
{
 
1057
    m_webkitPreservesPitch = preservesPitch;
 
1058
    
 
1059
    if (!m_player)
 
1060
        return;
 
1061
 
 
1062
    m_player->setPreservesPitch(preservesPitch);
645
1063
}
646
1064
 
647
1065
bool HTMLMediaElement::ended() const
659
1077
    setBooleanAttribute(autoplayAttr, b);
660
1078
}
661
1079
 
662
 
void HTMLMediaElement::play(ExceptionCode& ec)
663
 
{
664
 
    // 3.14.9.7. Playing the media resource
665
 
    if (!m_player || networkState() == EMPTY) {
666
 
        ec = 0;
667
 
        load(ec);
668
 
        if (ec)
669
 
            return;
670
 
    }
671
 
    ExceptionCode unused;
 
1080
bool HTMLMediaElement::autobuffer() const
 
1081
{
 
1082
    return hasAttribute(autobufferAttr);
 
1083
}
 
1084
 
 
1085
void HTMLMediaElement::setAutobuffer(bool b)
 
1086
{
 
1087
    setBooleanAttribute(autobufferAttr, b);
 
1088
}
 
1089
 
 
1090
void HTMLMediaElement::play()
 
1091
{
 
1092
    if (m_restrictions & RequireUserGestureForRateChangeRestriction && !processingUserGesture())
 
1093
        return;
 
1094
 
 
1095
    playInternal();
 
1096
}
 
1097
 
 
1098
void HTMLMediaElement::playInternal()
 
1099
{
 
1100
    // 4.8.10.9. Playing the media resource
 
1101
    if (!m_player || m_networkState == NETWORK_EMPTY)
 
1102
        scheduleLoad();
 
1103
 
672
1104
    if (endedPlayback()) {
673
 
        m_currentLoop = 0;
674
 
        seek(effectiveStart(), unused);
 
1105
        ExceptionCode unused;
 
1106
        seek(0, unused);
675
1107
    }
676
 
    setPlaybackRate(defaultPlaybackRate(), unused);
 
1108
    
 
1109
    setPlaybackRate(defaultPlaybackRate());
677
1110
    
678
1111
    if (m_paused) {
679
1112
        m_paused = false;
680
 
        dispatchEventAsync(eventNames().playEvent);
 
1113
        scheduleEvent(eventNames().playEvent);
 
1114
 
 
1115
        if (m_readyState <= HAVE_CURRENT_DATA)
 
1116
            scheduleEvent(eventNames().waitingEvent);
 
1117
        else if (m_readyState >= HAVE_FUTURE_DATA)
 
1118
            scheduleEvent(eventNames().playingEvent);
681
1119
    }
 
1120
    m_autoplaying = false;
 
1121
 
 
1122
    updatePlayState();
 
1123
}
 
1124
 
 
1125
void HTMLMediaElement::pause()
 
1126
{
 
1127
    if (m_restrictions & RequireUserGestureForRateChangeRestriction && !processingUserGesture())
 
1128
        return;
 
1129
 
 
1130
    pauseInternal();
 
1131
}
 
1132
 
 
1133
 
 
1134
void HTMLMediaElement::pauseInternal()
 
1135
{
 
1136
    // 4.8.10.9. Playing the media resource
 
1137
    if (!m_player || m_networkState == NETWORK_EMPTY)
 
1138
        scheduleLoad();
682
1139
 
683
1140
    m_autoplaying = false;
684
1141
    
685
 
    updatePlayState();
686
 
}
687
 
 
688
 
void HTMLMediaElement::pause(ExceptionCode& ec)
689
 
{
690
 
    // 3.14.9.7. Playing the media resource
691
 
    if (!m_player || networkState() == EMPTY) {
692
 
        ec = 0;
693
 
        load(ec);
694
 
        if (ec)
695
 
            return;
696
 
    }
697
 
 
698
1142
    if (!m_paused) {
699
1143
        m_paused = true;
700
 
        dispatchEventAsync(eventNames().timeupdateEvent);
701
 
        dispatchEventAsync(eventNames().pauseEvent);
 
1144
        scheduleTimeupdateEvent(false);
 
1145
        scheduleEvent(eventNames().pauseEvent);
702
1146
    }
703
1147
 
704
 
    m_autoplaying = false;
705
 
    
706
1148
    updatePlayState();
707
1149
}
708
1150
 
709
 
unsigned HTMLMediaElement::playCount() const
710
 
{
711
 
    bool ok;
712
 
    unsigned count = getAttribute(playcountAttr).string().toUInt(&ok);
713
 
    return (count > 0 && ok) ? count : 1; 
714
 
}
715
 
 
716
 
void HTMLMediaElement::setPlayCount(unsigned count, ExceptionCode& ec)
717
 
{
718
 
    if (!count) {
719
 
        ec = INDEX_SIZE_ERR;
720
 
        return;
721
 
    }
722
 
    setAttribute(playcountAttr, String::number(count));
723
 
    checkIfSeekNeeded();
724
 
}
725
 
 
726
 
float HTMLMediaElement::start() const 
727
 
728
 
    return getTimeOffsetAttribute(startAttr, 0); 
729
 
}
730
 
 
731
 
void HTMLMediaElement::setStart(float time) 
732
 
733
 
    setTimeOffsetAttribute(startAttr, time); 
734
 
    checkIfSeekNeeded();
735
 
}
736
 
 
737
 
float HTMLMediaElement::end() const 
738
 
739
 
    return getTimeOffsetAttribute(endAttr, std::numeric_limits<float>::infinity()); 
740
 
}
741
 
 
742
 
void HTMLMediaElement::setEnd(float time) 
743
 
744
 
    setTimeOffsetAttribute(endAttr, time); 
745
 
    checkIfSeekNeeded();
746
 
}
747
 
 
748
 
float HTMLMediaElement::loopStart() const 
749
 
750
 
    return getTimeOffsetAttribute(loopstartAttr, start()); 
751
 
}
752
 
 
753
 
void HTMLMediaElement::setLoopStart(float time) 
754
 
{
755
 
    setTimeOffsetAttribute(loopstartAttr, time); 
756
 
    checkIfSeekNeeded();
757
 
}
758
 
 
759
 
float HTMLMediaElement::loopEnd() const 
760
 
761
 
    return getTimeOffsetAttribute(loopendAttr, end()); 
762
 
}
763
 
 
764
 
void HTMLMediaElement::setLoopEnd(float time) 
765
 
766
 
    setTimeOffsetAttribute(loopendAttr, time); 
767
 
    checkIfSeekNeeded();
768
 
}
769
 
 
770
 
unsigned HTMLMediaElement::currentLoop() const
771
 
{
772
 
    return m_currentLoop;
773
 
}
774
 
 
775
 
void HTMLMediaElement::setCurrentLoop(unsigned currentLoop)
776
 
{
777
 
    m_currentLoop = currentLoop;
 
1151
bool HTMLMediaElement::loop() const
 
1152
{
 
1153
    return hasAttribute(loopAttr);
 
1154
}
 
1155
 
 
1156
void HTMLMediaElement::setLoop(bool b)
 
1157
{
 
1158
    setBooleanAttribute(loopAttr, b);
778
1159
}
779
1160
 
780
1161
bool HTMLMediaElement::controls() const
781
1162
{
 
1163
    Frame* frame = document()->frame();
 
1164
 
 
1165
    // always show controls when scripting is disabled
 
1166
    if (frame && !frame->script()->isEnabled())
 
1167
        return true;
 
1168
 
782
1169
    return hasAttribute(controlsAttr);
783
1170
}
784
1171
 
802
1189
    if (m_volume != vol) {
803
1190
        m_volume = vol;
804
1191
        updateVolume();
805
 
        dispatchEventAsync(eventNames().volumechangeEvent);
 
1192
        scheduleEvent(eventNames().volumechangeEvent);
806
1193
    }
807
1194
}
808
1195
 
816
1203
    if (m_muted != muted) {
817
1204
        m_muted = muted;
818
1205
        updateVolume();
819
 
        dispatchEventAsync(eventNames().volumechangeEvent);
 
1206
        scheduleEvent(eventNames().volumechangeEvent);
 
1207
    }
 
1208
}
 
1209
 
 
1210
void HTMLMediaElement::togglePlayState()
 
1211
{
 
1212
    // We can safely call the internal play/pause methods, which don't check restrictions, because
 
1213
    // this method is only called from the built-in media controller
 
1214
    if (canPlay())
 
1215
        playInternal();
 
1216
    else 
 
1217
        pauseInternal();
 
1218
}
 
1219
 
 
1220
void HTMLMediaElement::beginScrubbing()
 
1221
{
 
1222
    if (!paused()) {
 
1223
        if (ended()) {
 
1224
            // Because a media element stays in non-paused state when it reaches end, playback resumes 
 
1225
            // when the slider is dragged from the end to another position unless we pause first. Do 
 
1226
            // a "hard pause" so an event is generated, since we want to stay paused after scrubbing finishes.
 
1227
            pause();
 
1228
        } else {
 
1229
            // Not at the end but we still want to pause playback so the media engine doesn't try to
 
1230
            // continue playing during scrubbing. Pause without generating an event as we will 
 
1231
            // unpause after scrubbing finishes.
 
1232
            setPausedInternal(true);
 
1233
        }
 
1234
    }
 
1235
}
 
1236
 
 
1237
void HTMLMediaElement::endScrubbing()
 
1238
{
 
1239
    if (m_pausedInternal)
 
1240
        setPausedInternal(false);
 
1241
}
 
1242
 
 
1243
// The spec says to fire periodic timeupdate events (those sent while playing) every
 
1244
// "15 to 250ms", we choose the slowest frequency
 
1245
static const double maxTimeupdateEventFrequency = 0.25;
 
1246
 
 
1247
void HTMLMediaElement::startPlaybackProgressTimer()
 
1248
{
 
1249
    if (m_playbackProgressTimer.isActive())
 
1250
        return;
 
1251
 
 
1252
    m_previousProgressTime = WTF::currentTime();
 
1253
    m_previousProgress = 0;
 
1254
    m_playbackProgressTimer.startRepeating(maxTimeupdateEventFrequency);
 
1255
}
 
1256
 
 
1257
void HTMLMediaElement::playbackProgressTimerFired(Timer<HTMLMediaElement>*)
 
1258
{
 
1259
    ASSERT(m_player);
 
1260
    if (!m_playbackRate)
 
1261
        return;
 
1262
 
 
1263
    scheduleTimeupdateEvent(true);
 
1264
    
 
1265
    // FIXME: deal with cue ranges here
 
1266
}
 
1267
 
 
1268
void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent)
 
1269
{
 
1270
    double now = WTF::currentTime();
 
1271
    double timedelta = now - m_lastTimeUpdateEventWallTime;
 
1272
 
 
1273
    // throttle the periodic events
 
1274
    if (periodicEvent && timedelta < maxTimeupdateEventFrequency)
 
1275
        return;
 
1276
 
 
1277
    // Some media engines make multiple "time changed" callbacks at the same time, but we only want one
 
1278
    // event at a given time so filter here
 
1279
    float movieTime = m_player ? m_player->currentTime() : 0;
 
1280
    if (movieTime != m_lastTimeUpdateEventMovieTime) {
 
1281
        scheduleEvent(eventNames().timeupdateEvent);
 
1282
        m_lastTimeUpdateEventWallTime = now;
 
1283
        m_lastTimeUpdateEventMovieTime = movieTime;
820
1284
    }
821
1285
}
822
1286
 
823
1287
bool HTMLMediaElement::canPlay() const
824
1288
{
825
 
    return paused() || ended() || networkState() < LOADED_METADATA;
826
 
}
827
 
 
828
 
String HTMLMediaElement::pickMedia()
829
 
{
830
 
    // 3.14.9.2. Location of the media resource
831
 
    String mediaSrc = getAttribute(srcAttr);
832
 
    if (mediaSrc.isEmpty()) {
833
 
        for (Node* n = firstChild(); n; n = n->nextSibling()) {
834
 
            if (n->hasTagName(sourceTag)) {
835
 
                HTMLSourceElement* source = static_cast<HTMLSourceElement*>(n);
836
 
                if (!source->hasAttribute(srcAttr))
837
 
                    continue; 
838
 
                if (source->hasAttribute(mediaAttr)) {
839
 
                    MediaQueryEvaluator screenEval("screen", document()->frame(), renderer() ? renderer()->style() : 0);
840
 
                    RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(source->media());
841
 
                    if (!screenEval.eval(media.get()))
842
 
                        continue;
843
 
                }
844
 
                if (source->hasAttribute(typeAttr)) {
845
 
                    String type = source->type().stripWhiteSpace();
846
 
 
847
 
                    // "type" can have parameters after a semi-colon, strip them before checking with the type registry
848
 
                    int semi = type.find(';');
849
 
                    if (semi != -1)
850
 
                        type = type.left(semi).stripWhiteSpace();
851
 
 
852
 
                    if (!MIMETypeRegistry::isSupportedMediaMIMEType(type))
853
 
                        continue;
854
 
                }
855
 
                mediaSrc = source->src().string();
856
 
                break;
 
1289
    return paused() || ended() || m_readyState < HAVE_METADATA;
 
1290
}
 
1291
 
 
1292
float HTMLMediaElement::percentLoaded() const
 
1293
{
 
1294
    if (!m_player)
 
1295
        return 0;
 
1296
    float duration = m_player->duration();
 
1297
 
 
1298
    if (!duration || isinf(duration))
 
1299
        return 0;
 
1300
 
 
1301
    float buffered = 0;
 
1302
    RefPtr<TimeRanges> timeRanges = m_player->buffered();
 
1303
    for (unsigned i = 0; i < timeRanges->length(); ++i) {
 
1304
        ExceptionCode ignoredException;
 
1305
        float start = timeRanges->start(i, ignoredException);
 
1306
        float end = timeRanges->end(i, ignoredException);
 
1307
        buffered += end - start;
 
1308
    }
 
1309
    return buffered / duration;
 
1310
}
 
1311
 
 
1312
bool HTMLMediaElement::havePotentialSourceChild()
 
1313
{
 
1314
    // Stash the current <source> node so we can restore it after checking
 
1315
    // to see there is another potential
 
1316
    HTMLSourceElement* currentSourceNode = m_currentSourceNode;
 
1317
    KURL nextURL = selectNextSourceChild(0, DoNothing);
 
1318
    m_currentSourceNode = currentSourceNode;
 
1319
 
 
1320
    return nextURL.isValid();
 
1321
}
 
1322
 
 
1323
KURL HTMLMediaElement::selectNextSourceChild(ContentType *contentType, InvalidSourceAction actionIfInvalid)
 
1324
{
 
1325
    KURL mediaURL;
 
1326
    Node* node;
 
1327
    bool lookingForPreviousNode = m_currentSourceNode;
 
1328
    bool canUse = false;
 
1329
 
 
1330
    for (node = firstChild(); !canUse && node; node = node->nextSibling()) {
 
1331
        if (!node->hasTagName(sourceTag))
 
1332
            continue;
 
1333
 
 
1334
        if (lookingForPreviousNode) {
 
1335
            if (m_currentSourceNode == static_cast<HTMLSourceElement*>(node))
 
1336
                lookingForPreviousNode = false;
 
1337
            continue;
 
1338
        }
 
1339
 
 
1340
        HTMLSourceElement* source = static_cast<HTMLSourceElement*>(node);
 
1341
        if (!source->hasAttribute(srcAttr))
 
1342
            goto check_again; 
 
1343
 
 
1344
        if (source->hasAttribute(mediaAttr)) {
 
1345
            MediaQueryEvaluator screenEval("screen", document()->frame(), renderer() ? renderer()->style() : 0);
 
1346
            RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(source->media());
 
1347
            if (!screenEval.eval(media.get())) 
 
1348
                goto check_again;
 
1349
        }
 
1350
 
 
1351
        if (source->hasAttribute(typeAttr)) {
 
1352
            if (!MediaPlayer::supportsType(ContentType(source->type())))
 
1353
                goto check_again;
 
1354
        }
 
1355
 
 
1356
        // Is it safe to load this url?
 
1357
        mediaURL = source->src();
 
1358
        if (!mediaURL.isValid() || !isSafeToLoadURL(mediaURL, actionIfInvalid))
 
1359
            goto check_again;
 
1360
 
 
1361
        // Making it this far means the <source> looks reasonable
 
1362
        canUse = true;
 
1363
        if (contentType)
 
1364
            *contentType = ContentType(source->type());
 
1365
 
 
1366
check_again:
 
1367
        if (!canUse && actionIfInvalid == Complain)
 
1368
            source->scheduleErrorEvent();
 
1369
        m_currentSourceNode = static_cast<HTMLSourceElement*>(node);
 
1370
    }
 
1371
 
 
1372
    if (!canUse)
 
1373
        m_currentSourceNode = 0;
 
1374
    return canUse ? mediaURL : KURL();
 
1375
}
 
1376
 
 
1377
void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
 
1378
{
 
1379
    beginProcessingMediaPlayerCallback();
 
1380
 
 
1381
    // 4.8.10.10 step 12 & 13.  Needed if no ReadyState change is associated with the seek.
 
1382
    if (m_readyState >= HAVE_CURRENT_DATA && m_seeking) {
 
1383
        finishSeek();
 
1384
    }
 
1385
    
 
1386
    float now = currentTime();
 
1387
    float dur = duration();
 
1388
    if (!isnan(dur) && dur && now >= dur) {
 
1389
        if (loop()) {
 
1390
            ExceptionCode ignoredException;
 
1391
            m_sentEndEvent = false;
 
1392
            seek(0, ignoredException);
 
1393
        } else {
 
1394
            if (!m_sentEndEvent) {
 
1395
                m_sentEndEvent = true;
 
1396
                scheduleTimeupdateEvent(false);
 
1397
                scheduleEvent(eventNames().endedEvent);
857
1398
            }
858
1399
        }
859
1400
    }
860
 
    if (!mediaSrc.isEmpty())
861
 
        mediaSrc = document()->completeURL(mediaSrc).string();
862
 
    return mediaSrc;
863
 
}
864
 
 
865
 
void HTMLMediaElement::checkIfSeekNeeded()
866
 
{
867
 
    // 3.14.9.5. Offsets into the media resource
868
 
    // 1
869
 
    if (playCount() <= m_currentLoop)
870
 
        m_currentLoop = playCount() - 1;
871
 
    
872
 
    // 2
873
 
    if (networkState() <= LOADING)
874
 
        return;
875
 
    
876
 
    // 3
877
 
    ExceptionCode ec;
878
 
    float time = currentTime();
879
 
    if (!m_currentLoop && time < effectiveStart())
880
 
        seek(effectiveStart(), ec);
881
 
 
882
 
    // 4
883
 
    if (m_currentLoop && time < effectiveLoopStart())
884
 
        seek(effectiveLoopStart(), ec);
885
 
        
886
 
    // 5
887
 
    if (m_currentLoop < playCount() - 1 && time > effectiveLoopEnd()) {
888
 
        seek(effectiveLoopStart(), ec);
889
 
        m_currentLoop++;
890
 
    }
891
 
    
892
 
    // 6
893
 
    if (m_currentLoop == playCount() - 1 && time > effectiveEnd())
894
 
        seek(effectiveEnd(), ec);
895
 
 
896
 
    updatePlayState();
897
 
}
898
 
 
899
 
void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
900
 
{
901
 
    if (readyState() >= CAN_PLAY)
902
 
        m_seeking = false;
903
 
    
904
 
    if (m_currentLoop < playCount() - 1 && currentTime() >= effectiveLoopEnd()) {
905
 
        ExceptionCode ec;
906
 
        seek(effectiveLoopStart(), ec);
907
 
        m_currentLoop++;
908
 
        dispatchEventForType(eventNames().timeupdateEvent, false, true);
909
 
    }
910
 
    
911
 
    if (m_currentLoop == playCount() - 1 && currentTime() >= effectiveEnd()) {
912
 
        dispatchEventForType(eventNames().timeupdateEvent, false, true);
913
 
        dispatchEventForType(eventNames().endedEvent, false, true);
914
 
    }
915
 
 
916
 
    updatePlayState();
917
 
}
918
 
 
 
1401
    else
 
1402
        m_sentEndEvent = false;
 
1403
 
 
1404
    updatePlayState();
 
1405
    endProcessingMediaPlayerCallback();
 
1406
}
 
1407
 
 
1408
void HTMLMediaElement::mediaPlayerVolumeChanged(MediaPlayer*)
 
1409
{
 
1410
    beginProcessingMediaPlayerCallback();
 
1411
    updateVolume();
 
1412
    endProcessingMediaPlayerCallback();
 
1413
}
 
1414
 
 
1415
void HTMLMediaElement::mediaPlayerDurationChanged(MediaPlayer*)
 
1416
{
 
1417
    beginProcessingMediaPlayerCallback();
 
1418
    scheduleEvent(eventNames().durationchangeEvent);
 
1419
#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
 
1420
    if (renderer()) {
 
1421
        renderer()->updateFromElement();
 
1422
        if (renderer()->isVideo())
 
1423
            toRenderVideo(renderer())->videoSizeChanged();
 
1424
    }
 
1425
#endif        
 
1426
    endProcessingMediaPlayerCallback();
 
1427
}
 
1428
 
 
1429
void HTMLMediaElement::mediaPlayerRateChanged(MediaPlayer*)
 
1430
{
 
1431
    beginProcessingMediaPlayerCallback();
 
1432
    // Stash the rate in case the one we tried to set isn't what the engine is
 
1433
    // using (eg. it can't handle the rate we set)
 
1434
    m_playbackRate = m_player->rate();
 
1435
    endProcessingMediaPlayerCallback();
 
1436
}
 
1437
 
 
1438
void HTMLMediaElement::mediaPlayerSawUnsupportedTracks(MediaPlayer*)
 
1439
{
 
1440
    // The MediaPlayer came across content it cannot completely handle.
 
1441
    // This is normally acceptable except when we are in a standalone
 
1442
    // MediaDocument. If so, tell the document what has happened.
 
1443
    if (ownerDocument()->isMediaDocument()) {
 
1444
        MediaDocument* mediaDocument = static_cast<MediaDocument*>(ownerDocument());
 
1445
        mediaDocument->mediaElementSawUnsupportedTracks();
 
1446
    }
 
1447
}
 
1448
 
 
1449
// MediaPlayerPresentation methods
919
1450
void HTMLMediaElement::mediaPlayerRepaint(MediaPlayer*)
920
1451
{
 
1452
    beginProcessingMediaPlayerCallback();
921
1453
    if (renderer())
922
1454
        renderer()->repaint();
923
 
}
 
1455
    endProcessingMediaPlayerCallback();
 
1456
}
 
1457
 
 
1458
void HTMLMediaElement::mediaPlayerSizeChanged(MediaPlayer*)
 
1459
{
 
1460
    beginProcessingMediaPlayerCallback();
 
1461
#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
 
1462
    if (renderer() && renderer()->isVideo())
 
1463
        toRenderVideo(renderer())->videoSizeChanged();
 
1464
#endif        
 
1465
    endProcessingMediaPlayerCallback();
 
1466
}
 
1467
 
 
1468
#if USE(ACCELERATED_COMPOSITING)
 
1469
bool HTMLMediaElement::mediaPlayerRenderingCanBeAccelerated(MediaPlayer*)
 
1470
{
 
1471
    if (renderer() && renderer()->isVideo()) {
 
1472
        ASSERT(renderer()->view());
 
1473
        return renderer()->view()->compositor()->canAccelerateVideoRendering(toRenderVideo(renderer()));
 
1474
    }
 
1475
    return false;
 
1476
}
 
1477
 
 
1478
GraphicsLayer* HTMLMediaElement::mediaPlayerGraphicsLayer(MediaPlayer*)
 
1479
{
 
1480
    if (renderer() && renderer()->isVideo())
 
1481
        return toRenderVideo(renderer())->videoGraphicsLayer();
 
1482
    return 0;
 
1483
}
 
1484
#endif
924
1485
 
925
1486
PassRefPtr<TimeRanges> HTMLMediaElement::buffered() const
926
1487
{
927
 
    // FIXME real ranges support
928
 
    if (!m_player || !m_player->maxTimeBuffered())
 
1488
    if (!m_player)
929
1489
        return TimeRanges::create();
930
 
    return TimeRanges::create(0, m_player->maxTimeBuffered());
 
1490
    return m_player->buffered();
931
1491
}
932
1492
 
933
 
PassRefPtr<TimeRanges> HTMLMediaElement::played() const
 
1493
PassRefPtr<TimeRanges> HTMLMediaElement::played()
934
1494
{
935
 
    // FIXME track played
936
 
    return TimeRanges::create();
 
1495
    if (m_playing) {
 
1496
        float time = currentTime();
 
1497
        if (time > m_lastSeekTime)
 
1498
            addPlayedRange(m_lastSeekTime, time);
 
1499
    }
 
1500
 
 
1501
    if (!m_playedTimeRanges)
 
1502
        m_playedTimeRanges = TimeRanges::create();
 
1503
 
 
1504
    return m_playedTimeRanges->copy();
937
1505
}
938
1506
 
939
1507
PassRefPtr<TimeRanges> HTMLMediaElement::seekable() const
940
1508
{
941
1509
    // FIXME real ranges support
942
 
    if (!m_player || !m_player->maxTimeSeekable())
 
1510
    if (!maxTimeSeekable())
943
1511
        return TimeRanges::create();
944
 
    return TimeRanges::create(0, m_player->maxTimeSeekable());
945
 
}
946
 
 
947
 
float HTMLMediaElement::effectiveStart() const
948
 
{
949
 
    if (!m_player)
950
 
        return 0;
951
 
    return min(start(), m_player->duration());
952
 
}
953
 
 
954
 
float HTMLMediaElement::effectiveEnd() const
955
 
{
956
 
    if (!m_player)
957
 
        return 0;
958
 
    return min(max(end(), max(start(), loopStart())), m_player->duration());
959
 
}
960
 
 
961
 
float HTMLMediaElement::effectiveLoopStart() const
962
 
{
963
 
    if (!m_player)
964
 
        return 0;
965
 
    return min(loopStart(), m_player->duration());
966
 
}
967
 
 
968
 
float HTMLMediaElement::effectiveLoopEnd() const
969
 
{
970
 
    if (!m_player)
971
 
        return 0;
972
 
    return min(max(start(), max(loopStart(), loopEnd())), m_player->duration());
973
 
}
974
 
 
975
 
bool HTMLMediaElement::activelyPlaying() const
976
 
{
977
 
    return !paused() && readyState() >= CAN_PLAY && !endedPlayback(); // && !stoppedDueToErrors() && !pausedForUserInteraction();
 
1512
    return TimeRanges::create(minTimeSeekable(), maxTimeSeekable());
 
1513
}
 
1514
 
 
1515
bool HTMLMediaElement::potentiallyPlaying() const
 
1516
{
 
1517
    return !paused() && m_readyState >= HAVE_FUTURE_DATA && !endedPlayback() && !stoppedDueToErrors() && !pausedForUserInteraction();
978
1518
}
979
1519
 
980
1520
bool HTMLMediaElement::endedPlayback() const
981
1521
{
982
 
    return networkState() >= LOADED_METADATA && currentTime() >= effectiveEnd() && currentLoop() == playCount() - 1;
 
1522
    if (!m_player || m_readyState < HAVE_METADATA)
 
1523
        return false;
 
1524
    
 
1525
    float dur = duration();
 
1526
    return !isnan(dur) && currentTime() >= dur && !loop();
 
1527
}
 
1528
 
 
1529
bool HTMLMediaElement::stoppedDueToErrors() const
 
1530
{
 
1531
    if (m_readyState >= HAVE_METADATA && m_error) {
 
1532
        RefPtr<TimeRanges> seekableRanges = seekable();
 
1533
        if (!seekableRanges->contain(currentTime()))
 
1534
            return true;
 
1535
    }
 
1536
    
 
1537
    return false;
 
1538
}
 
1539
 
 
1540
bool HTMLMediaElement::pausedForUserInteraction() const
 
1541
{
 
1542
//    return !paused() && m_readyState >= HAVE_FUTURE_DATA && [UA requires a decitions from the user]
 
1543
    return false;
 
1544
}
 
1545
 
 
1546
float HTMLMediaElement::minTimeSeekable() const
 
1547
{
 
1548
    return 0;
 
1549
}
 
1550
 
 
1551
float HTMLMediaElement::maxTimeSeekable() const
 
1552
{
 
1553
    return m_player ? m_player->maxTimeSeekable() : 0;
983
1554
}
984
1555
    
985
1556
void HTMLMediaElement::updateVolume()
987
1558
    if (!m_player)
988
1559
        return;
989
1560
 
990
 
    Page* page = document()->page();
991
 
    float volumeMultiplier = page ? page->mediaVolume() : 1;
992
 
 
993
 
    m_player->setVolume(m_muted ? 0 : m_volume * volumeMultiplier);
 
1561
    // Avoid recursion when the player reports volume changes.
 
1562
    if (!processingMediaPlayerCallback()) {
 
1563
        Page* page = document()->page();
 
1564
        float volumeMultiplier = page ? page->mediaVolume() : 1;
 
1565
    
 
1566
        m_player->setVolume(m_muted ? 0 : m_volume * volumeMultiplier);
 
1567
    }
994
1568
    
995
1569
    if (renderer())
996
1570
        renderer()->updateFromElement();
1000
1574
{
1001
1575
    if (!m_player)
1002
1576
        return;
1003
 
    
 
1577
 
1004
1578
    if (m_pausedInternal) {
1005
1579
        if (!m_player->paused())
1006
1580
            m_player->pause();
 
1581
        m_playbackProgressTimer.stop();
1007
1582
        return;
1008
1583
    }
1009
1584
    
1010
 
    m_player->setEndTime(currentLoop() == playCount() - 1 ? effectiveEnd() : effectiveLoopEnd());
1011
 
 
1012
 
    bool shouldBePlaying = activelyPlaying() && currentTime() < effectiveEnd();
1013
 
    if (shouldBePlaying && m_player->paused())
 
1585
    bool shouldBePlaying = potentiallyPlaying();
 
1586
    bool playerPaused = m_player->paused();
 
1587
    if (shouldBePlaying && playerPaused) {
 
1588
        // Set rate before calling play in case the rate was set before the media engine wasn't setup.
 
1589
        // The media engine should just stash the rate since it isn't already playing.
 
1590
        m_player->setRate(m_playbackRate);
1014
1591
        m_player->play();
1015
 
    else if (!shouldBePlaying && !m_player->paused())
 
1592
        startPlaybackProgressTimer();
 
1593
        m_playing = true;
 
1594
    } else if (!shouldBePlaying && !playerPaused) {
1016
1595
        m_player->pause();
 
1596
        m_playbackProgressTimer.stop();
 
1597
        m_playing = false;
 
1598
        float time = currentTime();
 
1599
        if (time > m_lastSeekTime)
 
1600
            addPlayedRange(m_lastSeekTime, time);
 
1601
    }
1017
1602
    
1018
1603
    if (renderer())
1019
1604
        renderer()->updateFromElement();
1025
1610
    updatePlayState();
1026
1611
}
1027
1612
 
 
1613
void HTMLMediaElement::stopPeriodicTimers()
 
1614
{
 
1615
    m_progressEventTimer.stop();
 
1616
    m_playbackProgressTimer.stop();
 
1617
}
 
1618
 
 
1619
void HTMLMediaElement::userCancelledLoad()
 
1620
{
 
1621
    if (m_networkState == NETWORK_EMPTY || m_networkState >= NETWORK_LOADED)
 
1622
        return;
 
1623
 
 
1624
    // If the media data fetching process is aborted by the user:
 
1625
 
 
1626
    // 1 - The user agent should cancel the fetching process.
 
1627
#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
 
1628
    m_player.clear();
 
1629
#endif
 
1630
    stopPeriodicTimers();
 
1631
 
 
1632
    // 2 - Set the error attribute to a new MediaError object whose code attribute is set to MEDIA_ERR_ABORT.
 
1633
    m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
 
1634
 
 
1635
    // 3 - Queue a task to fire a progress event called abort at the media element, in the context
 
1636
    // of the fetching process started by this instance of this algorithm.
 
1637
    scheduleProgressEvent(eventNames().abortEvent);
 
1638
 
 
1639
    // 4 - Queue a task to fire a progress event called loadend at the media element, in the context
 
1640
    // of the fetching process started by this instance of this algorithm.
 
1641
    scheduleProgressEvent(eventNames().loadendEvent);
 
1642
 
 
1643
    // 5 - If the media element's readyState attribute has a value equal to HAVE_NOTHING, set the
 
1644
    // element's networkState attribute to the NETWORK_EMPTY value and queue a task to fire a
 
1645
    // simple event called emptied at the element. Otherwise, set set the element's networkState
 
1646
    // attribute to the NETWORK_IDLE value.
 
1647
    if (m_readyState == HAVE_NOTHING) {
 
1648
        m_networkState = NETWORK_EMPTY;
 
1649
        scheduleEvent(eventNames().emptiedEvent);
 
1650
    }
 
1651
    else
 
1652
        m_networkState = NETWORK_IDLE;
 
1653
 
 
1654
    // 6 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event.
 
1655
    m_delayingTheLoadEvent = false;
 
1656
 
 
1657
    // 7 - Abort the overall resource selection algorithm.
 
1658
    m_currentSourceNode = 0;
 
1659
}
 
1660
 
1028
1661
void HTMLMediaElement::documentWillBecomeInactive()
1029
1662
{
1030
 
    // 3.14.9.4. Loading the media resource
1031
 
    // 14
1032
 
    if (m_begun) {
1033
 
        // For simplicity cancel the incomplete load by deleting the player
1034
 
        m_player.clear();
1035
 
        m_progressEventTimer.stop();
1036
 
 
1037
 
        m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED);
1038
 
        m_begun = false;
1039
 
        initAndDispatchProgressEvent(eventNames().abortEvent);
1040
 
        if (m_networkState >= LOADING) {
1041
 
            m_networkState = EMPTY;
1042
 
            m_readyState = DATA_UNAVAILABLE;
1043
 
            dispatchEventForType(eventNames().emptiedEvent, false, true);
1044
 
        }
1045
 
    }
1046
1663
    m_inActiveDocument = false;
 
1664
    userCancelledLoad();
 
1665
 
1047
1666
    // Stop the playback without generating events
1048
1667
    setPausedInternal(true);
1049
1668
 
1050
1669
    if (renderer())
1051
1670
        renderer()->updateFromElement();
 
1671
 
 
1672
    stopPeriodicTimers();
 
1673
    cancelPendingEventsAndCallbacks();
1052
1674
}
1053
1675
 
1054
1676
void HTMLMediaElement::documentDidBecomeActive()
1058
1680
 
1059
1681
    if (m_error && m_error->code() == MediaError::MEDIA_ERR_ABORTED) {
1060
1682
        // Restart the load if it was aborted in the middle by moving the document to the page cache.
 
1683
        // m_error is only left at MEDIA_ERR_ABORTED when the document becomes inactive (it is set to
 
1684
        //  MEDIA_ERR_ABORTED while the abortEvent is being sent, but cleared immediately afterwards).
1061
1685
        // This behavior is not specified but it seems like a sensible thing to do.
1062
1686
        ExceptionCode ec;
1063
1687
        load(ec);
1064
1688
    }
1065
 
        
 
1689
 
1066
1690
    if (renderer())
1067
1691
        renderer()->updateFromElement();
1068
1692
}
1074
1698
 
1075
1699
void HTMLMediaElement::defaultEventHandler(Event* event)
1076
1700
{
 
1701
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
 
1702
    RenderObject* r = renderer();
 
1703
    if (!r || !r->isWidget())
 
1704
        return;
 
1705
 
 
1706
    Widget* widget = toRenderWidget(r)->widget();
 
1707
    if (widget)
 
1708
        widget->handleEvent(event);
 
1709
#else
1077
1710
    if (renderer() && renderer()->isMedia())
1078
 
        static_cast<RenderMedia*>(renderer())->forwardEvent(event);
 
1711
        toRenderMedia(renderer())->forwardEvent(event);
1079
1712
    if (event->defaultHandled())
1080
1713
        return;
1081
1714
    HTMLElement::defaultEventHandler(event);
1082
 
}
 
1715
#endif
 
1716
}
 
1717
 
 
1718
bool HTMLMediaElement::processingUserGesture() const
 
1719
{
 
1720
    Frame* frame = document()->frame();
 
1721
    FrameLoader* loader = frame ? frame->loader() : 0;
 
1722
 
 
1723
    // return 'true' for safety if we don't know the answer 
 
1724
    return loader ? loader->isProcessingUserGesture() : true;
 
1725
}
 
1726
 
 
1727
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
 
1728
 
 
1729
void HTMLMediaElement::deliverNotification(MediaPlayerProxyNotificationType notification)
 
1730
{
 
1731
    if (notification == MediaPlayerNotificationPlayPauseButtonPressed) {
 
1732
        togglePlayState();
 
1733
        return;
 
1734
    }
 
1735
 
 
1736
    if (m_player)
 
1737
        m_player->deliverNotification(notification);
 
1738
}
 
1739
 
 
1740
void HTMLMediaElement::setMediaPlayerProxy(WebMediaPlayerProxy* proxy)
 
1741
{
 
1742
    if (m_player)
 
1743
        m_player->setMediaPlayerProxy(proxy);
 
1744
}
 
1745
 
 
1746
String HTMLMediaElement::initialURL()
 
1747
{
 
1748
    KURL initialSrc = document()->completeURL(getAttribute(srcAttr));
 
1749
    
 
1750
    if (!initialSrc.isValid())
 
1751
        initialSrc = selectNextSourceChild(0, DoNothing);
 
1752
 
 
1753
    m_currentSrc = initialSrc.string();
 
1754
 
 
1755
    return initialSrc;
 
1756
}
 
1757
 
 
1758
void HTMLMediaElement::finishParsingChildren()
 
1759
{
 
1760
    HTMLElement::finishParsingChildren();
 
1761
    if (!m_player)
 
1762
        m_player.set(new MediaPlayer(this));
 
1763
    
 
1764
    document()->updateStyleIfNeeded();
 
1765
    if (m_needWidgetUpdate && renderer())
 
1766
        toRenderPartObject(renderer())->updateWidget(true);
 
1767
}
 
1768
 
 
1769
#endif
1083
1770
 
1084
1771
}
1085
1772