Source/core/rendering/RenderLayer.cpp
// 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.
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.
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 .
RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
                                       const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, bool appliedTransform,
                                       const HitTestingTransformState* transformState, double* zOffset)
{
    if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant())
        return 0;
    if (transform() && !appliedTransform) {
        if (enclosingPaginationLayer())
            return hitTestTransformedLayerInFragments(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset);
        if (parent()) {
            ClipRectsContext clipRectsContext(rootLayer, RootRelativeClipRects, IncludeOverlayScrollbarSize);
            ClipRect clipRect = clipper().backgroundClipRect(clipRectsContext);
            if (!clipRect.intersects(hitTestLocation))
                return 0;
        }
        return hitTestLayerByApplyingTransform(rootLayer, containerLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset);
    }
    m_stackingNode->updateLayerListsIfNeeded();
    update3DTransformedDescendantStatus();
    RefPtr<HitTestingTransformState> localTransformState;
    if (appliedTransform) {
        ASSERT(transformState);
        localTransformState = const_cast<HitTestingTransformState*>(transformState);
    } else if (transformState || m_has3DTransformedDescendant || preserves3D()) {
        localTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState);
    }
    if (localTransformState && renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden) {
        TransformationMatrix invertedMatrix = localTransformState->m_accumulatedTransform.inverse();
        if (invertedMatrix.m33() < 0)
            return 0;
    }
    RefPtr<HitTestingTransformState> unflattenedTransformState = localTransformState;
    if (localTransformState && !preserves3D()) {
        unflattenedTransformState = HitTestingTransformState::create(*localTransformState);
        localTransformState->flatten();
    }
    double localZOffset = -numeric_limits<double>::infinity();
    double* zOffsetForDescendantsPtr = 0;
    double* zOffsetForContentsPtr = 0;
    bool depthSortDescendants = false;
    if (preserves3D()) {
        depthSortDescendants = true;
        zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
        zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
    } else if (m_has3DTransformedDescendant) {
        depthSortDescendants = true;
        zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
        zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
    } else if (zOffset) {
        zOffsetForDescendantsPtr = 0;
        zOffsetForContentsPtr = zOffset;
    }
    RenderLayer* candidateLayer = 0;
    RenderLayer* hitLayer = hitTestChildren(PositiveZOrderChildren, rootLayer, request, result, hitTestRect, hitTestLocation,
                                        localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
    if (hitLayer) {
        if (!depthSortDescendants)
            return hitLayer;
        candidateLayer = hitLayer;
    }
    hitLayer = hitTestChildren(NormalFlowChildren, rootLayer, request, result, hitTestRect, hitTestLocation,
                           localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
    if (hitLayer) {
        if (!depthSortDescendants)
            return hitLayer;
        candidateLayer = hitLayer;
    }
    LayerFragments layerFragments;
    collectFragments(layerFragments, rootLayer, hitTestRect, RootRelativeClipRects, IncludeOverlayScrollbarSize);
    if (m_scrollableArea && m_scrollableArea->hitTestResizerInFragments(layerFragments, hitTestLocation)) {
        renderer()->updateHitTestResult(result, hitTestLocation.point());
        return this;
    }
    if (isSelfPaintingLayer()) {
        HitTestResult tempResult(result.hitTestLocation());
        bool insideFragmentForegroundRect = false;
        if (hitTestContentsForFragments(layerFragments, request, tempResult, hitTestLocation, HitTestDescendants, insideFragmentForegroundRect)
            && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
            if (result.isRectBasedTest())
                result.append(tempResult);
            else
                result = tempResult;
            if (!depthSortDescendants)
                return this;
            candidateLayer = this;
        } else if (insideFragmentForegroundRect && result.isRectBasedTest())
            result.append(tempResult);
    }
    hitLayer = hitTestChildren(NegativeZOrderChildren, rootLayer, request, result, hitTestRect, hitTestLocation,
        localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
    if (hitLayer) {
        if (!depthSortDescendants)
            return hitLayer;
        candidateLayer = hitLayer;
    }
    if (candidateLayer)
        return candidateLayer;
    if (isSelfPaintingLayer()) {
        HitTestResult tempResult(result.hitTestLocation());
        bool insideFragmentBackgroundRect = false;
        if (hitTestContentsForFragments(layerFragments, request, tempResult, hitTestLocation, HitTestSelf, insideFragmentBackgroundRect)
            && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
            if (result.isRectBasedTest())
                result.append(tempResult);
            else
                result = tempResult;
            return this;
        }
        if (insideFragmentBackgroundRect && result.isRectBasedTest())
            result.append(tempResult);
    }
    return 0;
}
RenderLayer * RenderLayer :: hitTestLayer ( RenderLayer * rootLayer , RenderLayer * containerLayer , const HitTestRequest & request , HitTestResult & result , const LayoutRect & hitTestRect , const HitTestLocation & hitTestLocation , bool appliedTransform , const HitTestingTransformState * transformState , double * zOffset ) { if ( ! isSelfPaintingLayer ( ) && ! hasSelfPaintingLayerDescendant ( ) ) return 0 ; if ( transform ( ) && ! appliedTransform ) { if ( enclosingPaginationLayer ( ) ) return hitTestTransformedLayerInFragments ( rootLayer , containerLayer , request , result , hitTestRect , hitTestLocation , transformState , zOffset ) ; if ( parent ( ) ) { ClipRectsContext clipRectsContext ( rootLayer , RootRelativeClipRects , IncludeOverlayScrollbarSize ) ; ClipRect clipRect = clipper ( ) . backgroundClipRect ( clipRectsContext ) ; if ( ! clipRect . intersects ( hitTestLocation ) ) return 0 ; } return hitTestLayerByApplyingTransform ( rootLayer , containerLayer , request , result , hitTestRect , hitTestLocation , transformState , zOffset ) ; } m_stackingNode -> updateLayerListsIfNeeded ( ) ; update3DTransformedDescendantStatus ( ) ; RefPtr < HitTestingTransformState > localTransformState ; if ( appliedTransform ) { ASSERT ( transformState ) ; localTransformState = const_cast < HitTestingTransformState * > ( transformState ) ; } else if ( transformState || m_has3DTransformedDescendant || preserves3D ( ) ) { localTransformState = createLocalTransformState ( rootLayer , containerLayer , hitTestRect , hitTestLocation , transformState ) ; } if ( localTransformState && renderer ( ) -> style ( ) -> backfaceVisibility ( ) == BackfaceVisibilityHidden ) { TransformationMatrix invertedMatrix = localTransformState -> m_accumulatedTransform . inverse ( ) ; if ( invertedMatrix . m33 ( ) < 0 ) return 0 ; } RefPtr < HitTestingTransformState > unflattenedTransformState = localTransformState ; if ( localTransformState && ! preserves3D ( ) ) { unflattenedTransformState = HitTestingTransformState :: create ( * localTransformState ) ; localTransformState -> flatten ( ) ; } double localZOffset = - numeric_limits < double > :: infinity ( ) ; double * zOffsetForDescendantsPtr = 0 ; double * zOffsetForContentsPtr = 0 ; bool depthSortDescendants = false ; if ( preserves3D ( ) ) { depthSortDescendants = true ; zOffsetForDescendantsPtr = zOffset ? zOffset : & localZOffset ; zOffsetForContentsPtr = zOffset ? zOffset : & localZOffset ; } else if ( m_has3DTransformedDescendant ) { depthSortDescendants = true ; zOffsetForDescendantsPtr = zOffset ? zOffset : & localZOffset ; zOffsetForContentsPtr = zOffset ? zOffset : & localZOffset ; } else if ( zOffset ) { zOffsetForDescendantsPtr = 0 ; zOffsetForContentsPtr = zOffset ; } RenderLayer * candidateLayer = 0 ; RenderLayer * hitLayer = hitTestChildren ( PositiveZOrderChildren , rootLayer , request , result , hitTestRect , hitTestLocation , localTransformState . get ( ) , zOffsetForDescendantsPtr , zOffset , unflattenedTransformState . get ( ) , depthSortDescendants ) ; if ( hitLayer ) { if ( ! depthSortDescendants ) return hitLayer ; candidateLayer = hitLayer ; } hitLayer = hitTestChildren ( NormalFlowChildren , rootLayer , request , result , hitTestRect , hitTestLocation , localTransformState . get ( ) , zOffsetForDescendantsPtr , zOffset , unflattenedTransformState . get ( ) , depthSortDescendants ) ; if ( hitLayer ) { if ( ! depthSortDescendants ) return hitLayer ; candidateLayer = hitLayer ; } LayerFragments layerFragments ; collectFragments ( layerFragments , rootLayer , hitTestRect , RootRelativeClipRects , IncludeOverlayScrollbarSize ) ; if ( m_scrollableArea && m_scrollableArea -> hitTestResizerInFragments ( layerFragments , hitTestLocation ) ) { renderer ( ) -> updateHitTestResult ( result , hitTestLocation . point ( ) ) ; return this ; } if ( isSelfPaintingLayer ( ) ) { HitTestResult tempResult ( result . hitTestLocation ( ) ) ; bool insideFragmentForegroundRect = false ; if ( hitTestContentsForFragments ( layerFragments , request , tempResult , hitTestLocation , HitTestDescendants , insideFragmentForegroundRect ) && isHitCandidate ( this , false , zOffsetForContentsPtr , unflattenedTransformState . get ( ) ) ) { if ( result . isRectBasedTest ( ) ) result . append ( tempResult ) ; else result = tempResult ; if ( ! depthSortDescendants ) return this ; candidateLayer = this ; } else if ( insideFragmentForegroundRect && result . isRectBasedTest ( ) ) result . append ( tempResult ) ; } hitLayer = hitTestChildren ( NegativeZOrderChildren , rootLayer , request , result , hitTestRect , hitTestLocation , localTransformState . get ( ) , zOffsetForDescendantsPtr , zOffset , unflattenedTransformState . get ( ) , depthSortDescendants ) ; if ( hitLayer ) { if ( ! depthSortDescendants ) return hitLayer ; candidateLayer = hitLayer ; } if ( candidateLayer ) return candidateLayer ; if ( isSelfPaintingLayer ( ) ) { HitTestResult tempResult ( result . hitTestLocation ( ) ) ; bool insideFragmentBackgroundRect = false ; if ( hitTestContentsForFragments ( layerFragments , request , tempResult , hitTestLocation , HitTestSelf , insideFragmentBackgroundRect ) && isHitCandidate ( this , false , zOffsetForContentsPtr , unflattenedTransformState . get ( ) ) ) { if ( result . isRectBasedTest ( ) ) result . append ( tempResult ) ; else result = tempResult ; return this ; } if ( insideFragmentBackgroundRect && result . isRectBasedTest ( ) ) result . append ( tempResult ) ; } return 0 ; }
hitTestLocation and hitTestRect are relative to rootLayer.
hitTestLocation and hitTestRect are relative to rootLayer .
// The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate. // Apply a transform if we have one. // Make sure the parent's clip rects have been calculated. // Go ahead and test the enclosing clip now. // Ensure our lists and 3d status are up-to-date. // We computed the correct state in the caller (above code), so just reference it. // We need transform state for the first time, or to offset the container state, so create it here. // Check for hit test on backface if backface-visibility is 'hidden' // If the z-vector of the matrix is negative, the back is facing towards the viewer. // Keep a copy of the pre-flattening state, for computing z-offsets for the container // This layer is flattening, so flatten the state passed to descendants. // The following are used for keeping track of the z-depth of the hit point of 3d-transformed // descendants. // Our layers can depth-test with our container, so share the z depth pointer with the container, if it passed one down. // Flattening layer with 3d children; use a local zOffset pointer to depth-test children and foreground. // Container needs us to give back a z offset for the hit layer. // This variable tracks which layer the mouse ends up being inside. // Begin by walking our list of positive layers from highest z-index down to the lowest z-index. // Now check our overflow objects. // Collect the fragments. This will compute the clip rectangles for each layer fragment. // Next we want to see if the mouse pos is inside the child RenderObjects of the layer. Check // every fragment in reverse order. // Hit test with a temporary HitTestResult, because we only want to commit to 'result' if we know we're frontmost. // Foreground can depth-sort with descendant layers, so keep this as a candidate. // Now check our negative z-index children. // If we found a layer, return. Child layers, and foreground always render in front of background.