Bug 592493 - Register border-images with the document image tracker.r=dbaron
authorBobby Holley <bobbyholley@gmail.com>
Tue, 07 Sep 2010 17:30:40 -0700
changeset 52148 d35c0d22fa7150b9c9c28a897bd9372456dff6ba
parent 52147 459a07b6bdee34c9691c324c4b830c6fc6d2af63
child 52149 fd33aa85de93cd0ff059b48f40b28d67438804b8
push idunknown
push userunknown
push dateunknown
reviewersdbaron
bugs592493
milestone2.0b6pre
Bug 592493 - Register border-images with the document image tracker.r=dbaron
layout/base/nsCSSRendering.cpp
layout/style/nsRuleNode.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/nsStyleStructInlines.h
layout/tables/nsTableCellFrame.cpp
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -496,24 +496,34 @@ nsCSSRendering::PaintBorder(nsPresContex
   if (!styleIfVisited) {
     PaintBorderWithStyleBorder(aPresContext, aRenderingContext, aForFrame,
                                aDirtyRect, aBorderArea, *styleBorder,
                                aStyleContext, aSkipSides);
     return;
   }
 
   nsStyleBorder newStyleBorder(*styleBorder);
+  // We're making an ephemeral stack copy here, so just copy this debug-only
+  // member to prevent assertions.
+#ifdef DEBUG
+  newStyleBorder.mImageTracked = styleBorder->mImageTracked;
+#endif
+
   NS_FOR_CSS_SIDES(side) {
     newStyleBorder.SetBorderColor(side,
       aStyleContext->GetVisitedDependentColor(
         nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_color)[side]));
   }
   PaintBorderWithStyleBorder(aPresContext, aRenderingContext, aForFrame,
                              aDirtyRect, aBorderArea, newStyleBorder,
                              aStyleContext, aSkipSides);
+
+#ifdef DEBUG
+  newStyleBorder.mImageTracked = false;
+#endif
 }
 
 void
 nsCSSRendering::PaintBorderWithStyleBorder(nsPresContext* aPresContext,
                                            nsIRenderingContext& aRenderingContext,
                                            nsIFrame* aForFrame,
                                            const nsRect& aDirtyRect,
                                            const nsRect& aBorderArea,
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -5278,16 +5278,19 @@ nsRuleNode::ComputeBorderData(void* aSta
     border->mBorderImageSplit = parentBorder->mBorderImageSplit;
     border->mBorderImageHFill = parentBorder->mBorderImageHFill;
     border->mBorderImageVFill = parentBorder->mBorderImageVFill;
     border->mHaveBorderImageWidth = parentBorder->mHaveBorderImageWidth;
     NS_SET_IMAGE_REQUEST(border->SetBorderImage, aContext,
                          parentBorder->GetBorderImage())
   }
 
+  if (border->HasBorderImage())
+    border->TrackImage(aContext->PresContext());
+
   COMPUTE_END_RESET(Border, border)
 }
 
 const void*
 nsRuleNode::ComputePaddingData(void* aStartStruct,
                                const nsRuleDataStruct& aData,
                                nsStyleContext* aContext,
                                nsRuleNode* aHighestNode,
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -370,19 +370,22 @@ nsChangeHint nsStylePadding::CalcDiffere
 nsChangeHint nsStylePadding::MaxDifference()
 {
   return NS_SubtractHint(NS_STYLE_HINT_REFLOW,
                          nsChangeHint_ClearDescendantIntrinsics);
 }
 #endif
 
 nsStyleBorder::nsStyleBorder(nsPresContext* aPresContext)
-  : mHaveBorderImageWidth(PR_FALSE),
-    mComputedBorder(0, 0, 0, 0),
-    mBorderImage(nsnull)
+  : mHaveBorderImageWidth(PR_FALSE)
+  , mComputedBorder(0, 0, 0, 0)
+  , mBorderImage(nsnull)
+#ifdef DEBUG
+  , mImageTracked(false)
+#endif
 {
   MOZ_COUNT_CTOR(nsStyleBorder);
   nscoord medium =
     (aPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
   NS_FOR_CSS_SIDES(side) {
     mBorder.side(side) = medium;
     mBorderStyle[side] = NS_STYLE_BORDER_STYLE_NONE | BORDER_COLOR_FOREGROUND;
     mBorderColor[side] = NS_RGB(0, 0, 0);
@@ -446,16 +449,18 @@ nsStyleBorder::nsStyleBorder(const nsSty
   }
   NS_FOR_CSS_HALF_CORNERS(corner) {
     mBorderRadius.Set(corner, aSrc.mBorderRadius.Get(corner));
   }
 }
 
 nsStyleBorder::~nsStyleBorder()
 {
+  NS_ABORT_IF_FALSE(!mImageTracked,
+                    "nsStyleBorder being destroyed while still tracking image!");
   MOZ_COUNT_DTOR(nsStyleBorder);
   if (mBorderColors) {
     for (PRInt32 i = 0; i < 4; i++)
       delete mBorderColors[i];
     delete [] mBorderColors;
   }
 }
 
@@ -464,16 +469,18 @@ nsStyleBorder::operator new(size_t sz, n
   void* result = aContext->AllocateFromShell(sz);
   if (result)
     memset(result, 0, sz);
   return result;
 }
   
 void 
 nsStyleBorder::Destroy(nsPresContext* aContext) {
+  if (mBorderImage)
+    UntrackImage(aContext);
   this->~nsStyleBorder();
   aContext->FreeToShell(sizeof(nsStyleBorder), this);
 }
 
 
 nsChangeHint nsStyleBorder::CalcDifference(const nsStyleBorder& aOther) const
 {
   nsChangeHint shadowDifference =
@@ -549,16 +556,52 @@ nsStyleBorder::GetActualBorder() const
     if (mHaveBorderImageWidth)
       return mBorderImageWidth;
     else
       return mBorder;
   else
     return mComputedBorder;
 }
 
+void
+nsStyleBorder::TrackImage(nsPresContext* aContext)
+{
+  // Sanity
+  NS_ABORT_IF_FALSE(!mImageTracked, "Already tracking image!");
+  NS_ABORT_IF_FALSE(mBorderImage, "Can't track null image!");
+
+  // Register the image with the document
+  nsIDocument* doc = aContext->Document();
+  if (doc)
+    doc->AddImage(mBorderImage);
+
+  // Mark state
+#ifdef DEBUG
+  mImageTracked = true;
+#endif
+}
+
+void
+nsStyleBorder::UntrackImage(nsPresContext* aContext)
+{
+  // Sanity
+  NS_ABORT_IF_FALSE(mImageTracked, "Image not tracked!");
+  NS_ABORT_IF_FALSE(mBorderImage, "Can't track null image!");
+
+  // Unregister the image with the document
+  nsIDocument* doc = aContext->Document();
+  if (doc)
+    doc->RemoveImage(mBorderImage);
+
+  // Mark state
+#ifdef DEBUG
+  mImageTracked = false;
+#endif
+}
+
 nsStyleOutline::nsStyleOutline(nsPresContext* aPresContext)
 {
   MOZ_COUNT_CTOR(nsStyleOutline);
   // spacing values not inherited
   nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
   NS_FOR_CSS_HALF_CORNERS(corner) {
     mOutlineRadius.Set(corner, zero);
   }
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -863,16 +863,21 @@ struct nsStyleBorder {
     mBorderColor[aSide] = aColor;
     mBorderStyle[aSide] &= ~BORDER_COLOR_SPECIAL;
   }
 
   // These are defined in nsStyleStructInlines.h
   inline void SetBorderImage(imgIRequest* aImage);
   inline imgIRequest* GetBorderImage() const;
 
+  bool HasBorderImage() {return !!mBorderImage;}
+
+  void TrackImage(nsPresContext* aContext);
+  void UntrackImage(nsPresContext* aContext);
+
   // These methods are used for the caller to caches the sub images created during
   // a border-image paint operation
   inline void SetSubImage(PRUint8 aIndex, imgIContainer* aSubImage) const;
   inline imgIContainer* GetSubImage(PRUint8 aIndex) const;
 
   void GetCompositeColors(PRInt32 aIndex, nsBorderColors** aColors) const
   {
     if (!mBorderColors)
@@ -898,16 +903,20 @@ struct nsStyleBorder {
 
   void SetBorderToForeground(mozilla::css::Side aSide)
   {
     NS_ASSERTION(aSide <= NS_SIDE_LEFT, "bad side");
     mBorderStyle[aSide] &= ~BORDER_COLOR_SPECIAL;
     mBorderStyle[aSide] |= BORDER_COLOR_FOREGROUND;
   }
 
+#ifdef DEBUG
+  bool mImageTracked;
+#endif
+
 protected:
   // mComputedBorder holds the CSS2.1 computed border-width values.  In
   // particular, these widths take into account the border-style for the
   // relevant side and the values are rounded to the nearest device
   // pixel.  They are also rounded (which is not part of the definition
   // of computed values).  However, they do *not* take into account the
   // presence of border-image.  See GetActualBorder above for how to
   // really get the actual border.
@@ -931,16 +940,18 @@ protected:
                                   // if -moz-border-colors is specified
 private:
   nsCOMPtr<imgIRequest> mBorderImage; // [reset]
 
   // Cache used by callers for border-image painting
   nsCOMArray<imgIContainer> mSubImages;
 
   nscoord       mTwipsPerPixel;
+
+  nsStyleBorder& operator=(const nsStyleBorder& aOther); // Not to be implemented
 };
 
 
 struct nsStyleOutline {
   nsStyleOutline(nsPresContext* aPresContext);
   nsStyleOutline(const nsStyleOutline& aOutline);
   ~nsStyleOutline(void) {
     MOZ_COUNT_DTOR(nsStyleOutline);
--- a/layout/style/nsStyleStructInlines.h
+++ b/layout/style/nsStyleStructInlines.h
@@ -48,30 +48,23 @@
 #include "imgIRequest.h"
 #include "imgIContainer.h"
 
 inline void
 nsStyleBorder::SetBorderImage(imgIRequest* aImage)
 {
   mBorderImage = aImage;
   mSubImages.Clear();
-
-  /*
-   * Request a decode to jump start decoding, and lock it to make sure it
-   * stays decoded.
-   */
-  if (mBorderImage) {
-    mBorderImage->RequestDecode();
-    mBorderImage->LockImage();
-  }
 }
 
 inline imgIRequest*
 nsStyleBorder::GetBorderImage() const
 {
+  NS_ABORT_IF_FALSE(!mBorderImage || mImageTracked,
+                    "Should be tracking any images we're going to use!");
   return mBorderImage;
 }
 
 inline PRBool nsStyleBorder::IsBorderImageLoaded() const
 {
   PRUint32 status;
   return mBorderImage &&
          NS_SUCCEEDED(mBorderImage->GetImageStatus(&status)) &&
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -1166,21 +1166,30 @@ nsBCTableCellFrame::PaintBackground(nsIR
                                     PRUint32             aFlags)
 {
   // make border-width reflect the half of the border-collapse
   // assigned border that's inside the cell
   nsMargin borderWidth;
   GetBorderWidth(borderWidth);
 
   nsStyleBorder myBorder(*GetStyleBorder());
+  // We're making an ephemeral stack copy here, so just copy this debug-only
+  // member to prevent assertions.
+#ifdef DEBUG
+  myBorder.mImageTracked = GetStyleBorder()->mImageTracked;
+#endif
 
   NS_FOR_CSS_SIDES(side) {
     myBorder.SetBorderWidth(side, borderWidth.side(side));
   }
 
   nsRect rect(aPt, GetSize());
   // bypassing nsCSSRendering::PaintBackground is safe because this kind
   // of frame cannot be used for the root element
   nsCSSRendering::PaintBackgroundWithSC(PresContext(), aRenderingContext, this,
                                         aDirtyRect, rect,
                                         GetStyleContext(), myBorder,
                                         aFlags, nsnull);
+
+#ifdef DEBUG
+  myBorder.mImageTracked = false;
+#endif
 }