1/*
2 * Copyright (C) 2010 Julien Chaffraix <jchaffraix@webkit.org>
3 * All right reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "XMLHttpRequestProgressEventThrottle.h"
29
30#include "EventTarget.h"
31#include "XMLHttpRequestProgressEvent.h"
32
33namespace WebCore {
34
35const double XMLHttpRequestProgressEventThrottle::minimumProgressEventDispatchingIntervalInSeconds = .05; // 50 ms per specification.
36
37XMLHttpRequestProgressEventThrottle::XMLHttpRequestProgressEventThrottle(EventTarget* target)
38    : m_target(target)
39    , m_loaded(0)
40    , m_total(0)
41    , m_suspended(false)
42{
43    ASSERT(target);
44}
45
46XMLHttpRequestProgressEventThrottle::~XMLHttpRequestProgressEventThrottle()
47{
48}
49
50void XMLHttpRequestProgressEventThrottle::dispatchProgressEvent(bool lengthComputable, unsigned long long loaded, unsigned long long total)
51{
52    ASSERT(!suspended());
53    if (!isActive()) {
54        // The timer is not active so the least frequent event for now is every byte.
55        // Just go ahead and dispatch the event.
56
57        // We should not have any pending loaded & total information from a previous run.
58        ASSERT(!m_loaded);
59        ASSERT(!m_total);
60
61        dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().progressEvent, lengthComputable, loaded, total));
62        startRepeating(minimumProgressEventDispatchingIntervalInSeconds);
63        return;
64    }
65
66    // The timer is already active so minimumProgressEventDispatchingIntervalInSeconds is the least frequent event.
67    m_lengthComputable = lengthComputable;
68    m_loaded = loaded;
69    m_total = total;
70}
71
72void XMLHttpRequestProgressEventThrottle::dispatchEvent(PassRefPtr<Event> event, ProgressEventAction progressEventAction)
73{
74    ASSERT(!suspended());
75    // We should not have any pending events from a previous resume.
76    ASSERT(!m_pausedEvent);
77
78    if (progressEventAction == FlushProgressEvent)
79        flushProgressEvent();
80
81    m_target->dispatchEvent(event);
82}
83
84void XMLHttpRequestProgressEventThrottle::flushProgressEvent()
85{
86    if (!hasEventToDispatch())
87        return;
88
89    PassRefPtr<Event> event = XMLHttpRequestProgressEvent::create(eventNames().progressEvent, m_lengthComputable, m_loaded, m_total);
90    m_loaded = 0;
91    m_total = 0;
92
93    // We stop the timer as this is called when no more events are supposed to occur.
94    stop();
95
96    m_target->dispatchEvent(event);
97}
98
99void XMLHttpRequestProgressEventThrottle::dispatchPausedEvent()
100{
101    ASSERT(!suspended());
102    if (!m_pausedEvent)
103        return;
104
105    m_target->dispatchEvent(m_pausedEvent);
106    m_pausedEvent = 0;
107}
108
109void XMLHttpRequestProgressEventThrottle::fired()
110{
111    ASSERT(isActive());
112    ASSERT(!suspended());
113    ASSERT(!m_pausedEvent);
114    if (!hasEventToDispatch()) {
115        // No progress event was queued since the previous dispatch, we can safely stop the timer.
116        stop();
117        return;
118    }
119
120    m_target->dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().progressEvent, m_lengthComputable, m_loaded, m_total));
121    m_total = 0;
122    m_loaded = 0;
123}
124
125bool XMLHttpRequestProgressEventThrottle::hasEventToDispatch() const
126{
127    return (m_total || m_loaded) && isActive();
128}
129
130void XMLHttpRequestProgressEventThrottle::suspend()
131{
132    ASSERT(!m_pausedEvent);
133
134    m_suspended = true;
135    // If we have a progress event waiting to be dispatched,
136    // just queue it.
137    if (hasEventToDispatch()) {
138        m_pausedEvent = XMLHttpRequestProgressEvent::create(eventNames().progressEvent, m_lengthComputable, m_loaded, m_total);
139        m_total = 0;
140        m_loaded = 0;
141    }
142    stop();
143}
144
145void XMLHttpRequestProgressEventThrottle::resume()
146{
147    ASSERT(!m_loaded);
148    ASSERT(!m_total);
149
150    m_suspended = false;
151    dispatchPausedEvent();
152}
153
154} // namespace WebCore
155