Back to index

lightning-sunbird  0.9+nobinonly
nsSHEntry.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; 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 the Mozilla browser.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications, Inc.
00020  * Portions created by the Initial Developer are Copyright (C) 1999
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Radha Kulkarni <radha@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or 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 #ifdef DEBUG_bryner
00041 #define DEBUG_PAGE_CACHE
00042 #endif
00043 
00044 // Local Includes
00045 #include "nsSHEntry.h"
00046 #include "nsXPIDLString.h"
00047 #include "nsReadableUtils.h"
00048 #include "nsIDocShellLoadInfo.h"
00049 #include "nsIDocShellTreeItem.h"
00050 #include "nsIDocument.h"
00051 #include "nsIDOMDocument.h"
00052 #include "plevent.h"
00053 #include "nsAutoPtr.h"
00054 #include "nsIEventQueue.h"
00055 #include "nsEventQueueUtils.h"
00056 #include "nsIPrincipal.h"
00057 #include "nsIScriptSecurityManager.h"
00058 
00059 static PRUint32 gEntryID = 0;
00060 
00061 //*****************************************************************************
00062 //***    nsSHEntry: Object Management
00063 //*****************************************************************************
00064 
00065 nsSHEntry::nsSHEntry() 
00066   : mLoadType(0)
00067   , mID(gEntryID++)
00068   , mPageIdentifier(mID)
00069   , mScrollPositionX(0)
00070   , mScrollPositionY(0)
00071   , mIsFrameNavigation(PR_FALSE)
00072   , mSaveLayoutState(PR_TRUE)
00073   , mExpired(PR_FALSE)
00074   , mSticky(PR_TRUE)
00075   , mParent(nsnull)
00076   , mViewerBounds(0, 0, 0, 0)
00077 {
00078 }
00079 
00080 nsSHEntry::nsSHEntry(const nsSHEntry &other)
00081   : mURI(other.mURI)
00082   , mReferrerURI(other.mReferrerURI)
00083   // XXX why not copy mDocument?
00084   , mTitle(other.mTitle)
00085   , mPostData(other.mPostData)
00086   , mLayoutHistoryState(other.mLayoutHistoryState)
00087   , mLoadType(0)         // XXX why not copy?
00088   , mID(other.mID)
00089   , mPageIdentifier(other.mPageIdentifier)
00090   , mScrollPositionX(0)  // XXX why not copy?
00091   , mScrollPositionY(0)  // XXX why not copy?
00092   , mIsFrameNavigation(other.mIsFrameNavigation)
00093   , mSaveLayoutState(other.mSaveLayoutState)
00094   , mExpired(other.mExpired)
00095   , mSticky(PR_TRUE)
00096   // XXX why not copy mContentType?
00097   , mCacheKey(other.mCacheKey)
00098   , mParent(other.mParent)
00099   , mViewerBounds(0, 0, 0, 0)
00100   , mOwner(other.mOwner)
00101 {
00102 }
00103 
00104 PR_STATIC_CALLBACK(PRBool)
00105 ClearParentPtr(nsISHEntry* aEntry, void* /* aData */)
00106 {
00107   if (aEntry) {
00108     aEntry->SetParent(nsnull);
00109   }
00110   return PR_TRUE;
00111 }
00112 
00113 nsSHEntry::~nsSHEntry()
00114 {
00115   // Since we never really remove kids from SHEntrys, we need to null
00116   // out the mParent pointers on all our kids.
00117   mChildren.EnumerateForwards(ClearParentPtr, nsnull);
00118   mChildren.Clear();
00119   RemoveDocumentObserver();
00120   if (mContentViewer)
00121     mContentViewer->Destroy();
00122 }
00123 
00124 //*****************************************************************************
00125 //    nsSHEntry: nsISupports
00126 //*****************************************************************************
00127 
00128 NS_IMPL_ISUPPORTS6(nsSHEntry, nsISHContainer, nsISHEntry,
00129                    nsISHEntry_MOZILLA_1_8_BRANCH,
00130                    nsISHEntry_MOZILLA_1_8_BRANCH2,
00131                    nsIHistoryEntry,
00132                    nsIDocumentObserver)
00133 
00134 //*****************************************************************************
00135 //    nsSHEntry: nsISHEntry
00136 //*****************************************************************************
00137 
00138 NS_IMETHODIMP nsSHEntry::SetScrollPosition(PRInt32 x, PRInt32 y)
00139 {
00140   mScrollPositionX = x;
00141   mScrollPositionY = y;
00142   return NS_OK;
00143 }
00144 
00145 NS_IMETHODIMP nsSHEntry::GetScrollPosition(PRInt32 *x, PRInt32 *y)
00146 {
00147   *x = mScrollPositionX;
00148   *y = mScrollPositionY;
00149   return NS_OK;
00150 }
00151 
00152 NS_IMETHODIMP nsSHEntry::GetURI(nsIURI** aURI)
00153 {
00154   *aURI = mURI;
00155   NS_IF_ADDREF(*aURI);
00156   return NS_OK;
00157 }
00158 
00159 NS_IMETHODIMP nsSHEntry::SetURI(nsIURI* aURI)
00160 {
00161   mURI = aURI;
00162   return NS_OK;
00163 }
00164 
00165 NS_IMETHODIMP nsSHEntry::GetReferrerURI(nsIURI **aReferrerURI)
00166 {
00167   *aReferrerURI = mReferrerURI;
00168   NS_IF_ADDREF(*aReferrerURI);
00169   return NS_OK;
00170 }
00171 
00172 NS_IMETHODIMP nsSHEntry::SetReferrerURI(nsIURI *aReferrerURI)
00173 {
00174   mReferrerURI = aReferrerURI;
00175   return NS_OK;
00176 }
00177 
00178 NS_IMETHODIMP
00179 nsSHEntry::SetContentViewer(nsIContentViewer *aViewer)
00180 {
00181   RemoveDocumentObserver();
00182   mContentViewer = aViewer;
00183 
00184   mDocument = nsnull;
00185   if (mContentViewer) {
00186     nsCOMPtr<nsIDOMDocument> domDoc;
00187     mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
00188     // Store observed document in strong pointer in case it is removed from
00189     // the contentviewer
00190     mDocument = do_QueryInterface(domDoc);
00191     if (mDocument) {
00192       mDocument->AddObserver(this);
00193     }
00194   }
00195 
00196   return NS_OK;
00197 }
00198 
00199 NS_IMETHODIMP
00200 nsSHEntry::GetContentViewer(nsIContentViewer **aResult)
00201 {
00202   *aResult = mContentViewer;
00203   NS_IF_ADDREF(*aResult);
00204   return NS_OK;
00205 }
00206 
00207 NS_IMETHODIMP
00208 nsSHEntry::GetAnyContentViewer(nsISHEntry **aOwnerEntry,
00209                                nsIContentViewer **aResult)
00210 {
00211   // Find a content viewer in the root node or any of its children,
00212   // assuming that there is only one content viewer total in any one
00213   // nsSHEntry tree
00214   GetContentViewer(aResult);
00215   if (*aResult) {
00216 #ifdef DEBUG_PAGE_CACHE 
00217     printf("Found content viewer\n");
00218 #endif
00219     *aOwnerEntry = this;
00220     NS_ADDREF(*aOwnerEntry);
00221     return NS_OK;
00222   }
00223   // The root SHEntry doesn't have a ContentViewer, so check child nodes
00224   for (PRInt32 i = 0; i < mChildren.Count(); i++) {
00225     nsISHEntry* child = mChildren[i];
00226     if (child) {
00227 #ifdef DEBUG_PAGE_CACHE
00228       printf("Evaluating SHEntry child %d\n", i);
00229 #endif
00230       child->GetAnyContentViewer(aOwnerEntry, aResult);
00231       if (*aResult) {
00232         return NS_OK;
00233       }
00234     }
00235   }
00236   return NS_OK;
00237 }
00238 
00239 NS_IMETHODIMP
00240 nsSHEntry::SetSticky(PRBool aSticky)
00241 {
00242   mSticky = aSticky;
00243   return NS_OK;
00244 }
00245 
00246 NS_IMETHODIMP
00247 nsSHEntry::GetSticky(PRBool *aSticky)
00248 {
00249   *aSticky = mSticky;
00250   return NS_OK;
00251 }
00252 
00253 NS_IMETHODIMP nsSHEntry::GetTitle(PRUnichar** aTitle)
00254 {
00255   // Check for empty title...
00256   if (mTitle.IsEmpty() && mURI) {
00257     // Default title is the URL.
00258     nsCAutoString spec;
00259     if (NS_SUCCEEDED(mURI->GetSpec(spec)))
00260       AppendUTF8toUTF16(spec, mTitle);
00261   }
00262 
00263   *aTitle = ToNewUnicode(mTitle);
00264   return NS_OK;
00265 }
00266 
00267 NS_IMETHODIMP nsSHEntry::SetTitle(const nsAString &aTitle)
00268 {
00269   mTitle = aTitle;
00270   return NS_OK;
00271 }
00272 
00273 NS_IMETHODIMP nsSHEntry::GetPostData(nsIInputStream** aResult)
00274 {
00275   *aResult = mPostData;
00276   NS_IF_ADDREF(*aResult);
00277   return NS_OK;
00278 }
00279 
00280 NS_IMETHODIMP nsSHEntry::SetPostData(nsIInputStream* aPostData)
00281 {
00282   mPostData = aPostData;
00283   return NS_OK;
00284 }
00285 
00286 NS_IMETHODIMP nsSHEntry::GetLayoutHistoryState(nsILayoutHistoryState** aResult)
00287 {
00288   *aResult = mLayoutHistoryState;
00289   NS_IF_ADDREF(*aResult);
00290   return NS_OK;
00291 }
00292 
00293 NS_IMETHODIMP nsSHEntry::SetLayoutHistoryState(nsILayoutHistoryState* aState)
00294 {
00295   NS_ENSURE_STATE(mSaveLayoutState || !aState);
00296   mLayoutHistoryState = aState;
00297   return NS_OK;
00298 }
00299 
00300 NS_IMETHODIMP nsSHEntry::GetLoadType(PRUint32 * aResult)
00301 {
00302   *aResult = mLoadType;
00303   return NS_OK;
00304 }
00305 
00306 NS_IMETHODIMP nsSHEntry::SetLoadType(PRUint32  aLoadType)
00307 {
00308   mLoadType = aLoadType;
00309   return NS_OK;
00310 }
00311 
00312 NS_IMETHODIMP nsSHEntry::GetID(PRUint32 * aResult)
00313 {
00314   *aResult = mID;
00315   return NS_OK;
00316 }
00317 
00318 NS_IMETHODIMP nsSHEntry::SetID(PRUint32  aID)
00319 {
00320   mID = aID;
00321   return NS_OK;
00322 }
00323 
00324 NS_IMETHODIMP nsSHEntry::GetPageIdentifier(PRUint32 * aResult)
00325 {
00326   *aResult = mPageIdentifier;
00327   return NS_OK;
00328 }
00329 
00330 NS_IMETHODIMP nsSHEntry::SetPageIdentifier(PRUint32 aPageIdentifier)
00331 {
00332   mPageIdentifier = aPageIdentifier;
00333   return NS_OK;
00334 }
00335 
00336 NS_IMETHODIMP nsSHEntry::GetIsSubFrame(PRBool * aFlag)
00337 {
00338   *aFlag = mIsFrameNavigation;
00339   return NS_OK;
00340 }
00341 
00342 NS_IMETHODIMP nsSHEntry::SetIsSubFrame(PRBool  aFlag)
00343 {
00344   mIsFrameNavigation = aFlag;
00345   return NS_OK;
00346 }
00347 
00348 NS_IMETHODIMP nsSHEntry::GetCacheKey(nsISupports** aResult)
00349 {
00350   *aResult = mCacheKey;
00351   NS_IF_ADDREF(*aResult);
00352   return NS_OK;
00353 }
00354 
00355 NS_IMETHODIMP nsSHEntry::SetCacheKey(nsISupports* aCacheKey)
00356 {
00357   mCacheKey = aCacheKey;
00358   return NS_OK;
00359 }
00360 
00361 NS_IMETHODIMP nsSHEntry::GetSaveLayoutStateFlag(PRBool * aFlag)
00362 {
00363   *aFlag = mSaveLayoutState;
00364   return NS_OK;
00365 }
00366 
00367 NS_IMETHODIMP nsSHEntry::SetSaveLayoutStateFlag(PRBool  aFlag)
00368 {
00369   mSaveLayoutState = aFlag;
00370 
00371   // if we are not allowed to hold layout history state, then make sure
00372   // that we are not holding it!
00373   if (!mSaveLayoutState)
00374     mLayoutHistoryState = nsnull;
00375 
00376   return NS_OK;
00377 }
00378 
00379 NS_IMETHODIMP nsSHEntry::GetExpirationStatus(PRBool * aFlag)
00380 {
00381   *aFlag = mExpired;
00382   return NS_OK;
00383 }
00384 
00385 NS_IMETHODIMP nsSHEntry::SetExpirationStatus(PRBool  aFlag)
00386 {
00387   mExpired = aFlag;
00388   return NS_OK;
00389 }
00390 
00391 NS_IMETHODIMP nsSHEntry::GetContentType(nsACString& aContentType)
00392 {
00393   aContentType = mContentType;
00394   return NS_OK;
00395 }
00396 
00397 NS_IMETHODIMP nsSHEntry::SetContentType(const nsACString& aContentType)
00398 {
00399   mContentType = aContentType;
00400   return NS_OK;
00401 }
00402 
00403 NS_IMETHODIMP
00404 nsSHEntry::Create(nsIURI * aURI, const nsAString &aTitle,
00405                   nsIInputStream * aInputStream,
00406                   nsILayoutHistoryState * aLayoutHistoryState,
00407                   nsISupports * aCacheKey, const nsACString& aContentType)
00408 {
00409   return Create_MOZILLA_1_8_BRANCH(aURI, aTitle, aInputStream,
00410                                    aLayoutHistoryState, aCacheKey,
00411                                    aContentType, nsnull);
00412 }
00413 
00414 NS_IMETHODIMP
00415 nsSHEntry::Create_MOZILLA_1_8_BRANCH(nsIURI * aURI, const nsAString &aTitle,
00416                                      nsIInputStream * aInputStream,
00417                                      nsILayoutHistoryState * aLayoutHistoryState,
00418                                      nsISupports * aCacheKey,
00419                                      const nsACString& aContentType,
00420                                      nsISupports* aOwner)
00421 {
00422   mURI = aURI;
00423   mTitle = aTitle;
00424   mPostData = aInputStream;
00425   mCacheKey = aCacheKey;
00426   mContentType = aContentType;
00427   mOwner = aOwner;
00428     
00429   // Set the LoadType by default to loadHistory during creation
00430   mLoadType = (PRUint32) nsIDocShellLoadInfo::loadHistory;
00431 
00432   // By default all entries are set false for subframe flag. 
00433   // nsDocShell::CloneAndReplace() which creates entries for
00434   // all subframe navigations, sets the flag to true.
00435   mIsFrameNavigation = PR_FALSE;
00436 
00437   // By default we save LayoutHistoryState
00438   mSaveLayoutState = PR_TRUE;
00439   mLayoutHistoryState = aLayoutHistoryState;
00440 
00441   //By default the page is not expired
00442   mExpired = PR_FALSE;
00443 
00444   return NS_OK;
00445 }
00446 
00447 NS_IMETHODIMP
00448 nsSHEntry::Clone(nsISHEntry ** aResult)
00449 {
00450   *aResult = new nsSHEntry(*this);
00451   if (!*aResult)
00452     return NS_ERROR_OUT_OF_MEMORY;
00453   NS_ADDREF(*aResult);
00454   return NS_OK;
00455 }
00456 
00457 NS_IMETHODIMP
00458 nsSHEntry::GetParent(nsISHEntry ** aResult)
00459 {
00460   NS_ENSURE_ARG_POINTER(aResult);
00461   *aResult = mParent;
00462   NS_IF_ADDREF(*aResult);
00463   return NS_OK;
00464 }
00465 
00466 NS_IMETHODIMP
00467 nsSHEntry::SetParent(nsISHEntry * aParent)
00468 {
00469   /* parent not Addrefed on purpose to avoid cyclic reference
00470    * Null parent is OK
00471    *
00472    * XXX this method should not be scriptable if this is the case!!
00473    */
00474   mParent = aParent;
00475   return NS_OK;
00476 }
00477 
00478 NS_IMETHODIMP
00479 nsSHEntry::SetWindowState(nsISupports *aState)
00480 {
00481   mWindowState = aState;
00482   return NS_OK;
00483 }
00484 
00485 NS_IMETHODIMP
00486 nsSHEntry::GetWindowState(nsISupports **aState)
00487 {
00488   NS_IF_ADDREF(*aState = mWindowState);
00489   return NS_OK;
00490 }
00491 
00492 NS_IMETHODIMP
00493 nsSHEntry::SetViewerBounds(const nsRect &aBounds)
00494 {
00495   mViewerBounds = aBounds;
00496   return NS_OK;
00497 }
00498 
00499 NS_IMETHODIMP
00500 nsSHEntry::GetViewerBounds(nsRect &aBounds)
00501 {
00502   aBounds = mViewerBounds;
00503   return NS_OK;
00504 }
00505 
00506 NS_IMETHODIMP
00507 nsSHEntry::GetOwner(nsISupports **aOwner)
00508 {
00509   NS_IF_ADDREF(*aOwner = mOwner);
00510   return NS_OK;
00511 }
00512 
00513 NS_IMETHODIMP
00514 nsSHEntry::GetOwnerURI(nsIURI **aOwnerURI)
00515 {
00516   nsCOMPtr<nsIPrincipal> prin(do_QueryInterface(mOwner));
00517   if (prin) {
00518     // Make sure not to hand out a ref to the principal's URI
00519     nsCOMPtr<nsIURI> uri;
00520     prin->GetURI(getter_AddRefs(uri));
00521     if (uri) {
00522       return uri->Clone(aOwnerURI);
00523     }
00524   }
00525 
00526   *aOwnerURI = nsnull;
00527   return NS_OK;
00528 }
00529 
00530 NS_IMETHODIMP
00531 nsSHEntry::SetOwnerURI(nsIURI *aOwnerURI)
00532 {
00533   nsCOMPtr<nsIScriptSecurityManager> secMan =
00534     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
00535   if (secMan && aOwnerURI) {
00536     nsCOMPtr<nsIPrincipal> prin;
00537     nsresult rv =
00538       secMan->GetCodebasePrincipal(aOwnerURI, getter_AddRefs(prin));
00539     NS_ENSURE_SUCCESS(rv, rv);
00540 
00541     mOwner = prin;
00542   }
00543 
00544   return NS_OK;
00545 }
00546 
00547 //*****************************************************************************
00548 //    nsSHEntry: nsISHContainer
00549 //*****************************************************************************
00550 
00551 NS_IMETHODIMP 
00552 nsSHEntry::GetChildCount(PRInt32 * aCount)
00553 {
00554   *aCount = mChildren.Count();
00555   return NS_OK;
00556 }
00557 
00558 NS_IMETHODIMP
00559 nsSHEntry::AddChild(nsISHEntry * aChild, PRInt32 aOffset)
00560 {
00561   NS_ENSURE_TRUE(aChild, NS_ERROR_FAILURE);
00562 
00563   NS_ENSURE_SUCCESS(aChild->SetParent(this), NS_ERROR_FAILURE);
00564 
00565   //
00566   // Bug 52670: Ensure children are added in order.
00567   //
00568   //  Later frames in the child list may load faster and get appended
00569   //  before earlier frames, causing session history to be scrambled.
00570   //  By growing the list here, they are added to the right position.
00571   //
00572   //  Assert that aOffset will not be so high as to grow us a lot.
00573   //
00574   NS_ASSERTION(aOffset < (mChildren.Count()+1023), "Large frames array!\n");
00575 
00576   if (aOffset < mChildren.Count()) {
00577     nsISHEntry* oldChild = mChildren.ObjectAt(aOffset);
00578     if (oldChild && oldChild != aChild) {
00579       NS_ERROR("Adding child where we already have a child?  "
00580                "This will likely misbehave");
00581       oldChild->SetParent(nsnull);
00582     }
00583   }
00584   
00585   // This implicitly extends the array to include aOffset
00586   mChildren.ReplaceObjectAt(aChild, aOffset);
00587 
00588   return NS_OK;
00589 }
00590 
00591 NS_IMETHODIMP
00592 nsSHEntry::RemoveChild(nsISHEntry * aChild)
00593 {
00594   NS_ENSURE_TRUE(aChild, NS_ERROR_FAILURE);
00595   PRBool childRemoved = mChildren.RemoveObject(aChild);
00596   if (childRemoved)
00597     aChild->SetParent(nsnull);
00598   return NS_OK;
00599 }
00600 
00601 NS_IMETHODIMP
00602 nsSHEntry::GetChildAt(PRInt32 aIndex, nsISHEntry ** aResult)
00603 {
00604   if (aIndex >= 0 && aIndex < mChildren.Count()) {
00605     *aResult = mChildren[aIndex];
00606     // yes, mChildren can have holes in it.  AddChild's offset parameter makes
00607     // that possible.
00608     NS_IF_ADDREF(*aResult);
00609   } else {
00610     *aResult = nsnull;
00611   }
00612   return NS_OK;
00613 }
00614 
00615 NS_IMETHODIMP
00616 nsSHEntry::AddChildShell(nsIDocShellTreeItem *aShell)
00617 {
00618   NS_ASSERTION(aShell, "Null child shell added to history entry");
00619   mChildShells.AppendObject(aShell);
00620   return NS_OK;
00621 }
00622 
00623 NS_IMETHODIMP
00624 nsSHEntry::ChildShellAt(PRInt32 aIndex, nsIDocShellTreeItem **aShell)
00625 {
00626   NS_IF_ADDREF(*aShell = mChildShells.SafeObjectAt(aIndex));
00627   return NS_OK;
00628 }
00629 
00630 NS_IMETHODIMP
00631 nsSHEntry::ClearChildShells()
00632 {
00633   mChildShells.Clear();
00634   return NS_OK;
00635 }
00636 
00637 NS_IMETHODIMP
00638 nsSHEntry::GetRefreshURIList(nsISupportsArray **aList)
00639 {
00640   NS_IF_ADDREF(*aList = mRefreshURIList);
00641   return NS_OK;
00642 }
00643 
00644 NS_IMETHODIMP
00645 nsSHEntry::SetRefreshURIList(nsISupportsArray *aList)
00646 {
00647   mRefreshURIList = aList;
00648   return NS_OK;
00649 }
00650 
00651 NS_IMETHODIMP
00652 nsSHEntry::SyncPresentationState()
00653 {
00654   if (mContentViewer && mWindowState) {
00655     // If we have a content viewer and a window state, we should be ok.
00656     return NS_OK;
00657   }
00658 
00659   DropPresentationState();
00660 
00661   return NS_OK;
00662 }
00663 
00664 void
00665 nsSHEntry::DropPresentationState()
00666 {
00667   nsRefPtr<nsSHEntry> kungFuDeathGrip = this;
00668 
00669   RemoveDocumentObserver();
00670   if (mContentViewer)
00671     mContentViewer->ClearHistoryEntry();
00672 
00673   mContentViewer = nsnull;
00674   mDocument = nsnull;
00675   mSticky = PR_TRUE;
00676   mWindowState = nsnull;
00677   mViewerBounds.SetRect(0, 0, 0, 0);
00678   mChildShells.Clear();
00679   mRefreshURIList = nsnull;
00680 }
00681 
00682 void
00683 nsSHEntry::RemoveDocumentObserver()
00684 {
00685   if (mDocument) {
00686     mDocument->RemoveObserver(this);
00687     mDocument = nsnull;
00688   }
00689 }
00690 
00691 //*****************************************************************************
00692 //    nsSHEntry: nsIDocumentObserver
00693 //*****************************************************************************
00694 
00695 NS_IMPL_NSIDOCUMENTOBSERVER_CORE_STUB(nsSHEntry)
00696 NS_IMPL_NSIDOCUMENTOBSERVER_LOAD_STUB(nsSHEntry)
00697 NS_IMPL_NSIDOCUMENTOBSERVER_REFLOW_STUB(nsSHEntry)
00698 NS_IMPL_NSIDOCUMENTOBSERVER_STATE_STUB(nsSHEntry)
00699 NS_IMPL_NSIDOCUMENTOBSERVER_STYLE_STUB(nsSHEntry)
00700 
00701 void
00702 nsSHEntry::CharacterDataChanged(nsIDocument* aDocument,
00703                                 nsIContent* aContent,
00704                                 PRBool aAppend)
00705 {
00706   DocumentMutated();
00707 }
00708 
00709 void
00710 nsSHEntry::AttributeChanged(nsIDocument* aDocument,
00711                             nsIContent* aContent,
00712                             PRInt32 aNameSpaceID,
00713                             nsIAtom* aAttribute,
00714                             PRInt32 aModType)
00715 {
00716   DocumentMutated();
00717 }
00718 
00719 void
00720 nsSHEntry::ContentAppended(nsIDocument* aDocument,
00721                         nsIContent* aContainer,
00722                         PRInt32 aNewIndexInContainer)
00723 {
00724   DocumentMutated();
00725 }
00726 
00727 void
00728 nsSHEntry::ContentInserted(nsIDocument* aDocument,
00729                            nsIContent* aContainer,
00730                            nsIContent* aChild,
00731                            PRInt32 aIndexInContainer)
00732 {
00733   DocumentMutated();
00734 }
00735 
00736 void
00737 nsSHEntry::ContentRemoved(nsIDocument* aDocument,
00738                           nsIContent* aContainer,
00739                           nsIContent* aChild,
00740                           PRInt32 aIndexInContainer)
00741 {
00742   DocumentMutated();
00743 }
00744 
00745 class DestroyViewerEvent : public PLEvent
00746 {
00747 public:
00748   DestroyViewerEvent(nsIContentViewer* aViewer, nsIDocument* aDocument);
00749 
00750   nsCOMPtr<nsIContentViewer> mViewer;
00751   nsCOMPtr<nsIDocument> mDocument;
00752 };
00753 
00754 PR_STATIC_CALLBACK(void*)
00755 HandleDestroyViewerEvent(PLEvent *aEvent)
00756 {
00757   nsIContentViewer* viewer = NS_STATIC_CAST(DestroyViewerEvent*, aEvent)->mViewer;
00758   if (viewer) {
00759     viewer->Destroy();
00760   }
00761 
00762   return nsnull;
00763 }
00764 
00765 PR_STATIC_CALLBACK(void)
00766 DestroyDestroyViewerEvent(PLEvent *aEvent)
00767 {
00768     delete NS_STATIC_CAST(DestroyViewerEvent*, aEvent);
00769 }
00770 
00771 DestroyViewerEvent::DestroyViewerEvent(nsIContentViewer* aViewer,
00772                                        nsIDocument* aDocument)
00773     : mViewer(aViewer),
00774       mDocument(aDocument)
00775 {
00776     PL_InitEvent(this, mViewer, ::HandleDestroyViewerEvent,
00777                  ::DestroyDestroyViewerEvent);
00778 }
00779 
00780 void
00781 nsSHEntry::DocumentMutated()
00782 {
00783   NS_ASSERTION(mContentViewer && mDocument,
00784                "we shouldn't still be observing the doc");
00785 
00786   // Release the reference to the contentviewer asynconously so that the
00787   // document doesn't get nuked mid-mutation.
00788   nsCOMPtr<nsIEventQueue> uiThreadQueue;
00789   NS_GetMainEventQ(getter_AddRefs(uiThreadQueue));
00790   if (!uiThreadQueue) {
00791     return;
00792   }
00793 
00794   PLEvent *evt = new DestroyViewerEvent(mContentViewer, mDocument);
00795   if (!evt) {
00796     return;
00797   }
00798 
00799   nsresult rv = uiThreadQueue->PostEvent(evt);
00800   if (NS_FAILED(rv)) {
00801     PL_DestroyEvent(evt);
00802   }
00803   else {
00804     // Drop presentation. Also ensures that we don't post more then one
00805     // PLEvent. Only do this if we succeeded in posting the event since
00806     // otherwise the document could be torn down mid mutation causing crashes.
00807     DropPresentationState();
00808   }
00809   // Warning! The call to DropPresentationState could have dropped the last
00810   // reference to this nsSHEntry, so no accessing members beyond here.
00811 }