Back to index

lightning-sunbird  0.9+nobinonly
imgRequestProxy.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 2001
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Stuart Parmenter <pavlov@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "imgRequestProxy.h"
00041 
00042 #include "nsIInputStream.h"
00043 #include "nsIComponentManager.h"
00044 #include "nsIServiceManager.h"
00045 #include "nsIMultiPartChannel.h"
00046 
00047 #include "nsAutoLock.h"
00048 #include "nsString.h"
00049 #include "nsXPIDLString.h"
00050 #include "nsReadableUtils.h"
00051 #include "nsCRT.h"
00052 
00053 #include "ImageErrors.h"
00054 #include "ImageLogging.h"
00055 
00056 #include "nspr.h"
00057 
00058 
00059 NS_IMPL_THREADSAFE_ISUPPORTS3(imgRequestProxy, imgIRequest, nsIRequest,
00060                               nsISupportsPriority)
00061 
00062 imgRequestProxy::imgRequestProxy() :
00063   mOwner(nsnull),
00064   mListener(nsnull),
00065   mLoadFlags(nsIRequest::LOAD_NORMAL),
00066   mCanceled(PR_FALSE),
00067   mIsInLoadGroup(PR_FALSE),
00068   mLock(nsnull)
00069 {
00070   /* member initializers and constructor code */
00071 
00072   mLock = PR_NewLock();
00073 }
00074 
00075 imgRequestProxy::~imgRequestProxy()
00076 {
00077   /* destructor code */
00078   NS_PRECONDITION(!mListener, "Someone forgot to properly cancel this request!");
00079   // Explicitly set mListener to null to ensure that the RemoveProxy
00080   // call below can't send |this| to an arbitrary listener while |this|
00081   // is being destroyed.
00082   mListener = nsnull;
00083 
00084   if (mOwner) {
00085     if (!mCanceled) {
00086       PR_Lock(mLock);
00087 
00088       mCanceled = PR_TRUE;
00089 
00090       PR_Unlock(mLock);
00091 
00092       /* Call RemoveProxy with a successful status.  This will keep the
00093          channel, if still downloading data, from being canceled if 'this' is
00094          the last observer.  This allows the image to continue to download and
00095          be cached even if no one is using it currently.
00096          
00097          Passing false to aNotify means that we will still get
00098          OnStopRequest, if needed.
00099        */
00100       mOwner->RemoveProxy(this, NS_OK, PR_FALSE);
00101     }
00102 
00103     NS_RELEASE(mOwner);
00104   }
00105 
00106   PR_DestroyLock(mLock);
00107 }
00108 
00109 
00110 
00111 nsresult imgRequestProxy::Init(imgRequest *request, nsILoadGroup *aLoadGroup, imgIDecoderObserver *aObserver)
00112 {
00113   NS_PRECONDITION(request, "no request");
00114   if (!request)
00115     return NS_ERROR_NULL_POINTER;
00116 
00117   LOG_SCOPE_WITH_PARAM(gImgLog, "imgRequestProxy::Init", "request", request);
00118 
00119   PR_Lock(mLock);
00120 
00121   mOwner = request;
00122   NS_ADDREF(mOwner);
00123 
00124   mListener = aObserver;
00125 
00126   mLoadGroup = aLoadGroup;
00127 
00128   PR_Unlock(mLock);
00129 
00130   request->AddProxy(this, PR_FALSE); // Pass PR_FALSE here so that AddProxy doesn't send all the On* notifications immediatly
00131 
00132   return NS_OK;
00133 }
00134 
00135 nsresult imgRequestProxy::ChangeOwner(imgRequest *aNewOwner)
00136 {
00137   if (mCanceled)
00138     return NS_OK;
00139 
00140   PR_Lock(mLock);
00141 
00142   // Passing false to aNotify means that mListener will still get
00143   // OnStopRequest, if needed.
00144   mOwner->RemoveProxy(this, NS_IMAGELIB_CHANGING_OWNER, PR_FALSE);
00145   NS_RELEASE(mOwner);
00146 
00147   mOwner = aNewOwner;
00148   NS_ADDREF(mOwner);
00149 
00150   mOwner->AddProxy(this, PR_FALSE);
00151 
00152   PR_Unlock(mLock);
00153 
00154   return NS_OK;
00155 }
00156 
00157 void imgRequestProxy::AddToLoadGroup()
00158 {
00159   NS_ASSERTION(!mIsInLoadGroup, "Whaa, we're already in the loadgroup!");
00160 
00161   if (!mIsInLoadGroup && mLoadGroup) {
00162     mLoadGroup->AddRequest(this, nsnull);
00163     mIsInLoadGroup = PR_TRUE;
00164   }
00165 }
00166 
00167 void imgRequestProxy::RemoveFromLoadGroup(PRBool releaseLoadGroup)
00168 {
00169   if (!mIsInLoadGroup)
00170     return;
00171 
00172   /* calling RemoveFromLoadGroup may cause the document to finish
00173      loading, which could result in our death.  We need to make sure
00174      that we stay alive long enough to fight another battle... at
00175      least until we exit this function.
00176   */
00177   nsCOMPtr<imgIRequest> kungFuDeathGrip(this);
00178 
00179   mLoadGroup->RemoveRequest(this, NS_OK, nsnull);
00180   mIsInLoadGroup = PR_FALSE;
00181 
00182   if (releaseLoadGroup) {
00183     // We're done with the loadgroup, release it.
00184     mLoadGroup = nsnull;
00185   }
00186 }
00187 
00188 
00191 /* readonly attribute wstring name; */
00192 NS_IMETHODIMP imgRequestProxy::GetName(nsACString &aName)
00193 {
00194   aName.Truncate();
00195   if (mOwner) {
00196     nsCOMPtr<nsIURI> uri;
00197     mOwner->GetURI(getter_AddRefs(uri));
00198     if (uri)
00199       uri->GetSpec(aName);
00200   }
00201   return NS_OK;
00202 }
00203 
00204 /* boolean isPending (); */
00205 NS_IMETHODIMP imgRequestProxy::IsPending(PRBool *_retval)
00206 {
00207     return NS_ERROR_NOT_IMPLEMENTED;
00208 }
00209 
00210 /* readonly attribute nsresult status; */
00211 NS_IMETHODIMP imgRequestProxy::GetStatus(nsresult *aStatus)
00212 {
00213     return NS_ERROR_NOT_IMPLEMENTED;
00214 }
00215 
00216 /* void cancel (in nsresult status); */
00217 NS_IMETHODIMP imgRequestProxy::Cancel(nsresult status)
00218 {
00219   if (mCanceled || !mOwner)
00220     return NS_ERROR_FAILURE;
00221 
00222   LOG_SCOPE(gImgLog, "imgRequestProxy::Cancel");
00223 
00224   PR_Lock(mLock);
00225 
00226   mCanceled = PR_TRUE;
00227 
00228   PR_Unlock(mLock);
00229 
00230   // Passing false to aNotify means that mListener will still get
00231   // OnStopRequest, if needed.
00232   mOwner->RemoveProxy(this, status, PR_FALSE);
00233 
00234   mListener = nsnull;
00235 
00236   return NS_OK;
00237 }
00238 
00239 /* void suspend (); */
00240 NS_IMETHODIMP imgRequestProxy::Suspend()
00241 {
00242     return NS_ERROR_NOT_IMPLEMENTED;
00243 }
00244 
00245 /* void resume (); */
00246 NS_IMETHODIMP imgRequestProxy::Resume()
00247 {
00248     return NS_ERROR_NOT_IMPLEMENTED;
00249 }
00250 
00251 /* attribute nsILoadGroup loadGroup */
00252 NS_IMETHODIMP imgRequestProxy::GetLoadGroup(nsILoadGroup **loadGroup)
00253 {
00254   nsAutoLock lock(mLock);
00255   NS_IF_ADDREF(*loadGroup = mLoadGroup.get());
00256   return NS_OK;
00257 }
00258 NS_IMETHODIMP imgRequestProxy::SetLoadGroup(nsILoadGroup *loadGroup)
00259 {
00260   nsAutoLock lock(mLock);
00261   mLoadGroup = loadGroup;
00262   return NS_OK;
00263 }
00264 
00265 /* attribute nsLoadFlags loadFlags */
00266 NS_IMETHODIMP imgRequestProxy::GetLoadFlags(nsLoadFlags *flags)
00267 {
00268   *flags = mLoadFlags;
00269   return NS_OK;
00270 }
00271 NS_IMETHODIMP imgRequestProxy::SetLoadFlags(nsLoadFlags flags)
00272 {
00273   mLoadFlags = flags;
00274   return NS_OK;
00275 }
00276 
00279 /* attribute imgIContainer image; */
00280 NS_IMETHODIMP imgRequestProxy::GetImage(imgIContainer * *aImage)
00281 {
00282   if (!mOwner)
00283     return NS_ERROR_FAILURE;
00284 
00285   nsAutoLock lock(mLock);
00286   mOwner->GetImage(aImage);
00287   return NS_OK;
00288 }
00289 
00290 /* readonly attribute unsigned long imageStatus; */
00291 NS_IMETHODIMP imgRequestProxy::GetImageStatus(PRUint32 *aStatus)
00292 {
00293   if (!mOwner) {
00294     *aStatus = imgIRequest::STATUS_ERROR;
00295     return NS_ERROR_FAILURE;
00296   }
00297 
00298   nsAutoLock lock(mLock);
00299   *aStatus = mOwner->GetImageStatus();
00300   return NS_OK;
00301 }
00302 
00303 /* readonly attribute nsIURI URI; */
00304 NS_IMETHODIMP imgRequestProxy::GetURI(nsIURI **aURI)
00305 {
00306   if (!mOwner)
00307     return NS_ERROR_FAILURE;
00308 
00309   nsAutoLock lock(mLock);
00310   return mOwner->GetURI(aURI);
00311 }
00312 
00313 /* readonly attribute imgIDecoderObserver decoderObserver; */
00314 NS_IMETHODIMP imgRequestProxy::GetDecoderObserver(imgIDecoderObserver **aDecoderObserver)
00315 {
00316   *aDecoderObserver = mListener;
00317   NS_IF_ADDREF(*aDecoderObserver);
00318   return NS_OK;
00319 }
00320 
00321 /* readonly attribute string mimeType; */
00322 NS_IMETHODIMP imgRequestProxy::GetMimeType(char **aMimeType)
00323 {
00324   if (!mOwner)
00325     return NS_ERROR_FAILURE;
00326 
00327   const char *type = mOwner->GetMimeType();
00328   if (!type)
00329     return NS_ERROR_FAILURE;
00330 
00331   *aMimeType = nsCRT::strdup(type);
00332 
00333   return NS_OK;
00334 }
00335 
00336 NS_IMETHODIMP imgRequestProxy::Clone(imgIDecoderObserver* aObserver,
00337                                      imgIRequest** aClone)
00338 {
00339   NS_PRECONDITION(aClone, "Null out param");
00340   *aClone = nsnull;
00341   imgRequestProxy* clone = new imgRequestProxy();
00342   if (!clone) {
00343     return NS_ERROR_OUT_OF_MEMORY;
00344   }
00345   NS_ADDREF(clone);
00346 
00347   // It is important to call |SetLoadFlags()| before calling |Init()| because
00348   // |Init()| adds the request to the loadgroup.
00349   // When a request is added to a loadgroup, its load flags are merged
00350   // with the load flags of the loadgroup.
00351   // XXXldb That's not true anymore.  Stuff from imgLoader adds the
00352   // request to the loadgroup.
00353   clone->SetLoadFlags(mLoadFlags);
00354   nsresult rv = clone->Init(mOwner, mLoadGroup, aObserver);
00355   if (NS_FAILED(rv)) {
00356     NS_RELEASE(clone);
00357     return rv;
00358   }
00359 
00360   // Assign to *aClone before calling NotifyProxyListener so that if
00361   // the caller expects to only be notified for requests it's already
00362   // holding pointers to it won't be surprised.
00363   *aClone = clone;
00364 
00365   // Send the notifications to the clone's observer
00366   mOwner->NotifyProxyListener(clone);
00367 
00368   return NS_OK;
00369 }
00370 
00373 NS_IMETHODIMP imgRequestProxy::GetPriority(PRInt32 *priority)
00374 {
00375   NS_ENSURE_STATE(mOwner);
00376   *priority = mOwner->Priority();
00377   return NS_OK;
00378 }
00379 
00380 NS_IMETHODIMP imgRequestProxy::SetPriority(PRInt32 priority)
00381 {
00382   NS_ENSURE_STATE(mOwner && !mCanceled);
00383   mOwner->AdjustPriority(this, priority - mOwner->Priority());
00384   return NS_OK;
00385 }
00386 
00387 NS_IMETHODIMP imgRequestProxy::AdjustPriority(PRInt32 priority)
00388 {
00389   NS_ENSURE_STATE(mOwner && !mCanceled);
00390   mOwner->AdjustPriority(this, priority);
00391   return NS_OK;
00392 }
00393 
00396 void imgRequestProxy::FrameChanged(imgIContainer *container, gfxIImageFrame *newframe, nsIntRect * dirtyRect)
00397 {
00398   LOG_FUNC(gImgLog, "imgRequestProxy::FrameChanged");
00399 
00400   if (mListener) {
00401     // Hold a ref to the listener while we call it, just in case.
00402     nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
00403     mListener->FrameChanged(container, newframe, dirtyRect);
00404   }
00405 }
00406 
00409 void imgRequestProxy::OnStartDecode()
00410 {
00411   LOG_FUNC(gImgLog, "imgRequestProxy::OnStartDecode");
00412 
00413   if (mListener) {
00414     // Hold a ref to the listener while we call it, just in case.
00415     nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
00416     mListener->OnStartDecode(this);
00417   }
00418 }
00419 
00420 void imgRequestProxy::OnStartContainer(imgIContainer *image)
00421 {
00422   LOG_FUNC(gImgLog, "imgRequestProxy::OnStartContainer");
00423 
00424   if (mListener) {
00425     // Hold a ref to the listener while we call it, just in case.
00426     nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
00427     mListener->OnStartContainer(this, image);
00428   }
00429 }
00430 
00431 void imgRequestProxy::OnStartFrame(gfxIImageFrame *frame)
00432 {
00433   LOG_FUNC(gImgLog, "imgRequestProxy::OnStartFrame");
00434 
00435   if (mListener) {
00436     // Hold a ref to the listener while we call it, just in case.
00437     nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
00438     mListener->OnStartFrame(this, frame);
00439   }
00440 }
00441 
00442 void imgRequestProxy::OnDataAvailable(gfxIImageFrame *frame, const nsIntRect * rect)
00443 {
00444   LOG_FUNC(gImgLog, "imgRequestProxy::OnDataAvailable");
00445 
00446   if (mListener) {
00447     // Hold a ref to the listener while we call it, just in case.
00448     nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
00449     mListener->OnDataAvailable(this, frame, rect);
00450   }
00451 }
00452 
00453 void imgRequestProxy::OnStopFrame(gfxIImageFrame *frame)
00454 {
00455   LOG_FUNC(gImgLog, "imgRequestProxy::OnStopFrame");
00456 
00457   if (mListener) {
00458     // Hold a ref to the listener while we call it, just in case.
00459     nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
00460     mListener->OnStopFrame(this, frame);
00461   }
00462 }
00463 
00464 void imgRequestProxy::OnStopContainer(imgIContainer *image)
00465 {
00466   LOG_FUNC(gImgLog, "imgRequestProxy::OnStopContainer");
00467 
00468   if (mListener) {
00469     // Hold a ref to the listener while we call it, just in case.
00470     nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
00471     mListener->OnStopContainer(this, image);
00472   }
00473 }
00474 
00475 void imgRequestProxy::OnStopDecode(nsresult status, const PRUnichar *statusArg)
00476 {
00477   LOG_FUNC(gImgLog, "imgRequestProxy::OnStopDecode");
00478 
00479   if (mListener) {
00480     // Hold a ref to the listener while we call it, just in case.
00481     nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
00482     mListener->OnStopDecode(this, status, statusArg);
00483   }
00484 }
00485 
00486 
00487 
00488 void imgRequestProxy::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
00489 {
00490 #ifdef PR_LOGGING
00491   nsCAutoString name;
00492   GetName(name);
00493   LOG_FUNC_WITH_PARAM(gImgLog, "imgRequestProxy::OnStartRequest", "name", name.get());
00494 #endif
00495 
00496   if (mListener) {
00497     // Hold a ref to the listener while we call it, just in case.
00498     nsCOMPtr<imgIDecoderObserver_MOZILLA_1_8_BRANCH> listener = do_QueryInterface(mListener);
00499     if (listener)
00500       listener->OnStartRequest(this);
00501   }
00502 }
00503 
00504 void imgRequestProxy::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
00505                                     nsresult statusCode, PRBool lastPart)
00506 {
00507 #ifdef PR_LOGGING
00508   nsCAutoString name;
00509   GetName(name);
00510   LOG_FUNC_WITH_PARAM(gImgLog, "imgRequestProxy::OnStopRequest", "name", name.get());
00511 #endif
00512 
00513   if (mListener) {
00514     // Hold a ref to the listener while we call it, just in case.
00515     nsCOMPtr<imgIDecoderObserver_MOZILLA_1_8_BRANCH> listener = do_QueryInterface(mListener);
00516     if (listener)
00517       listener->OnStopRequest(this, lastPart);
00518   }
00519 
00520   // If we're expecting more data from a multipart channel, re-add ourself
00521   // to the loadgroup so that the document doesn't lose track of the load.
00522   // If the request is already a background request and there's more data
00523   // coming, we can just leave the request in the loadgroup as-is.
00524   if (lastPart || (mLoadFlags & nsIRequest::LOAD_BACKGROUND) == 0) {
00525     RemoveFromLoadGroup(lastPart);
00526     // More data is coming, so change the request to be a background request
00527     // and put it back in the loadgroup.
00528     if (!lastPart) {
00529       mLoadFlags |= nsIRequest::LOAD_BACKGROUND;
00530       AddToLoadGroup();
00531     }
00532   }
00533 }
00534