Bug 505184. When 'deflation' of the background area is not required, paint table backgrounds using a dedicated nsDisplayBackground instead of the multipurpose nsDisplayTableBorderBackground. r=fantasai
authorRobert O'Callahan <robert@ocallahan.org>
Wed, 22 Jul 2009 12:44:52 +1200
changeset 30511 52021f21d6c4b8da714a76a306f7689117d14b23
parent 30510 b5bc3aa9111b327bc783a17b21f1ddc93f542b24
child 30512 dea7d0133961e97ff0fbb81105b73ba9f452b6d9
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfantasai
bugs505184
milestone1.9.2a1pre
Bug 505184. When 'deflation' of the background area is not required, paint table backgrounds using a dedicated nsDisplayBackground instead of the multipurpose nsDisplayTableBorderBackground. r=fantasai
gfx/public/nsMargin.h
layout/tables/nsTableFrame.cpp
layout/tables/nsTableFrame.h
layout/tables/nsTablePainter.cpp
layout/tables/nsTablePainter.h
--- a/gfx/public/nsMargin.h
+++ b/gfx/public/nsMargin.h
@@ -99,16 +99,18 @@ struct nsMargin {
                                                  right += aMargin.right;
                                                  bottom += aMargin.bottom;
                                                  return *this;}
   nsMargin& operator-=(const nsMargin& aMargin) {left -= aMargin.left;
                                                  top -= aMargin.top;
                                                  right -= aMargin.right;
                                                  bottom -= aMargin.bottom;
                                                  return *this;}
+
+  PRBool IsZero() { return !left && !top && !right && !bottom; }
 };
 
 struct nsIntMargin {
   PRInt32 top, right, bottom, left;
 
   // Constructors
   nsIntMargin() {}
   nsIntMargin(const nsIntMargin& aMargin) {*this = aMargin;}
@@ -133,11 +135,13 @@ struct nsIntMargin {
   PRBool operator!=(const nsIntMargin& aMargin) const {
     return (PRBool) ((left != aMargin.left) || (top != aMargin.top) ||
                      (right != aMargin.right) || (bottom != aMargin.bottom));
   }
   nsIntMargin operator+(const nsIntMargin& aMargin) const {
     return nsIntMargin(left + aMargin.left, top + aMargin.top,
                     right + aMargin.right, bottom + aMargin.bottom);
   }
+
+  PRBool IsZero() { return !left && !top && !right && !bottom; }
 };
 
 #endif /* NSMARGIN_H */
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -1404,62 +1404,65 @@ nsTableFrame::BuildDisplayList(nsDisplay
                                const nsRect&           aDirtyRect,
                                const nsDisplayListSet& aLists)
 {
   if (!IsVisibleInSelection(aBuilder))
     return NS_OK;
 
   DO_GLOBAL_REFLOW_COUNT_DSP_COLOR("nsTableFrame", NS_RGB(255,128,255));
 
+  if (GetStyleVisibility()->IsVisible()) {
+    nsMargin deflate = GetDeflationForBackground(PresContext());
+    // If 'deflate' is (0,0,0,0) then we can paint the table background
+    // in its own display item, so do that to take advantage of
+    // opacity and visibility optimizations
+    if (deflate.IsZero()) {
+      nsresult rv = DisplayBackgroundUnconditional(aBuilder, aLists, PR_FALSE);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+  }
+
   // This background is created regardless of whether this frame is
   // visible or not. Visibility decisions are delegated to the
-  // table background painter.
+  // table background painter. This handles borders and backgrounds
+  // for the table.
   nsDisplayTableItem* item = new (aBuilder) nsDisplayTableBorderBackground(this);
   nsresult rv = aLists.BorderBackground()->AppendNewToTop(item);
   NS_ENSURE_SUCCESS(rv, rv);
   
   return DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, item);
 }
 
+nsMargin
+nsTableFrame::GetDeflationForBackground(nsPresContext* aPresContext) const
+{
+  if (eCompatibility_NavQuirks != aPresContext->CompatibilityMode() ||
+      !IsBorderCollapse())
+    return nsMargin(0,0,0,0);
+
+  return GetOuterBCBorder();
+}
+
 // XXX We don't put the borders and backgrounds in tree order like we should.
 // That requires some major surgery which we aren't going to do right now.
 void
 nsTableFrame::PaintTableBorderBackground(nsIRenderingContext& aRenderingContext,
                                          const nsRect& aDirtyRect,
                                          nsPoint aPt)
 {
   nsPresContext* presContext = PresContext();
 
   TableBackgroundPainter painter(this, TableBackgroundPainter::eOrigin_Table,
                                  presContext, aRenderingContext,
                                  aDirtyRect, aPt);
-  nsresult rv;
-  
-  if (eCompatibility_NavQuirks == presContext->CompatibilityMode()) {
-    nsMargin deflate(0,0,0,0);
-    if (IsBorderCollapse()) {
-      PRInt32 p2t = nsPresContext::AppUnitsPerCSSPixel();
-      BCPropertyData* propData =
-        (BCPropertyData*)nsTableFrame::GetProperty((nsIFrame*)this,
-                                                   nsGkAtoms::tableBCProperty,
-                                                   PR_FALSE);
-      if (propData) {
-        deflate.top    = BC_BORDER_TOP_HALF_COORD(p2t, propData->mTopBorderWidth);
-        deflate.right  = BC_BORDER_RIGHT_HALF_COORD(p2t, propData->mRightBorderWidth);
-        deflate.bottom = BC_BORDER_BOTTOM_HALF_COORD(p2t, propData->mBottomBorderWidth);
-        deflate.left   = BC_BORDER_LEFT_HALF_COORD(p2t, propData->mLeftBorderWidth);
-      }
-    }
-    rv = painter.PaintTable(this, &deflate);
-    if (NS_FAILED(rv)) return;
-  }
-  else {
-    rv = painter.PaintTable(this, nsnull);
-    if (NS_FAILED(rv)) return;
-  }
+  nsMargin deflate = GetDeflationForBackground(presContext);
+  // If 'deflate' is (0,0,0,0) then we'll paint the table background
+  // in a separate display item, so don't do it here.
+  nsresult rv = painter.PaintTable(this, deflate, !deflate.IsZero());
+  if (NS_FAILED(rv)) return;
 
   if (GetStyleVisibility()->IsVisible()) {
     const nsStyleBorder* border = GetStyleBorder();
     if (!IsBorderCollapse()) {
       PRIntn skipSides = GetSkipSides();
       nsRect rect(aPt, mRect.Size());
       nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
                                   aDirtyRect, rect, *border, mStyleContext,
@@ -2588,16 +2591,17 @@ nsTableFrame::GetIncludedOuterBCBorder()
   return border;
 }
 
 nsMargin
 nsTableFrame::GetExcludedOuterBCBorder() const
 {
   return GetOuterBCBorder() - GetIncludedOuterBCBorder();
 }
+
 static
 void GetSeparateModelBorderPadding(const nsHTMLReflowState* aReflowState,
                                    nsStyleContext&          aStyleContext,
                                    nsMargin&                aBorderPadding)
 {
   // XXXbz Either we _do_ have a reflow state and then we can use its
   // mComputedBorderPadding or we don't and then we get the padding
   // wrong!
--- a/layout/tables/nsTableFrame.h
+++ b/layout/tables/nsTableFrame.h
@@ -293,16 +293,22 @@ public:
   nsMargin GetIncludedOuterBCBorder() const;
 
   /** Same as above, but only if it's excluded from the border-box width
    *  of the table.  This is the area that leaks out into the margin
    *  (or potentially past it, if there is no margin).
    */
   nsMargin GetExcludedOuterBCBorder() const;
 
+  /**
+   * In quirks mode, the size of the table background is reduced
+   * by the outer BC border. Compute the reduction needed.
+   */
+  nsMargin GetDeflationForBackground(nsPresContext* aPresContext) const;
+
   /** Get width of table + colgroup + col collapse: elements that
    *  continue along the length of the whole left side.
    *  see nsTablePainter about continuous borders
    */
   nscoord GetContinuousLeftBCBorderWidth() const;
   void SetContinuousLeftBCBorderWidth(nscoord aValue);
 
   friend class nsDelayedCalcBCBorders;
--- a/layout/tables/nsTablePainter.cpp
+++ b/layout/tables/nsTablePainter.cpp
@@ -277,25 +277,23 @@ TableBackgroundPainter::~TableBackground
   mRow.Destroy(mPresContext);
   MOZ_COUNT_DTOR(TableBackgroundPainter);
 }
 
 nsresult
 TableBackgroundPainter::PaintTableFrame(nsTableFrame*         aTableFrame,
                                         nsTableRowGroupFrame* aFirstRowGroup,
                                         nsTableRowGroupFrame* aLastRowGroup,
-                                        nsMargin*             aDeflate)
+                                        const nsMargin&       aDeflate)
 {
   NS_PRECONDITION(aTableFrame, "null frame");
   TableBackgroundData tableData;
   tableData.SetFull(aTableFrame);
   tableData.mRect.MoveTo(0,0); //using table's coords
-  if (aDeflate) {
-    tableData.mRect.Deflate(*aDeflate);
-  }
+  tableData.mRect.Deflate(aDeflate);
   if (mIsBorderCollapse && tableData.ShouldSetBCBorder()) {
     if (aFirstRowGroup && aLastRowGroup && mNumCols > 0) {
       //only handle non-degenerate tables; we need a more robust BC model
       //to make degenerate tables' borders reasonable to deal with
       nsMargin border, tempBorder;
       nsTableColFrame* colFrame = aTableFrame->GetColFrame(mNumCols - 1);
       if (colFrame) {
         colFrame->GetContinuousBCBorderWidth(tempBorder);
@@ -349,32 +347,37 @@ TableBackgroundPainter::TranslateContext
         mCols[i].mColGroup->mRect.MoveBy(-aDX, -aDY);
         lastColGroup = mCols[i].mColGroup;
       }
     }
   }
 }
 
 nsresult
-TableBackgroundPainter::PaintTable(nsTableFrame* aTableFrame,
-                                   nsMargin*     aDeflate)
+TableBackgroundPainter::PaintTable(nsTableFrame*   aTableFrame,
+                                   const nsMargin& aDeflate,
+                                   PRBool          aPaintTableBackground)
 {
   NS_PRECONDITION(aTableFrame, "null table frame");
 
   nsTableFrame::RowGroupArray rowGroups;
   aTableFrame->OrderRowGroups(rowGroups);
 
   if (rowGroups.Length() < 1) { //degenerate case
-    PaintTableFrame(aTableFrame, nsnull, nsnull, nsnull);
+    if (aPaintTableBackground) {
+      PaintTableFrame(aTableFrame, nsnull, nsnull, nsMargin(0,0,0,0));
+    }
     /* No cells; nothing else to paint */
     return NS_OK;
   }
 
-  PaintTableFrame(aTableFrame, rowGroups[0], rowGroups[rowGroups.Length() - 1],
-                  aDeflate);
+  if (aPaintTableBackground) {
+    PaintTableFrame(aTableFrame, rowGroups[0], rowGroups[rowGroups.Length() - 1],
+                    aDeflate);
+  }
 
   /*Set up column background/border data*/
   if (mNumCols > 0) {
     nsFrameList& colGroupList = aTableFrame->GetColGroups();
     NS_ASSERTION(colGroupList.FirstChild(), "table should have at least one colgroup");
 
     mCols = new ColData[mNumCols];
     if (!mCols) return NS_ERROR_OUT_OF_MEMORY;
--- a/layout/tables/nsTablePainter.h
+++ b/layout/tables/nsTablePainter.h
@@ -88,31 +88,36 @@ class TableBackgroundPainter
        In border-collapse, the *table* paints the cells' borders,
        so we need to make sure the backgrounds get painted first
        (underneath) by doing a cell-background-only painting pass.
     */
 
     /* ~*~ Using nsTablePainter Background Painting ~*~
 
        A call to PaintTable will normally paint all of the table's
-       elements (except the cells in non-BC). Elements with views
-       however, will be skipped and must create their own painter
-       to call the appropriate paint function in their ::Paint
+       elements (except for the table background, if aPaintTableBackground
+       is false).
+       Elements with views however, will be skipped and must create their
+       own painter to call the appropriate paint function in their ::Paint
        method (e.g. painter.PaintRow in nsTableRow::Paint)
     */
 
-    /** Paint background for the table frame and its children down through cells
+    /** Paint background for the table frame (if requested) and its children
+      * down through cells.
       * (Cells themselves will only be painted in border collapse)
       * Table must do a flagged TABLE_BG_PAINT ::Paint call on its
       * children afterwards
       * @param aTableFrame - the table frame
       * @param aDeflate    - deflation needed to bring table's mRect
       *                      to the outer grid lines in border-collapse
+      * @param aPaintTableBackground - if true, the table background
+      * is included, otherwise it isn't
       */
-    nsresult PaintTable(nsTableFrame* aTableFrame, nsMargin* aDeflate);
+    nsresult PaintTable(nsTableFrame* aTableFrame, const nsMargin& aDeflate,
+                        PRBool aPaintTableBackground);
 
     /** Paint background for the row group and its children down through cells
       * (Cells themselves will only be painted in border collapse)
       * Standards mode only
       * Table Row Group must do a flagged TABLE_BG_PAINT ::Paint call on its
       * children afterwards
       * @param aFrame - the table row group frame
       */
@@ -138,17 +143,17 @@ class TableBackgroundPainter
       * @param aLastRowGroup   - the last (in layout order) row group
       *                          may be null
       * @param aDeflate        - adjustment to frame's rect (used for quirks BC)
       *                          may be null
       */
     nsresult PaintTableFrame(nsTableFrame*         aTableFrame,
                              nsTableRowGroupFrame* aFirstRowGroup,
                              nsTableRowGroupFrame* aLastRowGroup,
-                             nsMargin*             aDeflate = nsnull);
+                             const nsMargin&       aDeflate);
 
     /* aPassThrough params indicate whether to paint the element or to just
      * pass through and paint underlying layers only
      * See Public versions for function descriptions
      */
     nsresult PaintRowGroup(nsTableRowGroupFrame* aFrame,
                            PRBool                aPassThrough);
     nsresult PaintRow(nsTableRowFrame* aFrame,