Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "nsBrowserStatusFilter.h"
7 : #include "mozilla/SystemGroup.h"
8 : #include "nsIChannel.h"
9 : #include "nsITimer.h"
10 : #include "nsIServiceManager.h"
11 : #include "nsString.h"
12 :
13 : using namespace mozilla;
14 :
15 : //-----------------------------------------------------------------------------
16 : // nsBrowserStatusFilter <public>
17 : //-----------------------------------------------------------------------------
18 :
19 2 : nsBrowserStatusFilter::nsBrowserStatusFilter()
20 : : mCurProgress(0)
21 : , mMaxProgress(0)
22 : , mStatusIsDirty(true)
23 : , mCurrentPercentage(0)
24 : , mTotalRequests(0)
25 : , mFinishedRequests(0)
26 : , mUseRealProgressFlag(false)
27 : , mDelayedStatus(false)
28 2 : , mDelayedProgress(false)
29 : {
30 2 : }
31 :
32 0 : nsBrowserStatusFilter::~nsBrowserStatusFilter()
33 : {
34 0 : if (mTimer) {
35 0 : mTimer->Cancel();
36 : }
37 0 : }
38 :
39 : //-----------------------------------------------------------------------------
40 : // nsBrowserStatusFilter::nsISupports
41 : //-----------------------------------------------------------------------------
42 :
43 345 : NS_IMPL_ISUPPORTS(nsBrowserStatusFilter,
44 : nsIWebProgress,
45 : nsIWebProgressListener,
46 : nsIWebProgressListener2,
47 : nsISupportsWeakReference)
48 :
49 : //-----------------------------------------------------------------------------
50 : // nsBrowserStatusFilter::nsIWebProgress
51 : //-----------------------------------------------------------------------------
52 :
53 : NS_IMETHODIMP
54 3 : nsBrowserStatusFilter::AddProgressListener(nsIWebProgressListener *aListener,
55 : uint32_t aNotifyMask)
56 : {
57 3 : mListener = aListener;
58 3 : return NS_OK;
59 : }
60 :
61 : NS_IMETHODIMP
62 1 : nsBrowserStatusFilter::RemoveProgressListener(nsIWebProgressListener *aListener)
63 : {
64 1 : if (aListener == mListener)
65 1 : mListener = nullptr;
66 1 : return NS_OK;
67 : }
68 :
69 : NS_IMETHODIMP
70 0 : nsBrowserStatusFilter::GetDOMWindow(mozIDOMWindowProxy **aResult)
71 : {
72 0 : NS_NOTREACHED("nsBrowserStatusFilter::GetDOMWindow");
73 0 : return NS_ERROR_NOT_IMPLEMENTED;
74 : }
75 :
76 : NS_IMETHODIMP
77 0 : nsBrowserStatusFilter::GetDOMWindowID(uint64_t *aResult)
78 : {
79 0 : *aResult = 0;
80 0 : NS_NOTREACHED("nsBrowserStatusFilter::GetDOMWindowID");
81 0 : return NS_ERROR_NOT_IMPLEMENTED;
82 : }
83 :
84 : NS_IMETHODIMP
85 0 : nsBrowserStatusFilter::GetInnerDOMWindowID(uint64_t *aResult)
86 : {
87 0 : *aResult = 0;
88 0 : NS_NOTREACHED("nsBrowserStatusFilter::GetInnerDOMWindowID");
89 0 : return NS_ERROR_NOT_IMPLEMENTED;
90 : }
91 :
92 : NS_IMETHODIMP
93 0 : nsBrowserStatusFilter::GetIsTopLevel(bool *aIsTopLevel)
94 : {
95 0 : *aIsTopLevel = false;
96 0 : NS_NOTREACHED("nsBrowserStatusFilter::GetIsTopLevel");
97 0 : return NS_ERROR_NOT_IMPLEMENTED;
98 : }
99 :
100 : NS_IMETHODIMP
101 0 : nsBrowserStatusFilter::GetIsLoadingDocument(bool *aIsLoadingDocument)
102 : {
103 0 : NS_NOTREACHED("nsBrowserStatusFilter::GetIsLoadingDocument");
104 0 : return NS_ERROR_NOT_IMPLEMENTED;
105 : }
106 :
107 : NS_IMETHODIMP
108 0 : nsBrowserStatusFilter::GetLoadType(uint32_t *aLoadType)
109 : {
110 0 : *aLoadType = 0;
111 0 : NS_NOTREACHED("nsBrowserStatusFilter::GetLoadType");
112 0 : return NS_ERROR_NOT_IMPLEMENTED;
113 : }
114 :
115 : //-----------------------------------------------------------------------------
116 : // nsBrowserStatusFilter::nsIWebProgressListener
117 : //-----------------------------------------------------------------------------
118 :
119 : NS_IMETHODIMP
120 30 : nsBrowserStatusFilter::OnStateChange(nsIWebProgress *aWebProgress,
121 : nsIRequest *aRequest,
122 : uint32_t aStateFlags,
123 : nsresult aStatus)
124 : {
125 30 : if (!mListener)
126 0 : return NS_OK;
127 :
128 30 : if (aStateFlags & STATE_START) {
129 11 : if (aStateFlags & STATE_IS_NETWORK) {
130 5 : ResetMembers();
131 : }
132 11 : if (aStateFlags & STATE_IS_REQUEST) {
133 11 : ++mTotalRequests;
134 :
135 : // if the total requests exceeds 1, then we'll base our progress
136 : // notifications on the percentage of completed requests.
137 : // otherwise, progress for the single request will be reported.
138 11 : mUseRealProgressFlag = (mTotalRequests == 1);
139 : }
140 : }
141 19 : else if (aStateFlags & STATE_STOP) {
142 14 : if (aStateFlags & STATE_IS_REQUEST) {
143 8 : ++mFinishedRequests;
144 : // Note: Do not return from here. This is necessary so that the
145 : // STATE_STOP can still be relayed to the listener if needed
146 : // (bug 209330)
147 8 : if (!mUseRealProgressFlag && mTotalRequests)
148 7 : OnProgressChange(nullptr, nullptr, 0, 0,
149 14 : mFinishedRequests, mTotalRequests);
150 : }
151 : }
152 5 : else if (aStateFlags & STATE_TRANSFERRING) {
153 5 : if (aStateFlags & STATE_IS_REQUEST) {
154 5 : if (!mUseRealProgressFlag && mTotalRequests)
155 5 : return OnProgressChange(nullptr, nullptr, 0, 0,
156 10 : mFinishedRequests, mTotalRequests);
157 : }
158 :
159 : // no need to forward this state change
160 0 : return NS_OK;
161 : } else {
162 : // no need to forward this state change
163 0 : return NS_OK;
164 : }
165 :
166 : // If we're here, we have either STATE_START or STATE_STOP. The
167 : // listener only cares about these in certain conditions.
168 25 : bool isLoadingDocument = false;
169 50 : if ((aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK ||
170 30 : (aStateFlags & nsIWebProgressListener::STATE_IS_REQUEST &&
171 16 : mFinishedRequests == mTotalRequests &&
172 4 : NS_SUCCEEDED(aWebProgress->GetIsLoadingDocument(&isLoadingDocument)) &&
173 2 : !isLoadingDocument))) {
174 9 : if (mTimer && (aStateFlags & nsIWebProgressListener::STATE_STOP)) {
175 2 : mTimer->Cancel();
176 2 : ProcessTimeout();
177 : }
178 :
179 9 : return mListener->OnStateChange(aWebProgress, aRequest, aStateFlags,
180 9 : aStatus);
181 : }
182 :
183 16 : return NS_OK;
184 : }
185 :
186 : NS_IMETHODIMP
187 19 : nsBrowserStatusFilter::OnProgressChange(nsIWebProgress *aWebProgress,
188 : nsIRequest *aRequest,
189 : int32_t aCurSelfProgress,
190 : int32_t aMaxSelfProgress,
191 : int32_t aCurTotalProgress,
192 : int32_t aMaxTotalProgress)
193 : {
194 19 : if (!mListener)
195 0 : return NS_OK;
196 :
197 19 : if (!mUseRealProgressFlag && aRequest)
198 5 : return NS_OK;
199 :
200 : //
201 : // limit frequency of calls to OnProgressChange
202 : //
203 :
204 14 : mCurProgress = (int64_t)aCurTotalProgress;
205 14 : mMaxProgress = (int64_t)aMaxTotalProgress;
206 :
207 14 : if (mDelayedProgress)
208 10 : return NS_OK;
209 :
210 4 : if (!mDelayedStatus) {
211 0 : MaybeSendProgress();
212 0 : StartDelayTimer();
213 : }
214 :
215 4 : mDelayedProgress = true;
216 :
217 4 : return NS_OK;
218 : }
219 :
220 : NS_IMETHODIMP
221 2 : nsBrowserStatusFilter::OnLocationChange(nsIWebProgress *aWebProgress,
222 : nsIRequest *aRequest,
223 : nsIURI *aLocation,
224 : uint32_t aFlags)
225 : {
226 2 : if (!mListener)
227 0 : return NS_OK;
228 :
229 2 : return mListener->OnLocationChange(aWebProgress, aRequest, aLocation,
230 2 : aFlags);
231 : }
232 :
233 : NS_IMETHODIMP
234 12 : nsBrowserStatusFilter::OnStatusChange(nsIWebProgress *aWebProgress,
235 : nsIRequest *aRequest,
236 : nsresult aStatus,
237 : const char16_t *aMessage)
238 : {
239 12 : if (!mListener)
240 0 : return NS_OK;
241 :
242 : //
243 : // limit frequency of calls to OnStatusChange
244 : //
245 12 : if (mStatusIsDirty || !mCurrentStatusMsg.Equals(aMessage)) {
246 11 : mStatusIsDirty = true;
247 11 : mStatusMsg = aMessage;
248 : }
249 :
250 12 : if (mDelayedStatus)
251 8 : return NS_OK;
252 :
253 4 : if (!mDelayedProgress) {
254 4 : MaybeSendStatus();
255 4 : StartDelayTimer();
256 : }
257 :
258 4 : mDelayedStatus = true;
259 :
260 4 : return NS_OK;
261 : }
262 :
263 : NS_IMETHODIMP
264 2 : nsBrowserStatusFilter::OnSecurityChange(nsIWebProgress *aWebProgress,
265 : nsIRequest *aRequest,
266 : uint32_t aState)
267 : {
268 2 : if (!mListener)
269 0 : return NS_OK;
270 :
271 2 : return mListener->OnSecurityChange(aWebProgress, aRequest, aState);
272 : }
273 :
274 : //-----------------------------------------------------------------------------
275 : // nsBrowserStatusFilter::nsIWebProgressListener2
276 : //-----------------------------------------------------------------------------
277 : NS_IMETHODIMP
278 0 : nsBrowserStatusFilter::OnProgressChange64(nsIWebProgress *aWebProgress,
279 : nsIRequest *aRequest,
280 : int64_t aCurSelfProgress,
281 : int64_t aMaxSelfProgress,
282 : int64_t aCurTotalProgress,
283 : int64_t aMaxTotalProgress)
284 : {
285 : // XXX truncates 64-bit to 32-bit
286 0 : return OnProgressChange(aWebProgress, aRequest,
287 : (int32_t)aCurSelfProgress,
288 : (int32_t)aMaxSelfProgress,
289 : (int32_t)aCurTotalProgress,
290 0 : (int32_t)aMaxTotalProgress);
291 : }
292 :
293 : NS_IMETHODIMP
294 0 : nsBrowserStatusFilter::OnRefreshAttempted(nsIWebProgress *aWebProgress,
295 : nsIURI *aUri,
296 : int32_t aDelay,
297 : bool aSameUri,
298 : bool *allowRefresh)
299 : {
300 : nsCOMPtr<nsIWebProgressListener2> listener =
301 0 : do_QueryInterface(mListener);
302 0 : if (!listener) {
303 0 : *allowRefresh = true;
304 0 : return NS_OK;
305 : }
306 :
307 0 : return listener->OnRefreshAttempted(aWebProgress, aUri, aDelay, aSameUri,
308 0 : allowRefresh);
309 : }
310 :
311 : //-----------------------------------------------------------------------------
312 : // nsBrowserStatusFilter <private>
313 : //-----------------------------------------------------------------------------
314 :
315 : void
316 5 : nsBrowserStatusFilter::ResetMembers()
317 : {
318 5 : mTotalRequests = 0;
319 5 : mFinishedRequests = 0;
320 5 : mUseRealProgressFlag = false;
321 5 : mMaxProgress = 0;
322 5 : mCurProgress = 0;
323 5 : mCurrentPercentage = 0;
324 5 : mStatusIsDirty = true;
325 5 : }
326 :
327 : void
328 4 : nsBrowserStatusFilter::MaybeSendProgress()
329 : {
330 4 : if (mCurProgress > mMaxProgress || mCurProgress <= 0)
331 0 : return;
332 :
333 : // check our percentage
334 4 : int32_t percentage = (int32_t) double(mCurProgress) * 100 / mMaxProgress;
335 :
336 : // The progress meter only updates for increases greater than 3 percent
337 4 : if (percentage > (mCurrentPercentage + 3)) {
338 4 : mCurrentPercentage = percentage;
339 : // XXX truncates 64-bit to 32-bit
340 12 : mListener->OnProgressChange(nullptr, nullptr, 0, 0,
341 4 : (int32_t)mCurProgress,
342 8 : (int32_t)mMaxProgress);
343 : }
344 : }
345 :
346 : void
347 8 : nsBrowserStatusFilter::MaybeSendStatus()
348 : {
349 8 : if (mStatusIsDirty) {
350 6 : mListener->OnStatusChange(nullptr, nullptr, NS_OK, mStatusMsg.get());
351 6 : mCurrentStatusMsg = mStatusMsg;
352 6 : mStatusIsDirty = false;
353 : }
354 8 : }
355 :
356 : nsresult
357 4 : nsBrowserStatusFilter::StartDelayTimer()
358 : {
359 4 : NS_ASSERTION(!DelayInEffect(), "delay should not be in effect");
360 :
361 4 : mTimer = do_CreateInstance("@mozilla.org/timer;1");
362 4 : if (!mTimer)
363 0 : return NS_ERROR_FAILURE;
364 :
365 : // Use the system group. The browser status filter is always used by chrome
366 : // code.
367 4 : mTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::Other));
368 4 : return mTimer->InitWithNamedFuncCallback(
369 : TimeoutHandler, this, 160, nsITimer::TYPE_ONE_SHOT,
370 4 : "nsBrowserStatusFilter::TimeoutHandler");
371 : }
372 :
373 : void
374 4 : nsBrowserStatusFilter::ProcessTimeout()
375 : {
376 4 : mTimer = nullptr;
377 :
378 4 : if (!mListener)
379 0 : return;
380 :
381 4 : if (mDelayedStatus) {
382 4 : mDelayedStatus = false;
383 4 : MaybeSendStatus();
384 : }
385 :
386 4 : if (mDelayedProgress) {
387 4 : mDelayedProgress = false;
388 4 : MaybeSendProgress();
389 : }
390 : }
391 :
392 : void
393 2 : nsBrowserStatusFilter::TimeoutHandler(nsITimer *aTimer, void *aClosure)
394 : {
395 2 : nsBrowserStatusFilter *self = reinterpret_cast<nsBrowserStatusFilter *>(aClosure);
396 2 : if (!self) {
397 0 : NS_ERROR("no self");
398 0 : return;
399 : }
400 :
401 2 : self->ProcessTimeout();
402 : }
|