author | Scott Johnson <sjohnson@mozilla.com> |
Mon, 03 Oct 2011 13:39:05 -0700 | |
changeset 79367 | 49d997bcdc608efa649731d93198624bfe62df0c |
parent 79366 | 5b4dd36b1f78f45308d5002a20192f238e2f8cf0 |
child 79368 | 7a32a21af687c0d22e2f37b4e38c64c98a3152cb |
push id | 434 |
push user | clegnitto@mozilla.com |
push date | Wed, 21 Dec 2011 12:10:54 +0000 |
treeherder | mozilla-beta@bddb6ed8dd47 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | roc |
bugs | 666446 |
milestone | 10.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
new file mode 100644 --- /dev/null +++ b/layout/xul/base/src/tree/src/nsITreeImageListener.h @@ -0,0 +1,64 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dave Hyatt <hyatt@mozilla.org> (Original Author) + * Jan Varga <varga@ku.sk> + * Scott Johnson <sjohnson@mozilla.com>, Mozilla Corporation + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsITreeImageListener_h__ +#define nsITreeImageListener_h__ + +// The interface for our image listener. +// {90586540-2D50-403e-8DCE-981CAA778444} +#define NS_ITREEIMAGELISTENER_IID \ +{ 0x90586540, 0x2d50, 0x403e, { 0x8d, 0xce, 0x98, 0x1c, 0xaa, 0x77, 0x84, 0x44 } } + +class nsITreeImageListener : public nsISupports +{ +public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_ITREEIMAGELISTENER_IID) + + NS_IMETHOD AddCell(PRInt32 aIndex, nsITreeColumn* aCol) = 0; + + /** + * Clear the internal frame pointer to prevent dereferencing an object + * that no longer exists. + */ + NS_IMETHOD ClearFrame() = 0; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(nsITreeImageListener, NS_ITREEIMAGELISTENER_IID) + +#endif
--- a/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp +++ b/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp @@ -49,16 +49,17 @@ #include "nsCOMPtr.h" #include "nsISupportsArray.h" #include "nsPresContext.h" #include "nsINameSpaceManager.h" #include "nsTreeBodyFrame.h" #include "nsTreeSelection.h" +#include "nsTreeImageListener.h" #include "nsGkAtoms.h" #include "nsCSSAnonBoxes.h" #include "nsIContent.h" #include "nsStyleContext.h" #include "nsIBoxObject.h" #include "nsGUIEvent.h" @@ -109,16 +110,24 @@ using namespace mozilla; // Enumeration function that cancels all the image requests in our cache static PLDHashOperator CancelImageRequest(const nsAString& aKey, nsTreeImageCacheEntry aEntry, void* aData) { + + // If our imgIRequest object was registered with the refresh driver, + // then we need to deregister it. + nsTreeBodyFrame* frame = static_cast<nsTreeBodyFrame*>(aData); + + nsLayoutUtils::DeregisterImageRequest(frame->PresContext(), aEntry.request, + nsnull); + aEntry.request->CancelAndForgetObserver(NS_BINDING_ABORTED); return PL_DHASH_NEXT; } // // NS_NewTreeFrame // // Creates a new tree frame @@ -159,17 +168,18 @@ nsTreeBodyFrame::nsTreeBodyFrame(nsIPres { mColumns = new nsTreeColumns(nsnull); NS_NewISupportsArray(getter_AddRefs(mScratchArray)); } // Destructor nsTreeBodyFrame::~nsTreeBodyFrame() { - mImageCache.EnumerateRead(CancelImageRequest, nsnull); + mImageCache.EnumerateRead(CancelImageRequest, this); + DetachImageListeners(); delete mSlots; } static void GetBorderPadding(nsStyleContext* aContext, nsMargin& aMargin) { aMargin.SizeTo(0, 0, 0, 0); if (!aContext->GetStylePadding()->GetPadding(aMargin)) { @@ -192,18 +202,21 @@ nsTreeBodyFrame::Init(nsIContent* aC nsIFrame* aPrevInFlow) { nsresult rv = nsLeafBoxFrame::Init(aContent, aParent, aPrevInFlow); NS_ENSURE_SUCCESS(rv, rv); mIndentation = GetIndentation(); mRowHeight = GetRowHeight(); + NS_ENSURE_TRUE(mCreatedListeners.Init(), NS_ERROR_OUT_OF_MEMORY); + NS_ENSURE_TRUE(mImageCache.Init(16), NS_ERROR_OUT_OF_MEMORY); EnsureBoxObject(); + return rv; } nsSize nsTreeBodyFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState) { EnsureView(); @@ -2149,20 +2162,24 @@ nsTreeBodyFrame::GetImage(PRInt32 aRowIn listener->AddCell(aRowIndex, aCol); return NS_OK; } } if (!*aResult) { // Create a new nsTreeImageListener object and pass it our row and column // information. - nsTreeImageListener* listener = new nsTreeImageListener(mTreeBoxObject); + nsTreeImageListener* listener = new nsTreeImageListener(this); if (!listener) return NS_ERROR_OUT_OF_MEMORY; + if (!mCreatedListeners.PutEntry(listener)) { + return NS_ERROR_FAILURE; + } + listener->AddCell(aRowIndex, aCol); nsCOMPtr<imgIDecoderObserver> imgDecoderObserver = listener; nsCOMPtr<imgIRequest> imageRequest; if (styleRequest) { styleRequest->Clone(imgDecoderObserver, getter_AddRefs(imageRequest)); } else { nsIDocument* doc = mContent->GetDocument(); @@ -4231,17 +4248,17 @@ nsTreeBodyFrame::GetBaseElement() return nsnull; } nsresult nsTreeBodyFrame::ClearStyleAndImageCaches() { mStyleCache.Clear(); - mImageCache.EnumerateRead(CancelImageRequest, nsnull); + mImageCache.EnumerateRead(CancelImageRequest, this); mImageCache.Clear(); return NS_OK; } /* virtual */ void nsTreeBodyFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) { nsLeafBoxFrame::DidSetStyleContext(aOldStyleContext); @@ -4463,16 +4480,30 @@ nsTreeBodyFrame::PostScrollEvent() nsRefPtr<ScrollEvent> ev = new ScrollEvent(this); if (NS_FAILED(NS_DispatchToCurrentThread(ev))) { NS_WARNING("failed to dispatch ScrollEvent"); } else { mScrollEvent = ev; } } +void +nsTreeBodyFrame::DetachImageListeners() +{ + mCreatedListeners.Clear(); +} + +void +nsTreeBodyFrame::RemoveTreeImageListener(nsTreeImageListener* aListener) +{ + if (aListener) { + mCreatedListeners.RemoveEntry(aListener); + } +} + #ifdef ACCESSIBILITY void nsTreeBodyFrame::FireRowCountChangedEvent(PRInt32 aIndex, PRInt32 aCount) { nsCOMPtr<nsIContent> content(GetBaseElement()); if (!content) return; @@ -4636,8 +4667,24 @@ nsTreeBodyFrame::FullScrollbarsUpdate(bo if (aNeedsFullInvalidation) { Invalidate(); } InvalidateScrollbars(parts, weakColumnsFrame); NS_ENSURE_TRUE(weakFrame.IsAlive(), PR_FALSE); nsContentUtils::AddScriptRunner(new nsOverflowChecker(this)); return weakFrame.IsAlive(); } + +nsresult +nsTreeBodyFrame::OnStartDecode(imgIRequest* aRequest) +{ + nsLayoutUtils::RegisterImageRequest(PresContext(), aRequest, nsnull); + return NS_OK; +} + +nsresult +nsTreeBodyFrame::OnStopDecode(imgIRequest* aRequest, nsresult aStatus, + const PRUnichar* aStatusArg) +{ + nsLayoutUtils::DeregisterImageRequestIfNotAnimated(PresContext(), aRequest, + nsnull); + return NS_OK; +}
--- a/layout/xul/base/src/tree/src/nsTreeBodyFrame.h +++ b/layout/xul/base/src/tree/src/nsTreeBodyFrame.h @@ -49,26 +49,27 @@ #include "nsICSSPseudoComparator.h" #include "nsIScrollbarMediator.h" #include "nsIDragSession.h" #include "nsITimer.h" #include "nsIReflowCallback.h" #include "nsTArray.h" #include "nsTreeStyleCache.h" #include "nsTreeColumns.h" -#include "nsTreeImageListener.h" #include "nsAutoPtr.h" #include "nsDataHashtable.h" #include "imgIRequest.h" #include "imgIDecoderObserver.h" #include "nsScrollbarFrame.h" #include "nsThreadUtils.h" #include "mozilla/LookAndFeel.h" +#include "nsITreeImageListener.h" class nsOverflowChecker; +class nsTreeImageListener; // An entry in the tree's image cache struct nsTreeImageCacheEntry { nsTreeImageCacheEntry() {} nsTreeImageCacheEntry(imgIRequest *aRequest, imgIDecoderObserver *aListener) : request(aRequest), listener(aListener) {} @@ -86,16 +87,23 @@ class NS_FINAL_CLASS nsTreeBodyFrame public: nsTreeBodyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); ~nsTreeBodyFrame(); NS_DECL_QUERYFRAME_TARGET(nsTreeBodyFrame) NS_DECL_QUERYFRAME NS_DECL_FRAMEARENA_HELPERS + // Callback handler methods for refresh driver based animations. + // Calls to these functions are forwarded from nsTreeImageListener. These + // mirror how nsImageFrame works. + nsresult OnStartDecode(imgIRequest* aRequest); + nsresult OnStopDecode(imgIRequest* aRequest, nsresult aStatus, + const PRUnichar* aStatusArg); + // non-virtual signatures like nsITreeBodyFrame nsresult GetColumns(nsITreeColumns **aColumns); nsresult GetView(nsITreeView **aView); nsresult SetView(nsITreeView *aView); nsresult GetFocused(bool *aFocused); nsresult SetFocused(bool aFocused); nsresult GetTreeBody(nsIDOMElement **aElement); nsresult GetRowHeight(PRInt32 *aValue); @@ -430,16 +438,25 @@ public: if (!aUnknownCol) return nsnull; nsTreeColumn* col; aUnknownCol->QueryInterface(NS_GET_IID(nsTreeColumn), (void**)&col); return col; } + /** + * Remove an nsITreeImageListener from being tracked by this frame. Only tree + * image listeners that are created by this frame are tracked. + * + * @param aListener A pointer to an nsTreeImageListener to no longer + * track. + */ + void RemoveTreeImageListener(nsTreeImageListener* aListener); + protected: // Create a new timer. This method is used to delay various actions like // opening/closing folders or tree scrolling. // aID is type of the action, aFunc is the function to be called when // the timer fires and aType is type of timer - one shot or repeating. nsresult CreateTimer(const mozilla::LookAndFeel::IntID aID, nsTimerCallbackFunc aFunc, PRInt32 aType, @@ -460,16 +477,22 @@ protected: void Revoke() { mInner = nsnull; } private: nsTreeBodyFrame* mInner; }; void PostScrollEvent(); void FireScrollEvent(); + /** + * Clear the pointer to this frame for all nsTreeImageListeners that were + * created by this frame. + */ + void DetachImageListeners(); + #ifdef ACCESSIBILITY /** * Fires 'treeRowCountChanged' event asynchronously. The event supports * nsIDOMDataContainerEvent interface that is used to expose the following * information structures. * * @param aIndex the row index rows are added/removed from * @param aCount the number of added/removed rows (the sign points to @@ -597,11 +620,16 @@ protected: // Data Members // Do we have a fixed number of onscreen rows? bool mHasFixedRowCount; bool mVerticalOverflow; bool mHorizontalOverflow; bool mReflowCallbackPosted; + + // Hash table to keep track of which listeners we created and thus + // have pointers to us. + nsTHashtable<nsPtrHashKey<nsTreeImageListener> > mCreatedListeners; + }; // class nsTreeBodyFrame #endif
--- a/layout/xul/base/src/tree/src/nsTreeImageListener.cpp +++ b/layout/xul/base/src/tree/src/nsTreeImageListener.cpp @@ -39,28 +39,51 @@ #include "nsTreeImageListener.h" #include "nsITreeBoxObject.h" #include "imgIRequest.h" #include "imgIContainer.h" NS_IMPL_ISUPPORTS3(nsTreeImageListener, imgIDecoderObserver, imgIContainerObserver, nsITreeImageListener) -nsTreeImageListener::nsTreeImageListener(nsITreeBoxObject* aTree) - : mTree(aTree), +nsTreeImageListener::nsTreeImageListener(nsTreeBodyFrame* aTreeFrame) + : mTreeFrame(aTreeFrame), mInvalidationSuppressed(PR_TRUE), mInvalidationArea(nsnull) { } nsTreeImageListener::~nsTreeImageListener() { delete mInvalidationArea; } +NS_IMETHODIMP +nsTreeImageListener::OnStartDecode(imgIRequest *aRequest) +{ + if (!mTreeFrame) { + return NS_OK; + } + + // grab the frame we want to use + return mTreeFrame->OnStartDecode(aRequest); +} + +NS_IMETHODIMP +nsTreeImageListener::OnStopDecode(imgIRequest *aRequest, + nsresult aStatus, + const PRUnichar *aStatusArg) +{ + if (!mTreeFrame) { + return NS_OK; + } + + return mTreeFrame->OnStopDecode(aRequest, aStatus, aStatusArg); +} + NS_IMETHODIMP nsTreeImageListener::OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage) { // Ensure the animation (if any) is started. Note: There is no // corresponding call to Decrement for this. This Increment will be // 'cleaned up' by the Request when it is destroyed, but only then. aRequest->IncrementAnimationConsumers(); return NS_OK; @@ -108,20 +131,26 @@ nsTreeImageListener::AddCell(PRInt32 aIn return NS_OK; } void nsTreeImageListener::Invalidate() { if (!mInvalidationSuppressed) { - for (InvalidationArea* currArea = mInvalidationArea; currArea; currArea = currArea->GetNext()) { + for (InvalidationArea* currArea = mInvalidationArea; currArea; + currArea = currArea->GetNext()) { // Loop from min to max, invalidating each cell that was listening for this image. for (PRInt32 i = currArea->GetMin(); i <= currArea->GetMax(); ++i) { - mTree->InvalidateCell(i, currArea->GetCol()); + if (mTreeFrame) { + nsITreeBoxObject* tree = mTreeFrame->GetTreeBoxObject(); + if (tree) { + tree->InvalidateCell(i, currArea->GetCol()); + } + } } } } } nsTreeImageListener::InvalidationArea::InvalidationArea(nsITreeColumn* aCol) : mCol(aCol), mMin(-1), // min should start out "undefined" @@ -135,8 +164,15 @@ nsTreeImageListener::InvalidationArea::A { if (mMin == -1) mMin = mMax = aIndex; else if (aIndex < mMin) mMin = aIndex; else if (aIndex > mMax) mMax = aIndex; } + +NS_IMETHODIMP +nsTreeImageListener::ClearFrame() +{ + mTreeFrame = nsnull; + return NS_OK; +}
--- a/layout/xul/base/src/tree/src/nsTreeImageListener.h +++ b/layout/xul/base/src/tree/src/nsTreeImageListener.h @@ -39,60 +39,50 @@ #ifndef nsTreeImageListener_h__ #define nsTreeImageListener_h__ #include "nsString.h" #include "nsCOMPtr.h" #include "nsITreeColumns.h" #include "nsStubImageDecoderObserver.h" - -class nsITreeBoxObject; - -// The interface for our image listener. -// {90586540-2D50-403e-8DCE-981CAA778444} -#define NS_ITREEIMAGELISTENER_IID \ -{ 0x90586540, 0x2d50, 0x403e, { 0x8d, 0xce, 0x98, 0x1c, 0xaa, 0x77, 0x84, 0x44 } } - -class nsITreeImageListener : public nsISupports -{ -public: - NS_DECLARE_STATIC_IID_ACCESSOR(NS_ITREEIMAGELISTENER_IID) - - NS_IMETHOD AddCell(PRInt32 aIndex, nsITreeColumn* aCol) = 0; -}; - -NS_DEFINE_STATIC_IID_ACCESSOR(nsITreeImageListener, NS_ITREEIMAGELISTENER_IID) +#include "nsTreeBodyFrame.h" +#include "nsITreeImageListener.h" // This class handles image load observation. class nsTreeImageListener : public nsStubImageDecoderObserver, public nsITreeImageListener { public: - nsTreeImageListener(nsITreeBoxObject* aTree); + nsTreeImageListener(nsTreeBodyFrame *aTreeFrame); ~nsTreeImageListener(); NS_DECL_ISUPPORTS // imgIDecoderObserver (override nsStubImageDecoderObserver) + NS_IMETHOD OnStartDecode(imgIRequest *aRequest); + NS_IMETHOD OnStopDecode(imgIRequest *aRequest, + nsresult aStatus, const PRUnichar *aStatusArg); NS_IMETHOD OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage); NS_IMETHOD OnDataAvailable(imgIRequest *aRequest, bool aCurrentFrame, const nsIntRect *aRect); // imgIContainerObserver (override nsStubImageDecoderObserver) NS_IMETHOD FrameChanged(imgIContainer *aContainer, const nsIntRect *aDirtyRect); NS_IMETHOD AddCell(PRInt32 aIndex, nsITreeColumn* aCol); + + NS_IMETHOD ClearFrame(); friend class nsTreeBodyFrame; protected: void UnsuppressInvalidation() { mInvalidationSuppressed = PR_FALSE; } void Invalidate(); private: - nsITreeBoxObject* mTree; + nsTreeBodyFrame* mTreeFrame; // A guard that prevents us from recursive painting. bool mInvalidationSuppressed; class InvalidationArea { public: InvalidationArea(nsITreeColumn* aCol); ~InvalidationArea() { delete mNext; }