Title: [98361] trunk
Revision
98361
Author
simon.fra...@apple.com
Date
2011-10-25 10:54:11 -0700 (Tue, 25 Oct 2011)

Log Message

REGRESSION (r88580): Cursor fails to change to pointer on embedded Google maps popups
https://bugs.webkit.org/show_bug.cgi?id=62797

Source/WebCore:

Reviewed by Chris Marrin.

When hit testing through transformed layers, RenderLayer would simply use
the composited bounds of the layer as the localHitTestRect for hit testing sublayers.
However, this broke hit testing on pages that have a composited, non-transformed layer
which falls outside the bounds of its parent, composited-transformed layer, like Google
Maps.

Fix by mapping the hitTestRect through transforms. However this is tricky, because
mapping a rect into the coordinate system of a layer can result in invalid rectangles
when point projection results in a negative w component. Fix TransformationMatrix::projectPoint()
to detect this case and replace X and Y with large values, and add boundsOfProjectedQuad(), which
maps rectangles with possibly-infinite location or bounds into rects which are representable
in an IntRect.

Tests: transforms/3d/hit-testing/composited-hit-test.html
       transforms/3d/hit-testing/rotated-hit-test-with-child.html
       transforms/3d/hit-testing/rotated-hit-test2.html

* platform/graphics/transforms/TransformationMatrix.cpp:
(WebCore::TransformationMatrix::projectPoint):
(WebCore::TransformationMatrix::projectQuad):
(WebCore::clampEdgeValue):
(WebCore::TransformationMatrix::boundsOfProjectedQuad):
* platform/graphics/transforms/TransformationMatrix.h:
* rendering/HitTestingTransformState.cpp:
(WebCore::HitTestingTransformState::boundsOfMappedQuad):
* rendering/HitTestingTransformState.h:
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::hitTestLayer):

LayoutTests:

Reviewed by Chris Marrin.

New tests for hit testing through various configurations of 3D transforms.

* platform/mac/transforms/3d/hit-testing/rotated-hit-test-expected.png: Removed.
* platform/mac/transforms/3d/hit-testing/rotated-hit-test-expected.txt: Removed.
* transforms/3d/hit-testing/composited-hit-test-expected.txt: Added.
* transforms/3d/hit-testing/composited-hit-test.html: Added.
* transforms/3d/hit-testing/resources/hit-test-utils.js: Added.
* transforms/3d/hit-testing/rotated-hit-test-expected.txt: Added.
* transforms/3d/hit-testing/rotated-hit-test-with-child-expected.txt: Added.
* transforms/3d/hit-testing/rotated-hit-test-with-child.html: Added.
* transforms/3d/hit-testing/rotated-hit-test.html:
* transforms/3d/hit-testing/rotated-hit-test2-expected.txt: Added.
* transforms/3d/hit-testing/rotated-hit-test2.html: Added.

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (98360 => 98361)


--- trunk/LayoutTests/ChangeLog	2011-10-25 17:44:31 UTC (rev 98360)
+++ trunk/LayoutTests/ChangeLog	2011-10-25 17:54:11 UTC (rev 98361)
@@ -1,3 +1,24 @@
+2011-10-25  Simon Fraser  <simon.fra...@apple.com>
+
+        REGRESSION (r88580): Cursor fails to change to pointer on embedded Google maps popups
+        https://bugs.webkit.org/show_bug.cgi?id=62797
+
+        Reviewed by Chris Marrin.
+        
+        New tests for hit testing through various configurations of 3D transforms.
+
+        * platform/mac/transforms/3d/hit-testing/rotated-hit-test-expected.png: Removed.
+        * platform/mac/transforms/3d/hit-testing/rotated-hit-test-expected.txt: Removed.
+        * transforms/3d/hit-testing/composited-hit-test-expected.txt: Added.
+        * transforms/3d/hit-testing/composited-hit-test.html: Added.
+        * transforms/3d/hit-testing/resources/hit-test-utils.js: Added.
+        * transforms/3d/hit-testing/rotated-hit-test-expected.txt: Added.
+        * transforms/3d/hit-testing/rotated-hit-test-with-child-expected.txt: Added.
+        * transforms/3d/hit-testing/rotated-hit-test-with-child.html: Added.
+        * transforms/3d/hit-testing/rotated-hit-test.html:
+        * transforms/3d/hit-testing/rotated-hit-test2-expected.txt: Added.
+        * transforms/3d/hit-testing/rotated-hit-test2.html: Added.
+
 2011-10-24  Jer Noble  <jer.no...@apple.com>
 
         compositing/video tests time out on Lion

Deleted: trunk/LayoutTests/platform/mac/transforms/3d/hit-testing/rotated-hit-test-expected.png


(Binary files differ)

Deleted: trunk/LayoutTests/platform/mac/transforms/3d/hit-testing/rotated-hit-test-expected.txt (98360 => 98361)


--- trunk/LayoutTests/platform/mac/transforms/3d/hit-testing/rotated-hit-test-expected.txt	2011-10-25 17:44:31 UTC (rev 98360)
+++ trunk/LayoutTests/platform/mac/transforms/3d/hit-testing/rotated-hit-test-expected.txt	2011-10-25 17:54:11 UTC (rev 98361)
@@ -1,14 +0,0 @@
-layer at (0,0) size 800x600
-  RenderView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  RenderBlock {HTML} at (0,0) size 800x600
-    RenderBody {BODY} at (8,8) size 784x584
-      RenderBlock {DIV} at (0,202) size 784x18
-        RenderText {#text} at (0,0) size 124x18
-          text run at (0,0) width 124: "Found box1: PASS"
-        RenderBR {BR} at (124,14) size 0x0
-layer at (8,8) size 202x202
-  RenderBlock {DIV} at (0,0) size 202x202 [border: (1px solid #000000)]
-    RenderText {#text} at (0,0) size 0x0
-layer at (9,9) size 200x200
-  RenderBlock {DIV} at (1,1) size 200x200 [bgcolor=#808080]

Added: trunk/LayoutTests/transforms/3d/hit-testing/composited-hit-test-expected.txt (0 => 98361)


--- trunk/LayoutTests/transforms/3d/hit-testing/composited-hit-test-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/transforms/3d/hit-testing/composited-hit-test-expected.txt	2011-10-25 17:54:11 UTC (rev 98361)
@@ -0,0 +1,5 @@
+Element at 48, 48 has id "container": PASS
+Element at 75, 75 has id "target": PASS
+Element at 100, 100 has id "target": PASS
+Element at 125, 125 has id "target": PASS
+
Property changes on: trunk/LayoutTests/transforms/3d/hit-testing/composited-hit-test-expected.txt
___________________________________________________________________

Added: svn:mime-type

Added: svn:keywords

Added: svn:eol-style

Added: trunk/LayoutTests/transforms/3d/hit-testing/composited-hit-test.html (0 => 98361)


--- trunk/LayoutTests/transforms/3d/hit-testing/composited-hit-test.html	                        (rev 0)
+++ trunk/LayoutTests/transforms/3d/hit-testing/composited-hit-test.html	2011-10-25 17:54:11 UTC (rev 98361)
@@ -0,0 +1,64 @@
+<html>
+<head>
+  <style>
+   body {
+     margin: 0;
+   }
+
+   #canvas {
+     width: 200px;
+     height: 200px;
+     position: relative;
+     background-color: silver;
+     -webkit-transform: translateZ(0px);
+   }
+   
+   #container {
+     left: 0px;
+     top: 0px;
+     z-index: 1;
+     border: 2px solid green;
+     -webkit-transform: translateZ(0px);
+   }
+   
+   .box {
+     position: absolute;
+     height: 100px;
+     width: 100px;
+   }
+   
+   #target {
+     left: 50px;
+     top: 50px;
+     background-color: blue;
+     cursor: pointer;
+   }
+   
+   .box:hover {
+     background-color: orange !important;
+   }
+   #results {
+     margin: 10px;
+   }
+  </style>
+  <script src=""
+  <script>
+    const hitTestData = [
+      { 'point': [48, 48], 'target' : 'container' },
+      { 'point': [75, 75], 'target' : 'target' },
+      { 'point': [100, 100], 'target' : 'target' },
+      { 'point': [125, 125], 'target' : 'target' },
+    ];
+    window.addEventListener('load', runTest, false);
+  </script>
+</head>
+<body>
+  <div id="canvas">
+    <div id="container" class="box">
+      <div id="target" class="box">
+      </div>
+    </div>
+  </div>
+  <div id="results"></div>
+</body>
+</html>
Property changes on: trunk/LayoutTests/transforms/3d/hit-testing/composited-hit-test.html
___________________________________________________________________

Added: svn:mime-type

Added: svn:keywords

Added: svn:eol-style

Added: trunk/LayoutTests/transforms/3d/hit-testing/resources/hit-test-utils.js (0 => 98361)


--- trunk/LayoutTests/transforms/3d/hit-testing/resources/hit-test-utils.js	                        (rev 0)
+++ trunk/LayoutTests/transforms/3d/hit-testing/resources/hit-test-utils.js	2011-10-25 17:54:11 UTC (rev 98361)
@@ -0,0 +1,20 @@
+if (window.layoutTestController)
+  layoutTestController.dumpAsText();
+
+function log(s)
+{
+  var results = document.getElementById('results');
+  results.innerHTML += s + '<br>';
+}
+
+function runTest()
+{
+  for (var i = 0; i < hitTestData.length; ++i) {
+    var test = hitTestData[i];
+    var hit = document.elementFromPoint(test.point[0], test.point[1]);
+    if (hit.id == test.target)
+      log('Element at ' + test.point[0] + ', ' + test.point[1] + ' has id \"' + hit.id  + '\": PASS');
+    else
+      log('Element at ' + test.point[0] + ', ' + test.point[1] + ' is ' + hit.id  + ': FAIL');
+  }
+}
Property changes on: trunk/LayoutTests/transforms/3d/hit-testing/resources/hit-test-utils.js
___________________________________________________________________

Added: svn:mime-type

Added: svn:keywords

Added: svn:eol-style

Added: trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test-expected.txt (0 => 98361)


--- trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test-expected.txt	2011-10-25 17:54:11 UTC (rev 98361)
@@ -0,0 +1,9 @@
+Element at 85, 100 has id "left": PASS
+Element at 155, 80 has id "top": PASS
+Element at 230, 80 has id "right": PASS
+Element at 155, 220 has id "bottom": PASS
+Element at 60, 60 has id "container": PASS
+Element at 100, 100 has id "container": PASS
+Element at 240, 240 has id "container": PASS
+Element at 200, 200 has id "container": PASS
+
Property changes on: trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test-expected.txt
___________________________________________________________________

Added: svn:mime-type

Added: svn:keywords

Added: svn:eol-style

Added: trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test-with-child-expected.txt (0 => 98361)


--- trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test-with-child-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test-with-child-expected.txt	2011-10-25 17:54:11 UTC (rev 98361)
@@ -0,0 +1,5 @@
+Element at 30, 30 has id "box1": PASS
+Element at 80, 100 has id "box1": PASS
+Element at 100, 120 has id "box2": PASS
+Element at 200, 250 has id "box2": PASS
+
Property changes on: trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test-with-child-expected.txt
___________________________________________________________________

Added: svn:mime-type

Added: svn:keywords

Added: svn:eol-style

Added: trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test-with-child.html (0 => 98361)


--- trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test-with-child.html	                        (rev 0)
+++ trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test-with-child.html	2011-10-25 17:54:11 UTC (rev 98361)
@@ -0,0 +1,64 @@
+<html>
+<head>
+  <style type="text/css" media="screen">
+  
+  div:hover {
+    outline: 2px solid orange;
+  }
+    #container {
+      width: 200px;
+      height: 200px;
+      border: 1px solid black;
+      -webkit-perspective: 500px;
+    }
+    
+    .box {
+      width: 200px;
+      height: 200px;
+      position: absolute;
+      background-color: gray;
+    }
+    
+    .middle {
+      -webkit-transform-origin: 10% 50%;
+      -webkit-transform: rotateY(40deg);
+    }
+    
+    .box:hover {
+      background-color: orange !important;
+    }
+    
+    .child {
+      position: absolute;
+      top: 100px;
+      left: 100px;
+      background-color: blue;
+      -webkit-transform: translateZ(1px);
+    }
+    
+    #results {
+      margin-top: 100px;
+    }
+  </style>
+  <script src=""
+  <script>
+    const hitTestData = [
+      { 'point': [30, 30], 'target' : 'box1' },
+      { 'point': [80, 100], 'target' : 'box1' },
+      { 'point': [100, 120], 'target' : 'box2' },
+      { 'point': [200, 250], 'target' : 'box2' },
+    ];
+    window.addEventListener('load', runTest, false);
+  </script>
+</head>
+<body>
+
+<div id="container">
+  <div class="middle box" id="box1">
+    <div class="child box" id="box2"></div>
+  </div>
+</div>
+
+<div id="results"></div>
+</body>
+</html>
Property changes on: trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test-with-child.html
___________________________________________________________________

Added: svn:mime-type

Added: svn:keywords

Added: svn:eol-style

Modified: trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test.html (98360 => 98361)


--- trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test.html	2011-10-25 17:44:31 UTC (rev 98360)
+++ trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test.html	2011-10-25 17:54:11 UTC (rev 98361)
@@ -1,60 +1,73 @@
 <html>
 <head>
-  <title>Hit testing of almost edge-on elements</title>
-  <style type="text/css" media="screen">
-  
-  div:hover {
-    outline: 2px solid orange;
-  }
+  <style type="text/css">
+    body {
+      margin: 0;
+    }
     #container {
       width: 200px;
       height: 200px;
+      margin: 50px;
       border: 1px solid black;
-      -webkit-perspective: 500;
+      -webkit-perspective: 500px;
     }
     
     .box {
-      display: inline-block;
+      position: absolute;
       width: 200px;
       height: 200px;
       background-color: gray;
+      opacity: 0.75;
+    }
+    
+    #left {
       -webkit-transform-origin: 10% 50%;
       -webkit-transform: rotateY(90deg);
     }
-    .box:hover {
-      background-color: orange;
+
+    #top {
+      -webkit-transform-origin: 50% 10%;
+      -webkit-transform: rotateX(-90deg);
     }
-  </style>
-  <script type="text/_javascript_" charset="utf-8">
-    function log(s)
-    {
-      var results = document.getElementById('results');
-      results.innerHTML += s + '<br>';
+
+    #right {
+      -webkit-transform-origin: 90% 50%;
+      -webkit-transform: rotateY(-90deg);
     }
 
-    function runTest()
-    {
-      var firstHit = document.elementFromPoint(40, 150);
-      
-      var box1 = document.getElementById('box1');
-      var container = document.getElementById('container');
+    #bottom {
+      -webkit-transform-origin: 50% 90%;
+      -webkit-transform: rotateX(90deg);
+    }
 
-      if (firstHit == box1)
-        log('Found box1: PASS');
-      else
-        log('Found ' + firstHit.id + ' : FAIL');
+    .box:hover {
+      background-color: orange;
     }
-    
+  </style>
+  <script src=""
+  <script>
+      const hitTestData = [
+        { 'point': [85, 100], 'target' : 'left' },
+        { 'point': [155, 80], 'target' : 'top' },
+        { 'point': [230, 80], 'target' : 'right' },
+        { 'point': [155, 220], 'target' : 'bottom' },
+        { 'point': [60, 60], 'target' : 'container' },
+        { 'point': [100, 100], 'target' : 'container' },
+        { 'point': [240, 240], 'target' : 'container' },
+        { 'point': [200, 200], 'target' : 'container' },
+      ];
+      window.addEventListener('load', runTest, false);
   </script>
 </head>
-<body _onload_="runTest()">
+<body>
 
 <div id="container">
-  <div class="box" id="box1"></div>
+  <div class="box" id="left"></div>
+  <div class="box" id="top"></div>
+  <div class="box" id="right"></div>
+  <div class="box" id="bottom"></div>
 </div>
 
-<div id="results">
-</div>
-
+<div id="results"></div>
 </body>
 </html>

Added: trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test2-expected.txt (0 => 98361)


--- trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test2-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test2-expected.txt	2011-10-25 17:54:11 UTC (rev 98361)
@@ -0,0 +1,9 @@
+Element at 170, 250 has id "left": PASS
+Element at 260, 170 has id "top": PASS
+Element at 330, 250 has id "right": PASS
+Element at 260, 330 has id "bottom": PASS
+Element at 60, 60 has id "container": PASS
+Element at 160, 160 has id "container": PASS
+Element at 190, 190 has id "container": PASS
+Element at 310, 310 has id "container": PASS
+
Property changes on: trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test2-expected.txt
___________________________________________________________________

Added: svn:mime-type

Added: svn:keywords

Added: svn:eol-style

Added: trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test2.html (0 => 98361)


--- trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test2.html	                        (rev 0)
+++ trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test2.html	2011-10-25 17:54:11 UTC (rev 98361)
@@ -0,0 +1,79 @@
+<html>
+<head>
+  <style>
+    body {
+      margin: 0;
+    }
+    
+    #container {
+      width: 400px;
+      height: 400px;
+      margin: 50px;
+      border: 1px solid black;
+      -webkit-perspective: 500px;
+    }
+    
+    .box {
+      position: absolute;
+      width: 200px;
+      height: 200px;
+      background-color: gray;
+      opacity: 0.75;
+    }
+    
+    #left {
+      -webkit-transform: rotateY(-75deg);
+      left: 20px;
+      top: 100px;
+    }
+
+    #top {
+      -webkit-transform: rotateX(75deg);
+      top: 20px;
+      left: 100px;
+    }
+
+    #right {
+      -webkit-transform: rotateY(75deg);
+      left: 180px;
+      top: 100px;
+    }
+
+    #bottom {
+      -webkit-transform: rotateX(-75deg);
+      top: 180px;
+      left: 100px;
+    }
+
+    .box:hover {
+      background-color: orange;
+    }
+  </style>
+  <script src=""
+  <script>
+      const hitTestData = [
+        { 'point': [170, 250], 'target' : 'left' },
+        { 'point': [260, 170], 'target' : 'top' },
+        { 'point': [330, 250], 'target' : 'right' },
+        { 'point': [260, 330], 'target' : 'bottom' },
+        { 'point': [60, 60], 'target' : 'container' },
+        { 'point': [160, 160], 'target' : 'container' },
+        { 'point': [190, 190], 'target' : 'container' },
+        { 'point': [310, 310], 'target' : 'container' },
+      ];
+      window.addEventListener('load', runTest, false);
+  </script>
+</head>
+<body>
+
+<div id="container">
+  <div class="box" id="left"></div>
+  <div class="box" id="top"></div>
+  <div class="box" id="right"></div>
+  <div class="box" id="bottom"></div>
+</div>
+
+<div id="results"></div>
+
+</body>
+</html>
Property changes on: trunk/LayoutTests/transforms/3d/hit-testing/rotated-hit-test2.html
___________________________________________________________________

Added: svn:mime-type

Added: svn:keywords

Added: svn:eol-style

Modified: trunk/Source/WebCore/ChangeLog (98360 => 98361)


--- trunk/Source/WebCore/ChangeLog	2011-10-25 17:44:31 UTC (rev 98360)
+++ trunk/Source/WebCore/ChangeLog	2011-10-25 17:54:11 UTC (rev 98361)
@@ -1,3 +1,39 @@
+2011-10-25  Simon Fraser  <simon.fra...@apple.com>
+
+        REGRESSION (r88580): Cursor fails to change to pointer on embedded Google maps popups
+        https://bugs.webkit.org/show_bug.cgi?id=62797
+
+        Reviewed by Chris Marrin.
+        
+        When hit testing through transformed layers, RenderLayer would simply use
+        the composited bounds of the layer as the localHitTestRect for hit testing sublayers.
+        However, this broke hit testing on pages that have a composited, non-transformed layer
+        which falls outside the bounds of its parent, composited-transformed layer, like Google
+        Maps.
+        
+        Fix by mapping the hitTestRect through transforms. However this is tricky, because
+        mapping a rect into the coordinate system of a layer can result in invalid rectangles
+        when point projection results in a negative w component. Fix TransformationMatrix::projectPoint()
+        to detect this case and replace X and Y with large values, and add boundsOfProjectedQuad(), which 
+        maps rectangles with possibly-infinite location or bounds into rects which are representable
+        in an IntRect.
+
+        Tests: transforms/3d/hit-testing/composited-hit-test.html
+               transforms/3d/hit-testing/rotated-hit-test-with-child.html
+               transforms/3d/hit-testing/rotated-hit-test2.html
+
+        * platform/graphics/transforms/TransformationMatrix.cpp:
+        (WebCore::TransformationMatrix::projectPoint):
+        (WebCore::TransformationMatrix::projectQuad):
+        (WebCore::clampEdgeValue):
+        (WebCore::TransformationMatrix::boundsOfProjectedQuad):
+        * platform/graphics/transforms/TransformationMatrix.h:
+        * rendering/HitTestingTransformState.cpp:
+        (WebCore::HitTestingTransformState::boundsOfMappedQuad):
+        * rendering/HitTestingTransformState.h:
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::hitTestLayer):
+
 2011-10-25  Adrienne Walker  <e...@google.com>
 
         [chromium] Batch up texture uploads so that they can be updated incrementally

Modified: trunk/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp (98360 => 98361)


--- trunk/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp	2011-10-25 17:44:31 UTC (rev 98360)
+++ trunk/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp	2011-10-25 17:54:11 UTC (rev 98361)
@@ -36,6 +36,8 @@
 #include <wtf/Assertions.h>
 #include <wtf/MathExtras.h>
 
+using namespace std;
+
 namespace WebCore {
 
 //
@@ -532,7 +534,7 @@
     return scaleNonUniform(1.0f, -1.0f);
 }
 
-FloatPoint TransformationMatrix::projectPoint(const FloatPoint& p) const
+FloatPoint TransformationMatrix::projectPoint(const FloatPoint& p, bool* clamped) const
 {
     // This is basically raytracing. We have a point in the destination
     // plane with z=0, and we cast a ray parallel to the z-axis from that
@@ -546,16 +548,24 @@
     // intersection point as a distance d from R0 in units of Rd by:
     // 
     // d = -dot (Pn', R0) / dot (Pn', Rd)
+    if (clamped)
+        *clamped = false;
     
     double x = p.x();
     double y = p.y();
     double z = -(m13() * x + m23() * y + m43()) / m33();
 
+    // FIXME: use multVecMatrix()
     double outX = x * m11() + y * m21() + z * m31() + m41();
     double outY = x * m12() + y * m22() + z * m32() + m42();
 
     double w = x * m14() + y * m24() + z * m34() + m44();
-    if (w != 1 && w != 0) {
+    if (w <= 0) {
+        outX = copysign(numeric_limits<int>::max(), outX);
+        outY = copysign(numeric_limits<int>::max(), outY);
+        if (clamped)
+            *clamped = true;
+    } else if (w != 1) {
         outX /= w;
         outY /= w;
     }
@@ -570,9 +580,39 @@
     projectedQuad.setP2(projectPoint(q.p2()));
     projectedQuad.setP3(projectPoint(q.p3()));
     projectedQuad.setP4(projectPoint(q.p4()));
+    
     return projectedQuad;
 }
 
+static float clampEdgeValue(float f)
+{
+    ASSERT(!isnan(f));
+    return min<float>(max<float>(f, -numeric_limits<int>::max() / 2), numeric_limits<int>::max() / 2);
+}
+
+IntRect TransformationMatrix::clampedBoundsOfProjectedQuad(const FloatQuad& q) const
+{
+    FloatRect mappedQuadBounds = projectQuad(q).boundingBox();
+
+    float left = clampEdgeValue(floorf(mappedQuadBounds.x()));
+    float top = clampEdgeValue(floorf(mappedQuadBounds.y()));
+
+    float right;
+    if (isinf(mappedQuadBounds.x()) && isinf(mappedQuadBounds.width()))
+        right = numeric_limits<int>::max() / 2;
+    else
+        right = clampEdgeValue(ceilf(mappedQuadBounds.maxX()));
+
+    float bottom;
+    if (isinf(mappedQuadBounds.y()) && isinf(mappedQuadBounds.height()))
+        bottom = numeric_limits<int>::max() / 2;
+    else
+        bottom = clampEdgeValue(ceilf(mappedQuadBounds.maxY()));
+    
+    return IntRect(clampToInteger(left), clampToInteger(top), 
+                   clampToInteger(right - left), clampToInteger(bottom - top));
+}
+
 FloatPoint TransformationMatrix::mapPoint(const FloatPoint& p) const
 {
     if (isIdentityOrTranslation())

Modified: trunk/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h (98360 => 98361)


--- trunk/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h	2011-10-25 17:44:31 UTC (rev 98360)
+++ trunk/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h	2011-10-25 17:54:11 UTC (rev 98361)
@@ -156,9 +156,12 @@
     // a ray perpendicular to the source plane and computing
     // the local x,y position of the point where that ray intersects
     // with the destination plane.
-    FloatPoint projectPoint(const FloatPoint&) const;
+    FloatPoint projectPoint(const FloatPoint&, bool* clamped = 0) const;
     // Projects the four corners of the quad
     FloatQuad projectQuad(const FloatQuad&) const;
+    // Projects the four corners of the quad and takes a bounding box,
+    // while sanitizing values created when the w component is negative.
+    IntRect clampedBoundsOfProjectedQuad(const FloatQuad&) const;
 
     double m11() const { return m_matrix[0][0]; }
     void setM11(double f) { m_matrix[0][0] = f; }

Modified: trunk/Source/WebCore/rendering/HitTestingTransformState.cpp (98360 => 98361)


--- trunk/Source/WebCore/rendering/HitTestingTransformState.cpp	2011-10-25 17:44:31 UTC (rev 98360)
+++ trunk/Source/WebCore/rendering/HitTestingTransformState.cpp	2011-10-25 17:54:11 UTC (rev 98361)
@@ -73,4 +73,9 @@
     return m_accumulatedTransform.inverse().projectQuad(m_lastPlanarQuad);
 }
 
+IntRect HitTestingTransformState::boundsOfMappedQuad() const
+{
+    return m_accumulatedTransform.inverse().clampedBoundsOfProjectedQuad(m_lastPlanarQuad);
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/rendering/HitTestingTransformState.h (98360 => 98361)


--- trunk/Source/WebCore/rendering/HitTestingTransformState.h	2011-10-25 17:44:31 UTC (rev 98360)
+++ trunk/Source/WebCore/rendering/HitTestingTransformState.h	2011-10-25 17:54:11 UTC (rev 98361)
@@ -58,6 +58,7 @@
 
     FloatPoint mappedPoint() const;
     FloatQuad mappedQuad() const;
+    IntRect boundsOfMappedQuad() const;
     void flatten();
 
     FloatPoint m_lastPlanarPoint;

Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (98360 => 98361)


--- trunk/Source/WebCore/rendering/RenderLayer.cpp	2011-10-25 17:44:31 UTC (rev 98360)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp	2011-10-25 17:54:11 UTC (rev 98361)
@@ -3142,14 +3142,7 @@
         // We can't just map hitTestPoint and hitTestRect because they may have been flattened (losing z)
         // by our container.
         LayoutPoint localPoint = roundedLayoutPoint(newTransformState->mappedPoint());
-        LayoutRect localHitTestRect;
-#if USE(ACCELERATED_COMPOSITING)
-        if (isComposited()) {
-            // It doesn't make sense to project hitTestRect into the plane of this layer, so use the same bounds we use for painting.
-            localHitTestRect = backing()->compositedBounds();
-        } else
-#endif
-            localHitTestRect = newTransformState->mappedQuad().enclosingBoundingBox();
+        LayoutRect localHitTestRect = newTransformState->boundsOfMappedQuad();
 
         // Now do a hit test with the root layer shifted to be us.
         return hitTestLayer(this, containerLayer, request, result, localHitTestRect, localPoint, true, newTransformState.get(), zOffset);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to