1 /* 2 * Copyright (C) 2010 Julien Chaffraix <jchaffraix (at) webkit.org> All right reserved. 3 * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) 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 "core/xml/XMLHttpRequestProgressEventThrottle.h" 29 30 #include "core/events/EventTarget.h" 31 #include "core/xml/XMLHttpRequestProgressEvent.h" 32 33 namespace blink { 34 35 class XMLHttpRequestProgressEventThrottle::DeferredEvent { 36 public: 37 DeferredEvent() { clear(); } 38 void set(bool lengthComputable, unsigned long long loaded, unsigned long long total) 39 { 40 m_isDeferred = true; 41 m_lengthComputable = lengthComputable; 42 m_loaded = loaded; 43 m_total = total; 44 } 45 void clear() 46 { 47 m_isDeferred = false; 48 m_lengthComputable = false; 49 m_loaded = 0; 50 m_total = 0; 51 } 52 bool isDeferred() const { return m_isDeferred; } 53 bool lengthComputable() const { return m_lengthComputable; } 54 unsigned long long loaded() const { return m_loaded; } 55 unsigned long long total() const { return m_total; } 56 57 private: 58 unsigned long long m_loaded; 59 unsigned long long m_total; 60 bool m_isDeferred; 61 bool m_lengthComputable; 62 }; 63 64 const double XMLHttpRequestProgressEventThrottle::minimumProgressEventDispatchingIntervalInSeconds = .05; // 50 ms per specification. 65 66 XMLHttpRequestProgressEventThrottle::XMLHttpRequestProgressEventThrottle(EventTarget* target) 67 : m_target(target) 68 , m_deferred(adoptPtr(new DeferredEvent)) 69 { 70 ASSERT(target); 71 } 72 73 XMLHttpRequestProgressEventThrottle::~XMLHttpRequestProgressEventThrottle() 74 { 75 } 76 77 void XMLHttpRequestProgressEventThrottle::dispatchProgressEvent(const AtomicString& type, bool lengthComputable, unsigned long long loaded, unsigned long long total) 78 { 79 // Given that ResourceDispatcher doesn't deliver an event when suspended, 80 // we don't have to worry about event dispatching while suspended. 81 if (type != EventTypeNames::progress) { 82 m_target->dispatchEvent(XMLHttpRequestProgressEvent::create(type, lengthComputable, loaded, total)); 83 return; 84 } 85 86 if (isActive()) { 87 m_deferred->set(lengthComputable, loaded, total); 88 } else { 89 m_target->dispatchEvent(XMLHttpRequestProgressEvent::create(type, lengthComputable, loaded, total)); 90 startOneShot(minimumProgressEventDispatchingIntervalInSeconds, FROM_HERE); 91 } 92 } 93 94 void XMLHttpRequestProgressEventThrottle::dispatchReadyStateChangeEvent(PassRefPtrWillBeRawPtr<Event> event, DeferredEventAction action) 95 { 96 // Given that ResourceDispatcher doesn't deliver an event when suspended, 97 // we don't have to worry about event dispatching while suspended. 98 if (action == Flush) { 99 dispatchDeferredEvent(); 100 stop(); 101 } else if (action == Clear) { 102 m_deferred->clear(); 103 stop(); 104 } 105 106 m_target->dispatchEvent(event); 107 } 108 109 void XMLHttpRequestProgressEventThrottle::dispatchDeferredEvent() 110 { 111 if (m_deferred->isDeferred()) { 112 m_target->dispatchEvent(XMLHttpRequestProgressEvent::create(EventTypeNames::progress, m_deferred->lengthComputable(), m_deferred->loaded(), m_deferred->total())); 113 m_deferred->clear(); 114 } 115 } 116 117 void XMLHttpRequestProgressEventThrottle::fired() 118 { 119 if (!m_deferred->isDeferred()) { 120 // No "progress" event was queued since the previous dispatch, we can 121 // safely stop the timer. 122 return; 123 } 124 125 dispatchDeferredEvent(); 126 127 // Watch if another "progress" ProgressEvent arrives in the next 50ms. 128 startOneShot(minimumProgressEventDispatchingIntervalInSeconds, FROM_HERE); 129 } 130 131 void XMLHttpRequestProgressEventThrottle::suspend() 132 { 133 stop(); 134 } 135 136 void XMLHttpRequestProgressEventThrottle::resume() 137 { 138 if (!m_deferred->isDeferred()) 139 return; 140 141 // Do not dispatch events inline here, since ExecutionContext is iterating 142 // over the list of active DOM objects to resume them, and any activated JS 143 // event-handler could insert new active DOM objects to the list. 144 startOneShot(0, FROM_HERE); 145 } 146 147 void XMLHttpRequestProgressEventThrottle::trace(Visitor* visitor) 148 { 149 visitor->trace(m_target); 150 } 151 152 } // namespace blink 153