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

Unified Diff: sky/engine/core/rendering/RenderLayer.cpp

Issue 945693002: Move hit testing out of RenderLayer into RenderBox. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: add to test case Created 5 years, 10 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 | « sky/engine/core/rendering/RenderLayer.h ('k') | sky/engine/core/rendering/RenderLayerModelObject.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sky/engine/core/rendering/RenderLayer.cpp
diff --git a/sky/engine/core/rendering/RenderLayer.cpp b/sky/engine/core/rendering/RenderLayer.cpp
index 37a3337f4332d393b09f653929a3195b6351c9c9..ed1bfc539649da1b32820049e0e325aa6b68114b 100644
--- a/sky/engine/core/rendering/RenderLayer.cpp
+++ b/sky/engine/core/rendering/RenderLayer.cpp
@@ -788,281 +788,6 @@ void RenderLayer::restoreClip(GraphicsContext* context, const LayoutRect& paintD
context->restore();
}
-Node* RenderLayer::enclosingElement() const
-{
- for (RenderObject* r = renderer(); r; r = r->parent()) {
- if (Node* e = r->node())
- return e;
- }
- ASSERT_NOT_REACHED();
- return 0;
-}
-
-// Compute the z-offset of the point in the transformState.
-// This is effectively projecting a ray normal to the plane of ancestor, finding where that
-// ray intersects target, and computing the z delta between those two points.
-static double computeZOffset(const HitTestingTransformState& transformState)
-{
- // We got an affine transform, so no z-offset
- if (transformState.m_accumulatedTransform.isAffine())
- return 0;
-
- // Flatten the point into the target plane
- FloatPoint targetPoint = transformState.mappedPoint();
-
- // Now map the point back through the transform, which computes Z.
- FloatPoint3D backmappedPoint = transformState.m_accumulatedTransform.mapPoint(FloatPoint3D(targetPoint));
- return backmappedPoint.z();
-}
-
-PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer,
- const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation,
- const HitTestingTransformState* containerTransformState,
- const LayoutPoint& translationOffset) const
-{
- RefPtr<HitTestingTransformState> transformState;
- LayoutPoint offset;
- if (containerTransformState) {
- // If we're already computing transform state, then it's relative to the container (which we know is non-null).
- transformState = HitTestingTransformState::create(*containerTransformState);
- convertToLayerCoords(containerLayer, offset);
- } else {
- // If this is the first time we need to make transform state, then base it off of hitTestLocation,
- // which is relative to rootLayer.
- transformState = HitTestingTransformState::create(hitTestLocation.transformedPoint(), hitTestLocation.transformedRect(), FloatQuad(hitTestRect));
- convertToLayerCoords(rootLayer, offset);
- }
- offset.moveBy(translationOffset);
-
- RenderObject* containerRenderer = containerLayer ? containerLayer->renderer() : 0;
- if (renderer()->shouldUseTransformFromContainer(containerRenderer)) {
- TransformationMatrix containerTransform;
- renderer()->getTransformFromContainer(containerRenderer, toLayoutSize(offset), containerTransform);
- transformState->applyTransform(containerTransform, HitTestingTransformState::AccumulateTransform);
- } else {
- transformState->translate(offset.x(), offset.y(), HitTestingTransformState::AccumulateTransform);
- }
-
- return transformState;
-}
-
-
-static bool isHitCandidate(bool canDepthSort, double* zOffset, const HitTestingTransformState* transformState)
-{
- // The hit layer is depth-sorting with other layers, so just say that it was hit.
- if (canDepthSort)
- return true;
-
- // We need to look at z-depth to decide if this layer was hit.
- if (zOffset) {
- ASSERT(transformState);
- // This is actually computing our z, but that's OK because the hitLayer is coplanar with us.
- double childZOffset = computeZOffset(*transformState);
- if (childZOffset > *zOffset) {
- *zOffset = childZOffset;
- return true;
- }
- return false;
- }
-
- return true;
-}
-
-// hitTestLocation and hitTestRect are relative to rootLayer.
-// A 'flattening' layer is one preserves3D() == false.
-// transformState.m_accumulatedTransform holds the transform from the containing flattening layer.
-// transformState.m_lastPlanarPoint is the hitTestLocation in the plane of the containing flattening layer.
-// transformState.m_lastPlanarQuad is the hitTestRect as a quad in the plane of the containing flattening layer.
-//
-// If zOffset is non-null (which indicates that the caller wants z offset information),
-// *zOffset on return is the z offset of the hit point relative to the containing flattening layer.
-bool RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
- const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation,
- const HitTestingTransformState* transformState, double* zOffset)
-{
- if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
- return 0;
-
- // The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate.
- RefPtr<HitTestingTransformState> localTransformState;
-
- LayoutRect localHitTestRect = hitTestRect;
- HitTestLocation localHitTestLocation = hitTestLocation;
-
- // We need transform state for the first time, or to offset the container state, or to accumulate the new transform.
- if (transform() || transformState || m_has3DTransformedDescendant || preserves3D())
- localTransformState = createLocalTransformState(rootLayer, containerLayer, localHitTestRect, localHitTestLocation, transformState);
-
- // Apply a transform if we have one.
- if (transform()) {
- // Make sure the parent's clip rects have been calculated.
- if (parent()) {
- ClipRect clipRect = clipper().backgroundClipRect(ClipRectsContext(rootLayer, RootRelativeClipRects));
- // Go ahead and test the enclosing clip now.
- if (!clipRect.intersects(localHitTestLocation))
- return 0;
- }
-
- // If the transform can't be inverted, then don't hit test this layer at all.
- if (!localTransformState->m_accumulatedTransform.isInvertible())
- return 0;
-
- // Compute the point and the hit test rect in the coords of this layer by using the values
- // from the transformState, which store the point and quad in the coords of the last flattened
- // layer, and the accumulated transform which lets up map through preserve-3d layers.
- //
- // We can't just map hitTestLocation and hitTestRect because they may have been flattened (losing z)
- // by our container.
- FloatPoint localPoint = localTransformState->mappedPoint();
- FloatQuad localPointQuad = localTransformState->mappedQuad();
- localHitTestRect = localTransformState->boundsOfMappedArea();
- if (localHitTestLocation.isRectBasedTest())
- localHitTestLocation = HitTestLocation(localPoint, localPointQuad);
- else
- localHitTestLocation = HitTestLocation(localPoint);
-
- // Now do a hit test with the root layer shifted to be us.
- rootLayer = this;
- }
-
- // Ensure our lists and 3d status are up-to-date.
- m_stackingNode->updateLayerListsIfNeeded();
- update3DTransformedDescendantStatus();
-
- // Check for hit test on backface if backface-visibility is 'hidden'
- if (localTransformState && renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden) {
- TransformationMatrix invertedMatrix = localTransformState->m_accumulatedTransform.inverse();
- // If the z-vector of the matrix is negative, the back is facing towards the viewer.
- if (invertedMatrix.m33() < 0)
- return 0;
- }
-
- RefPtr<HitTestingTransformState> unflattenedTransformState = localTransformState;
- if (localTransformState && !preserves3D()) {
- // Keep a copy of the pre-flattening state, for computing z-offsets for the container
- unflattenedTransformState = HitTestingTransformState::create(*localTransformState);
- // This layer is flattening, so flatten the state passed to descendants.
- localTransformState->flatten();
- }
-
- // The following are used for keeping track of the z-depth of the hit point of 3d-transformed
- // descendants.
- double localZOffset = -std::numeric_limits<double>::infinity();
- double* zOffsetForDescendantsPtr = 0;
- double* zOffsetForContentsPtr = 0;
-
- bool depthSortDescendants = false;
- if (preserves3D()) {
- depthSortDescendants = true;
- // Our layers can depth-test with our container, so share the z depth pointer with the container, if it passed one down.
- zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
- zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
- } else if (zOffset) {
- zOffsetForDescendantsPtr = 0;
- // Container needs us to give back a z offset for the hit layer.
- zOffsetForContentsPtr = zOffset;
- }
-
- // Begin by walking our list of positive layers from highest z-index down to the lowest z-index.
- bool hitLayer = hitTestChildren(PositiveZOrderChildren, rootLayer, request, result, localHitTestRect, localHitTestLocation,
- localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
- if (hitLayer && !depthSortDescendants)
- return true;
-
- // Now check our overflow objects.
- hitLayer = hitTestChildren(NormalFlowChildren, rootLayer, request, result, localHitTestRect, localHitTestLocation,
- localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
- if (hitLayer && !depthSortDescendants)
- return true;
-
- LayoutRect layerBounds;
- // FIXME(sky): Remove foregroundRect. It's unused.
- ClipRect contentRect, foregroundRect;
- ClipRectsContext clipRectsContext(rootLayer, RootRelativeClipRects);
- clipper().calculateRects(clipRectsContext, localHitTestRect, layerBounds, contentRect, foregroundRect);
-
- // Next we want to see if the mouse pos is inside the child RenderObjects of the layer.
- if (isSelfPaintingLayer() && contentRect.intersects(localHitTestLocation)) {
- // Hit test with a temporary HitTestResult, because we only want to commit to 'result' if we know we're frontmost.
- HitTestResult tempResult(result.hitTestLocation());
- if (hitTestContents(request, tempResult, layerBounds, localHitTestLocation)
- && isHitCandidate(false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
- if (result.isRectBasedTest())
- result.append(tempResult);
- else
- result = tempResult;
- if (!depthSortDescendants)
- return true;
- // Foreground can depth-sort with descendant layers, so keep this as a candidate.
- hitLayer = true;
- } else if (result.isRectBasedTest()) {
- result.append(tempResult);
- }
- }
-
- return hitLayer;
-}
-
-bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult& result, const LayoutRect& layerBounds, const HitTestLocation& hitTestLocation) const
-{
- ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant());
-
- if (!renderer()->hitTest(request, result, hitTestLocation, toLayoutPoint(layerBounds.location() - renderBoxLocation()))) {
- // It's wrong to set innerNode, but then claim that you didn't hit anything, unless it is
- // a rect-based test.
- ASSERT(!result.innerNode() || (result.isRectBasedTest() && result.rectBasedTestResult().size()));
- return false;
- }
-
- // For positioned generated content, we might still not have a
- // node by the time we get to the layer level, since none of
- // the content in the layer has an element. So just walk up
- // the tree.
- if (!result.innerNode() || !result.innerNonSharedNode()) {
- Node* e = enclosingElement();
- if (!result.innerNode())
- result.setInnerNode(e);
- if (!result.innerNonSharedNode())
- result.setInnerNonSharedNode(e);
- }
-
- return true;
-}
-
-bool RenderLayer::hitTestChildren(ChildrenIteration childrentoVisit, RenderLayer* rootLayer,
- const HitTestRequest& request, HitTestResult& result,
- const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation,
- const HitTestingTransformState* transformState,
- double* zOffsetForDescendants, double* zOffset,
- const HitTestingTransformState* unflattenedTransformState,
- bool depthSortDescendants)
-{
- if (!hasSelfPaintingLayerDescendant())
- return 0;
-
- bool hitLayer = false;
- RenderLayerStackingNodeReverseIterator iterator(*m_stackingNode, childrentoVisit);
- while (RenderLayerStackingNode* child = iterator.next()) {
- RenderLayer* childLayer = child->layer();
- HitTestResult tempResult(result.hitTestLocation());
- hitLayer |= childLayer->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestLocation, transformState, zOffsetForDescendants);
-
- // If it a rect-based test, we can safely append the temporary result since it might had hit
- // nodes but not necesserily had hitLayer set.
- if (result.isRectBasedTest())
- result.append(tempResult);
-
- if (hitLayer && isHitCandidate(depthSortDescendants, zOffset, unflattenedTransformState)) {
- if (!result.isRectBasedTest())
- result = tempResult;
- if (!depthSortDescendants)
- break;
- }
- }
-
- return hitLayer;
-}
-
bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const LayoutRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromRoot) const
{
// Always examine the canvas and the root.
« no previous file with comments | « sky/engine/core/rendering/RenderLayer.h ('k') | sky/engine/core/rendering/RenderLayerModelObject.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698