Bug 582476. Part 2. When painting SVG foreign objects make sure to set the painting to window flag correctly. r=roc a=blocking-betaN+
authorTimothy Nikkel <tnikkel@gmail.com>
Thu, 14 Oct 2010 20:03:45 -0500
changeset 55826 acc4673a58ac64487ccffb0bfb936e6a78a9fcec
parent 55825 c5c038c9b33496ce7a964fbfb9b38658d23b4f9b
child 55827 62d7a16bca1a50c6bdc368fe0a18615d3474d04e
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)
reviewersroc, blocking-betaN
bugs582476
milestone2.0b8pre
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
Bug 582476. Part 2. When painting SVG foreign objects make sure to set the painting to window flag correctly. r=roc a=blocking-betaN+
layout/base/nsDisplayList.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/reftests/bugs/582476-1-helper.html
layout/reftests/bugs/582476-1-ref-helper.html
layout/reftests/bugs/582476-1-ref.svg
layout/reftests/bugs/582476-1.svg
layout/reftests/bugs/reftest.list
layout/svg/base/src/nsSVGForeignObjectFrame.cpp
layout/svg/base/src/nsSVGOuterSVGFrame.cpp
layout/svg/base/src/nsSVGOuterSVGFrame.h
layout/svg/base/src/nsSVGUtils.cpp
layout/svg/base/src/nsSVGUtils.h
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -221,17 +221,17 @@ public:
    * @return Returns if this builder had to ignore painting suppression on some
    * document when building the display list.
    */
   PRBool GetHadToIgnorePaintSuppression() { return mHadToIgnoreSuppression; }
   /**
    * Call this if we're doing normal painting to the window.
    */
   void SetPaintingToWindow(PRBool aToWindow) { mIsPaintingToWindow = aToWindow; }
-  PRBool IsPaintingToWindow() { return mIsPaintingToWindow; }
+  PRBool IsPaintingToWindow() const { return mIsPaintingToWindow; }
   /**
    * Display the caret if needed.
    */
   nsresult DisplayCaret(nsIFrame* aFrame, const nsRect& aDirtyRect,
       nsDisplayList* aList) {
     nsIFrame* frame = GetCaretFrame();
     if (aFrame != frame) {
       return NS_OK;
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1269,17 +1269,17 @@ nsLayoutUtils::PaintFrame(nsIRenderingCo
   nsDisplayListBuilder builder(aFrame, PR_FALSE, !(aFlags & PAINT_HIDE_CARET));
   nsDisplayList list;
   if (aFlags & PAINT_IN_TRANSFORM) {
     builder.SetInTransform(PR_TRUE);
   }
   if (aFlags & PAINT_SYNC_DECODE_IMAGES) {
     builder.SetSyncDecodeImages(PR_TRUE);
   }
-  if (aFlags & PAINT_WIDGET_LAYERS) {
+  if (aFlags & PAINT_WIDGET_LAYERS || aFlags & PAINT_TO_WINDOW) {
     builder.SetPaintingToWindow(PR_TRUE);
   }
   if (aFlags & PAINT_IGNORE_SUPPRESSION) {
     builder.IgnorePaintSuppression();
   }
   nsRect canvasArea(nsPoint(0, 0), aFrame->GetSize());
   if (ignoreViewportScrolling) {
     NS_ASSERTION(!aFrame->GetParent(), "must have root frame");
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -521,17 +521,18 @@ public:
 
   enum {
     PAINT_IN_TRANSFORM = 0x01,
     PAINT_SYNC_DECODE_IMAGES = 0x02,
     PAINT_WIDGET_LAYERS = 0x04,
     PAINT_IGNORE_SUPPRESSION = 0x08,
     PAINT_DOCUMENT_RELATIVE = 0x10,
     PAINT_HIDE_CARET = 0x20,
-    PAINT_ALL_CONTINUATIONS = 0x40
+    PAINT_ALL_CONTINUATIONS = 0x40,
+    PAINT_TO_WINDOW = 0x80
   };
 
   /**
    * Given aFrame, the root frame of a stacking context, paint it and its
    * descendants to aRenderingContext.
    * @param aRenderingContext a rendering context translated so that (0,0)
    * is the origin of aFrame; for best results, (0,0) should transform
    * to pixel-aligned coordinates. This can be null, in which case
@@ -547,17 +548,18 @@ public:
    * PAINT_SYNC_DECODE_IMAGES is set, we force synchronous decode on all
    * images. If PAINT_WIDGET_LAYERS is set, aFrame must be a display root,
    * and we will use the frame's widget's layer manager to paint
    * even if aRenderingContext is non-null. This is useful if you want
    * to force rendering to use the widget's layer manager for testing
    * or speed. PAINT_WIDGET_LAYERS must be set if aRenderingContext is null.
    * If PAINT_DOCUMENT_RELATIVE is used, the visible region is interpreted
    * as being relative to the document.  (Normally it's relative to the CSS
-   * viewport.)
+   * viewport.) PAINT_TO_WINDOW sets painting to window to true on the display
+   * list builder even if we can't tell that we are painting to the window.
    *
    * So there are three possible behaviours:
    * 1) PAINT_WIDGET_LAYERS is set and aRenderingContext is null; we paint
    * by calling BeginTransaction on the widget's layer manager
    * 2) PAINT_WIDGET_LAYERS is set and aRenderingContext is non-null; we
    * paint by calling BeginTransactionWithTarget on the widget's layer
    * maanger
    * 3) PAINT_WIDGET_LAYERS is not set and aRenderingContext is non-null;
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/582476-1-helper.html
@@ -0,0 +1,6 @@
+<html>
+<body>
+<div style="height: 10000px;"></div>
+<div id="x" style="height: 100px; width: 100px; background: red;"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/582476-1-ref-helper.html
@@ -0,0 +1,6 @@
+<html>
+<body>
+<div style="height: 10000px;"></div>
+<div id="x" style="height: 100px; width: 100px; background: blue;"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/582476-1-ref.svg
@@ -0,0 +1,30 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+  <script>
+    iframeLoadedFirst = false;
+    parentLoadedFirst = false;
+
+    function iframeLoad() {
+      if (parentLoadedFirst) {
+        setup();
+      } else {
+        iframeLoadedFirst = true;
+      }
+    }
+
+    window.onload = function() {
+      if (iframeLoadedFirst) {
+        setup();
+      } else {
+        parentLoadedFirst = true;
+      }
+    }
+
+    function setup() {
+      var scrollTarget = document.getElementById("ifrm").contentWindow;
+      scrollTarget.scrollTo(0,100000);
+    }
+  </script>
+  <foreignObject height="100%" width="100%">
+    <iframe id="ifrm" onload="iframeLoad();" width="100%" height="100%" xmlns="http://www.w3.org/1999/xhtml" src="582476-1-ref-helper.html"/>
+  </foreignObject>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/582476-1.svg
@@ -0,0 +1,37 @@
+<svg xmlns="http://www.w3.org/2000/svg" class="reftest-wait">
+  <script>
+    window.addEventListener("MozReftestInvalidate", doTest, false);
+
+    iframeLoadedFirst = false;
+    parentLoadedFirst = false;
+
+    function iframeLoad() {
+      if (parentLoadedFirst) {
+        setup();
+      } else {
+        iframeLoadedFirst = true;
+      }
+    }
+
+    window.onload = function() {
+      if (iframeLoadedFirst) {
+        setup();
+      } else {
+        parentLoadedFirst = true;
+      }
+    }
+
+    function setup() {
+      var scrollTarget = document.getElementById("ifrm").contentWindow;
+      scrollTarget.scrollTo(0,100000);
+    }
+
+    function doTest() {
+      document.getElementById("ifrm").contentDocument.getElementById("x").style.background = "blue";
+      document.documentElement.removeAttribute('class');
+    }
+  </script>
+  <foreignObject height="100%" width="100%">
+    <iframe id="ifrm" onload="iframeLoad();" width="100%" height="100%" xmlns="http://www.w3.org/1999/xhtml" src="582476-1-helper.html"/>
+  </foreignObject>
+</svg>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1498,16 +1498,17 @@ random-if(layersGPUAccelerated) == 57932
 HTTP(..) == 580863-1.html 580863-1-ref.html
 random-if(layersGPUAccelerated) == 581317-1.html 581317-1-ref.html
 == 581579-1.html 581579-1-ref.html
 == 582037-1a.html 582037-1-ref.html
 == 582037-1b.html 582037-1-ref.html
 == 582037-2a.html 582037-2-ref.html
 == 582037-2b.html 582037-2-ref.html
 asserts(0-1) == 582146-1.html about:blank
+== 582476-1.svg 582476-1-ref.svg
 == 584400-dash-length.svg 584400-dash-length-ref.svg
 == 584699-1.html 584699-1-ref.html
 == 585598-2.xhtml 585598-2-ref.xhtml
 == 586400-1.html 586400-1-ref.html
 == 589672-1.html 589672-1-ref.html
 == 593544-1.html 593544-1-ref.html
 == 594624-1.html 594624-1-ref.html
 == 594737-1.html 594737-1-ref.html
--- a/layout/svg/base/src/nsSVGForeignObjectFrame.cpp
+++ b/layout/svg/base/src/nsSVGForeignObjectFrame.cpp
@@ -251,19 +251,22 @@ nsSVGForeignObjectFrame::PaintSVG(nsSVGR
   nsPoint tl(NSToCoordFloor(transDirtyRect.X()),
              NSToCoordFloor(transDirtyRect.Y()));
   nsPoint br(NSToCoordCeil(transDirtyRect.XMost()),
              NSToCoordCeil(transDirtyRect.YMost()));
   nsRect kidDirtyRect(tl.x, tl.y, br.x - tl.x, br.y - tl.y);
 
   kidDirtyRect.IntersectRect(kidDirtyRect, kid->GetRect());
 
+  PRUint32 flags = nsLayoutUtils::PAINT_IN_TRANSFORM;
+  if (aContext->IsPaintingToWindow()) {
+    flags |= nsLayoutUtils::PAINT_TO_WINDOW;
+  }
   nsresult rv = nsLayoutUtils::PaintFrame(ctx, kid, nsRegion(kidDirtyRect),
-                                          NS_RGBA(0,0,0,0),
-                                          nsLayoutUtils::PAINT_IN_TRANSFORM);
+                                          NS_RGBA(0,0,0,0), flags);
 
   gfx->Restore();
 
   return rv;
 }
 
 gfxMatrix
 nsSVGForeignObjectFrame::GetTransformMatrix(nsIFrame **aOutAncestor)
--- a/layout/svg/base/src/nsSVGOuterSVGFrame.cpp
+++ b/layout/svg/base/src/nsSVGOuterSVGFrame.cpp
@@ -461,17 +461,17 @@ nsDisplaySVG::HitTest(nsDisplayListBuild
   }
 }
 
 void
 nsDisplaySVG::Paint(nsDisplayListBuilder* aBuilder,
                     nsIRenderingContext* aCtx)
 {
   static_cast<nsSVGOuterSVGFrame*>(mFrame)->
-    Paint(*aCtx, mVisibleRect, ToReferenceFrame());
+    Paint(aBuilder, *aCtx, mVisibleRect, ToReferenceFrame());
 }
 
 // helper
 static inline PRBool
 DependsOnIntrinsicSize(const nsIFrame* aEmbeddingFrame)
 {
   const nsStylePosition *pos = aEmbeddingFrame->GetStylePosition();
   const nsStyleCoord &width = pos->mWidth;
@@ -536,17 +536,18 @@ nsSVGOuterSVGFrame::BuildDisplayList(nsD
   nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return aLists.Content()->AppendNewToTop(
       new (aBuilder) nsDisplaySVG(aBuilder, this));
 }
 
 void
-nsSVGOuterSVGFrame::Paint(nsIRenderingContext& aRenderingContext,
+nsSVGOuterSVGFrame::Paint(const nsDisplayListBuilder* aBuilder,
+                          nsIRenderingContext& aRenderingContext,
                           const nsRect& aDirtyRect, nsPoint aPt)
 {
   // initialize Mozilla rendering context
   aRenderingContext.PushState();
 
   nsRect viewportRect = GetContentRect();
   nsPoint viewportOffset = aPt + viewportRect.TopLeft() - GetPosition();
   viewportRect.MoveTo(viewportOffset);
@@ -560,16 +561,20 @@ nsSVGOuterSVGFrame::Paint(nsIRenderingCo
 #if defined(DEBUG) && defined(SVG_DEBUG_PAINT_TIMING)
   PRTime start = PR_Now();
 #endif
 
   nsIntRect dirtyPxRect = dirtyRect.ToOutsidePixels(PresContext()->AppUnitsPerDevPixel());
 
   nsSVGRenderState ctx(&aRenderingContext);
 
+  if (aBuilder->IsPaintingToWindow()) {
+    ctx.SetPaintingToWindow(PR_TRUE);
+  }
+
 #ifdef XP_MACOSX
   if (mEnableBitmapFallback) {
     // nquartz fallback paths, which svg tends to trigger, need
     // a non-window context target
     ctx.GetGfxContext()->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
   }
 #endif
 
--- a/layout/svg/base/src/nsSVGOuterSVGFrame.h
+++ b/layout/svg/base/src/nsSVGOuterSVGFrame.h
@@ -106,17 +106,18 @@ public:
 
   /**
    * Get the "type" of the frame
    *
    * @see nsGkAtoms::svgOuterSVGFrame
    */
   virtual nsIAtom* GetType() const;
 
-  void Paint(nsIRenderingContext& aRenderingContext,
+  void Paint(const nsDisplayListBuilder* aBuilder,
+             nsIRenderingContext& aRenderingContext,
              const nsRect& aDirtyRect, nsPoint aPt);
 
 #ifdef DEBUG
   NS_IMETHOD GetFrameName(nsAString& aResult) const
   {
     return MakeFrameName(NS_LITERAL_STRING("SVGOuterSVG"), aResult);
   }
 #endif
--- a/layout/svg/base/src/nsSVGUtils.cpp
+++ b/layout/svg/base/src/nsSVGUtils.cpp
@@ -1531,28 +1531,28 @@ nsSVGUtils::GetNumberListValue(nsIDOMSVG
     number->GetValue(&value);
   }
   return value;
 }
 
 // ----------------------------------------------------------------------
 
 nsSVGRenderState::nsSVGRenderState(nsIRenderingContext *aContext) :
-  mRenderMode(NORMAL), mRenderingContext(aContext)
+  mRenderMode(NORMAL), mRenderingContext(aContext), mPaintingToWindow(PR_FALSE)
 {
   mGfxContext = aContext->ThebesContext();
 }
 
 nsSVGRenderState::nsSVGRenderState(gfxContext *aContext) :
-  mRenderMode(NORMAL), mGfxContext(aContext)
+  mRenderMode(NORMAL), mGfxContext(aContext), mPaintingToWindow(PR_FALSE)
 {
 }
 
 nsSVGRenderState::nsSVGRenderState(gfxASurface *aSurface) :
-  mRenderMode(NORMAL)
+  mRenderMode(NORMAL), mPaintingToWindow(PR_FALSE)
 {
   mGfxContext = new gfxContext(aSurface);
 }
 
 nsIRenderingContext*
 nsSVGRenderState::GetRenderingContext(nsIFrame *aFrame)
 {
   if (!mRenderingContext) {
--- a/layout/svg/base/src/nsSVGUtils.h
+++ b/layout/svg/base/src/nsSVGUtils.h
@@ -170,20 +170,26 @@ public:
   nsSVGRenderState(gfxASurface *aSurface);
 
   nsIRenderingContext *GetRenderingContext(nsIFrame *aFrame);
   gfxContext *GetGfxContext() { return mGfxContext; }
 
   void SetRenderMode(RenderMode aMode) { mRenderMode = aMode; }
   RenderMode GetRenderMode() { return mRenderMode; }
 
+  void SetPaintingToWindow(PRBool aPaintingToWindow) {
+    mPaintingToWindow = aPaintingToWindow;
+  }
+  PRBool IsPaintingToWindow() { return mPaintingToWindow; }
+
 private:
   RenderMode                    mRenderMode;
   nsCOMPtr<nsIRenderingContext> mRenderingContext;
   nsRefPtr<gfxContext>          mGfxContext;
+  PRPackedBool                  mPaintingToWindow;
 };
 
 class nsAutoSVGRenderMode
 {
 public:
   nsAutoSVGRenderMode(nsSVGRenderState *aState,
                       nsSVGRenderState::RenderMode aMode) : mState(aState) {
     mOriginalMode = aState->GetRenderMode();