Bug 628949 - Update visible region / glass regions after we paint. r=roc a=2.0.
[mozilla-central.git] / netwerk / ipc / ChannelEventQueue.h
blob8e8eb7af5d4384535ed24ebdb6985e9dbcf59867
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=8 et :
3 */
4 /* ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at:
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
17 * The Original Code is Mozilla Code.
19 * The Initial Developer of the Original Code is
20 * The Mozilla Foundation
21 * Portions created by the Initial Developer are Copyright (C) 2010
22 * the Initial Developer. All Rights Reserved.
24 * Contributor(s):
25 * Josh Matthews <josh@joshmatthews.net> (initial developer)
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #ifndef mozilla_net_ChannelEventQueue_h
42 #define mozilla_net_ChannelEventQueue_h
44 namespace mozilla {
45 namespace net {
47 class ChannelEvent
49 public:
50 ChannelEvent() { MOZ_COUNT_CTOR(ChannelEvent); }
51 virtual ~ChannelEvent() { MOZ_COUNT_DTOR(ChannelEvent); }
52 virtual void Run() = 0;
55 // Workaround for Necko re-entrancy dangers. We buffer IPDL messages in a
56 // queue if still dispatching previous one(s) to listeners/observers.
57 // Otherwise synchronous XMLHttpRequests and/or other code that spins the
58 // event loop (ex: IPDL rpc) could cause listener->OnDataAvailable (for
59 // instance) to be called before mListener->OnStartRequest has completed.
61 template<class T> class AutoEventEnqueuerBase;
63 template<class T>
64 class ChannelEventQueue
66 public:
67 ChannelEventQueue(T* self) : mQueuePhase(PHASE_UNQUEUED)
68 , mSelf(self) {}
69 ~ChannelEventQueue() {}
71 protected:
72 void BeginEventQueueing();
73 void EndEventQueueing();
74 void EnqueueEvent(ChannelEvent* callback);
75 bool ShouldEnqueue();
76 void FlushEventQueue();
78 nsTArray<nsAutoPtr<ChannelEvent> > mEventQueue;
79 enum {
80 PHASE_UNQUEUED,
81 PHASE_QUEUEING,
82 PHASE_FINISHED_QUEUEING,
83 PHASE_FLUSHING
84 } mQueuePhase;
86 typedef AutoEventEnqueuerBase<T> AutoEventEnqueuer;
88 private:
89 T* mSelf;
91 friend class AutoEventEnqueuerBase<T>;
94 template<class T> inline void
95 ChannelEventQueue<T>::BeginEventQueueing()
97 if (mQueuePhase != PHASE_UNQUEUED)
98 return;
99 // Store incoming IPDL messages for later.
100 mQueuePhase = PHASE_QUEUEING;
103 template<class T> inline void
104 ChannelEventQueue<T>::EndEventQueueing()
106 if (mQueuePhase != PHASE_QUEUEING)
107 return;
109 mQueuePhase = PHASE_FINISHED_QUEUEING;
112 template<class T> inline bool
113 ChannelEventQueue<T>::ShouldEnqueue()
115 return mQueuePhase != PHASE_UNQUEUED || mSelf->IsSuspended();
118 template<class T> inline void
119 ChannelEventQueue<T>::EnqueueEvent(ChannelEvent* callback)
121 mEventQueue.AppendElement(callback);
124 template<class T> void
125 ChannelEventQueue<T>::FlushEventQueue()
127 NS_ABORT_IF_FALSE(mQueuePhase != PHASE_UNQUEUED,
128 "Queue flushing should not occur if PHASE_UNQUEUED");
130 // Queue already being flushed
131 if (mQueuePhase != PHASE_FINISHED_QUEUEING || mSelf->IsSuspended())
132 return;
134 nsRefPtr<T> kungFuDeathGrip(mSelf);
135 if (mEventQueue.Length() > 0) {
136 // It is possible for new callbacks to be enqueued as we are
137 // flushing the queue, so the queue must not be cleared until
138 // all callbacks have run.
139 mQueuePhase = PHASE_FLUSHING;
141 PRUint32 i;
142 for (i = 0; i < mEventQueue.Length(); i++) {
143 mEventQueue[i]->Run();
144 if (mSelf->IsSuspended())
145 break;
148 // We will always want to remove at least one finished callback.
149 if (i < mEventQueue.Length())
150 i++;
152 mEventQueue.RemoveElementsAt(0, i);
155 if (mSelf->IsSuspended())
156 mQueuePhase = PHASE_QUEUEING;
157 else
158 mQueuePhase = PHASE_UNQUEUED;
161 // Ensures any incoming IPDL msgs are queued during its lifetime, and flushes
162 // the queue when it goes out of scope.
163 template<class T>
164 class AutoEventEnqueuerBase
166 public:
167 AutoEventEnqueuerBase(ChannelEventQueue<T>* queue) : mEventQueue(queue)
169 mEventQueue->BeginEventQueueing();
171 ~AutoEventEnqueuerBase()
173 mEventQueue->EndEventQueueing();
174 mEventQueue->FlushEventQueue();
176 private:
177 ChannelEventQueue<T> *mEventQueue;
183 #endif