Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(868)

Unified Diff: ui/cc/cc/CCLayerTreeHostCommon.cpp

Issue 10701016: Initial import attempt, just to play with. Many things disabled/removed (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/cc/cc/CCLayerTreeHostCommon.h ('k') | ui/cc/cc/CCLayerTreeHostImpl.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/cc/cc/CCLayerTreeHostCommon.cpp
diff --git a/ui/cc/cc/CCLayerTreeHostCommon.cpp b/ui/cc/cc/CCLayerTreeHostCommon.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c59707a4b243b583b0453bc249b31f61b917665c
--- /dev/null
+++ b/ui/cc/cc/CCLayerTreeHostCommon.cpp
@@ -0,0 +1,976 @@
+/*
+ * Copyright (C) 2011 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/CCLayerTreeHostCommon.h"
+
+#include "FloatQuad.h"
+#include "IntRect.h"
+#include "LayerChromium.h"
+#include "RenderSurfaceChromium.h"
+#include "cc/CCLayerImpl.h"
+#include "cc/CCLayerIterator.h"
+#include "cc/CCLayerSorter.h"
+#include "cc/CCMathUtil.h"
+#include "cc/CCRenderSurface.h"
+#include <public/WebTransformationMatrix.h>
+
+using WebKit::WebTransformationMatrix;
+
+namespace WebCore {
+
+IntRect CCLayerTreeHostCommon::calculateVisibleRect(const IntRect& targetSurfaceRect, const IntRect& layerBoundRect, const WebTransformationMatrix& transform)
+{
+ // Is this layer fully contained within the target surface?
+ IntRect layerInSurfaceSpace = CCMathUtil::mapClippedRect(transform, layerBoundRect);
+ if (targetSurfaceRect.contains(layerInSurfaceSpace))
+ return layerBoundRect;
+
+ // If the layer doesn't fill up the entire surface, then find the part of
+ // the surface rect where the layer could be visible. This avoids trying to
+ // project surface rect points that are behind the projection point.
+ IntRect minimalSurfaceRect = targetSurfaceRect;
+ minimalSurfaceRect.intersect(layerInSurfaceSpace);
+
+ // Project the corners of the target surface rect into the layer space.
+ // This bounding rectangle may be larger than it needs to be (being
+ // axis-aligned), but is a reasonable filter on the space to consider.
+ // Non-invertible transforms will create an empty rect here.
+ const WebTransformationMatrix surfaceToLayer = transform.inverse();
+ IntRect layerRect = enclosingIntRect(CCMathUtil::projectClippedRect(surfaceToLayer, FloatRect(minimalSurfaceRect)));
+ layerRect.intersect(layerBoundRect);
+ return layerRect;
+}
+
+template<typename LayerType, typename RenderSurfaceType>
+static IntRect calculateLayerScissorRect(LayerType* layer, const FloatRect& rootScissorRect)
+{
+ RenderSurfaceType* targetSurface = layer->targetRenderSurface();
+
+ FloatRect rootScissorRectInTargetSurface = targetSurface->computeRootScissorRectInCurrentSurface(rootScissorRect);
+ FloatRect clipAndDamage;
+ if (layer->usesLayerClipping())
+ clipAndDamage = intersection(rootScissorRectInTargetSurface, layer->clipRect());
+ else
+ clipAndDamage = intersection(rootScissorRectInTargetSurface, targetSurface->contentRect());
+
+ return enclosingIntRect(clipAndDamage);
+}
+
+template<typename LayerType, typename RenderSurfaceType>
+static IntRect calculateSurfaceScissorRect(LayerType* layer, const FloatRect& rootScissorRect)
+{
+ LayerType* parentLayer = layer->parent();
+ RenderSurfaceType* targetSurface = parentLayer->targetRenderSurface();
+ ASSERT(targetSurface);
+
+ RenderSurfaceType* currentSurface = layer->renderSurface();
+ ASSERT(currentSurface);
+
+ FloatRect clipRect = currentSurface->clipRect();
+
+ // For surfaces, empty clipRect means the same as CCLayerImpl::usesLayerClipping being false
+ if (clipRect.isEmpty())
+ clipRect = intersection(targetSurface->contentRect(), currentSurface->drawableContentRect());
+
+ FloatRect rootScissorRectInTargetSurface = targetSurface->computeRootScissorRectInCurrentSurface(rootScissorRect);
+
+ FloatRect clipAndDamage = intersection(rootScissorRectInTargetSurface, clipRect);
+ return enclosingIntRect(clipAndDamage);
+}
+
+template<typename LayerType>
+static inline bool layerIsInExisting3DRenderingContext(LayerType* layer)
+{
+ // According to current W3C spec on CSS transforms, a layer is part of an established
+ // 3d rendering context if its parent has transform-style of preserves-3d.
+ return layer->parent() && layer->parent()->preserves3D();
+}
+
+template<typename LayerType>
+static bool layerIsRootOfNewRenderingContext(LayerType* layer)
+{
+ // According to current W3C spec on CSS transforms (Section 6.1), a layer is the
+ // beginning of 3d rendering context if its parent does not have transform-style:
+ // preserve-3d, but this layer itself does.
+ if (layer->parent())
+ return !layer->parent()->preserves3D() && layer->preserves3D();
+
+ return layer->preserves3D();
+}
+
+template<typename LayerType>
+static bool isLayerBackFaceVisible(LayerType* layer)
+{
+ // The current W3C spec on CSS transforms says that backface visibility should be
+ // determined differently depending on whether the layer is in a "3d rendering
+ // context" or not. For Chromium code, we can determine whether we are in a 3d
+ // rendering context by checking if the parent preserves 3d.
+
+ if (layerIsInExisting3DRenderingContext(layer))
+ return layer->drawTransform().isBackFaceVisible();
+
+ // In this case, either the layer establishes a new 3d rendering context, or is not in
+ // a 3d rendering context at all.
+ return layer->transform().isBackFaceVisible();
+}
+
+template<typename LayerType>
+static bool isSurfaceBackFaceVisible(LayerType* layer, const WebTransformationMatrix& drawTransform)
+{
+ if (layerIsInExisting3DRenderingContext(layer))
+ return drawTransform.isBackFaceVisible();
+
+ if (layerIsRootOfNewRenderingContext(layer))
+ return layer->transform().isBackFaceVisible();
+
+ // If the renderSurface is not part of a new or existing rendering context, then the
+ // layers that contribute to this surface will decide back-face visibility for themselves.
+ return false;
+}
+
+template<typename LayerType>
+static IntRect calculateVisibleLayerRect(LayerType* layer)
+{
+ ASSERT(layer->targetRenderSurface());
+
+ IntRect targetSurfaceRect = layer->targetRenderSurface()->contentRect();
+
+ if (layer->usesLayerClipping())
+ targetSurfaceRect.intersect(layer->clipRect());
+
+ if (targetSurfaceRect.isEmpty() || layer->contentBounds().isEmpty())
+ return IntRect();
+
+ // Note carefully these are aliases
+ const IntSize& bounds = layer->bounds();
+ const IntSize& contentBounds = layer->contentBounds();
+
+ const IntRect layerBoundRect = IntRect(IntPoint(), contentBounds);
+ WebTransformationMatrix transform = layer->drawTransform();
+
+ transform.scaleNonUniform(bounds.width() / static_cast<double>(contentBounds.width()),
+ bounds.height() / static_cast<double>(contentBounds.height()));
+ transform.translate(-contentBounds.width() / 2.0, -contentBounds.height() / 2.0);
+
+ IntRect visibleLayerRect = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerBoundRect, transform);
+ return visibleLayerRect;
+}
+
+static bool isScaleOrTranslation(const WebTransformationMatrix& m)
+{
+ return !m.m12() && !m.m13() && !m.m14()
+ && !m.m21() && !m.m23() && !m.m24()
+ && !m.m31() && !m.m32() && !m.m43()
+ && m.m44();
+}
+
+static inline bool layerOpacityIsOpaque(CCLayerImpl* layer)
+{
+ return layer->opacity() == 1;
+}
+
+static inline bool layerOpacityIsOpaque(LayerChromium* layer)
+{
+ // If the opacity is being animated then the opacity on the main thread is unreliable
+ // (since the impl thread may be using a different opacity), so it should not be trusted.
+ // In particular, it should not be treated as opaque.
+ return layer->opacity() == 1 && !layer->opacityIsAnimating();
+}
+
+static inline bool transformToParentIsKnown(CCLayerImpl*)
+{
+ return true;
+}
+
+static inline bool transformToParentIsKnown(LayerChromium* layer)
+{
+ return !layer->transformIsAnimating();
+}
+
+static inline bool transformToScreenIsKnown(CCLayerImpl*)
+{
+ return true;
+}
+
+static inline bool transformToScreenIsKnown(LayerChromium* layer)
+{
+ return !layer->screenSpaceTransformIsAnimating();
+}
+
+template<typename LayerType>
+static bool layerShouldBeSkipped(LayerType* layer)
+{
+ // Layers can be skipped if any of these conditions are met.
+ // - does not draw content.
+ // - is transparent
+ // - has empty bounds
+ // - the layer is not double-sided, but its back face is visible.
+ //
+ // Some additional conditions need to be computed at a later point after the recursion is finished.
+ // - the intersection of render surface content and layer clipRect is empty
+ // - the visibleLayerRect is empty
+ //
+ // Note, if the layer should not have been drawn due to being fully transparent,
+ // we would have skipped the entire subtree and never made it into this function,
+ // so it is safe to omit this check here.
+
+ if (!layer->drawsContent() || layer->bounds().isEmpty())
+ return true;
+
+ LayerType* backfaceTestLayer = layer;
+ if (layer->useParentBackfaceVisibility()) {
+ ASSERT(layer->parent());
+ ASSERT(!layer->parent()->useParentBackfaceVisibility());
+ backfaceTestLayer = layer->parent();
+ }
+
+ // The layer should not be drawn if (1) it is not double-sided and (2) the back of the layer is known to be facing the screen.
+ if (!backfaceTestLayer->doubleSided() && transformToScreenIsKnown(backfaceTestLayer) && isLayerBackFaceVisible(backfaceTestLayer))
+ return true;
+
+ return false;
+}
+
+static inline bool subtreeShouldBeSkipped(CCLayerImpl* layer)
+{
+ // The opacity of a layer always applies to its children (either implicitly
+ // via a render surface or explicitly if the parent preserves 3D), so the
+ // entire subtree can be skipped if this layer is fully transparent.
+ return !layer->opacity();
+}
+
+static inline bool subtreeShouldBeSkipped(LayerChromium* layer)
+{
+ // If the opacity is being animated then the opacity on the main thread is unreliable
+ // (since the impl thread may be using a different opacity), so it should not be trusted.
+ // In particular, it should not cause the subtree to be skipped.
+ return !layer->opacity() && !layer->opacityIsAnimating();
+}
+
+template<typename LayerType>
+static bool subtreeShouldRenderToSeparateSurface(LayerType* layer, bool axisAlignedWithRespectToParent)
+{
+ // Cache this value, because otherwise it walks the entire subtree several times.
+ bool descendantDrawsContent = layer->descendantDrawsContent();
+
+ //
+ // A layer and its descendants should render onto a new RenderSurface if any of these rules hold:
+ //
+
+ // If we force it.
+ if (layer->forceRenderSurface())
+ return true;
+
+ // If the layer uses a mask.
+ if (layer->maskLayer())
+ return true;
+
+ // If the layer has a reflection.
+ if (layer->replicaLayer())
+ return true;
+
+ // If the layer uses a CSS filter.
+ if (!layer->filters().isEmpty() || !layer->backgroundFilters().isEmpty())
+ return true;
+
+ // If the layer flattens its subtree (i.e. the layer doesn't preserve-3d), but it is
+ // treated as a 3D object by its parent (i.e. parent does preserve-3d).
+ if (layerIsInExisting3DRenderingContext(layer) && !layer->preserves3D() && descendantDrawsContent)
+ return true;
+
+ // If the layer clips its descendants but it is not axis-aligned with respect to its parent.
+ // On the main thread, when the transform is being animated, it is treated as unknown and we
+ // always error on the side of making a render surface, to let us consider descendents as
+ // not animating relative to their target to aid culling.
+ if (layer->masksToBounds() && (!axisAlignedWithRespectToParent || !transformToParentIsKnown(layer)) && descendantDrawsContent)
+ return true;
+
+ // If the layer has opacity != 1 and does not have a preserves-3d transform style.
+ // On the main thread, when opacity is being animated, it is treated as neither 1
+ // nor 0.
+ if (!layerOpacityIsOpaque(layer) && !layer->preserves3D() && descendantDrawsContent)
+ return true;
+
+ return false;
+}
+
+WebTransformationMatrix computeScrollCompensationForThisLayer(CCLayerImpl* scrollingLayer, const WebTransformationMatrix& parentMatrix)
+{
+ // For every layer that has non-zero scrollDelta, we have to compute a transform that can undo the
+ // scrollDelta translation. In particular, we want this matrix to premultiply a fixed-position layer's
+ // parentMatrix, so we design this transform in three steps as follows. The steps described here apply
+ // from right-to-left, so Step 1 would be the right-most matrix:
+ //
+ // Step 1. transform from target surface space to the exact space where scrollDelta is actually applied.
+ // -- this is inverse of the matrix in step 3
+ // Step 2. undo the scrollDelta
+ // -- this is just a translation by scrollDelta.
+ // Step 3. transform back to target surface space.
+ // -- this transform is the "partialLayerOriginTransform" = (parentMatrix * scale(layer->pageScaleDelta()));
+ //
+ // These steps create a matrix that both start and end in targetSurfaceSpace. So this matrix can
+ // pre-multiply any fixed-position layer's drawTransform to undo the scrollDeltas -- as long as
+ // that fixed position layer is fixed onto the same targetRenderSurface as this scrollingLayer.
+ //
+
+ WebTransformationMatrix partialLayerOriginTransform = parentMatrix;
+ partialLayerOriginTransform.scale(scrollingLayer->pageScaleDelta());
+
+ WebTransformationMatrix scrollCompensationForThisLayer = partialLayerOriginTransform; // Step 3
+ scrollCompensationForThisLayer.translate(scrollingLayer->scrollDelta().width(), scrollingLayer->scrollDelta().height()); // Step 2
+ scrollCompensationForThisLayer.multiply(partialLayerOriginTransform.inverse()); // Step 1
+ return scrollCompensationForThisLayer;
+}
+
+WebTransformationMatrix computeScrollCompensationMatrixForChildren(LayerChromium* currentLayer, const WebTransformationMatrix& currentParentMatrix, const WebTransformationMatrix& currentScrollCompensation)
+{
+ // The main thread (i.e. LayerChromium) does not need to worry about scroll compensation.
+ // So we can just return an identity matrix here.
+ return WebTransformationMatrix();
+}
+
+WebTransformationMatrix computeScrollCompensationMatrixForChildren(CCLayerImpl* layer, const WebTransformationMatrix& parentMatrix, const WebTransformationMatrix& currentScrollCompensationMatrix)
+{
+ // "Total scroll compensation" is the transform needed to cancel out all scrollDelta translations that
+ // occurred since the nearest container layer, even if there are renderSurfaces in-between.
+ //
+ // There are some edge cases to be aware of, that are not explicit in the code:
+ // - A layer that is both a fixed-position and container should not be its own container, instead, that means
+ // it is fixed to an ancestor, and is a container for any fixed-position descendants.
+ // - A layer that is a fixed-position container and has a renderSurface should behave the same as a container
+ // without a renderSurface, the renderSurface is irrelevant in that case.
+ // - A layer that does not have an explicit container is simply fixed to the viewport
+ // (i.e. the root renderSurface, and it would still compensate for root layer's scrollDelta).
+ // - If the fixed-position layer has its own renderSurface, then the renderSurface is
+ // the one who gets fixed.
+ //
+ // This function needs to be called AFTER layers create their own renderSurfaces.
+ //
+
+ // Avoid the overheads (including stack allocation and matrix initialization/copy) if we know that the scroll compensation doesn't need to be reset or adjusted.
+ if (!layer->isContainerForFixedPositionLayers() && layer->scrollDelta().isZero() && !layer->renderSurface())
+ return currentScrollCompensationMatrix;
+
+ // Start as identity matrix.
+ WebTransformationMatrix nextScrollCompensationMatrix;
+
+ // If this layer is not a container, then it inherits the existing scroll compensations.
+ if (!layer->isContainerForFixedPositionLayers())
+ nextScrollCompensationMatrix = currentScrollCompensationMatrix;
+
+ // If the current layer has a non-zero scrollDelta, then we should compute its local scrollCompensation
+ // and accumulate it to the nextScrollCompensationMatrix.
+ if (!layer->scrollDelta().isZero()) {
+ WebTransformationMatrix scrollCompensationForThisLayer = computeScrollCompensationForThisLayer(layer, parentMatrix);
+ nextScrollCompensationMatrix.multiply(scrollCompensationForThisLayer);
+ }
+
+ // If the layer created its own renderSurface, we have to adjust nextScrollCompensationMatrix.
+ // The adjustment allows us to continue using the scrollCompensation on the next surface.
+ // Step 1 (right-most in the math): transform from the new surface to the original ancestor surface
+ // Step 2: apply the scroll compensation
+ // Step 3: transform back to the new surface.
+ if (layer->renderSurface() && !nextScrollCompensationMatrix.isIdentity())
+ nextScrollCompensationMatrix = layer->renderSurface()->originTransform().inverse() * nextScrollCompensationMatrix * layer->renderSurface()->originTransform();
+
+ return nextScrollCompensationMatrix;
+}
+
+// Recursively walks the layer tree starting at the given node and computes all the
+// necessary transformations, clipRects, render surfaces, etc.
+template<typename LayerType, typename LayerList, typename RenderSurfaceType, typename LayerSorter>
+static bool calculateDrawTransformsInternal(LayerType* layer, LayerType* rootLayer, const WebTransformationMatrix& parentMatrix,
+ const WebTransformationMatrix& fullHierarchyMatrix, const WebTransformationMatrix& currentScrollCompensationMatrix,
+ RenderSurfaceType* nearestAncestorThatMovesPixels, LayerList& renderSurfaceLayerList, LayerList& layerList,
+ LayerSorter* layerSorter, int maxTextureSize)
+{
+ // This function computes the new matrix transformations recursively for this
+ // layer and all its descendants. It also computes the appropriate render surfaces.
+ // Some important points to remember:
+ //
+ // 0. Here, transforms are notated in Matrix x Vector order, and in words we describe what
+ // the transform does from left to right.
+ //
+ // 1. In our terminology, the "layer origin" refers to the top-left corner of a layer, and the
+ // positive Y-axis points downwards. This interpretation is valid because the orthographic
+ // projection applied at draw time flips the Y axis appropriately.
+ //
+ // 2. The anchor point, when given as a FloatPoint object, is specified in "unit layer space",
+ // where the bounds of the layer map to [0, 1]. However, as a WebTransformationMatrix object,
+ // the transform to the anchor point is specified in "pixel layer space", where the bounds
+ // of the layer map to [bounds.width(), bounds.height()].
+ //
+ // 3. The value of layer->position() is actually the position of the anchor point with respect to the position
+ // of the layer's origin. That is:
+ // layer->position() = positionOfLayerOrigin + anchorPoint (in pixel units)
+ //
+ // Or, equivalently,
+ // positionOfLayerOrigin.x = layer->position.x - (layer->anchorPoint.x * bounds.width)
+ // positionOfLayerOrigin.y = layer->position.y - (layer->anchorPoint.y * bounds.height)
+ //
+ // 4. Definition of various transforms used:
+ // M[parent] is the parent matrix, with respect to the nearest render surface, passed down recursively.
+ // M[root] is the full hierarchy, with respect to the root, passed down recursively.
+ // Tr[origin] is the translation matrix from the parent's origin to this layer's origin.
+ // Tr[origin2anchor] is the translation from the layer's origin to its anchor point
+ // Tr[origin2center] is the translation from the layer's origin to its center
+ // M[layer] is the layer's matrix (applied at the anchor point)
+ // M[sublayer] is the layer's sublayer transform (applied at the layer's center)
+ // Tr[anchor2center] is the translation offset from the anchor point and the center of the layer
+ //
+ // Some shortcuts and substitutions are used in the code to reduce matrix multiplications:
+ // Translating by the value of layer->position(), Tr[layer->position()] = Tr[origin] * Tr[origin2anchor]
+ // Tr[anchor2center] = Tr[origin2anchor].inverse() * Tr[origin2center]
+ //
+ // Some composite transforms can help in understanding the sequence of transforms:
+ // compositeLayerTransform = Tr[origin2anchor] * M[layer] * Tr[origin2anchor].inverse()
+ // compositeSublayerTransform = Tr[origin2center] * M[sublayer] * Tr[origin2center].inverse()
+ //
+ // In words, the layer transform is applied about the anchor point, and the sublayer transform is
+ // applied about the center of the layer.
+ //
+ // 5. When a layer (or render surface) is drawn, it is drawn into a "target render surface". Therefore the draw
+ // transform does not necessarily transform from screen space to local layer space. Instead, the draw transform
+ // is the transform between the "target render surface space" and local layer space. Note that render surfaces,
+ // except for the root, also draw themselves into a different target render surface, and so their draw
+ // transform and origin transforms are also described with respect to the target.
+ //
+ // Using these definitions, then:
+ //
+ // The draw transform for the layer is:
+ // M[draw] = M[parent] * Tr[origin] * compositeLayerTransform * Tr[origin2center]
+ // = M[parent] * Tr[layer->position()] * M[layer] * Tr[anchor2center]
+ //
+ // Interpreting the math left-to-right, this transforms from the layer's render surface to the center of the layer.
+ //
+ // The screen space transform is:
+ // M[screenspace] = M[root] * Tr[origin] * compositeLayerTransform
+ // = M[root] * Tr[layer->position()] * M[layer] * Tr[origin2anchor].inverse()
+ //
+ // Interpreting the math left-to-right, this transforms from the root layer space to the local layer's origin.
+ //
+ // The transform hierarchy that is passed on to children (i.e. the child's parentMatrix) is:
+ // M[parent]_for_child = M[parent] * Tr[origin] * compositeLayerTransform * compositeSublayerTransform
+ // = M[parent] * Tr[layer->position()] * M[layer] * Tr[anchor2center] * M[sublayer] * Tr[origin2center].inverse()
+ // = M[draw] * M[sublayer] * Tr[origin2center].inverse()
+ //
+ // and a similar matrix for the full hierarchy with respect to the root.
+ //
+ // Finally, note that the final matrix used by the shader for the layer is P * M[draw] * S . This final product
+ // is computed in drawTexturedQuad(), where:
+ // P is the projection matrix
+ // S is the scale adjustment (to scale up to the layer size)
+ //
+ // When a render surface has a replica layer, that layer's transform is used to draw a second copy of the surface.
+ // Transforms named here are relative to the surface, unless they specify they are relative to the replica layer.
+ //
+ // We will denote a scale by contents scale S[contentsScale]
+ //
+ // The render surface origin transform to its target surface origin is:
+ // M[surfaceOrigin] = M[owningLayer->Draw] * S[contentsScale].inverse() * Tr[origin2centerInScreenSpace].inverse()
+ //
+ // The render surface origin transform to its the root (screen space) origin is:
+ // M[surface2root] = M[owningLayer->screenspace] * S[contentsScale].inverse()
+ //
+ // The replica draw transform is:
+ // M[replicaDraw] = M[surfaceOrigin] * S[contentsScale] * Tr[replica->position()] * Tr[replica] * Tr[anchor2center] * S[contentsScale].inverse()
+ // = M[owningLayer->draw] * Tr[origin2center].inverse() * S[contentsScale] * Tr[replica->position()] * Tr[replica] * Tr[anchor2clippedCenter] * S[contentsScale].inverse()
+ //
+ // The replica origin transform to its target surface origin is:
+ // M[replicaOrigin] = S[contentsScale] * M[surfaceOrigin] * Tr[replica->position()] * Tr[replica] * Tr[origin2anchor].inverse() * S[contentsScale].invers()
+ //
+ // The replica origin transform to the root (screen space) origin is:
+ // M[replica2root] = M[surface2root] * Tr[replica->position()] * Tr[replica] * Tr[origin2anchor].inverse()
+ //
+
+ if (subtreeShouldBeSkipped(layer))
+ return false;
+
+ float drawOpacity = layer->opacity();
+ bool drawOpacityIsAnimating = layer->opacityIsAnimating();
+ if (layer->parent() && layer->parent()->preserves3D()) {
+ drawOpacity *= layer->parent()->drawOpacity();
+ drawOpacityIsAnimating |= layer->parent()->drawOpacityIsAnimating();
+ }
+
+ IntSize bounds = layer->bounds();
+ FloatPoint anchorPoint = layer->anchorPoint();
+ FloatPoint position = layer->position() - layer->scrollDelta();
+
+ // Offset between anchor point and the center of the quad.
+ float centerOffsetX = (0.5 - anchorPoint.x()) * bounds.width();
+ float centerOffsetY = (0.5 - anchorPoint.y()) * bounds.height();
+
+ WebTransformationMatrix layerLocalTransform;
+ // LT = Tr[origin] * S[pageScaleDelta]
+ layerLocalTransform.scale(layer->pageScaleDelta());
+ // LT = Tr[origin] * S[pageScaleDelta] * Tr[origin2anchor]
+ layerLocalTransform.translate3d(position.x(), position.y(), layer->anchorPointZ());
+ // LT = Tr[origin] * S[pageScaleDelta] * Tr[origin2anchor] * M[layer]
+ layerLocalTransform.multiply(layer->transform());
+ // LT = Tr[origin] * S[pageScaleDelta] * Tr[origin2anchor] * M[layer] * Tr[anchor2center]
+ layerLocalTransform.translate3d(centerOffsetX, centerOffsetY, -layer->anchorPointZ());
+
+ // The combinedTransform that gets computed below is effectively the layer's drawTransform, unless
+ // the layer itself creates a renderSurface. In that case, the renderSurface re-parents the transforms.
+ WebTransformationMatrix combinedTransform = parentMatrix;
+ combinedTransform.multiply(layerLocalTransform);
+
+ if (layer->fixedToContainerLayer()) {
+ // Special case: this layer is a composited fixed-position layer; we need to
+ // explicitly compensate for all ancestors' nonzero scrollDeltas to keep this layer
+ // fixed correctly.
+ combinedTransform = currentScrollCompensationMatrix * combinedTransform;
+ }
+
+ bool animatingTransformToTarget = layer->transformIsAnimating();
+ bool animatingTransformToScreen = animatingTransformToTarget;
+ if (layer->parent()) {
+ animatingTransformToTarget |= layer->parent()->drawTransformIsAnimating();
+ animatingTransformToScreen |= layer->parent()->screenSpaceTransformIsAnimating();
+ }
+
+ float contentsScale = layer->contentsScale();
+
+ FloatRect layerRect(-0.5 * layer->bounds().width(), -0.5 * layer->bounds().height(), layer->bounds().width(), layer->bounds().height());
+ IntRect transformedLayerRect;
+
+ // fullHierarchyMatrix is the matrix that transforms objects between screen space (except projection matrix) and the most recent RenderSurface's space.
+ // nextHierarchyMatrix will only change if this layer uses a new RenderSurface, otherwise remains the same.
+ WebTransformationMatrix nextHierarchyMatrix = fullHierarchyMatrix;
+
+ // FIXME: This seems like the wrong place to set this
+ layer->setUsesLayerClipping(false);
+
+ if (subtreeShouldRenderToSeparateSurface(layer, isScaleOrTranslation(combinedTransform))) {
+ // Check back-face visibility before continuing with this surface and its subtree
+ if (!layer->doubleSided() && transformToParentIsKnown(layer) && isSurfaceBackFaceVisible(layer, combinedTransform))
+ return false;
+
+ if (!layer->renderSurface())
+ layer->createRenderSurface();
+
+ RenderSurfaceType* renderSurface = layer->renderSurface();
+ renderSurface->clearLayerList();
+
+ // The origin of the new surface is the upper left corner of the layer.
+ WebTransformationMatrix drawTransform;
+ drawTransform.scale(contentsScale);
+ drawTransform.translate3d(0.5 * bounds.width(), 0.5 * bounds.height(), 0);
+ layer->setDrawTransform(drawTransform);
+
+ transformedLayerRect = IntRect(0, 0, contentsScale * bounds.width(), contentsScale * bounds.height());
+
+ // The opacity value is moved from the layer to its surface, so that the entire subtree properly inherits opacity.
+ renderSurface->setDrawOpacity(drawOpacity);
+ renderSurface->setDrawOpacityIsAnimating(drawOpacityIsAnimating);
+ layer->setDrawOpacity(1);
+ layer->setDrawOpacityIsAnimating(false);
+
+ WebTransformationMatrix surfaceOriginTransform = combinedTransform;
+ // The surfaceOriginTransform transforms points in the surface's content space
+ // to its parent's content space. Distances in these spaces are both in physical
+ // pixels, so we need to 'undo' the scale by contentsScale. Ultimately, the
+ // transform should map (0, 0) to contentsScale * position, and preserve distances.
+ // Note, the following two lines are not equivalent to translating by (bounds.width(),
+ // bounds.height). The effect on m41 and m42 would be identical, but the scale
+ // affects the entire matrix. We need to scale these other entries to avoid
+ // double scaling; we must remain in physical pixels.
+ surfaceOriginTransform.scale(1 / contentsScale);
+ surfaceOriginTransform.translate3d(-0.5 * transformedLayerRect.width(), -0.5 * transformedLayerRect.height(), 0);
+ renderSurface->setOriginTransform(surfaceOriginTransform);
+
+ renderSurface->setTargetSurfaceTransformsAreAnimating(animatingTransformToTarget);
+ renderSurface->setScreenSpaceTransformsAreAnimating(animatingTransformToScreen);
+ animatingTransformToTarget = false;
+ layer->setDrawTransformIsAnimating(animatingTransformToTarget);
+ layer->setScreenSpaceTransformIsAnimating(animatingTransformToScreen);
+
+ // Update the aggregate hierarchy matrix to include the transform of the newly created RenderSurface.
+ nextHierarchyMatrix.multiply(surfaceOriginTransform);
+
+ // The render surface clipRect contributes to the scissor rect that needs to
+ // be applied before drawing the render surface onto its containing
+ // surface and is therefore expressed in the parent's coordinate system.
+ renderSurface->setClipRect(layer->parent() ? layer->parent()->clipRect() : layer->clipRect());
+
+ // The layer's clipRect can be reset here. The renderSurface will correctly clip the subtree.
+ layer->setUsesLayerClipping(false);
+ layer->setClipRect(IntRect());
+
+ if (layer->maskLayer())
+ layer->maskLayer()->setTargetRenderSurface(renderSurface);
+
+ if (layer->replicaLayer() && layer->replicaLayer()->maskLayer())
+ layer->replicaLayer()->maskLayer()->setTargetRenderSurface(renderSurface);
+
+ renderSurface->setFilters(layer->filters());
+ if (renderSurface->filters().hasFilterThatMovesPixels())
+ nearestAncestorThatMovesPixels = renderSurface;
+ renderSurface->setNearestAncestorThatMovesPixels(nearestAncestorThatMovesPixels);
+
+ renderSurface->setBackgroundFilters(layer->backgroundFilters());
+
+ renderSurfaceLayerList.append(layer);
+ } else {
+ layer->setDrawTransform(combinedTransform);
+ layer->setDrawTransformIsAnimating(animatingTransformToTarget);
+ layer->setScreenSpaceTransformIsAnimating(animatingTransformToScreen);
+ transformedLayerRect = enclosingIntRect(CCMathUtil::mapClippedRect(layer->drawTransform(), layerRect));
+
+ layer->setDrawOpacity(drawOpacity);
+ layer->setDrawOpacityIsAnimating(drawOpacityIsAnimating);
+
+ if (layer != rootLayer) {
+ ASSERT(layer->parent());
+ layer->clearRenderSurface();
+
+ // Layers inherit the clip rect from their parent.
+ layer->setClipRect(layer->parent()->clipRect());
+ if (layer->parent()->usesLayerClipping())
+ layer->setUsesLayerClipping(true);
+
+ // Layers without their own renderSurface will render into the nearest ancestor surface.
+ layer->setTargetRenderSurface(layer->parent()->targetRenderSurface());
+ }
+ }
+
+ if (layer->masksToBounds()) {
+ IntRect clipRect = transformedLayerRect;
+
+ // If the layer already inherited a clipRect, we need to intersect with it before
+ // overriding the layer's clipRect and usesLayerClipping.
+ if (layer->usesLayerClipping())
+ clipRect.intersect(layer->clipRect());
+
+ layer->setClipRect(clipRect);
+ layer->setUsesLayerClipping(true);
+ }
+
+ // Note that at this point, layer->drawTransform() is not necessarily the same as local variable drawTransform.
+ // layerScreenSpaceTransform represents the transform between root layer's "screen space" and local layer space.
+ WebTransformationMatrix layerScreenSpaceTransform = nextHierarchyMatrix;
+ layerScreenSpaceTransform.multiply(layer->drawTransform());
+ layerScreenSpaceTransform.translate3d(-0.5 * bounds.width(), -0.5 * bounds.height(), 0);
+ layer->setScreenSpaceTransform(layerScreenSpaceTransform);
+
+ // drawableContentRect() is always stored in the coordinate system of the
+ // RenderSurface the layer draws into.
+ if (layer->drawsContent()) {
+ IntRect drawableContentRect = transformedLayerRect;
+ if (layer->usesLayerClipping())
+ drawableContentRect.intersect(layer->clipRect());
+ layer->setDrawableContentRect(drawableContentRect);
+ } else
+ layer->setDrawableContentRect(IntRect());
+
+ WebTransformationMatrix sublayerMatrix = layer->drawTransform();
+
+ // Flatten to 2D if the layer doesn't preserve 3D.
+ if (!layer->preserves3D()) {
+ sublayerMatrix.setM13(0);
+ sublayerMatrix.setM23(0);
+ sublayerMatrix.setM31(0);
+ sublayerMatrix.setM32(0);
+ sublayerMatrix.setM33(1);
+ sublayerMatrix.setM34(0);
+ sublayerMatrix.setM43(0);
+ }
+
+ // Apply the sublayer transform at the center of the layer.
+ sublayerMatrix.multiply(layer->sublayerTransform());
+
+ // The coordinate system given to children is located at the layer's origin, not the center.
+ sublayerMatrix.translate3d(-bounds.width() * 0.5, -bounds.height() * 0.5, 0);
+
+ LayerList& descendants = (layer->renderSurface() ? layer->renderSurface()->layerList() : layerList);
+
+ // Any layers that are appended after this point are in the layer's subtree and should be included in the sorting process.
+ unsigned sortingStartIndex = descendants.size();
+
+ if (!layerShouldBeSkipped(layer))
+ descendants.append(layer);
+
+ WebTransformationMatrix nextScrollCompensationMatrix = computeScrollCompensationMatrixForChildren(layer, parentMatrix, currentScrollCompensationMatrix);;
+
+ for (size_t i = 0; i < layer->children().size(); ++i) {
+ LayerType* child = layer->children()[i].get();
+ bool drawsContent = calculateDrawTransformsInternal<LayerType, LayerList, RenderSurfaceType, LayerSorter>(child, rootLayer, sublayerMatrix, nextHierarchyMatrix, nextScrollCompensationMatrix, nearestAncestorThatMovesPixels, renderSurfaceLayerList, descendants, layerSorter, maxTextureSize);
+
+ if (drawsContent) {
+ if (child->renderSurface()) {
+ RenderSurfaceType* childRenderSurface = child->renderSurface();
+ IntRect drawableContentRect = layer->drawableContentRect();
+ drawableContentRect.unite(enclosingIntRect(childRenderSurface->drawableContentRect()));
+ layer->setDrawableContentRect(drawableContentRect);
+ descendants.append(child);
+ } else {
+ IntRect drawableContentRect = layer->drawableContentRect();
+ drawableContentRect.unite(child->drawableContentRect());
+ layer->setDrawableContentRect(drawableContentRect);
+ }
+ }
+ }
+
+ if (layer->masksToBounds() || layer->maskLayer()) {
+ IntRect drawableContentRect = layer->drawableContentRect();
+ drawableContentRect.intersect(transformedLayerRect);
+ layer->setDrawableContentRect(drawableContentRect);
+ }
+
+ if (layer->renderSurface() && layer != rootLayer) {
+ RenderSurfaceType* renderSurface = layer->renderSurface();
+ IntRect clippedContentRect = layer->drawableContentRect();
+ FloatPoint surfaceCenter = FloatRect(clippedContentRect).center();
+
+ // Restrict the RenderSurface size to the portion that's visible.
+ FloatSize centerOffsetDueToClipping;
+
+ // Don't clip if the layer is reflected as the reflection shouldn't be
+ // clipped. If the layer is animating, then the surface's transform to
+ // its target is not known on the main thread, and we should not use it
+ // to clip.
+ if (!layer->replicaLayer() && transformToParentIsKnown(layer)) {
+ if (!renderSurface->clipRect().isEmpty() && !clippedContentRect.isEmpty()) {
+ IntRect surfaceClipRect = CCLayerTreeHostCommon::calculateVisibleRect(renderSurface->clipRect(), clippedContentRect, renderSurface->originTransform());
+ clippedContentRect.intersect(surfaceClipRect);
+ }
+ FloatPoint clippedSurfaceCenter = FloatRect(clippedContentRect).center();
+ centerOffsetDueToClipping = clippedSurfaceCenter - surfaceCenter;
+ }
+
+ // The RenderSurface backing texture cannot exceed the maximum supported
+ // texture size.
+ clippedContentRect.setWidth(std::min(clippedContentRect.width(), maxTextureSize));
+ clippedContentRect.setHeight(std::min(clippedContentRect.height(), maxTextureSize));
+
+ if (clippedContentRect.isEmpty())
+ renderSurface->clearLayerList();
+
+ renderSurface->setContentRect(clippedContentRect);
+
+ // Since the layer starts a new render surface we need to adjust its
+ // clipRect to be expressed in the new surface's coordinate system.
+ layer->setClipRect(layer->drawableContentRect());
+
+ // Adjust the origin of the transform to be the center of the render surface.
+ WebTransformationMatrix drawTransform = renderSurface->originTransform();
+ drawTransform.translate3d(surfaceCenter.x() + centerOffsetDueToClipping.width(), surfaceCenter.y() + centerOffsetDueToClipping.height(), 0);
+ renderSurface->setDrawTransform(drawTransform);
+
+ WebTransformationMatrix screenSpaceTransform = layer->screenSpaceTransform();
+ // The layer's screen space transform operates on layer rects, but the surfaces
+ // screen space transform operates on surface rects, which are in physical pixels,
+ // so we have to 'undo' the scale here.
+ screenSpaceTransform.scale(1 / contentsScale);
+ renderSurface->setScreenSpaceTransform(screenSpaceTransform);
+
+ if (layer->replicaLayer()) {
+ // Compute the transformation matrix used to draw the surface's replica to the target surface.
+ WebTransformationMatrix replicaDrawTransform = renderSurface->originTransform();
+
+ replicaDrawTransform.scale(contentsScale);
+ replicaDrawTransform.translate(layer->replicaLayer()->position().x(), layer->replicaLayer()->position().y());
+ replicaDrawTransform.multiply(layer->replicaLayer()->transform());
+ FloatPoint layerSpaceSurfaceCenter = surfaceCenter;
+ layerSpaceSurfaceCenter.scale(1 / contentsScale, 1 / contentsScale);
+ replicaDrawTransform.translate(layerSpaceSurfaceCenter.x() - anchorPoint.x() * bounds.width(), layerSpaceSurfaceCenter.y() - anchorPoint.y() * bounds.height());
+ replicaDrawTransform.scale(1 / contentsScale);
+
+ renderSurface->setReplicaDrawTransform(replicaDrawTransform);
+
+ WebTransformationMatrix surfaceOriginToReplicaOriginTransform;
+ surfaceOriginToReplicaOriginTransform.scale(contentsScale);
+ surfaceOriginToReplicaOriginTransform.translate(layer->replicaLayer()->position().x(), layer->replicaLayer()->position().y());
+ surfaceOriginToReplicaOriginTransform.multiply(layer->replicaLayer()->transform());
+ surfaceOriginToReplicaOriginTransform.translate(-anchorPoint.x() * bounds.width(), -anchorPoint.y() * bounds.height());
+ surfaceOriginToReplicaOriginTransform.scale(1 / contentsScale);
+
+ // Compute the replica's "originTransform" that maps from the replica's origin space to the target surface origin space.
+ WebTransformationMatrix replicaOriginTransform = layer->renderSurface()->originTransform() * surfaceOriginToReplicaOriginTransform;
+ renderSurface->setReplicaOriginTransform(replicaOriginTransform);
+
+ // Compute the replica's "screenSpaceTransform" that maps from the replica's origin space to the screen's origin space.
+ WebTransformationMatrix replicaScreenSpaceTransform = layer->renderSurface()->screenSpaceTransform() * surfaceOriginToReplicaOriginTransform;
+ renderSurface->setReplicaScreenSpaceTransform(replicaScreenSpaceTransform);
+ }
+
+ // If a render surface has no layer list, then it and none of its children needed to get drawn.
+ if (!layer->renderSurface()->layerList().size()) {
+ // FIXME: Originally we asserted that this layer was already at the end of the
+ // list, and only needed to remove that layer. For now, we remove the
+ // entire subtree of surfaces to fix a crash bug. The root cause is
+ // https://bugs.webkit.org/show_bug.cgi?id=74147 and we should be able
+ // to put the original assert after fixing that.
+ while (renderSurfaceLayerList.last() != layer) {
+ renderSurfaceLayerList.last()->clearRenderSurface();
+ renderSurfaceLayerList.removeLast();
+ }
+ ASSERT(renderSurfaceLayerList.last() == layer);
+ renderSurfaceLayerList.removeLast();
+ layer->clearRenderSurface();
+ return false;
+ }
+ }
+
+ // If neither this layer nor any of its children were added, early out.
+ if (sortingStartIndex == descendants.size())
+ return false;
+
+ // If preserves-3d then sort all the descendants in 3D so that they can be
+ // drawn from back to front. If the preserves-3d property is also set on the parent then
+ // skip the sorting as the parent will sort all the descendants anyway.
+ if (descendants.size() && layer->preserves3D() && (!layer->parent() || !layer->parent()->preserves3D()))
+ sortLayers(&descendants.at(sortingStartIndex), descendants.end(), layerSorter);
+
+ return true;
+}
+
+// FIXME: Instead of using the following function to set visibility rects on a second
+// tree pass, revise calculateVisibleLayerRect() so that this can be done in a single
+// pass inside calculateDrawTransformsInternal<>().
+template<typename LayerType, typename LayerList, typename RenderSurfaceType>
+static void calculateVisibleAndScissorRectsInternal(const LayerList& renderSurfaceLayerList, const FloatRect& rootScissorRect)
+{
+ // Use BackToFront since it's cheap and this isn't order-dependent.
+ typedef CCLayerIterator<LayerType, LayerList, RenderSurfaceType, CCLayerIteratorActions::BackToFront> CCLayerIteratorType;
+
+ CCLayerIteratorType end = CCLayerIteratorType::end(&renderSurfaceLayerList);
+ for (CCLayerIteratorType it = CCLayerIteratorType::begin(&renderSurfaceLayerList); it != end; ++it) {
+ if (it.representsTargetRenderSurface()) {
+ LayerType* maskLayer = it->maskLayer();
+ if (maskLayer)
+ maskLayer->setVisibleLayerRect(IntRect(IntPoint(), it->contentBounds()));
+ LayerType* replicaMaskLayer = it->replicaLayer() ? it->replicaLayer()->maskLayer() : 0;
+ if (replicaMaskLayer)
+ replicaMaskLayer->setVisibleLayerRect(IntRect(IntPoint(), it->contentBounds()));
+ } else if (it.representsItself()) {
+ IntRect visibleLayerRect = calculateVisibleLayerRect(*it);
+ it->setVisibleLayerRect(visibleLayerRect);
+
+ IntRect scissorRect = calculateLayerScissorRect<LayerType, RenderSurfaceType>(*it, rootScissorRect);
+ it->setScissorRect(scissorRect);
+ } else if (it.representsContributingRenderSurface()) {
+ IntRect scissorRect = calculateSurfaceScissorRect<LayerType, RenderSurfaceType>(*it, rootScissorRect);
+ it->renderSurface()->setScissorRect(scissorRect);
+ }
+ }
+}
+
+void CCLayerTreeHostCommon::calculateDrawTransforms(LayerChromium* layer, LayerChromium* rootLayer, const WebTransformationMatrix& parentMatrix, const WebTransformationMatrix& fullHierarchyMatrix, Vector<RefPtr<LayerChromium> >& renderSurfaceLayerList, Vector<RefPtr<LayerChromium> >& layerList, int maxTextureSize)
+{
+ WebTransformationMatrix scrollCompensationMatrix;
+ WebCore::calculateDrawTransformsInternal<LayerChromium, Vector<RefPtr<LayerChromium> >, RenderSurfaceChromium, void>(layer, rootLayer, parentMatrix, fullHierarchyMatrix, scrollCompensationMatrix, 0, renderSurfaceLayerList, layerList, 0, maxTextureSize);
+}
+
+void CCLayerTreeHostCommon::calculateDrawTransforms(CCLayerImpl* layer, CCLayerImpl* rootLayer, const WebTransformationMatrix& parentMatrix, const WebTransformationMatrix& fullHierarchyMatrix, Vector<CCLayerImpl*>& renderSurfaceLayerList, Vector<CCLayerImpl*>& layerList, CCLayerSorter* layerSorter, int maxTextureSize)
+{
+ WebTransformationMatrix scrollCompensationMatrix;
+ WebCore::calculateDrawTransformsInternal<CCLayerImpl, Vector<CCLayerImpl*>, CCRenderSurface, CCLayerSorter>(layer, rootLayer, parentMatrix, fullHierarchyMatrix, scrollCompensationMatrix, 0, renderSurfaceLayerList, layerList, layerSorter, maxTextureSize);
+}
+
+void CCLayerTreeHostCommon::calculateVisibleAndScissorRects(Vector<RefPtr<LayerChromium> >& renderSurfaceLayerList, const FloatRect& rootScissorRect)
+{
+ calculateVisibleAndScissorRectsInternal<LayerChromium, Vector<RefPtr<LayerChromium> >, RenderSurfaceChromium>(renderSurfaceLayerList, rootScissorRect);
+}
+
+void CCLayerTreeHostCommon::calculateVisibleAndScissorRects(Vector<CCLayerImpl*>& renderSurfaceLayerList, const FloatRect& rootScissorRect)
+{
+ calculateVisibleAndScissorRectsInternal<CCLayerImpl, Vector<CCLayerImpl*>, CCRenderSurface>(renderSurfaceLayerList, rootScissorRect);
+}
+
+static bool pointHitsRect(const IntPoint& viewportPoint, const WebTransformationMatrix& localSpaceToScreenSpaceTransform, FloatRect localSpaceRect)
+{
+ // If the transform is not invertible, then assume that this point doesn't hit this rect.
+ if (!localSpaceToScreenSpaceTransform.isInvertible())
+ return false;
+
+ // Transform the hit test point from screen space to the local space of the given rect.
+ bool clipped = false;
+ FloatPoint hitTestPointInLocalSpace = CCMathUtil::projectPoint(localSpaceToScreenSpaceTransform.inverse(), FloatPoint(viewportPoint), clipped);
+
+ // If projectPoint could not project to a valid value, then we assume that this point doesn't hit this rect.
+ if (clipped)
+ return false;
+
+ return localSpaceRect.contains(hitTestPointInLocalSpace);
+}
+
+static bool pointIsClippedBySurfaceOrClipRect(const IntPoint& viewportPoint, CCLayerImpl* layer)
+{
+ CCLayerImpl* currentLayer = layer;
+
+ // Walk up the layer tree and hit-test any renderSurfaces and any layer clipRects that are active.
+ while (currentLayer) {
+ if (currentLayer->renderSurface() && !pointHitsRect(viewportPoint, currentLayer->renderSurface()->screenSpaceTransform(), currentLayer->renderSurface()->contentRect()))
+ return true;
+
+ // Note that clipRects are actually in targetSurface space, so the transform we
+ // have to provide is the target surface's screenSpaceTransform.
+ if (currentLayer->usesLayerClipping() && !pointHitsRect(viewportPoint, currentLayer->targetRenderSurface()->screenSpaceTransform(), currentLayer->clipRect()))
+ return true;
+
+ currentLayer = currentLayer->parent();
+ }
+
+ // If we have finished walking all ancestors without having already exited, then the point is not clipped by any ancestors.
+ return false;
+}
+
+CCLayerImpl* CCLayerTreeHostCommon::findLayerThatIsHitByPoint(const IntPoint& viewportPoint, Vector<CCLayerImpl*>& renderSurfaceLayerList)
+{
+ CCLayerImpl* foundLayer = 0;
+
+ typedef CCLayerIterator<CCLayerImpl, Vector<CCLayerImpl*>, CCRenderSurface, CCLayerIteratorActions::FrontToBack> CCLayerIteratorType;
+ CCLayerIteratorType end = CCLayerIteratorType::end(&renderSurfaceLayerList);
+
+ for (CCLayerIteratorType it = CCLayerIteratorType::begin(&renderSurfaceLayerList); it != end; ++it) {
+ // We don't want to consider renderSurfaces for hit testing.
+ if (!it.representsItself())
+ continue;
+
+ CCLayerImpl* currentLayer = (*it);
+
+ FloatRect layerRect(FloatPoint::zero(), currentLayer->bounds());
+ if (!pointHitsRect(viewportPoint, currentLayer->screenSpaceTransform(), layerRect))
+ continue;
+
+ // At this point, we think the point does hit the layer, but we need to walk up
+ // the parents to ensure that the layer was not clipped in such a way that the
+ // hit point actually should not hit the layer.
+ if (pointIsClippedBySurfaceOrClipRect(viewportPoint, currentLayer))
+ continue;
+
+ foundLayer = currentLayer;
+ break;
+ }
+
+ // This can potentially return 0, which means the viewportPoint did not successfully hit test any layers, not even the root layer.
+ return foundLayer;
+}
+
+} // namespace WebCore
« no previous file with comments | « ui/cc/cc/CCLayerTreeHostCommon.h ('k') | ui/cc/cc/CCLayerTreeHostImpl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698