WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Should compile on linux now
bug-80806-20120403103148.patch (text/plain), 41.21 KB, created by
Shawn Singh
on 2012-04-03 10:31:49 PDT
(
hide
)
Description:
Should compile on linux now
Filename:
MIME Type:
Creator:
Shawn Singh
Created:
2012-04-03 10:31:49 PDT
Size:
41.21 KB
patch
obsolete
>Subversion Revision: 113049 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index db1ee625d981f9e7d4469c93c241bab608a1b973..f00aecdd313536002e424d91b7ca6b861f31895b 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,62 @@ >+2012-04-02 Shawn Singh <shawnsingh@chromium.org> >+ >+ [chromium] Need to clip to homogeneous w=0 plane when applying transforms. >+ https://bugs.webkit.org/show_bug.cgi?id=80806 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Unit tests added to CCLayerTreeHostCommon. This change is also >+ covered by other existing unit tests and layout tests. >+ >+ WebCore TransformationMatrix mapRect / mapQuad / projectQuad do >+ not properly handle the case where a surface is oriented partially >+ behind the camera, with a perspective projection. In this case, >+ projected points may appear to be valid in cartesian coordinates, >+ but they are indeed not valid, and they can only be detected in >+ homogeneous coordinates after applying the transform, before the >+ divide-by-w step. >+ >+ The correct solution is to clip geometry where w < 0. This patch >+ makes this change local to chromium only, to fix rendering bugs >+ that arise from this problem; Safari does not have these bugs >+ because it does not use the transforms outside of the GPU (which >+ does correctly handle this case). The primary fix is to correct >+ calculateVisibleLayerRect(), but other ancillary locations are >+ also fixed, in particular, the antialiasing code path is simply >+ skipped when this case arises. >+ >+ Eventually this math needs to be merged into TransformationMatrix, >+ to fix hit-testing bugs that occur in both Chromium and Safari. >+ >+ * WebCore.gypi: >+ * platform/graphics/chromium/LayerRendererChromium.cpp: >+ (WebCore::findTileProgramUniforms): >+ (WebCore::LayerRendererChromium::drawTileQuad): >+ * platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp: >+ (WebCore::CCLayerTreeHostCommon::calculateVisibleRect): >+ (WebCore::isScaleOrTranslation): >+ (WebCore::calculateDrawTransformsAndVisibilityInternal): >+ * platform/graphics/chromium/cc/CCMathUtil.cpp: Added. >+ (WebCore): >+ (HomogeneousCoordinate): >+ (WebCore::HomogeneousCoordinate::HomogeneousCoordinate): >+ (WebCore::HomogeneousCoordinate::shouldBeClipped): >+ (WebCore::HomogeneousCoordinate::cartesianPoint2d): >+ (WebCore::projectPoint): >+ (WebCore::mapPoint): >+ (WebCore::computeClippedPointForEdge): >+ (WebCore::computeClippedVerticesForTransformedQuad): >+ (WebCore::computeEnclosingRectOfClippedQuad): >+ (WebCore::CCMathUtil::mapClippedRect): >+ (WebCore::CCMathUtil::projectClippedRect): >+ (WebCore::CCMathUtil::mapQuad): >+ (WebCore::CCMathUtil::projectQuad): >+ * platform/graphics/chromium/cc/CCMathUtil.h: Added. >+ (WebCore): >+ (CCMathUtil): >+ * platform/graphics/chromium/cc/CCOcclusionTracker.cpp: >+ (WebCore::computeUnoccludedContentRect): >+ > 2012-04-03 Ryosuke Niwa <rniwa@webkit.org> > > REGRESSION(r80439): Crash in StylePropertySet::borderSpacingValue >diff --git a/Source/WebKit/chromium/ChangeLog b/Source/WebKit/chromium/ChangeLog >index ac1ea0f890443b01874ac750445d456a0498aac2..aa870b3e648df7c3b656c06e0ded06046b18b8b3 100644 >--- a/Source/WebKit/chromium/ChangeLog >+++ b/Source/WebKit/chromium/ChangeLog >@@ -1,3 +1,14 @@ >+2012-04-02 Shawn Singh <shawnsingh@chromium.org> >+ >+ [chromium] Need to clip to homogeneous w=0 plane when applying transforms. >+ https://bugs.webkit.org/show_bug.cgi?id=80806 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * tests/CCLayerTreeHostCommonTest.cpp: >+ (WebKitTests::TEST): >+ (WebKitTests): >+ > 2012-04-03 Bolin Hsu <bhsu@google.com> > > [Chromium] Add click count and modifiers to the factory method of mouse event. >diff --git a/Source/WebCore/WebCore.gypi b/Source/WebCore/WebCore.gypi >index ba4630db9ed7fa64f4f2ca72d17a4f01af5710cb..5e4da9ddedda770e1e3bb71966599edda4189dc6 100644 >--- a/Source/WebCore/WebCore.gypi >+++ b/Source/WebCore/WebCore.gypi >@@ -3622,6 +3622,8 @@ > 'platform/graphics/chromium/cc/CCLayerTreeHostCommon.h', > 'platform/graphics/chromium/cc/CCLayerTreeHostImpl.cpp', > 'platform/graphics/chromium/cc/CCLayerTreeHostImpl.h', >+ 'platform/graphics/chromium/cc/CCMathUtil.cpp', >+ 'platform/graphics/chromium/cc/CCMathUtil.h', > 'platform/graphics/chromium/cc/CCOcclusionTracker.cpp', > 'platform/graphics/chromium/cc/CCOcclusionTracker.h', > 'platform/graphics/chromium/cc/CCOverdrawMetrics.cpp', >diff --git a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp >index ccb1dd8d0b29c3722133fab6dd835a9b4828bb10..d2a89531441f69c2e3dd2577132ebbb6be493df1 100644 >--- a/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp >+++ b/Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp >@@ -55,6 +55,7 @@ > #include "cc/CCDebugBorderDrawQuad.h" > #include "cc/CCLayerImpl.h" > #include "cc/CCLayerTreeHostCommon.h" >+#include "cc/CCMathUtil.h" > #include "cc/CCProxy.h" > #include "cc/CCRenderPass.h" > #include "cc/CCRenderSurfaceDrawQuad.h" >@@ -576,9 +577,11 @@ static void tileUniformLocation(T program, TileProgramUniforms& uniforms) > uniforms.edgeLocation = program->fragmentShader().edgeLocation(); > } > >-static void findTileProgramUniforms(LayerRendererChromium* layerRenderer, const CCTileDrawQuad* quad, TileProgramUniforms& uniforms) >+static void findTileProgramUniforms(LayerRendererChromium* layerRenderer, const CCTileDrawQuad* quad, TileProgramUniforms& uniforms, bool quadIsClipped) > { >- if (quad->isAntialiased()) { >+ // For now, we simply skip anti-aliasing with the quad is clipped. This only happens >+ // on perspective transformed layers that go partially behind the camera. >+ if (quad->isAntialiased() && !quadIsClipped) { > if (quad->swizzleContents()) { > const CCTiledLayerImpl::ProgramSwizzleAA* program = layerRenderer->tilerProgramSwizzleAA(); > tileUniformLocation(program, uniforms); >@@ -641,8 +644,17 @@ void LayerRendererChromium::drawTileQuad(const CCTileDrawQuad* quad) > float fragmentTexScaleX = clampRect.width() / textureSize.width(); > float fragmentTexScaleY = clampRect.height() / textureSize.height(); > >+ >+ FloatQuad localQuad; >+ TransformationMatrix deviceTransform = TransformationMatrix(windowMatrix() * projectionMatrix() * quad->quadTransform()).to2dTransform(); >+ if (!deviceTransform.isInvertible()) >+ return; >+ >+ bool clipped = false; >+ FloatQuad deviceLayerQuad = CCMathUtil::mapQuad(deviceTransform, FloatQuad(quad->layerRect()), clipped); >+ > TileProgramUniforms uniforms; >- findTileProgramUniforms(this, quad, uniforms); >+ findTileProgramUniforms(this, quad, uniforms, clipped); > > GLC(context(), context()->useProgram(uniforms.program)); > GLC(context(), context()->uniform1i(uniforms.samplerLocation, 0)); >@@ -651,13 +663,8 @@ void LayerRendererChromium::drawTileQuad(const CCTileDrawQuad* quad) > GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, quad->textureFilter())); > GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, quad->textureFilter())); > >- FloatQuad localQuad; >- if (quad->isAntialiased()) { >- TransformationMatrix deviceTransform = TransformationMatrix(windowMatrix() * projectionMatrix() * quad->quadTransform()).to2dTransform(); >- if (!deviceTransform.isInvertible()) >- return; > >- FloatQuad deviceLayerQuad = deviceTransform.mapQuad(FloatQuad(quad->layerRect())); >+ if (!clipped && quad->isAntialiased()) { > > CCLayerQuad deviceLayerBounds = CCLayerQuad(FloatQuad(deviceLayerQuad.boundingBox())); > deviceLayerBounds.inflateAntiAliasingDistance(); >diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp >index 418dca190b3ebe644a24ac3ee282bb5f5c92962d..43759c3a035b1f4b8a5106dfda798b13eba5ec4f 100644 >--- a/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp >+++ b/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp >@@ -37,6 +37,7 @@ > #include "cc/CCLayerImpl.h" > #include "cc/CCLayerIterator.h" > #include "cc/CCLayerSorter.h" >+#include "cc/CCMathUtil.h" > #include "cc/CCRenderSurface.h" > > namespace WebCore { >@@ -44,7 +45,7 @@ namespace WebCore { > IntRect CCLayerTreeHostCommon::calculateVisibleRect(const IntRect& targetSurfaceRect, const IntRect& layerBoundRect, const TransformationMatrix& transform) > { > // Is this layer fully contained within the target surface? >- IntRect layerInSurfaceSpace = transform.mapRect(layerBoundRect); >+ IntRect layerInSurfaceSpace = CCMathUtil::mapClippedRect(transform, layerBoundRect); > if (targetSurfaceRect.contains(layerInSurfaceSpace)) > return layerBoundRect; > >@@ -59,7 +60,7 @@ IntRect CCLayerTreeHostCommon::calculateVisibleRect(const IntRect& targetSurface > // axis-aligned), but is a reasonable filter on the space to consider. > // Non-invertible transforms will create an empty rect here. > const TransformationMatrix surfaceToLayer = transform.inverse(); >- IntRect layerRect = surfaceToLayer.projectQuad(FloatQuad(FloatRect(minimalSurfaceRect))).enclosingBoundingBox(); >+ IntRect layerRect = enclosingIntRect(CCMathUtil::projectClippedRect(surfaceToLayer, FloatQuad(FloatRect(minimalSurfaceRect)))); > layerRect.intersect(layerBoundRect); > return layerRect; > } >@@ -70,7 +71,6 @@ static bool isScaleOrTranslation(const TransformationMatrix& m) > && !m.m21() && !m.m23() && !m.m24() > && !m.m31() && !m.m32() && !m.m43() > && m.m44(); >- > } > > template<typename LayerType> >@@ -409,7 +409,7 @@ static bool calculateDrawTransformsAndVisibilityInternal(LayerType* layer, Layer > layer->setDrawTransform(combinedTransform); > layer->setDrawTransformIsAnimating(animatingTransformToTarget); > layer->setScreenSpaceTransformIsAnimating(animatingTransformToScreen); >- transformedLayerRect = enclosingIntRect(layer->drawTransform().mapRect(layerRect)); >+ transformedLayerRect = enclosingIntRect(CCMathUtil::mapClippedRect(layer->drawTransform(), layerRect)); > > layer->setDrawOpacity(drawOpacity); > layer->setDrawOpacityIsAnimating(drawOpacityIsAnimating); >diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCMathUtil.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCMathUtil.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..1380166838de0e5e5704a533075ac406de671435 >--- /dev/null >+++ b/Source/WebCore/platform/graphics/chromium/cc/CCMathUtil.cpp >@@ -0,0 +1,252 @@ >+/* >+ * Copyright (C) 2012 Google Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED >+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE >+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY >+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES >+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; >+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON >+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS >+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+ >+#include "cc/CCMathUtil.h" >+ >+#include "FloatPoint.h" >+#include "FloatQuad.h" >+#include "IntRect.h" >+#include "TransformationMatrix.h" >+ >+namespace WebCore { >+ >+struct HomogeneousCoordinate { >+ >+ HomogeneousCoordinate(double newX, double newY, double newZ, double newW) >+ : x(newX) >+ , y(newY) >+ , z(newZ) >+ , w(newW) >+ { >+ } >+ >+ bool shouldBeClipped() const >+ { >+ return w <= 0; >+ } >+ >+ FloatPoint cartesianPoint2d() const >+ { >+ if (w == 1) >+ return FloatPoint(x, y); >+ >+ // For now, because this code is used privately only by CCMathUtil, it should never be called when w == 0, and we do not yet need to handle that case. >+ ASSERT(w); >+ double invW = 1.0 / w; >+ return FloatPoint(x * invW, y * invW); >+ } >+ >+ double x, y, z, w; >+}; >+ >+static HomogeneousCoordinate projectPoint(const TransformationMatrix& transform, const FloatPoint& p) >+{ >+ double x = p.x(); >+ double y = p.y(); >+ double z = -(transform.m13() * x + transform.m23() * y + transform.m43()) / transform.m33(); >+ // implicit definition of w = 1; >+ >+ double outX = x * transform.m11() + y * transform.m21() + z * transform.m31() + transform.m41(); >+ double outY = x * transform.m12() + y * transform.m22() + z * transform.m32() + transform.m42(); >+ double outZ = x * transform.m13() + y * transform.m23() + z * transform.m33() + transform.m43(); >+ double outW = x * transform.m14() + y * transform.m24() + z * transform.m34() + transform.m44(); >+ >+ HomogeneousCoordinate unclippedProjection(outX, outY, outZ, outW); >+ return unclippedProjection; >+} >+ >+static HomogeneousCoordinate mapPoint(const TransformationMatrix& transform, const FloatPoint& p) >+{ >+ double x = p.x(); >+ double y = p.y(); >+ // implicit definition of z = 0; >+ // implicit definition of w = 1; >+ >+ double outX = x * transform.m11() + y * transform.m21() + transform.m41(); >+ double outY = x * transform.m12() + y * transform.m22() + transform.m42(); >+ double outZ = x * transform.m13() + y * transform.m23() + transform.m43(); >+ double outW = x * transform.m14() + y * transform.m24() + transform.m44(); >+ >+ HomogeneousCoordinate mappedPoint(outX, outY, outZ, outW); >+ return mappedPoint; >+} >+ >+static HomogeneousCoordinate computeClippedPointForEdge(const HomogeneousCoordinate& h1, const HomogeneousCoordinate& h2) >+{ >+ // Points h1 and h2 form a line in 4d, and any point on that line can be represented >+ // as an interpolation between h1 and h2: >+ // p = (1-t) h1 + (t) h2 >+ // >+ // We want to compute point p such that p.w == 0. To do this, we solve for t in the >+ // following equation: >+ // p.w = 0 = (1-t) * h1.w + (t) * h2.w >+ // >+ // Once paramter t is known, the rest of p can be computed via p = (1-t) h1 + (t) h2. >+ >+ // Technically this is a special case of the following assertion, but its a good idea to keep it an explicit sanity check here. >+ ASSERT(h2.w != h1.w); >+ // Exactly one of h1 or h2 (but not both) must be on the negative side of the w plane when this is called. >+ ASSERT(h1.shouldBeClipped() ^ h2.shouldBeClipped()); >+ >+ double t = (-h1.w) / (h2.w - h1.w); >+ >+ double x = (1-t) * h1.x + t * h2.x; >+ double y = (1-t) * h1.y + t * h2.y; >+ double z = (1-t) * h1.z + t * h2.z; >+ double w = 0.00001; // or any positive non-zero small epsilon >+ >+ return HomogeneousCoordinate(x, y, z, w); >+} >+ >+static void computeClippedVerticesForTransformedQuad(const HomogeneousCoordinate& h1, const HomogeneousCoordinate& h2, const HomogeneousCoordinate& h3, const HomogeneousCoordinate& h4, Vector<HomogeneousCoordinate>& verticesOfClippedQuad) >+{ >+ // Perform clipping in this specific order so that vertices will retain their CW / CCW property. >+ >+ if (!h1.shouldBeClipped()) >+ verticesOfClippedQuad.append(h1); >+ >+ if (h1.shouldBeClipped() ^ h2.shouldBeClipped()) >+ verticesOfClippedQuad.append(computeClippedPointForEdge(h1, h2)); >+ >+ if (!h2.shouldBeClipped()) >+ verticesOfClippedQuad.append(h2); >+ >+ if (h2.shouldBeClipped() ^ h3.shouldBeClipped()) >+ verticesOfClippedQuad.append(computeClippedPointForEdge(h2, h3)); >+ >+ if (!h3.shouldBeClipped()) >+ verticesOfClippedQuad.append(h3); >+ >+ if (h3.shouldBeClipped() ^ h4.shouldBeClipped()) >+ verticesOfClippedQuad.append(computeClippedPointForEdge(h3, h4)); >+ >+ if (!h4.shouldBeClipped()) >+ verticesOfClippedQuad.append(h4); >+ >+ if (h4.shouldBeClipped() ^ h1.shouldBeClipped()) >+ verticesOfClippedQuad.append(computeClippedPointForEdge(h4, h1)); >+} >+ >+static FloatRect computeEnclosingRectOfClippedQuad(const Vector<HomogeneousCoordinate>& verticesOfClippedQuad) >+{ >+ // This function omputes the 2d FloatRect that encloses the clipped quad. Note that >+ // here we finally convert from homogeneous coordinates to cartesian coordinates >+ // (i.e. divide-by-w if needed). >+ >+ 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 (size_t i = 0; i < verticesOfClippedQuad.size(); ++i) { >+ FloatPoint clippedPoint = verticesOfClippedQuad[i].cartesianPoint2d(); >+ xmin = std::min(clippedPoint.x(), xmin); >+ xmax = std::max(clippedPoint.x(), xmax); >+ ymin = std::min(clippedPoint.y(), ymin); >+ ymax = std::max(clippedPoint.y(), ymax); >+ } >+ >+ FloatRect rect = FloatRect(FloatPoint(xmin, ymin), FloatSize(xmax - xmin, ymax - ymin)); >+ return rect; >+} >+ >+IntRect CCMathUtil::mapClippedRect(const TransformationMatrix& transform, const IntRect& srcRect) >+{ >+ return enclosingIntRect(mapClippedRect(transform, FloatRect(srcRect))); >+} >+ >+FloatRect CCMathUtil::mapClippedRect(const TransformationMatrix& transform, const FloatRect& srcRect) >+{ >+ // Step 1: Apply the transform, but retain the result in homogeneous coordinates. >+ FloatQuad q = FloatQuad(FloatRect(srcRect)); >+ HomogeneousCoordinate h1 = mapPoint(transform, q.p1()); >+ HomogeneousCoordinate h2 = mapPoint(transform, q.p2()); >+ HomogeneousCoordinate h3 = mapPoint(transform, q.p3()); >+ HomogeneousCoordinate h4 = mapPoint(transform, q.p4()); >+ >+ // Step 2: Collect the list of vertices that represent the clipped quad. >+ Vector<HomogeneousCoordinate> verticesOfClippedQuad; >+ computeClippedVerticesForTransformedQuad(h1, h2, h3, h4, verticesOfClippedQuad); >+ >+ // Step 3: After having clipped, now we can convert to cartesian coordinates and compute the 2d enclosing rect of the clipped points. >+ FloatRect enclosingRectOfClippedQuad = computeEnclosingRectOfClippedQuad(verticesOfClippedQuad); >+ return enclosingRectOfClippedQuad; >+} >+ >+FloatRect CCMathUtil::projectClippedRect(const TransformationMatrix& transform, const FloatQuad& q) >+{ >+ // Step 1: Perform the projection, but retain the result in homogeneous coordinates. >+ HomogeneousCoordinate h1 = projectPoint(transform, q.p1()); >+ HomogeneousCoordinate h2 = projectPoint(transform, q.p2()); >+ HomogeneousCoordinate h3 = projectPoint(transform, q.p3()); >+ HomogeneousCoordinate h4 = projectPoint(transform, q.p4()); >+ >+ // Step 2: Collect the list of vertices that represent the clipped quad. >+ Vector<HomogeneousCoordinate> verticesOfClippedQuad; >+ computeClippedVerticesForTransformedQuad(h1, h2, h3, h4, verticesOfClippedQuad); >+ >+ // Step 3: After having clipped, now we can convert to cartesian coordinates and compute the 2d enclosing rect of the clipped points. >+ FloatRect enclosingRectOfClippedQuad = computeEnclosingRectOfClippedQuad(verticesOfClippedQuad); >+ return enclosingRectOfClippedQuad; >+} >+ >+FloatQuad CCMathUtil::mapQuad(const TransformationMatrix& transform, const FloatQuad& q, bool& clamped) >+{ >+ // FIXME: this version of mapQuad is missing a useful optimization, isIdentityOrTranslation(), that is available only in TransformationMatrix.cpp >+ >+ HomogeneousCoordinate h1 = mapPoint(transform, q.p1()); >+ HomogeneousCoordinate h2 = mapPoint(transform, q.p2()); >+ HomogeneousCoordinate h3 = mapPoint(transform, q.p3()); >+ HomogeneousCoordinate h4 = mapPoint(transform, q.p4()); >+ >+ clamped = h1.shouldBeClipped() || h2.shouldBeClipped() || h3.shouldBeClipped() || h4.shouldBeClipped(); >+ >+ // Result will be invalid if clamped = true. But, compute it anyway just in case, to emulate existing behavior. >+ FloatQuad result; >+ result.setP1(h1.cartesianPoint2d()); >+ result.setP2(h2.cartesianPoint2d()); >+ result.setP3(h3.cartesianPoint2d()); >+ result.setP4(h4.cartesianPoint2d()); >+ return result; >+} >+ >+FloatQuad CCMathUtil::projectQuad(const TransformationMatrix& transform, const FloatQuad& q, bool& clamped) >+{ >+ FloatQuad projectedQuad; >+ bool clampedPoint; >+ projectedQuad.setP1(transform.projectPoint(q.p1(), &clampedPoint)); >+ clamped = clampedPoint; >+ projectedQuad.setP2(transform.projectPoint(q.p2(), &clampedPoint)); >+ clamped |= clampedPoint; >+ projectedQuad.setP3(transform.projectPoint(q.p3(), &clampedPoint)); >+ clamped |= clampedPoint; >+ projectedQuad.setP4(transform.projectPoint(q.p4(), &clampedPoint)); >+ clamped |= clampedPoint; >+ >+ return projectedQuad; >+} >+ >+} // namespace WebCore >diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCMathUtil.h b/Source/WebCore/platform/graphics/chromium/cc/CCMathUtil.h >new file mode 100644 >index 0000000000000000000000000000000000000000..23e97160d1f40e259a25735d1a6e5dafc251230f >--- /dev/null >+++ b/Source/WebCore/platform/graphics/chromium/cc/CCMathUtil.h >@@ -0,0 +1,60 @@ >+/* >+ * Copyright (C) 2012 Google Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED >+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE >+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY >+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES >+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; >+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON >+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS >+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#ifndef CCMathUtil_h >+#define CCMathUtil_h >+ >+namespace WebCore { >+ >+class IntRect; >+class FloatRect; >+class FloatQuad; >+class TransformationMatrix; >+ >+// This class contains math helper functionality that does not belong in WebCore. >+// It is possible that this functionality should be migrated to WebCore eventually. >+class CCMathUtil { >+public: >+ >+ // Background: TransformationMatrix code in WebCore does not do the right thing in >+ // mapRect / mapQuad / projectQuad when there is a perspective projection that causes >+ // one of the transformed vertices to go to w < 0. In those cases, it is necessary to >+ // perform clipping in homogeneous coordinates, after applying the transform, before >+ // dividing-by-w to convert to cartesian coordinates. >+ // >+ // These functions return the axis-aligned rect that encloses the correctly clipped, >+ // transformed polygon. >+ static IntRect mapClippedRect(const TransformationMatrix&, const IntRect&); >+ static FloatRect mapClippedRect(const TransformationMatrix&, const FloatRect&); >+ static FloatRect projectClippedRect(const TransformationMatrix&, const FloatQuad&); >+ >+ // NOTE: This function does not do correct clipping against w = 0 plane, but it >+ // correctly detects the clipped condition via the boolean clamped. >+ static FloatQuad mapQuad(const TransformationMatrix&, const FloatQuad&, bool& clamped); >+ static FloatQuad projectQuad(const TransformationMatrix&, const FloatQuad&, bool& clamped); >+}; >+ >+} // namespace WebCore >+ >+#endif // #define CCMathUtil_h >diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.cpp >index a5411eccf76151ea3bf0035cf998d0bcbdb327bb..69fa12ccee83087a230301fc91f56192d8512a44 100644 >--- a/Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.cpp >+++ b/Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.cpp >@@ -31,6 +31,7 @@ > > #include "LayerChromium.h" > #include "cc/CCLayerImpl.h" >+#include "cc/CCMathUtil.h" > > #include <algorithm> > >@@ -275,22 +276,6 @@ static inline IntRect rectSubtractRegion(const IntRect& rect, const Region& regi > return boundsRect; > } > >-static FloatQuad projectQuad(const TransformationMatrix& transform, const FloatQuad& q, bool& clamped) >-{ >- FloatQuad projectedQuad; >- bool clampedPoint; >- projectedQuad.setP1(transform.projectPoint(q.p1(), &clampedPoint)); >- clamped = clampedPoint; >- projectedQuad.setP2(transform.projectPoint(q.p2(), &clampedPoint)); >- clamped |= clampedPoint; >- projectedQuad.setP3(transform.projectPoint(q.p3(), &clampedPoint)); >- clamped |= clampedPoint; >- projectedQuad.setP4(transform.projectPoint(q.p4(), &clampedPoint)); >- clamped |= clampedPoint; >- >- return projectedQuad; >-} >- > static inline IntRect computeUnoccludedContentRect(const IntRect& contentRect, const TransformationMatrix& contentSpaceTransform, const IntRect& scissorRect, const Region& occlusion) > { > if (!contentSpaceTransform.isInvertible()) >@@ -300,7 +285,7 @@ static inline IntRect computeUnoccludedContentRect(const IntRect& contentRect, c > // Take the enclosingIntRect at each step, as we want to contain any unoccluded partial pixels in the resulting IntRect. > IntRect shrunkRect = rectSubtractRegion(intersection(enclosingIntRect(transformedRect), scissorRect), occlusion); > bool clamped; // FIXME: projectQuad returns invalid results when a point gets clamped. To be fixed in bug https://bugs.webkit.org/show_bug.cgi?id=80806. >- IntRect unoccludedRect = enclosingIntRect(projectQuad(contentSpaceTransform.inverse(), FloatQuad(FloatRect(shrunkRect)), clamped).boundingBox()); >+ IntRect unoccludedRect = enclosingIntRect(CCMathUtil::projectQuad(contentSpaceTransform.inverse(), FloatQuad(FloatRect(shrunkRect)), clamped).boundingBox()); > if (clamped) > return contentRect; > // The rect back in content space is a bounding box and may extend outside of the original contentRect, so clamp it to the contentRectBounds. >diff --git a/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp b/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp >index 4a9659ddd153eff6e6752ea20706e23c7e124b64..75ac5e83bbc808e53eab319ee08edf184ac9ca5a 100644 >--- a/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp >+++ b/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp >@@ -979,6 +979,252 @@ TEST(CCLayerTreeHostCommonTest, verifyAnimationsForRenderSurfaceHierarchy) > EXPECT_FLOAT_EQ(5.0, grandChildOfRS2->screenSpaceTransform().m42()); > } > >+TEST(CCLayerTreeHostCommonTest, verifyVisibleRectForIdentityTransform) >+{ >+ // Test the calculateVisibleRect() function works correctly for identity transforms. >+ >+ IntRect targetSurfaceRect = IntRect(IntPoint(0, 0), IntSize(100, 100)); >+ TransformationMatrix layerToSurfaceTransform; >+ >+ // Case 1: Layer is contained within the surface. >+ IntRect layerContentRect = IntRect(IntPoint(10, 10), IntSize(30, 30)); >+ IntRect expected = IntRect(IntPoint(10, 10), IntSize(30, 30)); >+ IntRect actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); >+ EXPECT_INT_RECT_EQ(expected, actual); >+ >+ // Case 2: Layer is outside the surface rect. >+ layerContentRect = IntRect(IntPoint(120, 120), IntSize(30, 30)); >+ actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); >+ EXPECT_TRUE(actual.isEmpty()); >+ >+ // Case 3: Layer is partially overlapping the surface rect. >+ layerContentRect = IntRect(IntPoint(80, 80), IntSize(30, 30)); >+ expected = IntRect(IntPoint(80, 80), IntSize(20, 20)); >+ actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); >+ EXPECT_INT_RECT_EQ(expected, actual); >+} >+ >+TEST(CCLayerTreeHostCommonTest, verifyVisibleRectForTranslations) >+{ >+ // Test the calculateVisibleRect() function works correctly for scaling transforms. >+ >+ IntRect targetSurfaceRect = IntRect(IntPoint(0, 0), IntSize(100, 100)); >+ IntRect layerContentRect = IntRect(IntPoint(0, 0), IntSize(30, 30)); >+ TransformationMatrix layerToSurfaceTransform; >+ >+ // Case 1: Layer is contained within the surface. >+ layerToSurfaceTransform.makeIdentity(); >+ layerToSurfaceTransform.translate(10, 10); >+ IntRect expected = IntRect(IntPoint(0, 0), IntSize(30, 30)); >+ IntRect actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); >+ EXPECT_INT_RECT_EQ(expected, actual); >+ >+ // Case 2: Layer is outside the surface rect. >+ layerToSurfaceTransform.makeIdentity(); >+ layerToSurfaceTransform.translate(120, 120); >+ actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); >+ EXPECT_TRUE(actual.isEmpty()); >+ >+ // Case 3: Layer is partially overlapping the surface rect. >+ layerToSurfaceTransform.makeIdentity(); >+ layerToSurfaceTransform.translate(80, 80); >+ expected = IntRect(IntPoint(0, 0), IntSize(20, 20)); >+ actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); >+ EXPECT_INT_RECT_EQ(expected, actual); >+} >+ >+TEST(CCLayerTreeHostCommonTest, verifyVisibleRectFor2DRotations) >+{ >+ // Test the calculateVisibleRect() function works correctly for rotations about z-axis (i.e. 2D rotations). >+ // Remember that calculateVisibleRect() should return the visible rect in the layer's space. >+ >+ IntRect targetSurfaceRect = IntRect(IntPoint(0, 0), IntSize(100, 100)); >+ IntRect layerContentRect = IntRect(IntPoint(0, 0), IntSize(30, 30)); >+ TransformationMatrix layerToSurfaceTransform; >+ >+ // Case 1: Layer is contained within the surface. >+ layerToSurfaceTransform.makeIdentity(); >+ layerToSurfaceTransform.translate(50, 50); >+ layerToSurfaceTransform.rotate(45); >+ IntRect expected = IntRect(IntPoint(0, 0), IntSize(30, 30)); >+ IntRect actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); >+ EXPECT_INT_RECT_EQ(expected, actual); >+ >+ // Case 2: Layer is outside the surface rect. >+ layerToSurfaceTransform.makeIdentity(); >+ layerToSurfaceTransform.translate(-50, 0); >+ layerToSurfaceTransform.rotate(45); >+ actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); >+ EXPECT_TRUE(actual.isEmpty()); >+ >+ // Case 3: The layer is rotated about its top-left corner. In surface space, the layer >+ // is oriented diagonally, with the left half outside of the renderSurface. In >+ // this case, the visible rect should still be the entire layer (remember the >+ // visible rect is computed in layer space); both the top-left and >+ // bottom-right corners of the layer are still visible. >+ layerToSurfaceTransform.makeIdentity(); >+ layerToSurfaceTransform.rotate(45); >+ expected = IntRect(IntPoint(0, 0), IntSize(30, 30)); >+ actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); >+ EXPECT_INT_RECT_EQ(expected, actual); >+ >+ // Case 4: The layer is rotated about its top-left corner, and translated upwards. In >+ // surface space, the layer is oriented diagonally, with only the top corner >+ // of the surface overlapping the layer. In layer space, the render surface >+ // overlaps the right side of the layer. The visible rect should be the >+ // layer's right half. >+ layerToSurfaceTransform.makeIdentity(); >+ layerToSurfaceTransform.translate(0, -sqrt(2) * 15); >+ layerToSurfaceTransform.rotate(45); >+ expected = IntRect(IntPoint(15, 0), IntSize(15, 30)); // right half of layer bounds. >+ actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); >+ EXPECT_INT_RECT_EQ(expected, actual); >+} >+ >+TEST(CCLayerTreeHostCommonTest, verifyVisibleRectFor3dOrthographicTransform) >+{ >+ // Test that the calculateVisibleRect() function works correctly for 3d transforms. >+ >+ IntRect targetSurfaceRect = IntRect(IntPoint(0, 0), IntSize(100, 100)); >+ IntRect layerContentRect = IntRect(IntPoint(0, 0), IntSize(100, 100)); >+ TransformationMatrix layerToSurfaceTransform; >+ >+ // Case 1: Orthographic projection of a layer rotated about y-axis by 45 degrees, should be fully contained in the renderSurface. >+ layerToSurfaceTransform.makeIdentity(); >+ layerToSurfaceTransform.rotate3d(0, 45, 0); >+ IntRect expected = IntRect(IntPoint(0, 0), IntSize(100, 100)); >+ IntRect actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); >+ EXPECT_INT_RECT_EQ(expected, actual); >+ >+ // Case 2: Orthographic projection of a layer rotated about y-axis by 45 degrees, but >+ // shifted to the side so only the right-half the layer would be visible on >+ // the surface. >+ double halfWidthOfRotatedLayer = (100.0 / sqrt(2)) * 0.5; // 100.0 is the un-rotated layer width; divided by sqrt(2) is the rotated width. >+ layerToSurfaceTransform.makeIdentity(); >+ layerToSurfaceTransform.translate(-halfWidthOfRotatedLayer, 0); >+ layerToSurfaceTransform.rotate3d(0, 45, 0); // rotates about the left edge of the layer >+ expected = IntRect(IntPoint(50, 0), IntSize(50, 100)); // right half of the layer. >+ actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); >+ EXPECT_INT_RECT_EQ(expected, actual); >+} >+ >+TEST(CCLayerTreeHostCommonTest, verifyVisibleRectFor3dPerspectiveTransform) >+{ >+ // Test the calculateVisibleRect() function works correctly when the layer has a >+ // perspective projection onto the target surface. >+ >+ IntRect targetSurfaceRect = IntRect(IntPoint(0, 0), IntSize(100, 100)); >+ IntRect layerContentRect = IntRect(IntPoint(-50, -50), IntSize(200, 200)); >+ TransformationMatrix layerToSurfaceTransform; >+ >+ // Case 1: Even though the layer is twice as large as the surface, due to perspective >+ // foreshortening, the layer will fit fully in the surface when its translated >+ // more than the perspective amount. >+ layerToSurfaceTransform.makeIdentity(); >+ >+ // The following sequence of transforms applies the perspective about the center of the surface. >+ layerToSurfaceTransform.translate(50, 50); >+ layerToSurfaceTransform.applyPerspective(9); >+ layerToSurfaceTransform.translate(-50, -50); >+ >+ // This translate places the layer in front of the surface's projection plane. >+ layerToSurfaceTransform.translate3d(0, 0, -20); >+ >+ IntRect expected = IntRect(IntPoint(-50, -50), IntSize(200, 200)); >+ IntRect actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); >+ EXPECT_INT_RECT_EQ(expected, actual); >+ >+ // Case 2: same projection as before, except that the layer is also translated to the >+ // side, so that only the right half of the layer should be visible. >+ // >+ // Explanation of expected result: >+ // The perspective ratio is (z distance between layer and camera origin) / (z distance between projection plane and camera origin) == (-29 / 9) >+ // Then, by similar triangles, if we want to move a layer by translating -50 units in projected surface units (so that only half of it is >+ // visible), then we would need to translate by (-29 / 9) * -50 == -161.1111 in the layer's units. >+ // >+ layerToSurfaceTransform.translate3d(-161.111111111111, 0, 0); >+ expected = IntRect(IntPoint(50, -50), IntSize(100, 200)); // The right half of the layer's bounding rect. >+ actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); >+ EXPECT_INT_RECT_EQ(expected, actual); >+} >+ >+TEST(CCLayerTreeHostCommonTest, verifyVisibleRectFor3dOrthographicIsNotClippedBehindSurface) >+{ >+ // There is currently no explicit concept of an orthographic projection plane in our >+ // code (nor in the CSS spec to my knowledge). Therefore, layers that are technically >+ // behind the surface in an orthographic world should not be clipped when they are >+ // flattened to the surface. >+ >+ IntRect targetSurfaceRect = IntRect(IntPoint(0, 0), IntSize(100, 100)); >+ IntRect layerContentRect = IntRect(IntPoint(0, 0), IntSize(100, 100)); >+ TransformationMatrix layerToSurfaceTransform; >+ >+ // This sequence of transforms effectively rotates the layer about the y-axis at the >+ // center of the layer. >+ layerToSurfaceTransform.makeIdentity(); >+ layerToSurfaceTransform.translate(50, 0); >+ layerToSurfaceTransform.rotate3d(0, 45, 0); >+ layerToSurfaceTransform.translate(-50, 0); >+ >+ IntRect expected = IntRect(IntPoint(0, 0), IntSize(100, 100)); >+ IntRect actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); >+ EXPECT_INT_RECT_EQ(expected, actual); >+} >+ >+ >+TEST(CCLayerTreeHostCommonTest, verifyVisibleRectFor3dPerspectiveIsClipped) >+{ >+ // Test the calculateVisibleRect() function works correctly when projecting a surface >+ // onto a layer, but the layer is partially behind the camera (not just behind the >+ // projection plane). In this case, the cartesian coordinates may seem to be valid, >+ // but actually they are not. The visibleRect needs to be properly clipped by the >+ // w = 0 plane in homogeneous coordinates before converting to cartesian coordinates. >+ >+ IntRect targetSurfaceRect = IntRect(IntPoint(-50, -50), IntSize(100, 100)); >+ IntRect layerContentRect = IntRect(IntPoint(-10, -1), IntSize(20, 2)); >+ TransformationMatrix layerToSurfaceTransform; >+ >+ // The layer is positioned so that the right half of the layer should be in front of >+ // the camera, while the other half is behind the surface's projection plane. The >+ // following sequence of transforms applies the perspective and rotation about the >+ // center of the layer. >+ layerToSurfaceTransform.makeIdentity(); >+ layerToSurfaceTransform.applyPerspective(1); >+ layerToSurfaceTransform.translate3d(0, 0, 1); >+ layerToSurfaceTransform.rotate3d(0, 45, 0); >+ >+ int expectedXPosition = -10; >+ int expectedWidth = 10; >+ IntRect actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); >+ EXPECT_EQ(expectedXPosition, actual.x()); >+ EXPECT_EQ(expectedWidth, actual.width()); >+} >+ >+TEST(CCLayerTreeHostCommonTest, verifyVisibleRectForPerspectiveUnprojection) >+{ >+ // To determine visibleRect in layer space, there needs to be an un-projection from >+ // surface space to layer space. When the original transform was a perspective >+ // projection that was clipped, it returns a rect that encloses the clipped bounds. >+ // Un-projecting this new rect may require clipping again. >+ >+ // This sequence of transforms causes one corner of the layer to protrude across the w = 0 plane, and should be clipped. >+ IntRect targetSurfaceRect = IntRect(IntPoint(-50, -50), IntSize(100, 100)); >+ IntRect layerContentRect = IntRect(IntPoint(-10, -10), IntSize(20, 20)); >+ TransformationMatrix layerToSurfaceTransform; >+ layerToSurfaceTransform.makeIdentity(); >+ layerToSurfaceTransform.applyPerspective(1); >+ layerToSurfaceTransform.translate3d(0, 0, -5); >+ layerToSurfaceTransform.rotate3d(0, 45, 0); >+ layerToSurfaceTransform.rotate3d(80, 0, 0); >+ >+ // Only the corner of the layer is not visible on the surface because of being >+ // clipped. But, the net result of rounding visible region to an axis-aligned rect is >+ // that the entire layer should still be considered visible. >+ IntRect expected = IntRect(IntPoint(-10, -10), IntSize(20, 20)); >+ IntRect actual = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerContentRect, layerToSurfaceTransform); >+ EXPECT_INT_RECT_EQ(expected, actual); >+} >+ > // FIXME: > // continue working on https://bugs.webkit.org/show_bug.cgi?id=68942 > // - add a test to verify clipping that changes the "center point"
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 80806
:
135264
|
135357
|
135468
|
135711
|
135844