Diff
Modified: trunk/Source/WebCore/ChangeLog (113605 => 113606)
--- trunk/Source/WebCore/ChangeLog 2012-04-09 19:31:39 UTC (rev 113605)
+++ trunk/Source/WebCore/ChangeLog 2012-04-09 19:31:56 UTC (rev 113606)
@@ -1,3 +1,30 @@
+2012-04-09 Shawn Singh <[email protected]>
+
+ [chromium] Fix layer sorting perspective w if w becomes negative
+ https://bugs.webkit.org/show_bug.cgi?id=82997
+
+ Reviewed by Adrienne Walker.
+
+ Unit test added to CCLayerSorterTest.cpp.
+
+ This is a follow-up patch after r113364. That other patch
+ implemented proper clipping so that perspective transforms do not
+ accidentally make geometry disappear. This patch fixes a similar
+ problem in the layer sorter code so that layers do not
+ accidentally get sorted incorrectly.
+
+ * platform/graphics/chromium/cc/CCLayerSorter.cpp:
+ (WebCore::CCLayerSorter::LayerShape::LayerShape):
+ * platform/graphics/chromium/cc/CCMathUtil.cpp:
+ (WebCore::computeEnclosingRect):
+ (WebCore::addVertexToClippedQuad):
+ (WebCore::CCMathUtil::mapClippedQuad):
+ (WebCore):
+ (WebCore::CCMathUtil::computeEnclosingRectOfVertices):
+ * platform/graphics/chromium/cc/CCMathUtil.h:
+ (WebCore):
+ (CCMathUtil):
+
2012-04-09 Martin Robinson <[email protected]>
[soup] Crash while loading http://www.jusco.cn
Modified: trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerSorter.cpp (113605 => 113606)
--- trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerSorter.cpp 2012-04-09 19:31:39 UTC (rev 113605)
+++ trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerSorter.cpp 2012-04-09 19:31:56 UTC (rev 113606)
@@ -27,6 +27,7 @@
#include "cc/CCLayerSorter.h"
#include "TransformationMatrix.h"
+#include "cc/CCMathUtil.h"
#include "cc/CCRenderSurface.h"
#include <limits.h>
#include <wtf/Deque.h>
@@ -158,9 +159,31 @@
FloatPoint(-width * 0.5, -height * 0.5));
// Compute the projection of the layer quad onto the z = 0 plane.
- projectedQuad = drawTransform.mapQuad(layerQuad);
- projectedBounds = projectedQuad.boundingBox();
+ FloatPoint clippedQuad[8];
+ int numVerticesInClippedQuad;
+ CCMathUtil::mapClippedQuad(drawTransform, layerQuad, clippedQuad, numVerticesInClippedQuad);
+
+ if (numVerticesInClippedQuad < 3) {
+ projectedBounds = FloatRect();
+ return;
+ }
+
+ projectedBounds = CCMathUtil::computeEnclosingRectOfVertices(clippedQuad, numVerticesInClippedQuad);
+
+ // NOTE: it will require very significant refactoring and overhead to deal with
+ // generalized polygons or multiple quads per layer here. For the sake of layer
+ // sorting it is equally correct to take a subsection of the polygon that can be made
+ // into a quad. This will only be incorrect in the case of intersecting layers, which
+ // are not supported yet anyway.
+ projectedQuad.setP1(clippedQuad[0]);
+ projectedQuad.setP2(clippedQuad[1]);
+ projectedQuad.setP3(clippedQuad[2]);
+ if (numVerticesInClippedQuad >= 4)
+ projectedQuad.setP4(clippedQuad[3]);
+ else
+ projectedQuad.setP4(clippedQuad[2]); // this will be a degenerate quad that is actually a triangle.
+
// Compute the normal of the layer's plane.
FloatPoint3D c1 = drawTransform.mapPoint(FloatPoint3D(0, 0, 0));
FloatPoint3D c2 = drawTransform.mapPoint(FloatPoint3D(0, 1, 0));
Modified: trunk/Source/WebCore/platform/graphics/chromium/cc/CCMathUtil.cpp (113605 => 113606)
--- trunk/Source/WebCore/platform/graphics/chromium/cc/CCMathUtil.cpp 2012-04-09 19:31:39 UTC (rev 113605)
+++ trunk/Source/WebCore/platform/graphics/chromium/cc/CCMathUtil.cpp 2012-04-09 19:31:56 UTC (rev 113606)
@@ -131,12 +131,23 @@
ymax = std::max(p.y(), ymax);
}
-static FloatRect computeEnclosingRectOfClippedQuad(const HomogeneousCoordinate& h1, const HomogeneousCoordinate& h2, const HomogeneousCoordinate& h3, const HomogeneousCoordinate& h4)
+static FloatRect computeEnclosingRect(const HomogeneousCoordinate& h1, const HomogeneousCoordinate& h2, const HomogeneousCoordinate& h3, const HomogeneousCoordinate& h4)
{
// This function performs clipping as necessary and computes the enclosing 2d
// FloatRect of the vertices. Doing these two steps simultaneously allows us to avoid
// the overhead of storing an unknown number of clipped vertices.
+ // If no vertices on the quad are clipped, then we can simply return the enclosing rect directly.
+ bool somethingClipped = h1.shouldBeClipped() || h2.shouldBeClipped() || h3.shouldBeClipped() || h4.shouldBeClipped();
+ if (!somethingClipped) {
+ FloatQuad mappedQuad = FloatQuad(h1.cartesianPoint2d(), h2.cartesianPoint2d(), h3.cartesianPoint2d(), h4.cartesianPoint2d());
+ return mappedQuad.boundingBox();
+ }
+
+ bool everythingClipped = h1.shouldBeClipped() && h2.shouldBeClipped() && h3.shouldBeClipped() && h4.shouldBeClipped();
+ if (everythingClipped)
+ return FloatRect();
+
float xmin = std::numeric_limits<float>::max();
float xmax = std::numeric_limits<float>::min();
float ymin = std::numeric_limits<float>::max();
@@ -169,16 +180,10 @@
return FloatRect(FloatPoint(xmin, ymin), FloatSize(xmax - xmin, ymax - ymin));
}
-static FloatRect computeEnclosingRect(const HomogeneousCoordinate& h1, const HomogeneousCoordinate& h2, const HomogeneousCoordinate& h3, const HomogeneousCoordinate& h4)
+static inline void addVertexToClippedQuad(const FloatPoint& newVertex, FloatPoint clippedQuad[8], int& numVerticesInClippedQuad)
{
- // If no vertices on the quad are clipped, then we can simply return the enclosing rect directly.
- bool clipped = h1.shouldBeClipped() || h2.shouldBeClipped() || h3.shouldBeClipped() || h4.shouldBeClipped();
- if (!clipped) {
- FloatQuad mappedQuad = FloatQuad(h1.cartesianPoint2d(), h2.cartesianPoint2d(), h3.cartesianPoint2d(), h4.cartesianPoint2d());
- return mappedQuad.boundingBox();
- }
-
- return computeEnclosingRectOfClippedQuad(h1, h2, h3, h4);
+ clippedQuad[numVerticesInClippedQuad] = newVertex;
+ numVerticesInClippedQuad++;
}
IntRect CCMathUtil::mapClippedRect(const TransformationMatrix& transform, const IntRect& srcRect)
@@ -216,6 +221,60 @@
return computeEnclosingRect(h1, h2, h3, h4);
}
+void CCMathUtil::mapClippedQuad(const TransformationMatrix& transform, const FloatQuad& srcQuad, FloatPoint clippedQuad[8], int& numVerticesInClippedQuad)
+{
+ HomogeneousCoordinate h1 = mapPoint(transform, srcQuad.p1());
+ HomogeneousCoordinate h2 = mapPoint(transform, srcQuad.p2());
+ HomogeneousCoordinate h3 = mapPoint(transform, srcQuad.p3());
+ HomogeneousCoordinate h4 = mapPoint(transform, srcQuad.p4());
+
+ // The order of adding the vertices to the array is chosen so that clockwise / counter-clockwise orientation is retained.
+
+ numVerticesInClippedQuad = 0;
+
+ if (!h1.shouldBeClipped())
+ addVertexToClippedQuad(h1.cartesianPoint2d(), clippedQuad, numVerticesInClippedQuad);
+
+ if (h1.shouldBeClipped() ^ h2.shouldBeClipped())
+ addVertexToClippedQuad(computeClippedPointForEdge(h1, h2).cartesianPoint2d(), clippedQuad, numVerticesInClippedQuad);
+
+ if (!h2.shouldBeClipped())
+ addVertexToClippedQuad(h2.cartesianPoint2d(), clippedQuad, numVerticesInClippedQuad);
+
+ if (h2.shouldBeClipped() ^ h3.shouldBeClipped())
+ addVertexToClippedQuad(computeClippedPointForEdge(h2, h3).cartesianPoint2d(), clippedQuad, numVerticesInClippedQuad);
+
+ if (!h3.shouldBeClipped())
+ addVertexToClippedQuad(h3.cartesianPoint2d(), clippedQuad, numVerticesInClippedQuad);
+
+ if (h3.shouldBeClipped() ^ h4.shouldBeClipped())
+ addVertexToClippedQuad(computeClippedPointForEdge(h3, h4).cartesianPoint2d(), clippedQuad, numVerticesInClippedQuad);
+
+ if (!h4.shouldBeClipped())
+ addVertexToClippedQuad(h4.cartesianPoint2d(), clippedQuad, numVerticesInClippedQuad);
+
+ if (h4.shouldBeClipped() ^ h1.shouldBeClipped())
+ addVertexToClippedQuad(computeClippedPointForEdge(h4, h1).cartesianPoint2d(), clippedQuad, numVerticesInClippedQuad);
+
+ ASSERT(numVerticesInClippedQuad <= 8);
+}
+
+FloatRect CCMathUtil::computeEnclosingRectOfVertices(FloatPoint vertices[], int numVertices)
+{
+ if (numVertices < 2)
+ return FloatRect();
+
+ float xmin = std::numeric_limits<float>::max();
+ float xmax = std::numeric_limits<float>::min();
+ float ymin = std::numeric_limits<float>::max();
+ float ymax = std::numeric_limits<float>::min();
+
+ for (int i = 0; i < numVertices; ++i)
+ expandBoundsToIncludePoint(xmin, xmax, ymin, ymax, vertices[i]);
+
+ return FloatRect(FloatPoint(xmin, ymin), FloatSize(xmax - xmin, ymax - ymin));
+}
+
FloatQuad CCMathUtil::mapQuad(const TransformationMatrix& transform, const FloatQuad& q, bool& clipped)
{
if (transform.isIdentityOrTranslation()) {
Modified: trunk/Source/WebCore/platform/graphics/chromium/cc/CCMathUtil.h (113605 => 113606)
--- trunk/Source/WebCore/platform/graphics/chromium/cc/CCMathUtil.h 2012-04-09 19:31:39 UTC (rev 113605)
+++ trunk/Source/WebCore/platform/graphics/chromium/cc/CCMathUtil.h 2012-04-09 19:31:56 UTC (rev 113606)
@@ -28,6 +28,7 @@
namespace WebCore {
class IntRect;
+class FloatPoint;
class FloatRect;
class FloatQuad;
class TransformationMatrix;
@@ -49,8 +50,15 @@
static FloatRect mapClippedRect(const TransformationMatrix&, const FloatRect&);
static FloatRect projectClippedRect(const TransformationMatrix&, const FloatRect&);
- // NOTE: This function does not do correct clipping against w = 0 plane, but it
- // correctly detects the clipped condition via the boolean clipped.
+ // Returns an array of vertices that represent the clipped polygon. After returning, indexes from
+ // 0 to numVerticesInClippedQuad are valid in the clippedQuad array. Note that
+ // numVerticesInClippedQuad may be zero, which means the entire quad was clipped, and
+ // none of the vertices in the array are valid.
+ static void mapClippedQuad(const TransformationMatrix&, const FloatQuad& srcQuad, FloatPoint clippedQuad[8], int& numVerticesInClippedQuad);
+ static FloatRect computeEnclosingRectOfVertices(FloatPoint vertices[], int numVertices);
+
+ // NOTE: These functions do not do correct clipping against w = 0 plane, but they
+ // correctly detect the clipped condition via the boolean clipped.
static FloatQuad mapQuad(const TransformationMatrix&, const FloatQuad&, bool& clipped);
static FloatQuad projectQuad(const TransformationMatrix&, const FloatQuad&, bool& clipped);
};
Modified: trunk/Source/WebKit/chromium/ChangeLog (113605 => 113606)
--- trunk/Source/WebKit/chromium/ChangeLog 2012-04-09 19:31:39 UTC (rev 113605)
+++ trunk/Source/WebKit/chromium/ChangeLog 2012-04-09 19:31:56 UTC (rev 113606)
@@ -1,3 +1,14 @@
+2012-04-09 Shawn Singh <[email protected]>
+
+ [chromium] Fix layer sorting perspective w if w becomes negative
+ https://bugs.webkit.org/show_bug.cgi?id=82997
+
+ Reviewed by Adrienne Walker.
+
+ * tests/CCLayerSorterTest.cpp:
+ (WebCore::TEST):
+ (WebCore):
+
2012-04-09 Dana Jansens <[email protected]>
[chromium] Flip transition painting delayed with threaded animations
Modified: trunk/Source/WebKit/chromium/tests/CCLayerSorterTest.cpp (113605 => 113606)
--- trunk/Source/WebKit/chromium/tests/CCLayerSorterTest.cpp 2012-04-09 19:31:39 UTC (rev 113605)
+++ trunk/Source/WebKit/chromium/tests/CCLayerSorterTest.cpp 2012-04-09 19:31:56 UTC (rev 113606)
@@ -27,6 +27,7 @@
#include "cc/CCLayerSorter.h"
#include "cc/CCLayerImpl.h"
+#include "cc/CCMathUtil.h"
#include "cc/CCSingleThreadProxy.h"
#include <gtest/gtest.h>
@@ -155,6 +156,44 @@
EXPECT_EQ(CCLayerSorter::None, overlapResult);
}
+TEST(CCLayerSorterTest, LayersUnderPathologicalPerspectiveTransform)
+{
+ CCLayerSorter::ABCompareResult overlapResult;
+ const float zThreshold = 0.1f;
+ float weight = 0;
+
+ // On perspective projection, if w becomes negative, the re-projected point will be
+ // invalid and un-usable. Correct code needs to clip away portions of the geometry
+ // where w < 0. If the code uses the invalid value, it will think that a layer has
+ // different bounds than it really does, which can cause things to sort incorrectly.
+
+ TransformationMatrix perspectiveMatrix;
+ perspectiveMatrix.applyPerspective(1);
+
+ TransformationMatrix transformA;
+ transformA.translate3d(-15, 0, -2);
+ CCLayerSorter::LayerShape layerA(10, 10, perspectiveMatrix * transformA);
+
+ // With this sequence of transforms, when layer B is correctly clipped, it will be
+ // visible on the left half of the projection plane, in front of layerA. When it is
+ // not clipped, its bounds will actually incorrectly appear much smaller and the
+ // correct sorting dependency will not be found.
+ TransformationMatrix transformB;
+ transformB.translate3d(0, 0, 0.7);
+ transformB.rotate3d(0, 45, 0);
+ CCLayerSorter::LayerShape layerB(10, 10, perspectiveMatrix * transformB);
+
+ // Sanity check that the test case actually covers the intended scenario, where part
+ // of layer B go behind the w = 0 plane.
+ FloatQuad testQuad = FloatQuad(FloatRect(FloatPoint(-0.5, -0.5), FloatSize(1, 1)));
+ bool clipped = false;
+ CCMathUtil::mapQuad(perspectiveMatrix * transformB, testQuad, clipped);
+ ASSERT_TRUE(clipped);
+
+ overlapResult = CCLayerSorter::checkOverlap(&layerA, &layerB, zThreshold, weight);
+ EXPECT_EQ(CCLayerSorter::ABeforeB, overlapResult);
+}
+
TEST(CCLayerSorterTest, verifyExistingOrderingPreservedWhenNoZDiff)
{
DebugScopedSetImplThread thisScopeIsOnImplThread;