<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[164252] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/164252">164252</a></dd>
<dt>Author</dt> <dd>simon.fraser@apple.com</dd>
<dt>Date</dt> <dd>2014-02-17 15:45:44 -0800 (Mon, 17 Feb 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>box-shadows get truncated with a combination of transforms and clip: (affects Google Maps)
https://bugs.webkit.org/show_bug.cgi?id=128937

Source/WebCore:

Reviewed by Dean Jackson.

RenderLayer::calculateLayerBounds() incorrectly assumed that if localClipRect() returns
a non-infinite rect, that rect is OK to use as the compositing bounds.

That is not a valid assumption when clip() has a larger rect than the element (e.g.
with negative top/left in the rect). In that case, localClipRect() still just
returns the background rect, but we actually need a larger compositing layer
to show the unclipped parts of descendants.

Fix by detecting clip() that exceeds the renderer bounds, and when it does,
not early returning in the UseLocalClipRectIfPossible clause.

Test: compositing/geometry/css-clip-oversize.html

* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::localClipRect): Do a convertToLayerCoords()
because we need offsetFromRoot later, and we can pass our value down to
calculateRects(). Compute clipExceedsBounds based on the CSS clip rect.
(WebCore::RenderLayer::calculateClipRects): Don't early return if clipExceedsBounds
is true.
* rendering/RenderLayer.h:

LayoutTests:

Reviewed by Dean Jackson.

Test with CSS clip() with a rect larger than the border box, and compositing.

* compositing/geometry/clip-expected.txt: New expectation. This is a progression.
* compositing/geometry/css-clip-oversize-expected.html: Added.
* compositing/geometry/css-clip-oversize.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestscompositinggeometryclipexpectedtxt">trunk/LayoutTests/compositing/geometry/clip-expected.txt</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderLayercpp">trunk/Source/WebCore/rendering/RenderLayer.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderLayerh">trunk/Source/WebCore/rendering/RenderLayer.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestscompositinggeometrycssclipoversizeexpectedhtml">trunk/LayoutTests/compositing/geometry/css-clip-oversize-expected.html</a></li>
<li><a href="#trunkLayoutTestscompositinggeometrycssclipoversizehtml">trunk/LayoutTests/compositing/geometry/css-clip-oversize.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (164251 => 164252)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-02-17 23:29:31 UTC (rev 164251)
+++ trunk/LayoutTests/ChangeLog        2014-02-17 23:45:44 UTC (rev 164252)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2014-02-17  Simon Fraser  &lt;simon.fraser@apple.com&gt;
+
+        box-shadows get truncated with a combination of transforms and clip: (affects Google Maps)
+        https://bugs.webkit.org/show_bug.cgi?id=128937
+
+        Reviewed by Dean Jackson.
+        
+        Test with CSS clip() with a rect larger than the border box, and compositing.
+
+        * compositing/geometry/clip-expected.txt: New expectation. This is a progression.
+        * compositing/geometry/css-clip-oversize-expected.html: Added.
+        * compositing/geometry/css-clip-oversize.html: Added.
+
</ins><span class="cx"> 2014-02-17  Chris Fleizach  &lt;cfleizach@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         AX: Invalid cast in WebCore::AccessibilityTable::isDataTable (CRBug 280352)
</span></span></pre></div>
<a id="trunkLayoutTestscompositinggeometryclipexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/compositing/geometry/clip-expected.txt (164251 => 164252)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/compositing/geometry/clip-expected.txt        2014-02-17 23:29:31 UTC (rev 164251)
+++ trunk/LayoutTests/compositing/geometry/clip-expected.txt        2014-02-17 23:45:44 UTC (rev 164252)
</span><span class="lines">@@ -8,9 +8,8 @@
</span><span class="cx">       (contentsOpaque 1)
</span><span class="cx">       (children 2
</span><span class="cx">         (GraphicsLayer
</span><del>-          (position 20.00 20.00)
-          (bounds 100.00 100.00)
-          (contentsOpaque 1)
</del><ins>+          (position 15.00 15.00)
+          (bounds 110.00 110.00)
</ins><span class="cx">           (drawsContent 1)
</span><span class="cx">           (transform [1.00 0.00 0.00 0.00] [0.00 1.00 0.00 0.00] [0.00 0.00 1.00 0.00] [0.00 0.00 1.00 1.00])
</span><span class="cx">         )
</span></span></pre></div>
<a id="trunkLayoutTestscompositinggeometrycssclipoversizeexpectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/compositing/geometry/css-clip-oversize-expected.html (0 => 164252)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/compositing/geometry/css-clip-oversize-expected.html                                (rev 0)
+++ trunk/LayoutTests/compositing/geometry/css-clip-oversize-expected.html        2014-02-17 23:45:44 UTC (rev 164252)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+
+&lt;html&gt;
+&lt;head&gt;
+    &lt;style&gt;
+        .parent {
+            position: absolute;
+            height: 100px;
+            width: 500px;
+            margin: 50px;
+            background: silver;
+            clip: rect(0px, 520px, 600px, -20px); /* top, right, bottom, left */
+            -webkit-transform: translateZ(0);
+        }        
+
+        .child {
+            position: absolute;
+            top: 50px;
+            height: 100px;
+            width: 400px;
+            background: #ffea61;
+            box-shadow: 0 0 50px black;
+        }
+    &lt;/style&gt;
+&lt;/head&gt;
+&lt;body&gt;
+    &lt;div class=&quot;shared parent&quot;&gt;
+      &lt;div class=&quot;shared child&quot;&gt;&lt;/div&gt;
+    &lt;/div&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestscompositinggeometrycssclipoversizehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/compositing/geometry/css-clip-oversize.html (0 => 164252)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/compositing/geometry/css-clip-oversize.html                                (rev 0)
+++ trunk/LayoutTests/compositing/geometry/css-clip-oversize.html        2014-02-17 23:45:44 UTC (rev 164252)
</span><span class="lines">@@ -0,0 +1,30 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+
+&lt;html&gt;
+&lt;head&gt;
+    &lt;style&gt;
+        .parent {
+            position: absolute;
+            height: 100px;
+            width: 500px;
+            margin: 50px;
+            background: silver;
+            clip: rect(0px, 520px, 600px, -20px); /* top, right, bottom, left */
+        }        
+
+        .child {
+            position: absolute;
+            top: 50px;
+            height: 100px;
+            width: 400px;
+            background: #ffea61;
+            box-shadow: 0 0 50px black;
+        }
+    &lt;/style&gt;
+&lt;/head&gt;
+&lt;body&gt;
+    &lt;div class=&quot;shared parent&quot;&gt;
+      &lt;div class=&quot;shared child&quot;&gt;&lt;/div&gt;
+    &lt;/div&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (164251 => 164252)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-02-17 23:29:31 UTC (rev 164251)
+++ trunk/Source/WebCore/ChangeLog        2014-02-17 23:45:44 UTC (rev 164252)
</span><span class="lines">@@ -1,3 +1,31 @@
</span><ins>+2014-02-17  Simon Fraser  &lt;simon.fraser@apple.com&gt;
+
+        box-shadows get truncated with a combination of transforms and clip: (affects Google Maps)
+        https://bugs.webkit.org/show_bug.cgi?id=128937
+
+        Reviewed by Dean Jackson.
+        
+        RenderLayer::calculateLayerBounds() incorrectly assumed that if localClipRect() returns
+        a non-infinite rect, that rect is OK to use as the compositing bounds.
+        
+        That is not a valid assumption when clip() has a larger rect than the element (e.g.
+        with negative top/left in the rect). In that case, localClipRect() still just
+        returns the background rect, but we actually need a larger compositing layer
+        to show the unclipped parts of descendants.
+        
+        Fix by detecting clip() that exceeds the renderer bounds, and when it does,
+        not early returning in the UseLocalClipRectIfPossible clause.
+
+        Test: compositing/geometry/css-clip-oversize.html
+
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::localClipRect): Do a convertToLayerCoords()
+        because we need offsetFromRoot later, and we can pass our value down to
+        calculateRects(). Compute clipExceedsBounds based on the CSS clip rect.
+        (WebCore::RenderLayer::calculateClipRects): Don't early return if clipExceedsBounds
+        is true.
+        * rendering/RenderLayer.h:
+
</ins><span class="cx"> 2014-02-17  Antti Koivisto  &lt;antti@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Make TreeScope::rootNode return a reference
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderLayercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (164251 => 164252)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderLayer.cpp        2014-02-17 23:29:31 UTC (rev 164251)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp        2014-02-17 23:45:44 UTC (rev 164252)
</span><span class="lines">@@ -5526,20 +5526,32 @@
</span><span class="cx">     return clippingRootLayer-&gt;renderer().localToAbsoluteQuad(FloatQuad(backgroundRect.rect())).enclosingBoundingBox();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-LayoutRect RenderLayer::localClipRect() const
</del><ins>+LayoutRect RenderLayer::localClipRect(bool&amp; clipExceedsBounds) const
</ins><span class="cx"> {
</span><ins>+    clipExceedsBounds = false;
+    
</ins><span class="cx">     // FIXME: border-radius not accounted for.
</span><span class="cx">     // FIXME: Regions not accounted for.
</span><span class="cx">     RenderLayer* clippingRootLayer = clippingRootForPainting();
</span><ins>+
+    LayoutPoint offsetFromRoot;
+    convertToLayerCoords(clippingRootLayer, offsetFromRoot);
+
</ins><span class="cx">     LayoutRect layerBounds;
</span><span class="cx">     ClipRect backgroundRect, foregroundRect, outlineRect;
</span><span class="cx">     ClipRectsContext clipRectsContext(clippingRootLayer, 0, PaintingClipRects);
</span><del>-    calculateRects(clipRectsContext, LayoutRect::infiniteRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
</del><ins>+    calculateRects(clipRectsContext, LayoutRect::infiniteRect(), layerBounds, backgroundRect, foregroundRect, outlineRect, &amp;offsetFromRoot);
</ins><span class="cx"> 
</span><span class="cx">     LayoutRect clipRect = backgroundRect.rect();
</span><span class="cx">     if (clipRect == LayoutRect::infiniteRect())
</span><span class="cx">         return clipRect;
</span><span class="cx"> 
</span><ins>+    if (renderer().hasClip()) {
+        // CSS clip may be larger than our border box.
+        LayoutRect cssClipRect = toRenderBox(renderer()).clipRect(offsetFromRoot, clipRectsContext.region);
+        clipExceedsBounds = !clipRect.contains(cssClipRect);
+    }
+
</ins><span class="cx">     LayoutPoint clippingRootOffset;
</span><span class="cx">     convertToLayerCoords(clippingRootLayer, clippingRootOffset);
</span><span class="cx">     clipRect.moveBy(-clippingRootOffset);
</span><span class="lines">@@ -5729,8 +5741,9 @@
</span><span class="cx">     LayoutRect unionBounds = boundingBoxRect;
</span><span class="cx"> 
</span><span class="cx">     if (flags &amp; UseLocalClipRectIfPossible) {
</span><del>-        LayoutRect localClipRect = this-&gt;localClipRect();
-        if (localClipRect != LayoutRect::infiniteRect()) {
</del><ins>+        bool clipExceedsBounds = false;
+        LayoutRect localClipRect = this-&gt;localClipRect(clipExceedsBounds);
+        if (localClipRect != LayoutRect::infiniteRect() &amp;&amp; !clipExceedsBounds) {
</ins><span class="cx">             if ((flags &amp; IncludeSelfTransform) &amp;&amp; paintsWithTransform(PaintBehaviorNormal))
</span><span class="cx">                 localClipRect = transform()-&gt;mapRect(localClipRect);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderLayerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderLayer.h (164251 => 164252)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderLayer.h        2014-02-17 23:29:31 UTC (rev 164251)
+++ trunk/Source/WebCore/rendering/RenderLayer.h        2014-02-17 23:45:44 UTC (rev 164252)
</span><span class="lines">@@ -693,7 +693,7 @@
</span><span class="cx"> 
</span><span class="cx">     LayoutRect childrenClipRect() const; // Returns the foreground clip rect of the layer in the document's coordinate space.
</span><span class="cx">     LayoutRect selfClipRect() const; // Returns the background clip rect of the layer in the document's coordinate space.
</span><del>-    LayoutRect localClipRect() const; // Returns the background clip rect of the layer in the local coordinate space.
</del><ins>+    LayoutRect localClipRect(bool&amp; clipExceedsBounds) const; // Returns the background clip rect of the layer in the local coordinate space.
</ins><span class="cx"> 
</span><span class="cx">     // Pass offsetFromRoot if known.
</span><span class="cx">     bool intersectsDamageRect(const LayoutRect&amp; layerBounds, const LayoutRect&amp; damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot = 0, RenderRegion* = 0) const;
</span></span></pre>
</div>
</div>

</body>
</html>