Transform-style should not kill position:fixed
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 12 Dec 2014 01:59:37 +0000 (01:59 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 12 Dec 2014 01:59:37 +0000 (01:59 +0000)
https://bugs.webkit.org/show_bug.cgi?id=138122

Reviewed by Dean Jackson.

Source/WebCore:

Various bits of rendering code checked RenderObject::hasTransform() for various
reasons. Confusingly, this meant "has transform, or preserve-3d, or perspective".

This patch teases those behaviors apart to produce the following behavior:

1. "transform" acts as containing block for fixed position (no behavior change).
2. "transform" acts as containing block for absolute/relative position (no behavior change).
3. "perspective" does not act as containing block for fixed position (no behavior change).
4. "perspective" acts as containing block for absolute/relative position (no behavior change).
5. "preserve-3d" does not act as containing block for fixed position (behavior change).
6. "preserve-3d" acts as containing block for absolute/relative position. This is not a
behavior change, but seems like incorrect behavior (https://www.w3.org/Bugs/Public/show_bug.cgi?id=27566).
However, we may be forced to keep it for compatibility.

The gist of the change is to rename RenderObject::hasTransform() to RenderObject::hasTransformRelatedProperty(),
and add hasTransform() with the more restrictive meaning. All call sites of hasTransform() were examined
and fixed to produce the desired behaviors.

Tests: transforms/2d/perspective-not-fixed-container.html
       transforms/2d/preserve3d-not-fixed-container.html
       transforms/perspective-is-containing-block-for-absolute.html
       transforms/preserve3d-is-containing-block-for-absolute.html
       transforms/transform-is-containing-block-for-absolute.html

* css/CSSComputedStyleDeclaration.cpp:
(WebCore::computedTransform): Now we can just test hasTransform().
* rendering/LogicalSelectionOffsetCaches.h:
(WebCore::isContainingBlockCandidateForAbsolutelyPositionedObject): For now, this
can just use hasTransformRelatedProperty(), but if we change [6] above this will have
to change (as documented in the comment). Also FIXME comments about sharing code.
* rendering/RenderBox.cpp:
(WebCore::RenderBox::updateFromStyle):
(WebCore::RenderBox::mapLocalToContainer): Can just use hasTransform() now.
(WebCore::RenderBox::pushMappingToContainer): Ditto.
(WebCore::RenderBox::mapAbsoluteToLocalPoint): Ditto.
(WebCore::RenderBox::layoutOverflowRectForPropagation): Ditto.
* rendering/RenderBox.h: All transform-related properties create RenderLayers.
* rendering/RenderBoxModelObject.h: Ditto.
* rendering/RenderElement.cpp:
(WebCore::RenderElement::styleWillChange):
* rendering/RenderGeometryMap.cpp:
(WebCore::canMapBetweenRenderersViaLayers): Rename to clarify. We need to not map via
layers if we have a perspective (since we need to generate a perspective matrix). It's
OK with preserve-3d though.
(WebCore::RenderGeometryMap::pushMappingsToAncestor):
(WebCore::canMapBetweenRenderers): Deleted.
* rendering/RenderInline.cpp:
(WebCore::RenderInline::updateFromStyle):
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::updateTransform): Can just check hasTransform().
(WebCore::RenderLayer::updateLayerPosition): Avoid calling parent() and enclosingPositionedAncestor() twice.
(WebCore::RenderLayer::perspectiveTransform): Do the fast bit check hasTransformRelatedProperty() first.
(WebCore::RenderLayer::perspectiveOrigin): Ditto.
(WebCore::isContainerForPositioned): This code has to now have different behavior for absolute and fixed
position. Changed it to call existing functions, rather than having a 3rd place that has to know about
containing block rules.
(WebCore::RenderLayer::enclosingAncestorForPosition): Call isContainerForPositioned() now.
(WebCore::accumulateOffsetTowardsAncestor): Call enclosingAncestorForPosition().
(WebCore::RenderLayer::createLocalTransformState):
(WebCore::RenderLayer::calculateClipRects):
(WebCore::isPositionedContainer): Deleted.
(WebCore::isFixedPositionedContainer): Deleted.
(WebCore::RenderLayer::enclosingPositionedAncestor): Deleted.
* rendering/RenderLayer.h:
* rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::updateGeometry):
* rendering/RenderLayerModelObject.cpp:
(WebCore::RenderLayerModelObject::styleDidChange):
* rendering/RenderObject.cpp:
(WebCore::RenderObject::shouldUseTransformFromContainer): Can just check hasTransform() now.
(WebCore::RenderObject::container):
* rendering/RenderObject.h:
(WebCore::RenderObject::hasTransformRelatedProperty):
(WebCore::RenderObject::hasTransform):
(WebCore::RenderObject::setHasTransformRelatedProperty):
(WebCore::RenderObject::RenderObjectBitfields::RenderObjectBitfields):
(WebCore::RenderObject::setHasTransform): Deleted.
* rendering/RenderTableRow.h:
* rendering/RenderView.cpp:
(WebCore::RenderView::mapLocalToContainer): nullptr goodness.
(WebCore::RenderView::pushMappingToContainer): Ditto.
(WebCore::RenderView::mapAbsoluteToLocalPoint): Ditto.

LayoutTests:

New tests and updated results:

* platform/mac/compositing/tiling/rotated-tiled-preserve3d-clamped-expected.txt: Progression, caused
by RenderLayerBacking::updateCompositedBounds() now allowing shouldClipCompositedBounds on
preserve-3d layers, since they are no longer considered to have a transform.
* platform/mac/compositing/visible-rect/3d-transform-style-expected.txt: Ditto.
* transforms/2d/perspective-not-fixed-container-expected.html: Added.
* transforms/2d/perspective-not-fixed-container.html: Added. Tests that
perspective does not act as containing block for fixed position (not a behavior change).
* transforms/2d/preserve3d-not-fixed-container-expected.html: Added.
* transforms/2d/preserve3d-not-fixed-container.html: Added. Tests that
preserve3d does not act as containing block for fixed position. This is a behavior change.
* transforms/perspective-is-containing-block-for-absolute-expected.html: Added.
* transforms/perspective-is-containing-block-for-absolute.html: Added. Tests that
perspective is a as containing block for absolute/relative position. This is not a behavior change.
* transforms/preserve3d-is-containing-block-for-absolute-expected.html: Added.
* transforms/preserve3d-is-containing-block-for-absolute.html: Added. Tests that
preserve3d is a as containing block for absolute/relative position. This is not a behavior change,
but seems like incorrect behavior for now.
* transforms/transform-is-containing-block-for-absolute-expected.html: Added.
* transforms/transform-is-containing-block-for-absolute.html: Added. Tests that
transform is a as containing block for absolute/relative position. This is not a behavior change.

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

36 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/ios-simulator-wk2/compositing/tiling/rotated-tiled-preserve3d-clamped-expected.txt
LayoutTests/platform/ios-simulator/compositing/tiling/rotated-tiled-preserve3d-clamped-expected.txt
LayoutTests/platform/mac-wk2/compositing/tiling/rotated-tiled-preserve3d-clamped-expected.txt
LayoutTests/platform/mac/compositing/tiling/rotated-tiled-preserve3d-clamped-expected.txt
LayoutTests/platform/mac/compositing/visible-rect/3d-transform-style-expected.txt
LayoutTests/platform/win/compositing/tiling/rotated-tiled-preserve3d-clamped-expected.txt
LayoutTests/transforms/2d/perspective-not-fixed-container-expected.html [new file with mode: 0644]
LayoutTests/transforms/2d/perspective-not-fixed-container.html [new file with mode: 0644]
LayoutTests/transforms/2d/preserve3d-not-fixed-container-expected.html [new file with mode: 0644]
LayoutTests/transforms/2d/preserve3d-not-fixed-container.html [new file with mode: 0644]
LayoutTests/transforms/perspective-is-containing-block-for-absolute-expected.html [new file with mode: 0644]
LayoutTests/transforms/perspective-is-containing-block-for-absolute.html [new file with mode: 0644]
LayoutTests/transforms/preserve3d-is-containing-block-for-absolute-expected.html [new file with mode: 0644]
LayoutTests/transforms/preserve3d-is-containing-block-for-absolute.html [new file with mode: 0644]
LayoutTests/transforms/transform-is-containing-block-for-absolute-expected.html [new file with mode: 0644]
LayoutTests/transforms/transform-is-containing-block-for-absolute.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/css/CSSComputedStyleDeclaration.cpp
Source/WebCore/rendering/LogicalSelectionOffsetCaches.h
Source/WebCore/rendering/RenderBox.cpp
Source/WebCore/rendering/RenderBox.h
Source/WebCore/rendering/RenderBoxModelObject.h
Source/WebCore/rendering/RenderElement.cpp
Source/WebCore/rendering/RenderGeometryMap.cpp
Source/WebCore/rendering/RenderInline.cpp
Source/WebCore/rendering/RenderLayer.cpp
Source/WebCore/rendering/RenderLayer.h
Source/WebCore/rendering/RenderLayerBacking.cpp
Source/WebCore/rendering/RenderLayerCompositor.cpp
Source/WebCore/rendering/RenderLayerModelObject.cpp
Source/WebCore/rendering/RenderObject.cpp
Source/WebCore/rendering/RenderObject.h
Source/WebCore/rendering/RenderRegion.cpp
Source/WebCore/rendering/RenderTableRow.h
Source/WebCore/rendering/RenderView.cpp

index 2d09bdd..8aa4bde 100644 (file)
@@ -1,3 +1,33 @@
+2014-12-11  Simon Fraser  <simon.fraser@apple.com>
+
+        Transform-style should not kill position:fixed
+        https://bugs.webkit.org/show_bug.cgi?id=138122
+
+        Reviewed by Dean Jackson.
+        
+        New tests and updated results:
+
+        * platform/mac/compositing/tiling/rotated-tiled-preserve3d-clamped-expected.txt: Progression, caused
+        by RenderLayerBacking::updateCompositedBounds() now allowing shouldClipCompositedBounds on
+        preserve-3d layers, since they are no longer considered to have a transform.
+        * platform/mac/compositing/visible-rect/3d-transform-style-expected.txt: Ditto.
+        * transforms/2d/perspective-not-fixed-container-expected.html: Added.
+        * transforms/2d/perspective-not-fixed-container.html: Added. Tests that
+        perspective does not act as containing block for fixed position (not a behavior change).
+        * transforms/2d/preserve3d-not-fixed-container-expected.html: Added.
+        * transforms/2d/preserve3d-not-fixed-container.html: Added. Tests that
+        preserve3d does not act as containing block for fixed position. This is a behavior change.
+        * transforms/perspective-is-containing-block-for-absolute-expected.html: Added.
+        * transforms/perspective-is-containing-block-for-absolute.html: Added. Tests that
+        perspective is a as containing block for absolute/relative position. This is not a behavior change.
+        * transforms/preserve3d-is-containing-block-for-absolute-expected.html: Added.
+        * transforms/preserve3d-is-containing-block-for-absolute.html: Added. Tests that
+        preserve3d is a as containing block for absolute/relative position. This is not a behavior change,
+        but seems like incorrect behavior for now.
+        * transforms/transform-is-containing-block-for-absolute-expected.html: Added.
+        * transforms/transform-is-containing-block-for-absolute.html: Added. Tests that
+        transform is a as containing block for absolute/relative position. This is not a behavior change.
+
 2014-12-11  Roger Fong  <roger_fong@apple.com>
 
         Implement frag depth as a WebGL 1 extension.
index 2069c77..f20e07a 100644 (file)
@@ -27,7 +27,6 @@
               (contentsScale 2.00)
               (children 1
                 (GraphicsLayer
-                  (bounds 500.00 0.00)
                   (preserves3D 1)
                   (visible rect 0.00, 0.00 0.00 x 0.00)
                   (contentsScale 2.00)
index 2069c77..f20e07a 100644 (file)
@@ -27,7 +27,6 @@
               (contentsScale 2.00)
               (children 1
                 (GraphicsLayer
-                  (bounds 500.00 0.00)
                   (preserves3D 1)
                   (visible rect 0.00, 0.00 0.00 x 0.00)
                   (contentsScale 2.00)
index 2ad1b63..42cdd77 100644 (file)
@@ -27,7 +27,6 @@
               (contentsScale 1.00)
               (children 1
                 (GraphicsLayer
-                  (bounds 500.00 0.00)
                   (preserves3D 1)
                   (visible rect 0.00, 0.00 0.00 x 0.00)
                   (contentsScale 1.00)
index 7f3905a..8a1cbde 100644 (file)
@@ -24,7 +24,6 @@
               (contentsScale 1.00)
               (children 1
                 (GraphicsLayer
-                  (bounds 500.00 0.00)
                   (preserves3D 1)
                   (visible rect 0.00, 0.00 0.00 x 0.00)
                   (contentsScale 1.00)
index de8c6e5..a96f17e 100644 (file)
@@ -24,7 +24,6 @@
               (contentsScale 1.00)
               (children 1
                 (GraphicsLayer
-                  (bounds 200.00 0.00)
                   (preserves3D 1)
                   (visible rect 0.00, 0.00 0.00 x 0.00)
                   (contentsScale 1.00)
@@ -56,7 +55,6 @@
               (contentsScale 1.00)
               (children 1
                 (GraphicsLayer
-                  (bounds 200.00 0.00)
                   (preserves3D 1)
                   (visible rect 0.00, 0.00 0.00 x 0.00)
                   (contentsScale 1.00)
index d4ba2df..1ba0678 100644 (file)
@@ -19,7 +19,6 @@
               (visible rect 0.00, 0.00 500.00 x 300.00)
               (children 1
                 (GraphicsLayer
-                  (bounds 500.00 0.00)
                   (preserves3D 1)
                   (visible rect 0.00, 0.00 0.00 x 0.00)
                   (children 1
diff --git a/LayoutTests/transforms/2d/perspective-not-fixed-container-expected.html b/LayoutTests/transforms/2d/perspective-not-fixed-container-expected.html
new file mode 100644 (file)
index 0000000..fc51851
--- /dev/null
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+  <style>
+    body {
+      margin: 0;
+      height: 1000px;
+    }
+
+    body > div {
+      outline: 1px solid black;
+    }
+    
+    .box {
+      width: 100px;
+      height: 100px;
+    }
+
+    .fixed {
+      position: fixed;
+      top: 100px;
+      background-color: green;
+    }
+
+    .transformed {
+      -webkit-transform: translateZ(1px);
+    }
+  </style>
+  <script>
+    // Scroll on load to test fixed positioning.
+    window.addEventListener('load', function() {
+      window.scrollTo(0, 100);
+    }, false)
+  </script>
+</head>
+<body>
+
+  <div class="box" style="margin: 150px 50px;">
+    <div class="fixed box">
+        <div class="transformed box"></div> <!-- Necessary to activate preserve3d compositing -->
+    </div>
+  </div>
+
+  <div class="fixed box" style="left: 250px;">
+    <div class="transformed box"></div> <!-- Necessary to activate preserve3d compositing -->
+  </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/transforms/2d/perspective-not-fixed-container.html b/LayoutTests/transforms/2d/perspective-not-fixed-container.html
new file mode 100644 (file)
index 0000000..dfa97ec
--- /dev/null
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+  <style>
+    body {
+      margin: 0;
+      height: 1000px;
+    }
+    
+    body > div {
+      outline: 1px solid black;
+    }
+    
+    .box {
+      width: 100px;
+      height: 100px;
+    }
+
+    .fixed {
+      position: fixed;
+      top: 100px;
+      background-color: green;
+    }
+
+    .perspective {
+      -webkit-perspective: 500px;
+    }
+
+    .transformed {
+      -webkit-transform: translateZ(1px);
+    }
+  </style>
+  <script>
+    // Scroll on load to test fixed positioning.
+    window.addEventListener('load', function() {
+      window.scrollTo(0, 100);
+    }, false)
+  </script>
+</head>
+<body>
+
+  <div class="perspective box" style="margin: 150px 50px;">
+    <div class="fixed box">
+        <div class="transformed box"></div> <!-- Necessary to activate preserve3d compositing -->
+    </div>
+  </div>
+
+  <div class="perspective fixed box" style="left: 250px;">
+    <div class="transformed box"></div> <!-- Necessary to activate preserve3d compositing -->
+  </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/transforms/2d/preserve3d-not-fixed-container-expected.html b/LayoutTests/transforms/2d/preserve3d-not-fixed-container-expected.html
new file mode 100644 (file)
index 0000000..542473e
--- /dev/null
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+  <style>
+    body {
+      margin: 0;
+      height: 1000px;
+    }
+    
+    body > div {
+      outline: 1px solid black;
+    }
+
+    .box {
+      width: 100px;
+      height: 100px;
+    }
+
+    .fixed {
+      position: fixed;
+      top: 100px;
+      background-color: green;
+    }
+
+    .transformed {
+      -webkit-transform: translateZ(1px);
+    }
+  </style>
+  <script>
+    // Scroll on load to test fixed positioning.
+    window.addEventListener('load', function() {
+      window.scrollTo(0, 100);
+    }, false)
+  </script>
+</head>
+<body>
+
+  <div class="box" style="margin: 150px 50px;">
+    <div class="fixed box">
+        <div class="transformed box"></div> <!-- Necessary to activate preserve3d compositing -->
+    </div>
+  </div>
+
+  <div class="fixed box" style="left: 250px;">
+    <div class="transformed box"></div> <!-- Necessary to activate preserve3d compositing -->
+  </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/transforms/2d/preserve3d-not-fixed-container.html b/LayoutTests/transforms/2d/preserve3d-not-fixed-container.html
new file mode 100644 (file)
index 0000000..cee35e4
--- /dev/null
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+  <style>
+    body {
+      margin: 0;
+      height: 1000px;
+    }
+
+    body > div {
+      outline: 1px solid black;
+    }
+    
+    .box {
+      width: 100px;
+      height: 100px;
+    }
+
+    .fixed {
+      position: fixed;
+      top: 100px;
+      background-color: green;
+    }
+
+    .preserve3d {
+      -webkit-transform-style: preserve-3d;
+    }
+
+    .transformed {
+      -webkit-transform: translateZ(1px);
+    }
+  </style>
+  <script>
+    // Scroll on load to test fixed positioning.
+    window.addEventListener('load', function() {
+      window.scrollTo(0, 100);
+    }, false)
+  </script>
+</head>
+<body>
+
+  <div class="preserve3d box" style="margin: 150px 50px;">
+    <div class="fixed box">
+        <div class="transformed box"></div> <!-- Necessary to activate preserve3d compositing -->
+    </div>
+  </div>
+
+  <div class="preserve3d fixed box" style="left: 250px;">
+    <div class="transformed box"></div> <!-- Necessary to activate preserve3d compositing -->
+  </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/transforms/perspective-is-containing-block-for-absolute-expected.html b/LayoutTests/transforms/perspective-is-containing-block-for-absolute-expected.html
new file mode 100644 (file)
index 0000000..46d8628
--- /dev/null
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        .container {
+            position: relative;
+            margin: 50px;
+            height: 100px;
+            width: 100px;
+            border: 1px solid black;
+        }
+        .box {
+            position: absolute;
+            top: 0;
+            left: 0;
+            height: 100%;
+            width: 100%;
+            background-color: gray;
+        }
+    </style>
+</head>
+<body>
+<div class="container">
+    <div class="box"></div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/transforms/perspective-is-containing-block-for-absolute.html b/LayoutTests/transforms/perspective-is-containing-block-for-absolute.html
new file mode 100644 (file)
index 0000000..23c4ee6
--- /dev/null
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        .container {
+            margin: 50px;
+            height: 100px;
+            width: 100px;
+            border: 1px solid black;
+            -webkit-perspective: 100px;
+        }
+        .box {
+            position: absolute;
+            top: 0;
+            left: 0;
+            height: 100%;
+            width: 100%;
+            background-color: gray;
+        }
+    </style>
+</head>
+<body>
+<div class="container">
+    <div class="box"></div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/transforms/preserve3d-is-containing-block-for-absolute-expected.html b/LayoutTests/transforms/preserve3d-is-containing-block-for-absolute-expected.html
new file mode 100644 (file)
index 0000000..46d8628
--- /dev/null
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        .container {
+            position: relative;
+            margin: 50px;
+            height: 100px;
+            width: 100px;
+            border: 1px solid black;
+        }
+        .box {
+            position: absolute;
+            top: 0;
+            left: 0;
+            height: 100%;
+            width: 100%;
+            background-color: gray;
+        }
+    </style>
+</head>
+<body>
+<div class="container">
+    <div class="box"></div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/transforms/preserve3d-is-containing-block-for-absolute.html b/LayoutTests/transforms/preserve3d-is-containing-block-for-absolute.html
new file mode 100644 (file)
index 0000000..716e976
--- /dev/null
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        .container {
+            margin: 50px;
+            height: 100px;
+            width: 100px;
+            border: 1px solid black;
+            -webkit-transform-style: preserve-3d;
+            -moz-transform-style: preserve-3d;
+            transform-style: preserve-3d;
+        }
+        .box {
+            position: absolute;
+            top: 0;
+            left: 0;
+            height: 100%;
+            width: 100%;
+            background-color: gray;
+        }
+    </style>
+</head>
+<body>
+<div class="container">
+    <div class="box"></div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/transforms/transform-is-containing-block-for-absolute-expected.html b/LayoutTests/transforms/transform-is-containing-block-for-absolute-expected.html
new file mode 100644 (file)
index 0000000..46d8628
--- /dev/null
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        .container {
+            position: relative;
+            margin: 50px;
+            height: 100px;
+            width: 100px;
+            border: 1px solid black;
+        }
+        .box {
+            position: absolute;
+            top: 0;
+            left: 0;
+            height: 100%;
+            width: 100%;
+            background-color: gray;
+        }
+    </style>
+</head>
+<body>
+<div class="container">
+    <div class="box"></div>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/transforms/transform-is-containing-block-for-absolute.html b/LayoutTests/transforms/transform-is-containing-block-for-absolute.html
new file mode 100644 (file)
index 0000000..e091c6a
--- /dev/null
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        .container {
+            margin: 50px;
+            height: 100px;
+            width: 100px;
+            border: 1px solid black;
+            -webkit-transform: translate(0, 0);
+        }
+        .box {
+            position: absolute;
+            top: 0;
+            left: 0;
+            height: 100%;
+            width: 100%;
+            background-color: gray;
+        }
+    </style>
+</head>
+<body>
+<div class="container">
+    <div class="box"></div>
+</div>
+</body>
+</html>
index 7b8068c..6933822 100644 (file)
@@ -1,3 +1,93 @@
+2014-12-11  Simon Fraser  <simon.fraser@apple.com>
+
+        Transform-style should not kill position:fixed
+        https://bugs.webkit.org/show_bug.cgi?id=138122
+
+        Reviewed by Dean Jackson.
+        
+        Various bits of rendering code checked RenderObject::hasTransform() for various
+        reasons. Confusingly, this meant "has transform, or preserve-3d, or perspective".
+        
+        This patch teases those behaviors apart to produce the following behavior:
+        
+        1. "transform" acts as containing block for fixed position (no behavior change).
+        2. "transform" acts as containing block for absolute/relative position (no behavior change).
+        3. "perspective" does not act as containing block for fixed position (no behavior change).
+        4. "perspective" acts as containing block for absolute/relative position (no behavior change).
+        5. "preserve-3d" does not act as containing block for fixed position (behavior change).
+        6. "preserve-3d" acts as containing block for absolute/relative position. This is not a
+        behavior change, but seems like incorrect behavior (https://www.w3.org/Bugs/Public/show_bug.cgi?id=27566).
+        However, we may be forced to keep it for compatibility.
+        
+        The gist of the change is to rename RenderObject::hasTransform() to RenderObject::hasTransformRelatedProperty(),
+        and add hasTransform() with the more restrictive meaning. All call sites of hasTransform() were examined
+        and fixed to produce the desired behaviors.
+
+        Tests: transforms/2d/perspective-not-fixed-container.html
+               transforms/2d/preserve3d-not-fixed-container.html
+               transforms/perspective-is-containing-block-for-absolute.html
+               transforms/preserve3d-is-containing-block-for-absolute.html
+               transforms/transform-is-containing-block-for-absolute.html
+
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::computedTransform): Now we can just test hasTransform().
+        * rendering/LogicalSelectionOffsetCaches.h:
+        (WebCore::isContainingBlockCandidateForAbsolutelyPositionedObject): For now, this
+        can just use hasTransformRelatedProperty(), but if we change [6] above this will have
+        to change (as documented in the comment). Also FIXME comments about sharing code.
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::updateFromStyle):
+        (WebCore::RenderBox::mapLocalToContainer): Can just use hasTransform() now.
+        (WebCore::RenderBox::pushMappingToContainer): Ditto.
+        (WebCore::RenderBox::mapAbsoluteToLocalPoint): Ditto.
+        (WebCore::RenderBox::layoutOverflowRectForPropagation): Ditto.
+        * rendering/RenderBox.h: All transform-related properties create RenderLayers.
+        * rendering/RenderBoxModelObject.h: Ditto.
+        * rendering/RenderElement.cpp:
+        (WebCore::RenderElement::styleWillChange):
+        * rendering/RenderGeometryMap.cpp:
+        (WebCore::canMapBetweenRenderersViaLayers): Rename to clarify. We need to not map via
+        layers if we have a perspective (since we need to generate a perspective matrix). It's
+        OK with preserve-3d though.
+        (WebCore::RenderGeometryMap::pushMappingsToAncestor):
+        (WebCore::canMapBetweenRenderers): Deleted.
+        * rendering/RenderInline.cpp:
+        (WebCore::RenderInline::updateFromStyle):
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::updateTransform): Can just check hasTransform().
+        (WebCore::RenderLayer::updateLayerPosition): Avoid calling parent() and enclosingPositionedAncestor() twice.
+        (WebCore::RenderLayer::perspectiveTransform): Do the fast bit check hasTransformRelatedProperty() first.
+        (WebCore::RenderLayer::perspectiveOrigin): Ditto.
+        (WebCore::isContainerForPositioned): This code has to now have different behavior for absolute and fixed
+        position. Changed it to call existing functions, rather than having a 3rd place that has to know about
+        containing block rules.
+        (WebCore::RenderLayer::enclosingAncestorForPosition): Call isContainerForPositioned() now.
+        (WebCore::accumulateOffsetTowardsAncestor): Call enclosingAncestorForPosition().
+        (WebCore::RenderLayer::createLocalTransformState):
+        (WebCore::RenderLayer::calculateClipRects):
+        (WebCore::isPositionedContainer): Deleted.
+        (WebCore::isFixedPositionedContainer): Deleted.
+        (WebCore::RenderLayer::enclosingPositionedAncestor): Deleted.
+        * rendering/RenderLayer.h:
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::RenderLayerBacking::updateGeometry):
+        * rendering/RenderLayerModelObject.cpp:
+        (WebCore::RenderLayerModelObject::styleDidChange):
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::shouldUseTransformFromContainer): Can just check hasTransform() now.
+        (WebCore::RenderObject::container):
+        * rendering/RenderObject.h:
+        (WebCore::RenderObject::hasTransformRelatedProperty):
+        (WebCore::RenderObject::hasTransform):
+        (WebCore::RenderObject::setHasTransformRelatedProperty):
+        (WebCore::RenderObject::RenderObjectBitfields::RenderObjectBitfields):
+        (WebCore::RenderObject::setHasTransform): Deleted.
+        * rendering/RenderTableRow.h:
+        * rendering/RenderView.cpp:
+        (WebCore::RenderView::mapLocalToContainer): nullptr goodness.
+        (WebCore::RenderView::pushMappingToContainer): Ditto.
+        (WebCore::RenderView::mapAbsoluteToLocalPoint): Ditto.
+
 2014-12-11  Rich Tibbett <rich.tibbett@gmail.com>
 
         [iOS] Normalize iOS DeviceOrientation beta/gamma per spec.
index 9214b18..8682128 100644 (file)
@@ -847,7 +847,7 @@ static PassRef<WebKitCSSTransformValue> matrixTransformValue(const Transformatio
 
 static PassRef<CSSValue> computedTransform(RenderObject* renderer, const RenderStyle* style)
 {
-    if (!renderer || !renderer->hasTransform() || !style->hasTransform())
+    if (!renderer || !renderer->hasTransform())
         return cssValuePool().createIdentifierValue(CSSValueNone);
 
     FloatRect pixelSnappedRect;
index 59839e6..c5a3368 100644 (file)
 
 namespace WebCore {
 
+// FIXME: share code with RenderObject::container().
 static inline bool isContainingBlockCandidateForAbsolutelyPositionedObject(RenderElement& object)
 {
+    // FIXME: hasTransformRelatedProperty() includes preserves3D() check, but this may need to change: https://www.w3.org/Bugs/Public/show_bug.cgi?id=27566
     return object.style().position() != StaticPosition
-        || (object.hasTransform() && object.isRenderBlock())
+        || (object.isRenderBlock() && object.hasTransformRelatedProperty())
         || object.isSVGForeignObject()
         || object.isRenderView();
 }
@@ -38,6 +40,7 @@ static inline bool isNonRenderBlockInline(RenderElement& object)
     return (object.isInline() && !object.isReplaced()) || !object.isRenderBlock();
 }
 
+// FIXME: share code with RenderObject::container().
 static inline RenderBlock* containingBlockForFixedPosition(RenderElement* parent)
 {
     RenderElement* object = parent;
index 1c158d8..97dbacc 100644 (file)
@@ -484,7 +484,7 @@ void RenderBox::updateFromStyle()
         }
     }
 
-    setHasTransform(styleToUse.hasTransformRelatedProperty());
+    setHasTransformRelatedProperty(styleToUse.hasTransformRelatedProperty());
     setHasReflection(styleToUse.boxReflect());
 }
 
@@ -1918,10 +1918,9 @@ void RenderBox::mapLocalToContainer(const RenderLayerModelObject* repaintContain
         return;
 
     bool isFixedPos = style().position() == FixedPosition;
-    bool hasTransform = hasLayer() && layer()->transform();
     // If this box has a transform, it acts as a fixed position container for fixed descendants,
     // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
-    if (hasTransform && !isFixedPos)
+    if (hasTransform() && !isFixedPos)
         mode &= ~IsFixed;
     else if (isFixedPos)
         mode |= IsFixed;
@@ -1967,8 +1966,6 @@ const RenderObject* RenderBox::pushMappingToContainer(const RenderLayerModelObje
         return nullptr;
 
     bool isFixedPos = style().position() == FixedPosition;
-    bool hasTransform = hasLayer() && layer()->transform();
-
     LayoutSize adjustmentForSkippedAncestor;
     if (ancestorSkipped) {
         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
@@ -1985,10 +1982,10 @@ const RenderObject* RenderBox::pushMappingToContainer(const RenderLayerModelObje
         getTransformFromContainer(container, containerOffset, t);
         t.translateRight(adjustmentForSkippedAncestor.width(), adjustmentForSkippedAncestor.height());
         
-        geometryMap.push(this, t, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform);
+        geometryMap.push(this, t, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform());
     } else {
         containerOffset += adjustmentForSkippedAncestor;
-        geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform);
+        geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform());
     }
     
     return ancestorSkipped ? ancestorToStopAt : container;
@@ -1997,8 +1994,7 @@ const RenderObject* RenderBox::pushMappingToContainer(const RenderLayerModelObje
 void RenderBox::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const
 {
     bool isFixedPos = style().position() == FixedPosition;
-    bool hasTransform = hasLayer() && layer()->transform();
-    if (hasTransform && !isFixedPos) {
+    if (hasTransform() && !isFixedPos) {
         // If this box has a transform, it acts as a fixed position container for fixed descendants,
         // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
         mode &= ~IsFixed;
@@ -4566,7 +4562,7 @@ LayoutRect RenderBox::layoutOverflowRectForPropagation(RenderStyle* parentStyle)
     if (!hasOverflowClip())
         rect.unite(layoutOverflowRect());
 
-    bool hasTransform = hasLayer() && layer()->transform();
+    bool hasTransform = this->hasTransform();
 #if PLATFORM(IOS)
     if (isInFlowPositioned() || (hasTransform && document().settings()->shouldTransformsAffectOverflow())) {
 #else
index 7f347c5..560287c 100644 (file)
@@ -53,7 +53,7 @@ public:
     virtual bool requiresLayer() const override
     {
         return isRoot() || isPositioned() || createsGroup() || hasClipPath() || hasOverflowClip()
-            || hasTransform() || hasHiddenBackface() || hasReflection() || style().specifiesColumns()
+            || hasTransformRelatedProperty() || hasHiddenBackface() || hasReflection() || style().specifiesColumns()
             || !style().hasAutoZIndex();
     }
 
index 0702d41..4f0cd52 100644 (file)
@@ -142,7 +142,7 @@ public:
 
     virtual void updateFromStyle() override;
 
-    virtual bool requiresLayer() const override { return isRoot() || isPositioned() || createsGroup() || hasClipPath() || hasTransform() || hasHiddenBackface() || hasReflection(); }
+    virtual bool requiresLayer() const override { return isRoot() || isPositioned() || createsGroup() || hasClipPath() || hasTransformRelatedProperty() || hasHiddenBackface() || hasReflection(); }
 
     // This will work on inlines to return the bounding box of all of the lines' border boxes.
     virtual IntRect borderBoundingBox() const = 0;
index 8817200..b64c25d 100644 (file)
@@ -858,7 +858,7 @@ void RenderElement::styleWillChange(StyleDifference diff, const RenderStyle& new
         setHorizontalWritingMode(true);
         setHasBoxDecorations(false);
         setHasOverflowClip(false);
-        setHasTransform(false);
+        setHasTransformRelatedProperty(false);
         setHasReflection(false);
     } else {
         s_affectsParentBlock = false;
index 611b35a..ee73479 100644 (file)
@@ -155,14 +155,17 @@ void RenderGeometryMap::pushMappingsToAncestor(const RenderObject* renderer, con
     ASSERT(m_mapping.isEmpty() || m_mapping[0].m_renderer->isRenderView());
 }
 
-static bool canMapBetweenRenderers(const RenderLayerModelObject& renderer, const RenderLayerModelObject& ancestor)
+static bool canMapBetweenRenderersViaLayers(const RenderLayerModelObject& renderer, const RenderLayerModelObject& ancestor)
 {
     for (const RenderElement* current = &renderer; ; current = current->parent()) {
         const RenderStyle& style = current->style();
         if (style.position() == FixedPosition || style.isFlippedBlocksWritingMode())
             return false;
 
-        if (current->hasTransform() || current->isRenderFlowThread())
+        if (current->hasTransformRelatedProperty() && (current->style().hasTransform() || current->style().hasPerspective()))
+            return false;
+        
+        if (current->isRenderFlowThread())
             return false;
 
         if (current->isSVGRoot())
@@ -181,7 +184,7 @@ void RenderGeometryMap::pushMappingsToAncestor(const RenderLayer* layer, const R
 
     // We have to visit all the renderers to detect flipped blocks. This might defeat the gains
     // from mapping via layers.
-    bool canConvertInLayerTree = ancestorLayer ? canMapBetweenRenderers(layer->renderer(), ancestorLayer->renderer()) : false;
+    bool canConvertInLayerTree = ancestorLayer ? canMapBetweenRenderersViaLayers(layer->renderer(), ancestorLayer->renderer()) : false;
 
     if (canConvertInLayerTree) {
         LayoutSize layerOffset = layer->offsetFromAncestor(ancestorLayer);
index 4fa7eda..5376016 100644 (file)
@@ -124,7 +124,7 @@ void RenderInline::updateFromStyle()
     RenderBoxModelObject::updateFromStyle();
 
     // FIXME: Support transforms and reflections on inline flows someday.
-    setHasTransform(false);
+    setHasTransformRelatedProperty(false);
     setHasReflection(false);    
 }
 
index d9d5d27..6e410b9 100644 (file)
@@ -77,6 +77,7 @@
 #include "HitTestRequest.h"
 #include "HitTestResult.h"
 #include "InspectorInstrumentation.h"
+#include "LogicalSelectionOffsetCaches.h"
 #include "OverflowEvent.h"
 #include "OverlapTestRequestClient.h"
 #include "Page.h"
@@ -830,9 +831,7 @@ void RenderLayer::dirtyAncestorChainHasBlendingDescendants()
 
 void RenderLayer::updateTransform()
 {
-    // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set,
-    // so check style too.
-    bool hasTransform = renderer().hasTransform() && renderer().style().hasTransform();
+    bool hasTransform = renderer().hasTransform();
     bool had3DTransform = has3DTransform();
 
     bool hadTransform = !!m_transform;
@@ -1210,10 +1209,10 @@ bool RenderLayer::updateLayerPosition()
         localPoint += box->topLeftLocationOffset();
     }
 
-    if (!renderer().isOutOfFlowPositioned() && renderer().parent()) {
+    RenderElement* ancestor;
+    if (!renderer().isOutOfFlowPositioned() && (ancestor = renderer().parent())) {
         // We must adjust our position by walking up the render tree looking for the
         // nearest enclosing object with a layer.
-        RenderElement* ancestor = renderer().parent();
         while (ancestor && !ancestor->hasLayer()) {
             if (is<RenderBox>(*ancestor) && !is<RenderTableRow>(*ancestor)) {
                 // Rows and cells share the same coordinate space (that of the section).
@@ -1229,9 +1228,8 @@ bool RenderLayer::updateLayerPosition()
     }
     
     // Subtract our parent's scroll offset.
-    if (renderer().isOutOfFlowPositioned() && enclosingPositionedAncestor()) {
-        RenderLayer* positionedParent = enclosingPositionedAncestor();
-
+    RenderLayer* positionedParent;
+    if (renderer().isOutOfFlowPositioned() && (positionedParent = enclosingAncestorForPosition(renderer().style().position()))) {
         // For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
         if (positionedParent->renderer().hasOverflowClip()) {
             LayoutSize offset = positionedParent->scrolledContentOffset();
@@ -1269,7 +1267,7 @@ bool RenderLayer::updateLayerPosition()
 
 TransformationMatrix RenderLayer::perspectiveTransform() const
 {
-    if (!renderer().hasTransform())
+    if (!renderer().hasTransformRelatedProperty())
         return TransformationMatrix();
 
     const RenderStyle& style = renderer().style();
@@ -1299,7 +1297,7 @@ TransformationMatrix RenderLayer::perspectiveTransform() const
 
 FloatPoint RenderLayer::perspectiveOrigin() const
 {
-    if (!renderer().hasTransform())
+    if (!renderer().hasTransformRelatedProperty())
         return FloatPoint();
 
     const LayoutRect borderBox = downcast<RenderBox>(renderer()).borderBoxRect();
@@ -1319,20 +1317,25 @@ RenderLayer* RenderLayer::stackingContainer() const
     return layer;
 }
 
-static inline bool isPositionedContainer(RenderLayer* layer)
+static inline bool isContainerForPositioned(RenderLayer& layer, EPosition position)
 {
-    return layer->isRootLayer() || layer->renderer().isPositioned() || layer->hasTransform();
-}
+    switch (position) {
+    case FixedPosition:
+        return layer.renderer().canContainFixedPositionObjects();
 
-static inline bool isFixedPositionedContainer(RenderLayer* layer)
-{
-    return layer->isRootLayer() || layer->hasTransform();
+    case AbsolutePosition:
+        return isContainingBlockCandidateForAbsolutelyPositionedObject(layer.renderer());
+    
+    default:
+        ASSERT_NOT_REACHED();
+        return false;
+    }
 }
 
-RenderLayer* RenderLayer::enclosingPositionedAncestor() const
+RenderLayer* RenderLayer::enclosingAncestorForPosition(EPosition position) const
 {
     RenderLayer* curr = parent();
-    while (curr && !isPositionedContainer(curr))
+    while (curr && !isContainerForPositioned(*curr, position))
         curr = curr->parent();
 
     return curr;
@@ -1911,7 +1914,7 @@ static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLay
             if (currLayer == ancestorLayer)
                 foundAncestor = true;
 
-            if (isFixedPositionedContainer(currLayer)) {
+            if (isContainerForPositioned(*currLayer, FixedPosition)) {
                 fixedPositionContainerLayer = currLayer;
                 ASSERT_UNUSED(foundAncestor, foundAncestor);
                 break;
@@ -1948,14 +1951,14 @@ static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLay
 
     RenderLayer* parentLayer;
     if (position == AbsolutePosition || position == FixedPosition) {
-        // Do what enclosingPositionedAncestor() does, but check for ancestorLayer along the way.
+        // Do what enclosingAncestorForPosition() does, but check for ancestorLayer along the way.
         parentLayer = layer->parent();
         bool foundAncestorFirst = false;
         while (parentLayer) {
             // RenderFlowThread is a positioned container, child of RenderView, positioned at (0,0).
             // This implies that, for out-of-flow positioned elements inside a RenderFlowThread,
             // we are bailing out before reaching root layer.
-            if (isPositionedContainer(parentLayer))
+            if (isContainerForPositioned(*parentLayer, position))
                 break;
 
             if (parentLayer == ancestorLayer) {
@@ -1973,8 +1976,8 @@ static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLay
 
         if (foundAncestorFirst) {
             // Found ancestorLayer before the abs. positioned container, so compute offset of both relative
-            // to enclosingPositionedAncestor and subtract.
-            RenderLayer* positionedAncestor = parentLayer->enclosingPositionedAncestor();
+            // to enclosingAncestorForPosition and subtract.
+            RenderLayer* positionedAncestor = parentLayer->enclosingAncestorForPosition(position);
             LayoutSize thisCoords = layer->offsetFromAncestor(positionedAncestor);
             LayoutSize ancestorCoords = ancestorLayer->offsetFromAncestor(positionedAncestor);
             location += (thisCoords - ancestorCoords);
@@ -4718,7 +4721,7 @@ PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(Rend
     }
     offset += translationOffset;
 
-    RenderObject* containerRenderer = containerLayer ? &containerLayer->renderer() : 0;
+    RenderObject* containerRenderer = containerLayer ? &containerLayer->renderer() : nullptr;
     if (renderer().shouldUseTransformFromContainer(containerRenderer)) {
         TransformationMatrix containerTransform;
         renderer().getTransformFromContainer(containerRenderer, offset, containerTransform);
@@ -6215,7 +6218,7 @@ bool RenderLayer::shouldBeNormalFlowOnly() const
         || (renderer().style().specifiesColumns() && !isRootLayer())
         || renderer().isInFlowRenderFlowThread())
         && !renderer().isPositioned()
-        && !renderer().hasTransform()
+        && !renderer().hasTransformRelatedProperty()
         && !renderer().hasClipPath()
         && !renderer().hasFilter()
         && !renderer().hasBackdropFilter()
index 7313672..4115f0b 100644 (file)
@@ -619,7 +619,7 @@ public:
 
     // Gets the nearest enclosing positioned ancestor layer (also includes
     // the <html> layer and the root layer).
-    RenderLayer* enclosingPositionedAncestor() const;
+    RenderLayer* enclosingAncestorForPosition(EPosition) const;
 
     // Returns the nearest enclosing layer that is scrollable.
     RenderLayer* enclosingScrollableLayer() const;
index 7937c11..9beb4ef 100644 (file)
@@ -822,7 +822,7 @@ void RenderLayerBacking::updateGeometry()
         m_maskLayer->setOffsetFromRenderer(m_graphicsLayer->offsetFromRenderer());
     }
     
-    if (m_owningLayer.hasTransform()) {
+    if (m_owningLayer.renderer().hasTransformRelatedProperty()) {
         // Update properties that depend on layer dimensions.
         FloatPoint3D transformOrigin = computeTransformOriginForPainting(downcast<RenderBox>(renderer()).borderBoxRect());
         // Get layout bounds in the coords of compAncestor to match relativeCompositingBounds.
index 3e6c65d..184aa35 100644 (file)
@@ -2261,7 +2261,7 @@ CompositingReasons RenderLayerCompositor::reasonsForCompositing(const RenderLaye
         reasons |= CompositingReasonNegativeZIndexChildren;
         break;
     case RenderLayer::IndirectCompositingReason::GraphicalEffect:
-        if (renderer->layer()->transform())
+        if (renderer->hasTransform())
             reasons |= CompositingReasonTransformWithCompositedDescendants;
 
         if (renderer->isTransparent())
index 0a00e85..72eff9b 100644 (file)
@@ -147,7 +147,7 @@ void RenderLayerModelObject::styleDidChange(StyleDifference diff, const RenderSt
         if (oldStyle->hasBlendMode())
             layer()->parent()->dirtyAncestorChainHasBlendingDescendants();
 #endif
-        setHasTransform(false); // Either a transform wasn't specified or the object doesn't support transforms, so just null out the bit.
+        setHasTransformRelatedProperty(false); // All transform-related propeties force layers, so we know we don't have one or the object doesn't support them.
         setHasReflection(false);
         layer()->removeOnlyThisLayer(); // calls destroyLayer() which clears m_layer
         if (s_wasFloating && isFloating())
index 25612ba..fb78f3e 100644 (file)
@@ -1648,9 +1648,7 @@ void RenderObject::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformSt
 bool RenderObject::shouldUseTransformFromContainer(const RenderObject* containerObject) const
 {
 #if ENABLE(3D_RENDERING)
-    // hasTransform() indicates whether the object has transform, transform-style or perspective. We just care about transform,
-    // so check the layer's transform directly.
-    return (hasLayer() && downcast<RenderLayerModelObject>(*this).layer()->transform()) || (containerObject && containerObject->style().hasPerspective());
+    return hasTransform() || (containerObject && containerObject->style().hasPerspective());
 #else
     UNUSED_PARAM(containerObject);
     return hasTransform();
@@ -1811,6 +1809,7 @@ RenderElement* RenderObject::container(const RenderLayerModelObject* repaintCont
         // we'll just return 0).
         // FIXME: The definition of view() has changed to not crawl up the render tree.  It might
         // be safe now to use it.
+        // FIXME: share code with containingBlockForFixedPosition().
         while (o && o->parent() && !(o->hasTransform() && o->isRenderBlock())) {
             // foreignObject is the containing block for its contents.
             if (o->isSVGForeignObject())
@@ -1830,7 +1829,9 @@ RenderElement* RenderObject::container(const RenderLayerModelObject* repaintCont
         // Same goes here.  We technically just want our containing block, but
         // we may not have one if we're part of an uninstalled subtree.  We'll
         // climb as high as we can though.
-        while (o && o->style().position() == StaticPosition && !o->isRenderView() && !(o->hasTransform() && o->isRenderBlock())) {
+        // FIXME: share code with isContainingBlockCandidateForAbsolutelyPositionedObject().
+        // FIXME: hasTransformRelatedProperty() includes preserves3D() check, but this may need to change: https://www.w3.org/Bugs/Public/show_bug.cgi?id=27566
+        while (o && o->style().position() == StaticPosition && !o->isRenderView() && !(o->hasTransformRelatedProperty() && o->isRenderBlock())) {
             if (o->isSVGForeignObject()) // foreignObject is the containing block for contents inside it
                 break;
 
index 84f2255..bb8617b 100644 (file)
@@ -550,7 +550,8 @@ public:
 
     bool hasOverflowClip() const { return m_bitfields.hasOverflowClip(); }
 
-    bool hasTransform() const { return m_bitfields.hasTransform(); }
+    bool hasTransformRelatedProperty() const { return m_bitfields.hasTransformRelatedProperty(); } // Transform, perspective or transform-style: preserve-3d.
+    bool hasTransform() const { return hasTransformRelatedProperty() && style().hasTransform(); }
 
     inline bool preservesNewline() const;
 
@@ -616,7 +617,7 @@ public:
     void setHorizontalWritingMode(bool b = true) { m_bitfields.setHorizontalWritingMode(b); }
     void setHasOverflowClip(bool b = true) { m_bitfields.setHasOverflowClip(b); }
     void setHasLayer(bool b = true) { m_bitfields.setHasLayer(b); }
-    void setHasTransform(bool b = true) { m_bitfields.setHasTransform(b); }
+    void setHasTransformRelatedProperty(bool b = true) { m_bitfields.setHasTransformRelatedProperty(b); }
     void setHasReflection(bool b = true) { m_bitfields.setHasReflection(b); }
 
     // Hook so that RenderTextControl can return the line height of its inner renderer.
@@ -927,7 +928,7 @@ private:
             , m_isDragging(false)
             , m_hasLayer(false)
             , m_hasOverflowClip(false)
-            , m_hasTransform(false)
+            , m_hasTransformRelatedProperty(false)
             , m_hasReflection(false)
             , m_everHadLayout(false)
             , m_childrenInline(false)
@@ -958,7 +959,7 @@ private:
 
         ADD_BOOLEAN_BITFIELD(hasLayer, HasLayer);
         ADD_BOOLEAN_BITFIELD(hasOverflowClip, HasOverflowClip); // Set in the case of overflow:auto/scroll/hidden
-        ADD_BOOLEAN_BITFIELD(hasTransform, HasTransform);
+        ADD_BOOLEAN_BITFIELD(hasTransformRelatedProperty, HasTransformRelatedProperty);
         ADD_BOOLEAN_BITFIELD(hasReflection, HasReflection);
 
         ADD_BOOLEAN_BITFIELD(everHadLayout, EverHadLayout);
index ff29c28..a574114 100644 (file)
@@ -544,7 +544,7 @@ LayoutRect RenderRegion::layoutOverflowRectForBoxForPropagation(const RenderBox*
     if (!box->hasOverflowClip())
         rect.unite(layoutOverflowRectForBox(box));
 
-    bool hasTransform = box->hasLayer() && box->layer()->transform();
+    bool hasTransform = box->hasTransform();
     if (box->isInFlowPositioned() || hasTransform) {
         if (hasTransform)
             rect = box->layer()->currentTransform().mapRect(rect);
index 1096120..5d01149 100644 (file)
@@ -103,7 +103,7 @@ private:
     virtual void layout() override;
     virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const override;
 
-    virtual bool requiresLayer() const override { return hasOverflowClip() || hasTransform() || hasHiddenBackface() || hasClipPath() || createsGroup() || isStickyPositioned(); }
+    virtual bool requiresLayer() const override { return hasOverflowClip() || hasTransformRelatedProperty() || hasHiddenBackface() || hasClipPath() || createsGroup() || isStickyPositioned(); }
 
     virtual void paint(PaintInfo&, const LayoutPoint&) override;
 
index d1d5336..3de8961 100644 (file)
@@ -420,9 +420,9 @@ void RenderView::mapLocalToContainer(const RenderLayerModelObject* repaintContai
     ASSERT_ARG(repaintContainer, !repaintContainer || repaintContainer == this);
     ASSERT_UNUSED(wasFixed, !wasFixed || *wasFixed == (mode & IsFixed));
 
-    if (!repaintContainer && mode & UseTransforms && shouldUseTransformFromContainer(0)) {
+    if (!repaintContainer && mode & UseTransforms && shouldUseTransformFromContainer(nullptr)) {
         TransformationMatrix t;
-        getTransformFromContainer(0, LayoutSize(), t);
+        getTransformFromContainer(nullptr, LayoutSize(), t);
         transformState.applyTransform(t);
     }
     
@@ -446,9 +446,9 @@ const RenderObject* RenderView::pushMappingToContainer(const RenderLayerModelObj
     LayoutSize scrollOffset = frameView().scrollOffsetForFixedPosition();
 #endif
 
-    if (!ancestorToStopAt && shouldUseTransformFromContainer(0)) {
+    if (!ancestorToStopAt && shouldUseTransformFromContainer(nullptr)) {
         TransformationMatrix t;
-        getTransformFromContainer(0, LayoutSize(), t);
+        getTransformFromContainer(nullptr, LayoutSize(), t);
         geometryMap.pushView(this, scrollOffset, &t);
     } else
         geometryMap.pushView(this, scrollOffset);
@@ -465,9 +465,9 @@ void RenderView::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformStat
         transformState.move(frameView().scrollOffsetForFixedPosition());
 #endif
 
-    if (mode & UseTransforms && shouldUseTransformFromContainer(0)) {
+    if (mode & UseTransforms && shouldUseTransformFromContainer(nullptr)) {
         TransformationMatrix t;
-        getTransformFromContainer(0, LayoutSize(), t);
+        getTransformFromContainer(nullptr, LayoutSize(), t);
         transformState.applyTransform(t);
     }
 }