Bug 531371. Correctly propagate the backround from a <body style="display: table"> to the viewport as needed. r=bzbarsky
authorRobert O'Callahan <robert@ocallahan.org>
Tue, 01 Dec 2009 12:21:00 -0500
changeset 35300 4f6f09ec444781ee31866476b2c5c4549b2d39f9
parent 35299 568231ef38d94a9b32990b92cb457430ceadd20b
child 35301 7eee0279ea09bc92e54c6a441ce7cc7dbd14e77d
push id10558
push userbzbarsky@mozilla.com
push dateTue, 01 Dec 2009 17:22:24 +0000
treeherdermozilla-central@4f6f09ec4447 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs531371
milestone1.9.3a1pre
Bug 531371. Correctly propagate the backround from a <body style="display: table"> to the viewport as needed. r=bzbarsky
content/base/src/nsGenericElement.cpp
layout/base/nsCSSRendering.cpp
layout/base/nsCSSRendering.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/reftests/bugs/531371-1-ref.html
layout/reftests/bugs/531371-1.html
layout/reftests/bugs/reftest.list
layout/style/nsComputedDOMStyle.cpp
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -1127,19 +1127,17 @@ nsNSElementTearoff::GetElementsByClassNa
 {
   return nsDocument::GetElementsByClassNameHelper(mContent, aClasses, aReturn);
 }
 
 nsIFrame*
 nsGenericElement::GetStyledFrame()
 {
   nsIFrame *frame = GetPrimaryFrame(Flush_Layout);
-
-  return (frame && frame->GetType() == nsGkAtoms::tableOuterFrame) ?
-    frame->GetFirstChild(nsnull) : frame;
+  return frame ? nsLayoutUtils::GetStyleFrame(frame) : nsnull;
 }
 
 void
 nsGenericElement::GetOffsetRect(nsRect& aRect, nsIContent** aOffsetParent)
 {
   *aOffsetParent = nsnull;
   aRect = nsRect();
 
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -957,17 +957,17 @@ nsCSSRendering::IsCanvasFrame(nsIFrame* 
   return frameType == nsGkAtoms::canvasFrame ||
          frameType == nsGkAtoms::rootFrame ||
          frameType == nsGkAtoms::pageFrame ||
          frameType == nsGkAtoms::pageContentFrame ||
          frameType == nsGkAtoms::viewportFrame;
 }
 
 nsIFrame*
-nsCSSRendering::FindRootFrame(nsIFrame* aForFrame)
+nsCSSRendering::FindBackgroundStyleFrame(nsIFrame* aForFrame)
 {
   const nsStyleBackground* result = aForFrame->GetStyleBackground();
 
   // Check if we need to do propagation from BODY rather than HTML.
   if (result->IsTransparent()) {
     nsIContent* content = aForFrame->GetContent();
     // The root element content can't be null. We wouldn't know what
     // frame to create for aFrame.
@@ -985,17 +985,17 @@ nsCSSRendering::FindRootFrame(nsIFrame* 
         // nsParser::Terminate will call |DidBuildModel| methods
         // through to the content sink, which will call |StartLayout|
         // and thus |InitialReflow| on the pres shell.  See bug 119351
         // for the ugly details.
         if (bodyContent) {
           nsIFrame *bodyFrame = aForFrame->PresContext()->GetPresShell()->
             GetPrimaryFrameFor(bodyContent);
           if (bodyFrame) {
-            return bodyFrame;
+            return nsLayoutUtils::GetStyleFrame(bodyFrame);
           }
         }
       }
     }
   }
 
   return aForFrame;
 }
@@ -1025,17 +1025,17 @@ nsCSSRendering::FindRootFrame(nsIFrame* 
  *
  * |FindBackground| returns true if a background should be painted, and
  * the resulting style context to use for the background information
  * will be filled in to |aBackground|.
  */
 const nsStyleBackground*
 nsCSSRendering::FindRootFrameBackground(nsIFrame* aForFrame)
 {
-  return FindRootFrame(aForFrame)->GetStyleBackground();
+  return FindBackgroundStyleFrame(aForFrame)->GetStyleBackground();
 }
 
 inline PRBool
 FindElementBackground(nsIFrame* aForFrame, nsIFrame* aRootElementFrame,
                       const nsStyleBackground** aBackground)
 {
   if (aForFrame == aRootElementFrame) {
     // We must have propagated our background to the viewport or canvas. Abort.
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -133,19 +133,23 @@ struct nsCSSRendering {
   static void PaintGradient(nsPresContext* aPresContext,
                             nsIRenderingContext& aRenderingContext,
                             nsStyleGradient* aGradient,
                             const nsRect& aDirtyRect,
                             const nsRect& aOneCellArea,
                             const nsRect& aFillArea);
 
   /**
-   * Gets the root frame for the frame
+   * Find the frame whose background style should be used to draw the
+   * canvas background. aForFrame must be the frame for the root element
+   * whose background style should be used. This function will return
+   * aForFrame unless the <body> background should be propagated, in
+   * which case we return the frame associated with the <body>'s background.
    */
-  static nsIFrame* FindRootFrame(nsIFrame* aForFrame);
+  static nsIFrame* FindBackgroundStyleFrame(nsIFrame* aForFrame);
 
   /**
    * @return PR_TRUE if |aFrame| is a canvas frame, in the CSS sense.
    */
   static PRBool IsCanvasFrame(nsIFrame* aFrame);
 
   /**
    * Fill in an nsStyleBackground to be used to paint the background
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -222,16 +222,29 @@ nsLayoutUtils::GetClosestFrameOfType(nsI
   for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent()) {
     if (frame->GetType() == aFrameType) {
       return frame;
     }
   }
   return nsnull;
 }
 
+// static
+nsIFrame*
+nsLayoutUtils::GetStyleFrame(nsIFrame* aFrame)
+{
+  if (aFrame->GetType() == nsGkAtoms::tableOuterFrame) {
+    nsIFrame* inner = aFrame->GetFirstChild(nsnull);
+    NS_ASSERTION(inner, "Outer table must have an inner");
+    return inner;
+  }
+
+  return aFrame;
+}
+
 nsIFrame*
 nsLayoutUtils::GetFloatFromPlaceholder(nsIFrame* aFrame) {
   NS_ASSERTION(nsGkAtoms::placeholderFrame == aFrame->GetType(),
                "Must have a placeholder here");
   if (aFrame->GetStateBits() & PLACEHOLDER_FOR_FLOAT) {
     nsIFrame *outOfFlowFrame =
       nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
     NS_ASSERTION(outOfFlowFrame->GetStyleDisplay()->IsFloating(),
@@ -2785,17 +2798,17 @@ nsLayoutUtils::GetClosestLayer(nsIFrame*
   return aFrame->PresContext()->PresShell()->FrameManager()->GetRootFrame();
 }
 
 gfxPattern::GraphicsFilter
 nsLayoutUtils::GetGraphicsFilterForFrame(nsIFrame* aForFrame)
 {
 #ifdef MOZ_SVG
   nsIFrame *frame = nsCSSRendering::IsCanvasFrame(aForFrame) ?
-    nsCSSRendering::FindRootFrame(aForFrame) : aForFrame;
+    nsCSSRendering::FindBackgroundStyleFrame(aForFrame) : aForFrame;
 
   switch (frame->GetStyleSVG()->mImageRendering) {
   case NS_STYLE_IMAGE_RENDERING_OPTIMIZESPEED:
     return gfxPattern::FILTER_FAST;
   case NS_STYLE_IMAGE_RENDERING_OPTIMIZEQUALITY:
     return gfxPattern::FILTER_BEST;
   case NS_STYLE_IMAGE_RENDERING_CRISPEDGES:
     return gfxPattern::FILTER_NEAREST;
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -117,16 +117,24 @@ public:
    *         such ancestor exists
    */
   static nsIFrame* GetPageFrame(nsIFrame* aFrame)
   {
     return GetClosestFrameOfType(aFrame, nsGkAtoms::pageFrame);
   }
 
   /**
+   * Given a frame which is the primary frame for an element,
+   * return the frame that has the non-psuedoelement style context for
+   * the content.
+   * This is aPrimaryFrame itself except for tableOuter frames.
+   */
+  static nsIFrame* GetStyleFrame(nsIFrame* aPrimaryFrame);
+
+  /**
    * IsGeneratedContentFor returns PR_TRUE if aFrame is the outermost
    * frame for generated content of type aPseudoElement for aContent.
    * aFrame *might not* have the aPseudoElement pseudo-style! For example
    * it might be a table outer frame and the inner table frame might
    * have the pseudo-style.
    *
    * @param aContent the content node we're looking at.  If this is
    *        null, then we just assume that aFrame has the right content
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/531371-1-ref.html
@@ -0,0 +1,3 @@
+<!DOCTYPE HTML>
+<html style="display:table; background:lime;">
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/531371-1.html
@@ -0,0 +1,5 @@
+<!DOCTYPE HTML>
+<html>
+<body style="display:table; background:lime;">
+</body>
+</html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1342,9 +1342,10 @@ fails-if(MOZ_WIDGET_TOOLKIT!="cocoa") ==
 == 527464-1.html 527464-ref.html
 == 528038-1a.html 528038-1-ref.html
 == 528038-1b.html 528038-1-ref.html
 == 528038-1c.html 528038-1-ref.html
 == 528038-1d.html 528038-1-ref.html
 == 528038-1e.html 528038-1-ref.html
 == 528038-1f.html 528038-1-ref.html
 == 528038-2.html 528038-2-ref.html
+== 531371-1.html 531371-1-ref.html
 == 530686-1.html 530686-1-ref.html
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -312,32 +312,16 @@ nsComputedDOMStyle::GetPropertyValue(con
 
   if (val) {
     rv = val->GetCssText(aReturn);
   }
 
   return rv;
 }
 
-static nsStyleContext*
-GetStyleContextForFrame(nsIFrame* aFrame)
-{
-  nsStyleContext* styleContext = aFrame->GetStyleContext();
-
-  /* For tables the primary frame is the "outer frame" but the style
-   * rules are applied to the "inner frame".  Luckily, the "outer
-   * frame" actually inherits style from the "inner frame" so we can
-   * just move one level up in the style context hierarchy....
-   */
-  if (aFrame->GetType() == nsGkAtoms::tableOuterFrame)
-    return styleContext->GetParent();
-
-  return styleContext;
-}    
-
 /* static */
 already_AddRefed<nsStyleContext>
 nsComputedDOMStyle::GetStyleContextForContent(nsIContent* aContent,
                                               nsIAtom* aPseudo,
                                               nsIPresShell* aPresShell)
 {
   NS_ASSERTION(aContent->IsNodeOfType(nsINode::eELEMENT),
                "aContent must be an element");
@@ -368,17 +352,18 @@ nsComputedDOMStyle::GetStyleContextForCo
     aPresShell = GetPresShellForContent(aContent);
     if (!aPresShell)
       return nsnull;
   }
 
   if (!aPseudo) {
     nsIFrame* frame = aPresShell->GetPrimaryFrameFor(aContent);
     if (frame) {
-      nsStyleContext* result = GetStyleContextForFrame(frame);
+      nsStyleContext* result =
+        nsLayoutUtils::GetStyleFrame(frame)->GetStyleContext();
       // Don't use the style context if it was influenced by
       // pseudo-elements, since then it's not the primary style
       // for this element.
       if (!result->HasPseudoElementData()) {
         // this function returns an addrefed style context
         result->AddRef();
         return result;
       }