From 8a55beea1eff9aae6d70d4b8e0431e830d6a6254 Mon Sep 17 00:00:00 2001 From: "hyatt%netscape.com" Date: Sat, 24 Mar 2001 01:50:33 +0000 Subject: [PATCH] Turning on images in outliner. r=pav, sr=brendan --- .../src/outliner/src/nsOutlinerBodyFrame.cpp | 341 ++++++++++++++++-- .../src/outliner/src/nsOutlinerBodyFrame.h | 67 +++- .../xul/base/src/tree/src/nsTreeBodyFrame.cpp | 341 ++++++++++++++++-- .../xul/base/src/tree/src/nsTreeBodyFrame.h | 67 +++- themes/modern/global/outliner.css | 16 +- themes/modern/messenger/threadPane.css | 21 ++ 6 files changed, 774 insertions(+), 79 deletions(-) diff --git a/layout/xul/base/src/outliner/src/nsOutlinerBodyFrame.cpp b/layout/xul/base/src/outliner/src/nsOutlinerBodyFrame.cpp index 11ba25d37a0a..dc2897bed1e8 100644 --- a/layout/xul/base/src/outliner/src/nsOutlinerBodyFrame.cpp +++ b/layout/xul/base/src/outliner/src/nsOutlinerBodyFrame.cpp @@ -56,9 +56,14 @@ #include "nsWidgetsCID.h" #include "nsBoxFrame.h" #include "nsBoxObject.h" +#include "nsIURL.h" +#include "nsNetUtil.h" + #ifdef USE_IMG2 #include "imgIRequest.h" #include "imgIContainer.h" +#include "imgIContainerObserver.h" +#include "imgILoader.h" #endif #define ELLIPSIS "..." @@ -138,6 +143,9 @@ nsOutlinerColumn::nsOutlinerColumn(nsIContent* aColElement, nsIFrame* aFrame) // Fetch the ID. mColElement->GetAttribute(kNameSpaceID_None, nsHTMLAtoms::id, mID); + // Cache the ID as an atom. + mIDAtom = getter_AddRefs(NS_NewAtom(mID)); + // Fetch the crop style. mCropStyle = 0; nsAutoString crop; @@ -216,6 +224,7 @@ nsOutlinerBodyFrame::nsOutlinerBodyFrame(nsIPresShell* aPresShell) // Destructor nsOutlinerBodyFrame::~nsOutlinerBodyFrame() { + delete mImageCache; } NS_IMETHODIMP_(nsrefcnt) @@ -438,9 +447,25 @@ NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateRow(PRInt32 aIndex) return NS_OK; } -NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateCell(PRInt32 aRow, const PRUnichar *aColID) +NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateCell(PRInt32 aIndex, const PRUnichar *aColID) { - return NS_ERROR_NOT_IMPLEMENTED; + if (aIndex < mTopRowIndex || aIndex > mTopRowIndex + mPageCount + 1) + return NS_OK; + + nscoord currX = mInnerBox.x; + for (nsOutlinerColumn* currCol = mColumns; currCol && currX < mInnerBox.x+mInnerBox.width; + currCol = currCol->GetNext()) { + nsRect colRect(currX, mInnerBox.y, currCol->GetWidth(), mInnerBox.height); + PRInt32 overflow = colRect.x+colRect.width-(mInnerBox.x+mInnerBox.width); + if (overflow > 0) + colRect.width -= overflow; + + if (nsCRT::strcmp(currCol->GetID(), aColID) == 0) { + nsLeafBoxFrame::Invalidate(mPresContext, colRect, PR_FALSE); + break; + } + } + return NS_OK; } NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateRange(PRInt32 aStart, PRInt32 aEnd) @@ -630,10 +655,8 @@ NS_IMETHODIMP nsOutlinerBodyFrame::RowCountChanged(PRInt32 aIndex, PRInt32 aCoun } void -nsOutlinerBodyFrame::PrefillPropertyArray(PRInt32 aRowIndex, const PRUnichar* aColID) +nsOutlinerBodyFrame::PrefillPropertyArray(PRInt32 aRowIndex, nsOutlinerColumn* aCol) { - // XXX Automatically fill in the following props: container, open - // And colID too, if it is non-empty? mScratchArray->Clear(); // focus @@ -669,20 +692,82 @@ nsOutlinerBodyFrame::PrefillPropertyArray(PRInt32 aRowIndex, const PRUnichar* aC mScratchArray->AppendElement(nsXULAtoms::open); } } + + if (aCol) { + nsCOMPtr colID; + aCol->GetIDAtom(getter_AddRefs(colID)); + mScratchArray->AppendElement(colID); + } } #ifdef USE_IMG2 nsresult -nsOutlinerBodyFrame::GetImage(nsIStyleContext* aStyleContext, imgIContainer** aResult) +nsOutlinerBodyFrame::GetImage(PRInt32 aRowIndex, const PRUnichar* aColID, + nsIStyleContext* aStyleContext, imgIContainer** aResult) { *aResult = nsnull; if (mImageCache) { // Look the image up in our cache. + nsISupportsKey key(aStyleContext); + nsCOMPtr imgReq = getter_AddRefs(NS_STATIC_CAST(imgIRequest*, mImageCache->Get(&key))); + if (imgReq) { + // Find out if the image has loaded. + PRUint32 status; + imgReq->GetImageStatus(&status); + imgReq->GetImage(aResult); // We hand back the image here. The GetImage call addrefs *aResult. + PRUint32 numFrames = 1; + if (*aResult) + (*aResult)->GetNumFrames(&numFrames); + + if ((!(status & imgIRequest::STATUS_LOAD_COMPLETE)) || numFrames > 1) { + // We either aren't done loading, or we're animating. Add our row as a listener for invalidations. + nsCOMPtr obs; + imgReq->GetDecoderObserver(getter_AddRefs(obs)); + nsCOMPtr listener(do_QueryInterface(obs)); + if (listener) + listener->AddRow(aRowIndex); + } + } } if (!*aResult) { - // We missed. Create a new imgIRequest object and pass it our row and column - // information. + // We missed. Kick off the image load. + // Obtain the URL from the style context. + const nsStyleList* myList = + (const nsStyleList*)aStyleContext->GetStyleData(eStyleStruct_List); + + if (myList->mListStyleImage.Length() > 0) { + // Create a new nsOutlinerImageListener object and pass it our row and column + // information. + nsOutlinerImageListener* listener = new nsOutlinerImageListener(mOutlinerBoxObject, aColID); + if (!listener) + return NS_ERROR_OUT_OF_MEMORY; + + listener->AddRow(aRowIndex); + + nsCOMPtr baseURI; + nsCOMPtr doc; + mContent->GetDocument(*getter_AddRefs(doc)); + doc->GetBaseURL(*getter_AddRefs(baseURI)); + + nsCOMPtr srcURI; + NS_NewURI(getter_AddRefs(srcURI), myList->mListStyleImage, baseURI); + + nsCOMPtr imageRequest; + + nsresult rv; + nsCOMPtr il(do_GetService("@mozilla.org/image/loader;1", &rv)); + il->LoadImage(srcURI, nsnull, listener, mPresContext, getter_AddRefs(imageRequest)); + + if (!mImageCache) { + mImageCache = new nsSupportsHashtable(32); + if (!mImageCache) + return NS_ERROR_OUT_OF_MEMORY; + } + + nsISupportsKey key(aStyleContext); + mImageCache->Put(&key, imageRequest); + } } return NS_OK; } @@ -690,6 +775,8 @@ nsOutlinerBodyFrame::GetImage(nsIStyleContext* aStyleContext, imgIContainer** aR nsRect nsOutlinerBodyFrame::GetImageSize(nsIStyleContext* aStyleContext) { + // XXX We should respond to visibility rules for collapsed vs. hidden. + // This method returns the width of the twisty INCLUDING borders and padding. // It first checks the style context for a width. If none is found, it tries to // use the default image width for the twisty. If no image is found, it defaults @@ -736,13 +823,21 @@ nsRect nsOutlinerBodyFrame::GetImageSize(nsIStyleContext* aStyleContext) nsCOMPtr image; imgReq->GetImage(getter_AddRefs(image)); if (image) { - // Get the size from the image. - nscoord width; - image->GetWidth(&width); - r.width += width; - nscoord height; - image->GetHeight(&height); - r.height += height; + float p2t; + mPresContext->GetPixelsToTwips(&p2t); + + if (needWidth) { + // Get the size from the image. + nscoord width; + image->GetWidth(&width); + r.width += NSIntPixelsToTwips(width, p2t); + } + + if (needHeight) { + nscoord height; + image->GetHeight(&height); + r.height += NSIntPixelsToTwips(height, p2t); + } } } } @@ -917,7 +1012,7 @@ NS_IMETHODIMP nsOutlinerBodyFrame::PaintColumn(nsOutlinerColumn* aColumn, // Now obtain the properties for our cell. // XXX Automatically fill in the following props: open, container, selected, focused, and the col ID. - PrefillPropertyArray(-1, aColumn->GetID()); + PrefillPropertyArray(-1, aColumn); nsCOMPtr elt(do_QueryInterface(aColumn->GetElement())); mView->GetColumnProperties(aColumn->GetID(), elt, mScratchArray); @@ -954,7 +1049,7 @@ NS_IMETHODIMP nsOutlinerBodyFrame::PaintRow(int aRowIndex, const nsRect& aRowRec // Now obtain the properties for our row. // XXX Automatically fill in the following props: open, container, selected, focused - PrefillPropertyArray(aRowIndex, NS_LITERAL_STRING("").get()); + PrefillPropertyArray(aRowIndex, nsnull); mView->GetRowProperties(aRowIndex, mScratchArray); // Resolve style for the row. It contains all the info we need to lay ourselves @@ -996,9 +1091,9 @@ NS_IMETHODIMP nsOutlinerBodyFrame::PaintRow(int aRowIndex, const nsRect& aRowRec return NS_OK; } -NS_IMETHODIMP nsOutlinerBodyFrame::PaintCell(int aRowIndex, +NS_IMETHODIMP nsOutlinerBodyFrame::PaintCell(int aRowIndex, nsOutlinerColumn* aColumn, - const nsRect& aCellRect, + const nsRect& aCellRect, nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, @@ -1009,7 +1104,7 @@ NS_IMETHODIMP nsOutlinerBodyFrame::PaintCell(int aRowIndex, // Now obtain the properties for our cell. // XXX Automatically fill in the following props: open, container, selected, focused, and the col ID. - PrefillPropertyArray(aRowIndex, NS_LITERAL_STRING("").get()); + PrefillPropertyArray(aRowIndex, aColumn); mView->GetCellProperties(aRowIndex, aColumn->GetID(), mScratchArray); // Resolve style for the cell. It contains all the info we need to lay ourselves @@ -1056,7 +1151,7 @@ NS_IMETHODIMP nsOutlinerBodyFrame::PaintCell(int aRowIndex, GetPseudoStyleContext(aPresContext, nsXULAtoms::mozoutlinerline, getter_AddRefs(lineContext)); const nsStyleDisplay* displayStyle = (const nsStyleDisplay*)lineContext->GetStyleData(eStyleStruct_Display); - if (displayStyle->IsVisibleOrCollapsed() && level) { + if (displayStyle->IsVisibleOrCollapsed() && level && NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { // Paint the connecting lines. aRenderingContext.PushState(); @@ -1102,20 +1197,25 @@ NS_IMETHODIMP nsOutlinerBodyFrame::PaintCell(int aRowIndex, nsRect dirtyRect; if (dirtyRect.IntersectRect(aDirtyRect, twistyRect)) PaintTwisty(aRowIndex, aColumn, twistyRect, aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, - remainingWidth); + remainingWidth, currX); } - // XXX Now paint the various images. + // Now paint the icon for our cell. + nsRect iconRect(currX, cellRect.y, remainingWidth, cellRect.height); + nsRect dirtyRect; + if (dirtyRect.IntersectRect(aDirtyRect, iconRect)) + PaintImage(aRowIndex, aColumn, iconRect, aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, + remainingWidth, currX); // Now paint our text, but only if we aren't a cycler column. // XXX until we have the ability to load images, allow the view to // insert text into cycler columns... -// if (!aColumn->IsCycler()) { + if (!aColumn->IsCycler()) { nsRect textRect(currX, cellRect.y, remainingWidth, cellRect.height); nsRect dirtyRect; if (dirtyRect.IntersectRect(aDirtyRect, textRect)) PaintText(aRowIndex, aColumn, textRect, aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); - //} + } return NS_OK; } @@ -1128,7 +1228,8 @@ nsOutlinerBodyFrame::PaintTwisty(int aRowIndex, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer, - nscoord& aRemainingWidth) + nscoord& aRemainingWidth, + nscoord& aCurrX) { // Paint the twisty, but only if we are a non-empty container. PRBool shouldPaint = PR_FALSE; @@ -1142,7 +1243,6 @@ nsOutlinerBodyFrame::PaintTwisty(int aRowIndex, } // Resolve style for the twisty. - PrefillPropertyArray(aRowIndex, aColumn->GetID()); nsCOMPtr twistyContext; GetPseudoStyleContext(aPresContext, nsXULAtoms::mozoutlinertwisty, getter_AddRefs(twistyContext)); @@ -1166,26 +1266,35 @@ nsOutlinerBodyFrame::PaintTwisty(int aRowIndex, nsRect copyRect(twistyRect); copyRect.Inflate(twistyMargin); aRemainingWidth -= copyRect.width; + aCurrX += copyRect.width; if (shouldPaint) { // If the layer is the background layer, we must paint our borders and background for our // image rect. if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) PaintBackgroundLayer(twistyContext, aPresContext, aRenderingContext, twistyRect, aDirtyRect); - else { + else if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { // Time to paint the twisty. - // Adjust the rect for its border and padding. AdjustForBorderPadding(twistyContext, twistyRect); + AdjustForBorderPadding(twistyContext, imageSize); #ifdef USE_IMG2 // Get the image for drawing. nsCOMPtr image; - GetImage(twistyContext, getter_AddRefs(image)); + GetImage(aRowIndex, aColumn->GetID(), twistyContext, getter_AddRefs(image)); if (image) { - // We got an image. Paint it. nsPoint p(twistyRect.x, twistyRect.y); - aRenderingContext.DrawImage(image, &twistyRect, &p); + + // Center the image. XXX Obey vertical-align style prop? + if (imageSize.height < twistyRect.height) { + p.y += (twistyRect.height - imageSize.height)/2; + if (((twistyRect.height - imageSize.height)/15)%2 != 0) + p.y -= 15; + } + + // Paint the image. + aRenderingContext.DrawImage(image, &imageSize, &p); } #endif } @@ -1194,6 +1303,84 @@ nsOutlinerBodyFrame::PaintTwisty(int aRowIndex, return NS_OK; } +NS_IMETHODIMP +nsOutlinerBodyFrame::PaintImage(int aRowIndex, + nsOutlinerColumn* aColumn, + const nsRect& aImageRect, + nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer, + nscoord& aRemainingWidth, + nscoord& aCurrX) +{ + // Resolve style for the image. + nsCOMPtr imageContext; + GetPseudoStyleContext(aPresContext, nsXULAtoms::mozoutlinerimage, getter_AddRefs(imageContext)); + + // Obtain the margins for the twisty and then deflate our rect by that + // amount. The twisty is assumed to be contained within the deflated rect. + nsRect imageRect(aImageRect); + const nsStyleMargin* imageMarginData = (const nsStyleMargin*)imageContext->GetStyleData(eStyleStruct_Margin); + nsMargin imageMargin; + imageMarginData->GetMargin(imageMargin); + imageRect.Deflate(imageMargin); + + // If the column isn't a cycler, the image rect extends all the way to the end of the cell. + // This is incorrect. We need to determine the image rect's true width. This is done by + // examining the style context for a width first. If it has one, we use that. If it doesn't, + // we use the image's natural width. + // If the image hasn't loaded and if no width is specified, then we just bail. + nsRect imageSize = GetImageSize(imageContext); + if (!aColumn->IsCycler()) + imageRect.width = imageSize.width; + + // Subtract out the remaining width. + nsRect copyRect(imageRect); + copyRect.Inflate(imageMargin); + aRemainingWidth -= copyRect.width; + aCurrX += copyRect.width; + + // If the layer is the background layer, we must paint our borders and background for our + // image rect. + if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) + PaintBackgroundLayer(imageContext, aPresContext, aRenderingContext, imageRect, aDirtyRect); + else if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { + // Time to paint the twisty. + // Adjust the rect for its border and padding. + AdjustForBorderPadding(imageContext, imageRect); + AdjustForBorderPadding(imageContext, imageSize); + +#ifdef USE_IMG2 + // Get the image for drawing. + nsCOMPtr image; + GetImage(aRowIndex, aColumn->GetID(), imageContext, getter_AddRefs(image)); + if (image) { + nsPoint p(imageRect.x, imageRect.y); + + // Center the image. XXX Obey vertical-align style prop? + if (imageSize.height < imageRect.height) { + p.y += (imageRect.height - imageSize.height)/2; + if (((imageRect.height - imageSize.height)/15)%2 != 0) + p.y -= 15; // One pixel in twips + } + + // For cyclers, we also want to center the image in the column. + if (aColumn->IsCycler() && imageSize.width < imageRect.width) { + p.x += (imageRect.width - imageSize.width)/2; + if (((imageRect.width - imageSize.width)/15)%2 != 0) + p.x -= 15; // One pixel in twips + } + + // Paint the image. + aRenderingContext.DrawImage(image, &imageSize, &p); + } +#endif + } + + return NS_OK; +} + NS_IMETHODIMP nsOutlinerBodyFrame::PaintText(int aRowIndex, nsOutlinerColumn* aColumn, const nsRect& aTextRect, @@ -1228,7 +1415,7 @@ NS_IMETHODIMP nsOutlinerBodyFrame::PaintText(int aRowIndex, // text rect. if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) PaintBackgroundLayer(textContext, aPresContext, aRenderingContext, textRect, aDirtyRect); - else { + else if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { // Time to paint our text. // Adjust the rect for its border and padding. AdjustForBorderPadding(textContext, textRect); @@ -1590,3 +1777,91 @@ NS_INTERFACE_MAP_BEGIN(nsOutlinerBodyFrame) NS_INTERFACE_MAP_ENTRY(nsIScrollbarMediator) NS_INTERFACE_MAP_END_INHERITING(nsLeafFrame) +// ============================================================================== +// The ImageListener implementation +// ============================================================================== + +#ifdef USE_IMG2 +NS_IMPL_ISUPPORTS3(nsOutlinerImageListener, imgIDecoderObserver, imgIContainerObserver, nsIOutlinerImageListener) + +nsOutlinerImageListener::nsOutlinerImageListener(nsIOutlinerBoxObject* aOutliner, const PRUnichar* aID) +{ + NS_INIT_ISUPPORTS(); + mOutliner = aOutliner; + mColID = aID; + mMin = mMax = 0; +} + +nsOutlinerImageListener::~nsOutlinerImageListener() +{ +} + +NS_IMETHODIMP nsOutlinerImageListener::OnStartDecode(imgIRequest *aRequest, nsISupports *aContext) +{ + return NS_OK; +} + +NS_IMETHODIMP nsOutlinerImageListener::OnStartContainer(imgIRequest *aRequest, nsISupports *aContext, imgIContainer *aImage) +{ + return NS_OK; +} + +NS_IMETHODIMP nsOutlinerImageListener::OnStartFrame(imgIRequest *aRequest, nsISupports *aContext, gfxIImageFrame *aFrame) +{ + return NS_OK; +} + +NS_IMETHODIMP nsOutlinerImageListener::OnDataAvailable(imgIRequest *aRequest, nsISupports *aContext, gfxIImageFrame *aFrame, const nsRect *aRect) +{ + Invalidate(); + return NS_OK; +} + +NS_IMETHODIMP nsOutlinerImageListener::OnStopFrame(imgIRequest *aRequest, nsISupports *aContext, gfxIImageFrame *aFrame) +{ + return NS_OK; +} + +NS_IMETHODIMP nsOutlinerImageListener::OnStopContainer(imgIRequest *aRequest, nsISupports *aContext, imgIContainer *aImage) +{ + // XXX This invalidate can go away once libpr0n starts properly firing an onDataAvailable + // to me for cached images. + Invalidate(); + return NS_OK; +} + +NS_IMETHODIMP nsOutlinerImageListener::OnStopDecode(imgIRequest *aRequest, nsISupports *aContext, nsresult status, const PRUnichar *statusArg) +{ + return NS_OK; +} + +NS_IMETHODIMP nsOutlinerImageListener::FrameChanged(imgIContainer *aContainer, nsISupports *aContext, gfxIImageFrame *newframe, nsRect * dirtyRect) +{ + Invalidate(); + return NS_OK; +} + +NS_IMETHODIMP +nsOutlinerImageListener::AddRow(int aIndex) +{ + if (aIndex < mMin) + mMin = aIndex; + else if (aIndex > mMax) + mMax = aIndex; + + return NS_OK; +} + +NS_IMETHODIMP +nsOutlinerImageListener::Invalidate() +{ + // Loop from min to max, invalidating each cell that was listening for this image. + for (PRInt32 i = mMin; i <= mMax; i++) { + mOutliner->InvalidateCell(i, mColID.GetUnicode()); + } + + return NS_OK; +} +#endif + + diff --git a/layout/xul/base/src/outliner/src/nsOutlinerBodyFrame.h b/layout/xul/base/src/outliner/src/nsOutlinerBodyFrame.h index 9f0733735ea8..6273cafb6acd 100644 --- a/layout/xul/base/src/outliner/src/nsOutlinerBodyFrame.h +++ b/layout/xul/base/src/outliner/src/nsOutlinerBodyFrame.h @@ -29,6 +29,10 @@ #include "nsIScrollbarMediator.h" #include "nsIWidget.h" +#ifdef USE_IMG2 +#include "imgIDecoderObserver.h" +#endif + class nsSupportsHashtable; class nsDFAState : public nsHashKey @@ -123,6 +127,8 @@ class nsOutlinerColumn { nsOutlinerColumn* mNext; nsString mID; + nsCOMPtr mIDAtom; + PRUint32 mCropStyle; PRUint32 mTextAlignment; @@ -144,12 +150,52 @@ public: nscoord GetWidth(); const PRUnichar* GetID() { return mID.GetUnicode(); }; + void GetIDAtom(nsIAtom** aResult) { *aResult = mIDAtom; NS_IF_ADDREF(*aResult); }; + PRBool IsPrimary() { return mIsPrimaryCol; }; PRBool IsCycler() { return mIsCyclerCol; }; PRInt32 GetCropStyle() { return mCropStyle; }; }; +#ifdef USE_IMG2 +// The interface for our image listener. +// {90586540-2D50-403e-8DCE-981CAA778444} +#define NS_IOUTLINERIMAGELISTENER_IID \ +{ 0x90586540, 0x2d50, 0x403e, { 0x8d, 0xce, 0x98, 0x1c, 0xaa, 0x77, 0x84, 0x44 } } + +class nsIOutlinerImageListener : public nsISupports +{ +public: + static const nsIID& GetIID() { static nsIID iid = NS_IOUTLINERIMAGELISTENER_IID; return iid; } + +public: + NS_IMETHOD AddRow(int aIndex)=0; + NS_IMETHOD Invalidate()=0; +}; + +// This class handles image load observation. +class nsOutlinerImageListener : public imgIDecoderObserver, public nsIOutlinerImageListener +{ +public: + nsOutlinerImageListener(nsIOutlinerBoxObject* aOutliner, const PRUnichar* aColID); + virtual ~nsOutlinerImageListener(); + + NS_DECL_ISUPPORTS + NS_DECL_IMGIDECODEROBSERVER + NS_DECL_IMGICONTAINEROBSERVER + + NS_IMETHOD AddRow(int aIndex); + NS_IMETHOD Invalidate(); + +private: + int mMin; + int mMax; + nsString mColID; + nsIOutlinerBoxObject* mOutliner; +}; +#endif + // The actual frame that paints the cells and rows. class nsOutlinerBodyFrame : public nsLeafBoxFrame, public nsIOutlinerBoxObject, public nsICSSPseudoComparator, public nsIScrollbarMediator @@ -216,7 +262,19 @@ public: nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer, - nscoord& aRemainingWidth); + nscoord& aRemainingWidth, + nscoord& aCurrX); + + // This method paints the image inside the cell of an outliner. + NS_IMETHOD PaintImage(int aRowIndex, + nsOutlinerColumn* aColumn, + const nsRect& aImageRect, + nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer, + nscoord& aRemainingWidth, + nscoord& aCurrX); // This method paints the text string inside a particular cell of the outliner. NS_IMETHOD PaintText(int aRowIndex, @@ -247,7 +305,8 @@ protected: #ifdef USE_IMG2 // Fetch an image from the image cache. - nsresult GetImage(nsIStyleContext* aContext, imgIContainer** aResult); + nsresult GetImage(PRInt32 aRowIndex, const PRUnichar* aColID, + nsIStyleContext* aStyleContext, imgIContainer** aResult); #endif // Returns the size of a given image. This size *includes* border and @@ -274,8 +333,8 @@ protected: void UpdateScrollbar(); // Use to auto-fill some of the common properties without the view having to do it. - // Examples include container, open, selected, and focused. - void PrefillPropertyArray(PRInt32 aRowIndex, const PRUnichar* aColID); + // Examples include container, open, selected, and focus. + void PrefillPropertyArray(PRInt32 aRowIndex, nsOutlinerColumn* aCol); // Our internal scroll method, used by all the public scroll methods. nsresult ScrollInternal(PRInt32 aRow); diff --git a/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp b/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp index 11ba25d37a0a..dc2897bed1e8 100644 --- a/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp +++ b/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp @@ -56,9 +56,14 @@ #include "nsWidgetsCID.h" #include "nsBoxFrame.h" #include "nsBoxObject.h" +#include "nsIURL.h" +#include "nsNetUtil.h" + #ifdef USE_IMG2 #include "imgIRequest.h" #include "imgIContainer.h" +#include "imgIContainerObserver.h" +#include "imgILoader.h" #endif #define ELLIPSIS "..." @@ -138,6 +143,9 @@ nsOutlinerColumn::nsOutlinerColumn(nsIContent* aColElement, nsIFrame* aFrame) // Fetch the ID. mColElement->GetAttribute(kNameSpaceID_None, nsHTMLAtoms::id, mID); + // Cache the ID as an atom. + mIDAtom = getter_AddRefs(NS_NewAtom(mID)); + // Fetch the crop style. mCropStyle = 0; nsAutoString crop; @@ -216,6 +224,7 @@ nsOutlinerBodyFrame::nsOutlinerBodyFrame(nsIPresShell* aPresShell) // Destructor nsOutlinerBodyFrame::~nsOutlinerBodyFrame() { + delete mImageCache; } NS_IMETHODIMP_(nsrefcnt) @@ -438,9 +447,25 @@ NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateRow(PRInt32 aIndex) return NS_OK; } -NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateCell(PRInt32 aRow, const PRUnichar *aColID) +NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateCell(PRInt32 aIndex, const PRUnichar *aColID) { - return NS_ERROR_NOT_IMPLEMENTED; + if (aIndex < mTopRowIndex || aIndex > mTopRowIndex + mPageCount + 1) + return NS_OK; + + nscoord currX = mInnerBox.x; + for (nsOutlinerColumn* currCol = mColumns; currCol && currX < mInnerBox.x+mInnerBox.width; + currCol = currCol->GetNext()) { + nsRect colRect(currX, mInnerBox.y, currCol->GetWidth(), mInnerBox.height); + PRInt32 overflow = colRect.x+colRect.width-(mInnerBox.x+mInnerBox.width); + if (overflow > 0) + colRect.width -= overflow; + + if (nsCRT::strcmp(currCol->GetID(), aColID) == 0) { + nsLeafBoxFrame::Invalidate(mPresContext, colRect, PR_FALSE); + break; + } + } + return NS_OK; } NS_IMETHODIMP nsOutlinerBodyFrame::InvalidateRange(PRInt32 aStart, PRInt32 aEnd) @@ -630,10 +655,8 @@ NS_IMETHODIMP nsOutlinerBodyFrame::RowCountChanged(PRInt32 aIndex, PRInt32 aCoun } void -nsOutlinerBodyFrame::PrefillPropertyArray(PRInt32 aRowIndex, const PRUnichar* aColID) +nsOutlinerBodyFrame::PrefillPropertyArray(PRInt32 aRowIndex, nsOutlinerColumn* aCol) { - // XXX Automatically fill in the following props: container, open - // And colID too, if it is non-empty? mScratchArray->Clear(); // focus @@ -669,20 +692,82 @@ nsOutlinerBodyFrame::PrefillPropertyArray(PRInt32 aRowIndex, const PRUnichar* aC mScratchArray->AppendElement(nsXULAtoms::open); } } + + if (aCol) { + nsCOMPtr colID; + aCol->GetIDAtom(getter_AddRefs(colID)); + mScratchArray->AppendElement(colID); + } } #ifdef USE_IMG2 nsresult -nsOutlinerBodyFrame::GetImage(nsIStyleContext* aStyleContext, imgIContainer** aResult) +nsOutlinerBodyFrame::GetImage(PRInt32 aRowIndex, const PRUnichar* aColID, + nsIStyleContext* aStyleContext, imgIContainer** aResult) { *aResult = nsnull; if (mImageCache) { // Look the image up in our cache. + nsISupportsKey key(aStyleContext); + nsCOMPtr imgReq = getter_AddRefs(NS_STATIC_CAST(imgIRequest*, mImageCache->Get(&key))); + if (imgReq) { + // Find out if the image has loaded. + PRUint32 status; + imgReq->GetImageStatus(&status); + imgReq->GetImage(aResult); // We hand back the image here. The GetImage call addrefs *aResult. + PRUint32 numFrames = 1; + if (*aResult) + (*aResult)->GetNumFrames(&numFrames); + + if ((!(status & imgIRequest::STATUS_LOAD_COMPLETE)) || numFrames > 1) { + // We either aren't done loading, or we're animating. Add our row as a listener for invalidations. + nsCOMPtr obs; + imgReq->GetDecoderObserver(getter_AddRefs(obs)); + nsCOMPtr listener(do_QueryInterface(obs)); + if (listener) + listener->AddRow(aRowIndex); + } + } } if (!*aResult) { - // We missed. Create a new imgIRequest object and pass it our row and column - // information. + // We missed. Kick off the image load. + // Obtain the URL from the style context. + const nsStyleList* myList = + (const nsStyleList*)aStyleContext->GetStyleData(eStyleStruct_List); + + if (myList->mListStyleImage.Length() > 0) { + // Create a new nsOutlinerImageListener object and pass it our row and column + // information. + nsOutlinerImageListener* listener = new nsOutlinerImageListener(mOutlinerBoxObject, aColID); + if (!listener) + return NS_ERROR_OUT_OF_MEMORY; + + listener->AddRow(aRowIndex); + + nsCOMPtr baseURI; + nsCOMPtr doc; + mContent->GetDocument(*getter_AddRefs(doc)); + doc->GetBaseURL(*getter_AddRefs(baseURI)); + + nsCOMPtr srcURI; + NS_NewURI(getter_AddRefs(srcURI), myList->mListStyleImage, baseURI); + + nsCOMPtr imageRequest; + + nsresult rv; + nsCOMPtr il(do_GetService("@mozilla.org/image/loader;1", &rv)); + il->LoadImage(srcURI, nsnull, listener, mPresContext, getter_AddRefs(imageRequest)); + + if (!mImageCache) { + mImageCache = new nsSupportsHashtable(32); + if (!mImageCache) + return NS_ERROR_OUT_OF_MEMORY; + } + + nsISupportsKey key(aStyleContext); + mImageCache->Put(&key, imageRequest); + } } return NS_OK; } @@ -690,6 +775,8 @@ nsOutlinerBodyFrame::GetImage(nsIStyleContext* aStyleContext, imgIContainer** aR nsRect nsOutlinerBodyFrame::GetImageSize(nsIStyleContext* aStyleContext) { + // XXX We should respond to visibility rules for collapsed vs. hidden. + // This method returns the width of the twisty INCLUDING borders and padding. // It first checks the style context for a width. If none is found, it tries to // use the default image width for the twisty. If no image is found, it defaults @@ -736,13 +823,21 @@ nsRect nsOutlinerBodyFrame::GetImageSize(nsIStyleContext* aStyleContext) nsCOMPtr image; imgReq->GetImage(getter_AddRefs(image)); if (image) { - // Get the size from the image. - nscoord width; - image->GetWidth(&width); - r.width += width; - nscoord height; - image->GetHeight(&height); - r.height += height; + float p2t; + mPresContext->GetPixelsToTwips(&p2t); + + if (needWidth) { + // Get the size from the image. + nscoord width; + image->GetWidth(&width); + r.width += NSIntPixelsToTwips(width, p2t); + } + + if (needHeight) { + nscoord height; + image->GetHeight(&height); + r.height += NSIntPixelsToTwips(height, p2t); + } } } } @@ -917,7 +1012,7 @@ NS_IMETHODIMP nsOutlinerBodyFrame::PaintColumn(nsOutlinerColumn* aColumn, // Now obtain the properties for our cell. // XXX Automatically fill in the following props: open, container, selected, focused, and the col ID. - PrefillPropertyArray(-1, aColumn->GetID()); + PrefillPropertyArray(-1, aColumn); nsCOMPtr elt(do_QueryInterface(aColumn->GetElement())); mView->GetColumnProperties(aColumn->GetID(), elt, mScratchArray); @@ -954,7 +1049,7 @@ NS_IMETHODIMP nsOutlinerBodyFrame::PaintRow(int aRowIndex, const nsRect& aRowRec // Now obtain the properties for our row. // XXX Automatically fill in the following props: open, container, selected, focused - PrefillPropertyArray(aRowIndex, NS_LITERAL_STRING("").get()); + PrefillPropertyArray(aRowIndex, nsnull); mView->GetRowProperties(aRowIndex, mScratchArray); // Resolve style for the row. It contains all the info we need to lay ourselves @@ -996,9 +1091,9 @@ NS_IMETHODIMP nsOutlinerBodyFrame::PaintRow(int aRowIndex, const nsRect& aRowRec return NS_OK; } -NS_IMETHODIMP nsOutlinerBodyFrame::PaintCell(int aRowIndex, +NS_IMETHODIMP nsOutlinerBodyFrame::PaintCell(int aRowIndex, nsOutlinerColumn* aColumn, - const nsRect& aCellRect, + const nsRect& aCellRect, nsIPresContext* aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, @@ -1009,7 +1104,7 @@ NS_IMETHODIMP nsOutlinerBodyFrame::PaintCell(int aRowIndex, // Now obtain the properties for our cell. // XXX Automatically fill in the following props: open, container, selected, focused, and the col ID. - PrefillPropertyArray(aRowIndex, NS_LITERAL_STRING("").get()); + PrefillPropertyArray(aRowIndex, aColumn); mView->GetCellProperties(aRowIndex, aColumn->GetID(), mScratchArray); // Resolve style for the cell. It contains all the info we need to lay ourselves @@ -1056,7 +1151,7 @@ NS_IMETHODIMP nsOutlinerBodyFrame::PaintCell(int aRowIndex, GetPseudoStyleContext(aPresContext, nsXULAtoms::mozoutlinerline, getter_AddRefs(lineContext)); const nsStyleDisplay* displayStyle = (const nsStyleDisplay*)lineContext->GetStyleData(eStyleStruct_Display); - if (displayStyle->IsVisibleOrCollapsed() && level) { + if (displayStyle->IsVisibleOrCollapsed() && level && NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { // Paint the connecting lines. aRenderingContext.PushState(); @@ -1102,20 +1197,25 @@ NS_IMETHODIMP nsOutlinerBodyFrame::PaintCell(int aRowIndex, nsRect dirtyRect; if (dirtyRect.IntersectRect(aDirtyRect, twistyRect)) PaintTwisty(aRowIndex, aColumn, twistyRect, aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, - remainingWidth); + remainingWidth, currX); } - // XXX Now paint the various images. + // Now paint the icon for our cell. + nsRect iconRect(currX, cellRect.y, remainingWidth, cellRect.height); + nsRect dirtyRect; + if (dirtyRect.IntersectRect(aDirtyRect, iconRect)) + PaintImage(aRowIndex, aColumn, iconRect, aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, + remainingWidth, currX); // Now paint our text, but only if we aren't a cycler column. // XXX until we have the ability to load images, allow the view to // insert text into cycler columns... -// if (!aColumn->IsCycler()) { + if (!aColumn->IsCycler()) { nsRect textRect(currX, cellRect.y, remainingWidth, cellRect.height); nsRect dirtyRect; if (dirtyRect.IntersectRect(aDirtyRect, textRect)) PaintText(aRowIndex, aColumn, textRect, aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); - //} + } return NS_OK; } @@ -1128,7 +1228,8 @@ nsOutlinerBodyFrame::PaintTwisty(int aRowIndex, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer, - nscoord& aRemainingWidth) + nscoord& aRemainingWidth, + nscoord& aCurrX) { // Paint the twisty, but only if we are a non-empty container. PRBool shouldPaint = PR_FALSE; @@ -1142,7 +1243,6 @@ nsOutlinerBodyFrame::PaintTwisty(int aRowIndex, } // Resolve style for the twisty. - PrefillPropertyArray(aRowIndex, aColumn->GetID()); nsCOMPtr twistyContext; GetPseudoStyleContext(aPresContext, nsXULAtoms::mozoutlinertwisty, getter_AddRefs(twistyContext)); @@ -1166,26 +1266,35 @@ nsOutlinerBodyFrame::PaintTwisty(int aRowIndex, nsRect copyRect(twistyRect); copyRect.Inflate(twistyMargin); aRemainingWidth -= copyRect.width; + aCurrX += copyRect.width; if (shouldPaint) { // If the layer is the background layer, we must paint our borders and background for our // image rect. if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) PaintBackgroundLayer(twistyContext, aPresContext, aRenderingContext, twistyRect, aDirtyRect); - else { + else if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { // Time to paint the twisty. - // Adjust the rect for its border and padding. AdjustForBorderPadding(twistyContext, twistyRect); + AdjustForBorderPadding(twistyContext, imageSize); #ifdef USE_IMG2 // Get the image for drawing. nsCOMPtr image; - GetImage(twistyContext, getter_AddRefs(image)); + GetImage(aRowIndex, aColumn->GetID(), twistyContext, getter_AddRefs(image)); if (image) { - // We got an image. Paint it. nsPoint p(twistyRect.x, twistyRect.y); - aRenderingContext.DrawImage(image, &twistyRect, &p); + + // Center the image. XXX Obey vertical-align style prop? + if (imageSize.height < twistyRect.height) { + p.y += (twistyRect.height - imageSize.height)/2; + if (((twistyRect.height - imageSize.height)/15)%2 != 0) + p.y -= 15; + } + + // Paint the image. + aRenderingContext.DrawImage(image, &imageSize, &p); } #endif } @@ -1194,6 +1303,84 @@ nsOutlinerBodyFrame::PaintTwisty(int aRowIndex, return NS_OK; } +NS_IMETHODIMP +nsOutlinerBodyFrame::PaintImage(int aRowIndex, + nsOutlinerColumn* aColumn, + const nsRect& aImageRect, + nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer, + nscoord& aRemainingWidth, + nscoord& aCurrX) +{ + // Resolve style for the image. + nsCOMPtr imageContext; + GetPseudoStyleContext(aPresContext, nsXULAtoms::mozoutlinerimage, getter_AddRefs(imageContext)); + + // Obtain the margins for the twisty and then deflate our rect by that + // amount. The twisty is assumed to be contained within the deflated rect. + nsRect imageRect(aImageRect); + const nsStyleMargin* imageMarginData = (const nsStyleMargin*)imageContext->GetStyleData(eStyleStruct_Margin); + nsMargin imageMargin; + imageMarginData->GetMargin(imageMargin); + imageRect.Deflate(imageMargin); + + // If the column isn't a cycler, the image rect extends all the way to the end of the cell. + // This is incorrect. We need to determine the image rect's true width. This is done by + // examining the style context for a width first. If it has one, we use that. If it doesn't, + // we use the image's natural width. + // If the image hasn't loaded and if no width is specified, then we just bail. + nsRect imageSize = GetImageSize(imageContext); + if (!aColumn->IsCycler()) + imageRect.width = imageSize.width; + + // Subtract out the remaining width. + nsRect copyRect(imageRect); + copyRect.Inflate(imageMargin); + aRemainingWidth -= copyRect.width; + aCurrX += copyRect.width; + + // If the layer is the background layer, we must paint our borders and background for our + // image rect. + if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) + PaintBackgroundLayer(imageContext, aPresContext, aRenderingContext, imageRect, aDirtyRect); + else if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { + // Time to paint the twisty. + // Adjust the rect for its border and padding. + AdjustForBorderPadding(imageContext, imageRect); + AdjustForBorderPadding(imageContext, imageSize); + +#ifdef USE_IMG2 + // Get the image for drawing. + nsCOMPtr image; + GetImage(aRowIndex, aColumn->GetID(), imageContext, getter_AddRefs(image)); + if (image) { + nsPoint p(imageRect.x, imageRect.y); + + // Center the image. XXX Obey vertical-align style prop? + if (imageSize.height < imageRect.height) { + p.y += (imageRect.height - imageSize.height)/2; + if (((imageRect.height - imageSize.height)/15)%2 != 0) + p.y -= 15; // One pixel in twips + } + + // For cyclers, we also want to center the image in the column. + if (aColumn->IsCycler() && imageSize.width < imageRect.width) { + p.x += (imageRect.width - imageSize.width)/2; + if (((imageRect.width - imageSize.width)/15)%2 != 0) + p.x -= 15; // One pixel in twips + } + + // Paint the image. + aRenderingContext.DrawImage(image, &imageSize, &p); + } +#endif + } + + return NS_OK; +} + NS_IMETHODIMP nsOutlinerBodyFrame::PaintText(int aRowIndex, nsOutlinerColumn* aColumn, const nsRect& aTextRect, @@ -1228,7 +1415,7 @@ NS_IMETHODIMP nsOutlinerBodyFrame::PaintText(int aRowIndex, // text rect. if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) PaintBackgroundLayer(textContext, aPresContext, aRenderingContext, textRect, aDirtyRect); - else { + else if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { // Time to paint our text. // Adjust the rect for its border and padding. AdjustForBorderPadding(textContext, textRect); @@ -1590,3 +1777,91 @@ NS_INTERFACE_MAP_BEGIN(nsOutlinerBodyFrame) NS_INTERFACE_MAP_ENTRY(nsIScrollbarMediator) NS_INTERFACE_MAP_END_INHERITING(nsLeafFrame) +// ============================================================================== +// The ImageListener implementation +// ============================================================================== + +#ifdef USE_IMG2 +NS_IMPL_ISUPPORTS3(nsOutlinerImageListener, imgIDecoderObserver, imgIContainerObserver, nsIOutlinerImageListener) + +nsOutlinerImageListener::nsOutlinerImageListener(nsIOutlinerBoxObject* aOutliner, const PRUnichar* aID) +{ + NS_INIT_ISUPPORTS(); + mOutliner = aOutliner; + mColID = aID; + mMin = mMax = 0; +} + +nsOutlinerImageListener::~nsOutlinerImageListener() +{ +} + +NS_IMETHODIMP nsOutlinerImageListener::OnStartDecode(imgIRequest *aRequest, nsISupports *aContext) +{ + return NS_OK; +} + +NS_IMETHODIMP nsOutlinerImageListener::OnStartContainer(imgIRequest *aRequest, nsISupports *aContext, imgIContainer *aImage) +{ + return NS_OK; +} + +NS_IMETHODIMP nsOutlinerImageListener::OnStartFrame(imgIRequest *aRequest, nsISupports *aContext, gfxIImageFrame *aFrame) +{ + return NS_OK; +} + +NS_IMETHODIMP nsOutlinerImageListener::OnDataAvailable(imgIRequest *aRequest, nsISupports *aContext, gfxIImageFrame *aFrame, const nsRect *aRect) +{ + Invalidate(); + return NS_OK; +} + +NS_IMETHODIMP nsOutlinerImageListener::OnStopFrame(imgIRequest *aRequest, nsISupports *aContext, gfxIImageFrame *aFrame) +{ + return NS_OK; +} + +NS_IMETHODIMP nsOutlinerImageListener::OnStopContainer(imgIRequest *aRequest, nsISupports *aContext, imgIContainer *aImage) +{ + // XXX This invalidate can go away once libpr0n starts properly firing an onDataAvailable + // to me for cached images. + Invalidate(); + return NS_OK; +} + +NS_IMETHODIMP nsOutlinerImageListener::OnStopDecode(imgIRequest *aRequest, nsISupports *aContext, nsresult status, const PRUnichar *statusArg) +{ + return NS_OK; +} + +NS_IMETHODIMP nsOutlinerImageListener::FrameChanged(imgIContainer *aContainer, nsISupports *aContext, gfxIImageFrame *newframe, nsRect * dirtyRect) +{ + Invalidate(); + return NS_OK; +} + +NS_IMETHODIMP +nsOutlinerImageListener::AddRow(int aIndex) +{ + if (aIndex < mMin) + mMin = aIndex; + else if (aIndex > mMax) + mMax = aIndex; + + return NS_OK; +} + +NS_IMETHODIMP +nsOutlinerImageListener::Invalidate() +{ + // Loop from min to max, invalidating each cell that was listening for this image. + for (PRInt32 i = mMin; i <= mMax; i++) { + mOutliner->InvalidateCell(i, mColID.GetUnicode()); + } + + return NS_OK; +} +#endif + + diff --git a/layout/xul/base/src/tree/src/nsTreeBodyFrame.h b/layout/xul/base/src/tree/src/nsTreeBodyFrame.h index 9f0733735ea8..6273cafb6acd 100644 --- a/layout/xul/base/src/tree/src/nsTreeBodyFrame.h +++ b/layout/xul/base/src/tree/src/nsTreeBodyFrame.h @@ -29,6 +29,10 @@ #include "nsIScrollbarMediator.h" #include "nsIWidget.h" +#ifdef USE_IMG2 +#include "imgIDecoderObserver.h" +#endif + class nsSupportsHashtable; class nsDFAState : public nsHashKey @@ -123,6 +127,8 @@ class nsOutlinerColumn { nsOutlinerColumn* mNext; nsString mID; + nsCOMPtr mIDAtom; + PRUint32 mCropStyle; PRUint32 mTextAlignment; @@ -144,12 +150,52 @@ public: nscoord GetWidth(); const PRUnichar* GetID() { return mID.GetUnicode(); }; + void GetIDAtom(nsIAtom** aResult) { *aResult = mIDAtom; NS_IF_ADDREF(*aResult); }; + PRBool IsPrimary() { return mIsPrimaryCol; }; PRBool IsCycler() { return mIsCyclerCol; }; PRInt32 GetCropStyle() { return mCropStyle; }; }; +#ifdef USE_IMG2 +// The interface for our image listener. +// {90586540-2D50-403e-8DCE-981CAA778444} +#define NS_IOUTLINERIMAGELISTENER_IID \ +{ 0x90586540, 0x2d50, 0x403e, { 0x8d, 0xce, 0x98, 0x1c, 0xaa, 0x77, 0x84, 0x44 } } + +class nsIOutlinerImageListener : public nsISupports +{ +public: + static const nsIID& GetIID() { static nsIID iid = NS_IOUTLINERIMAGELISTENER_IID; return iid; } + +public: + NS_IMETHOD AddRow(int aIndex)=0; + NS_IMETHOD Invalidate()=0; +}; + +// This class handles image load observation. +class nsOutlinerImageListener : public imgIDecoderObserver, public nsIOutlinerImageListener +{ +public: + nsOutlinerImageListener(nsIOutlinerBoxObject* aOutliner, const PRUnichar* aColID); + virtual ~nsOutlinerImageListener(); + + NS_DECL_ISUPPORTS + NS_DECL_IMGIDECODEROBSERVER + NS_DECL_IMGICONTAINEROBSERVER + + NS_IMETHOD AddRow(int aIndex); + NS_IMETHOD Invalidate(); + +private: + int mMin; + int mMax; + nsString mColID; + nsIOutlinerBoxObject* mOutliner; +}; +#endif + // The actual frame that paints the cells and rows. class nsOutlinerBodyFrame : public nsLeafBoxFrame, public nsIOutlinerBoxObject, public nsICSSPseudoComparator, public nsIScrollbarMediator @@ -216,7 +262,19 @@ public: nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer, - nscoord& aRemainingWidth); + nscoord& aRemainingWidth, + nscoord& aCurrX); + + // This method paints the image inside the cell of an outliner. + NS_IMETHOD PaintImage(int aRowIndex, + nsOutlinerColumn* aColumn, + const nsRect& aImageRect, + nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer, + nscoord& aRemainingWidth, + nscoord& aCurrX); // This method paints the text string inside a particular cell of the outliner. NS_IMETHOD PaintText(int aRowIndex, @@ -247,7 +305,8 @@ protected: #ifdef USE_IMG2 // Fetch an image from the image cache. - nsresult GetImage(nsIStyleContext* aContext, imgIContainer** aResult); + nsresult GetImage(PRInt32 aRowIndex, const PRUnichar* aColID, + nsIStyleContext* aStyleContext, imgIContainer** aResult); #endif // Returns the size of a given image. This size *includes* border and @@ -274,8 +333,8 @@ protected: void UpdateScrollbar(); // Use to auto-fill some of the common properties without the view having to do it. - // Examples include container, open, selected, and focused. - void PrefillPropertyArray(PRInt32 aRowIndex, const PRUnichar* aColID); + // Examples include container, open, selected, and focus. + void PrefillPropertyArray(PRInt32 aRowIndex, nsOutlinerColumn* aCol); // Our internal scroll method, used by all the public scroll methods. nsresult ScrollInternal(PRInt32 aRow); diff --git a/themes/modern/global/outliner.css b/themes/modern/global/outliner.css index 043f89ada8b9..1bc0c0fc0901 100644 --- a/themes/modern/global/outliner.css +++ b/themes/modern/global/outliner.css @@ -89,11 +89,7 @@ outlinercol { } outlinerbody:-moz-outliner-line { - border: 1px dotted #808080; -} - -outlinerbody:-moz-outliner-line(selected) { - border: 1px dotted #000000; + visibility: hidden; /* Turned off in modern. */ } /* ..... internal box ..... */ @@ -155,3 +151,13 @@ outlinercol:hover:active > .outlinercol-image-box { .outliner-colpicker-icon { list-style-image : url("chrome://global/skin/tree/columnpicker.gif"); } + +/* twisty rules */ +outlinerbody:-moz-outliner-twisty { + padding-right: 2px; + width: 10px; /* The image's width is 10 pixels */ + list-style-image: url("chrome://global/skin/tree/twisty-clsd.gif"); +} + +outlinerbody:-moz-outliner-twisty(open) { + list-style-image: url("chrome://global/skin/tree/twisty-open.gif"); diff --git a/themes/modern/messenger/threadPane.css b/themes/modern/messenger/threadPane.css index bbf143222984..74a6766402d2 100644 --- a/themes/modern/messenger/threadPane.css +++ b/themes/modern/messenger/threadPane.css @@ -94,6 +94,13 @@ outlinercol.threadColumnHeader[sortDirection="descending"] { /* message row icons */ +outlinerbody:-moz-outliner-image(threadCol, container) { + list-style-image: url("chrome://messenger/skin/icons/thread-closed.gif"); +} + +outlinerbody:-moz-outliner-image(threadCol, container, open) { + list-style-image: url("chrome://messenger/skin/icons/thread-open.gif"); +} /* ..... read column ..... */ @@ -104,7 +111,13 @@ outlinercol.readColumnHeader { /* message row icons */ +outlinerbody:-moz-outliner-image(unreadButtonColHeader) { + list-style-image: url("chrome://messenger/skin/icons/readcol-read.gif"); +} +outlinerbody:-moz-outliner-image(unreadButtonColHeader, unread) { + list-style-image: url("chrome://messenger/skin/icons/readcol-unread.gif"); +} /* ..... flag column ..... */ @@ -113,3 +126,11 @@ outlinercol.flagColumnHeader { } /* message row icons */ + +outlinerbody:-moz-outliner-image(flaggedCol) { + list-style-image: url("chrome://messenger/skin/icons/readcol-read.gif"); +} + +outlinerbody:-moz-outliner-image(flaggedCol, flagged) { + list-style-image: url("chrome://messenger/skin/icons/flagcol-flagged.gif"); +} \ No newline at end of file