Composited negative z-index elements are hidden behind the body sometimes
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 27 Nov 2016 02:06:59 +0000 (02:06 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 27 Nov 2016 02:06:59 +0000 (02:06 +0000)
https://bugs.webkit.org/show_bug.cgi?id=165080
rdar://problem/22260229

Reviewed by Zalan Bujtas.

Source/WebCore:

If the <body> falls into the "directly composited background color" code path
(say, because it's composited because of composited negative z-index children,
and has content of its own), then we failed to take root background propagation
into account, and put the opaque root background color on the body's layer.

Fix by sharing some code from RenderBox related to whether the body's renderer
paints its background.

Tests cover the buggy case, and the case where the <html> has its own background color.

Tests: compositing/backgrounds/negative-z-index-behind-body-non-propagated.html
       compositing/backgrounds/negative-z-index-behind-body.html

* rendering/RenderBox.cpp:
(WebCore::RenderBox::paintsOwnBackground):
(WebCore::RenderBox::paintBackground):
(WebCore::RenderBox::backgroundIsKnownToBeOpaqueInRect):
(WebCore::skipBodyBackground): Deleted.
* rendering/RenderBox.h:
* rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::updateDirectlyCompositedBackgroundColor):

LayoutTests:

* compositing/backgrounds/negative-z-index-behind-body-expected.html: Added.
* compositing/backgrounds/negative-z-index-behind-body-non-propagated-expected.html: Added.
* compositing/backgrounds/negative-z-index-behind-body-non-propagated.html: Added.
* compositing/backgrounds/negative-z-index-behind-body.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208981 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/compositing/backgrounds/negative-z-index-behind-body-expected.html [new file with mode: 0644]
LayoutTests/compositing/backgrounds/negative-z-index-behind-body-non-propagated-expected.html [new file with mode: 0644]
LayoutTests/compositing/backgrounds/negative-z-index-behind-body-non-propagated.html [new file with mode: 0644]
LayoutTests/compositing/backgrounds/negative-z-index-behind-body.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderBox.cpp
Source/WebCore/rendering/RenderBox.h
Source/WebCore/rendering/RenderLayerBacking.cpp

index c526a3a..4d02394 100644 (file)
@@ -1,5 +1,18 @@
 2016-11-26  Simon Fraser  <simon.fraser@apple.com>
 
+        Composited negative z-index elements are hidden behind the body sometimes
+        https://bugs.webkit.org/show_bug.cgi?id=165080
+        rdar://problem/22260229
+
+        Reviewed by Zalan Bujtas.
+
+        * compositing/backgrounds/negative-z-index-behind-body-expected.html: Added.
+        * compositing/backgrounds/negative-z-index-behind-body-non-propagated-expected.html: Added.
+        * compositing/backgrounds/negative-z-index-behind-body-non-propagated.html: Added.
+        * compositing/backgrounds/negative-z-index-behind-body.html: Added.
+
+2016-11-26  Simon Fraser  <simon.fraser@apple.com>
+
         Convert testharnessreport.js to LF linebreaks, from CRLF, which broke patches.
 
         * resources/testharnessreport.js:
diff --git a/LayoutTests/compositing/backgrounds/negative-z-index-behind-body-expected.html b/LayoutTests/compositing/backgrounds/negative-z-index-behind-body-expected.html
new file mode 100644 (file)
index 0000000..3084cb6
--- /dev/null
@@ -0,0 +1,9 @@
+<style>
+.green {
+    background-color: green;
+    width: 200px;
+    height: 200px;
+}
+</style>
+<body>
+<div class="green"></div>
diff --git a/LayoutTests/compositing/backgrounds/negative-z-index-behind-body-non-propagated-expected.html b/LayoutTests/compositing/backgrounds/negative-z-index-behind-body-non-propagated-expected.html
new file mode 100644 (file)
index 0000000..4ad7e66
--- /dev/null
@@ -0,0 +1,21 @@
+<style>
+html {
+    background: gray;
+}
+body {
+    background: silver;
+}
+
+div {
+    position: absolute;
+    z-index: -1;
+}
+.green {
+    background-color: green;
+    width: 200px;
+    height: 200px;
+}
+</style>
+<body>
+<div class="green"></div>
+<div></div>
diff --git a/LayoutTests/compositing/backgrounds/negative-z-index-behind-body-non-propagated.html b/LayoutTests/compositing/backgrounds/negative-z-index-behind-body-non-propagated.html
new file mode 100644 (file)
index 0000000..92a8a46
--- /dev/null
@@ -0,0 +1,23 @@
+<style>
+html {
+    background: gray;
+}
+body {
+    position: relative;
+    background: silver;
+}
+
+div {
+    position: absolute;
+    z-index: -1;
+    transform: translateZ(0);
+}
+.green {
+    background-color: green;
+    width: 200px;
+    height: 200px;
+}
+</style>
+<body>
+<div class="green"></div>
+<div></div>
diff --git a/LayoutTests/compositing/backgrounds/negative-z-index-behind-body.html b/LayoutTests/compositing/backgrounds/negative-z-index-behind-body.html
new file mode 100644 (file)
index 0000000..efc8778
--- /dev/null
@@ -0,0 +1,21 @@
+<style>
+body {
+    position: relative;
+    background: white;
+}
+
+div {
+    position: absolute;
+    z-index: -1;
+    transform: translateZ(0);
+}
+
+.green {
+    background-color: green;
+    width: 200px;
+    height: 200px;
+}
+</style>
+<body>
+<div class="green"></div>
+<div></div>
index 03ca92b..5552e4c 100644 (file)
@@ -1,3 +1,33 @@
+2016-11-26  Simon Fraser  <simon.fraser@apple.com>
+
+        Composited negative z-index elements are hidden behind the body sometimes
+        https://bugs.webkit.org/show_bug.cgi?id=165080
+        rdar://problem/22260229
+
+        Reviewed by Zalan Bujtas.
+
+        If the <body> falls into the "directly composited background color" code path
+        (say, because it's composited because of composited negative z-index children,
+        and has content of its own), then we failed to take root background propagation
+        into account, and put the opaque root background color on the body's layer.
+
+        Fix by sharing some code from RenderBox related to whether the body's renderer
+        paints its background.
+        
+        Tests cover the buggy case, and the case where the <html> has its own background color.
+
+        Tests: compositing/backgrounds/negative-z-index-behind-body-non-propagated.html
+               compositing/backgrounds/negative-z-index-behind-body.html
+
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::paintsOwnBackground):
+        (WebCore::RenderBox::paintBackground):
+        (WebCore::RenderBox::backgroundIsKnownToBeOpaqueInRect):
+        (WebCore::skipBodyBackground): Deleted.
+        * rendering/RenderBox.h:
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::RenderLayerBacking::updateDirectlyCompositedBackgroundColor):
+
 2016-11-25  Myles C. Maxfield  <mmaxfield@apple.com>
 
         [CSS Font Loading] FontFace.load() promises don't always fire
index fa4542d..017d802 100644 (file)
@@ -130,17 +130,6 @@ static void removeControlStatesForRenderer(const RenderBox& renderer)
 
 bool RenderBox::s_hadOverflowClip = false;
 
-static bool skipBodyBackground(const RenderBox* bodyElementRenderer)
-{
-    ASSERT(bodyElementRenderer->isBody());
-    // The <body> only paints its background if the root element has defined a background independent of the body,
-    // or if the <body>'s parent is not the document element's renderer (e.g. inside SVG foreignObject).
-    auto documentElementRenderer = bodyElementRenderer->document().documentElement()->renderer();
-    return documentElementRenderer
-        && !documentElementRenderer->hasBackground()
-        && (documentElementRenderer == bodyElementRenderer->parent());
-}
-
 RenderBox::RenderBox(Element& element, RenderStyle&& style, BaseTypeFlags baseTypeFlags)
     : RenderBoxModelObject(element, WTFMove(style), baseTypeFlags)
 {
@@ -1383,16 +1372,33 @@ void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& pai
         paintInfo.context().endTransparencyLayer();
 }
 
+bool RenderBox::paintsOwnBackground() const
+{
+    if (isBody()) {
+        // The <body> only paints its background if the root element has defined a background independent of the body,
+        // or if the <body>'s parent is not the document element's renderer (e.g. inside SVG foreignObject).
+        auto documentElementRenderer = document().documentElement()->renderer();
+        return !documentElementRenderer
+            || documentElementRenderer->hasBackground()
+            || (documentElementRenderer != parent());
+    }
+    
+    return true;
+}
+
 void RenderBox::paintBackground(const PaintInfo& paintInfo, const LayoutRect& paintRect, BackgroundBleedAvoidance bleedAvoidance)
 {
     if (isDocumentElementRenderer()) {
         paintRootBoxFillLayers(paintInfo);
         return;
     }
-    if (isBody() && skipBodyBackground(this))
+
+    if (!paintsOwnBackground())
         return;
+
     if (backgroundIsKnownToBeObscured(paintRect.location()) && !boxShadowShouldBeAppliedToBackground(paintRect.location(), bleedAvoidance))
         return;
+
     paintFillLayers(paintInfo, style().visitedDependentColor(CSSPropertyBackgroundColor), style().backgroundLayers(), paintRect, bleedAvoidance);
 }
 
@@ -1419,7 +1425,7 @@ bool RenderBox::getBackgroundPaintedExtent(const LayoutPoint& paintOffset, Layou
 
 bool RenderBox::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
 {
-    if (isBody() && skipBodyBackground(this))
+    if (!paintsOwnBackground())
         return false;
 
     Color backgroundColor = style().visitedDependentColor(CSSPropertyBackgroundColor);
index 2a68cfd..0529204 100644 (file)
@@ -56,6 +56,9 @@ public:
     }
 
     bool backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const final;
+    
+    // Returns false for the body renderer if its background is propagated to the root.
+    bool paintsOwnBackground() const;
 
     // Use this with caution! No type checking is done!
     RenderBox* firstChildBox() const;
index 0324723..ed11088 100644 (file)
@@ -1809,7 +1809,7 @@ Color RenderLayerBacking::rendererBackgroundColor() const
 
 void RenderLayerBacking::updateDirectlyCompositedBackgroundColor(bool isSimpleContainer, bool& didUpdateContentsRect)
 {
-    if (!isSimpleContainer) {
+    if (!isSimpleContainer || (is<RenderBox>(renderer()) && !downcast<RenderBox>(renderer()).paintsOwnBackground())) {
         m_graphicsLayer->setContentsToSolidColor(Color());
         return;
     }