Example #1
0
bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom)
{
    LayoutPoint adjustedLocation = accumulatedOffset + roundedLayoutPoint(topLeft());

    // Hit test the markup box.
    if (InlineBox* markupBox = this->markupBox()) {
        RenderStyle* style = renderer().style(isFirstLineStyle());
        LayoutUnit mtx = adjustedLocation.x() + m_logicalWidth - markupBox->x();
        LayoutUnit mty = adjustedLocation.y() + style->fontMetrics().ascent() - (markupBox->y() + markupBox->renderer().style(isFirstLineStyle())->fontMetrics().ascent());
        if (markupBox->nodeAtPoint(request, result, locationInContainer, LayoutPoint(mtx, mty), lineTop, lineBottom)) {
            renderer().updateHitTestResult(result, locationInContainer.point() - LayoutSize(mtx, mty));
            return true;
        }
    }

    FloatPoint boxOrigin = locationIncludingFlipping();
    boxOrigin.moveBy(accumulatedOffset);
    FloatRect boundsRect(boxOrigin, size());
    if (visibleToHitTestRequest(request) && boundsRect.intersects(HitTestLocation::rectForPoint(locationInContainer.point(), 0, 0, 0, 0))) {
        renderer().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
        if (!result.addNodeToRectBasedTestResult(renderer().node(), request, locationInContainer, boundsRect))
            return true;
    }

    return false;
}
Example #2
0
bool LayoutPart::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
{
    if (!widget() || !widget()->isFrameView() || !result.hitTestRequest().allowsChildFrameContent())
        return nodeAtPointOverWidget(result, locationInContainer, accumulatedOffset, action);

    FrameView* childFrameView = toFrameView(widget());
    LayoutView* childRoot = childFrameView->layoutView();

    if (visibleToHitTestRequest(result.hitTestRequest()) && childRoot) {
        LayoutPoint adjustedLocation = accumulatedOffset + location();
        LayoutPoint contentOffset = LayoutPoint(borderLeft() + paddingLeft(), borderTop() + paddingTop()) - LayoutSize(childFrameView->scrollOffset());
        HitTestLocation newHitTestLocation(locationInContainer, -adjustedLocation - contentOffset);
        HitTestRequest newHitTestRequest(result.hitTestRequest().type() | HitTestRequest::ChildFrameHitTest);
        HitTestResult childFrameResult(newHitTestRequest, newHitTestLocation);

        bool isInsideChildFrame = childRoot->hitTest(newHitTestRequest, newHitTestLocation, childFrameResult);

        if (result.hitTestRequest().listBased())
            result.append(childFrameResult);
        else if (isInsideChildFrame)
            result = childFrameResult;

        if (isInsideChildFrame)
            return true;
    }

    return nodeAtPointOverWidget(result, locationInContainer, accumulatedOffset, action);
}
bool LayoutPart::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
{
    if (!widget() || !widget()->isFrameView() || !result.hitTestRequest().allowsChildFrameContent())
        return nodeAtPointOverWidget(result, locationInContainer, accumulatedOffset, action);

    // A hit test can never hit an off-screen element; only off-screen iframes are throttled;
    // therefore, hit tests can skip descending into throttled iframes.
    if (toFrameView(widget())->shouldThrottleRendering())
        return nodeAtPointOverWidget(result, locationInContainer, accumulatedOffset, action);

    ASSERT(document().lifecycle().state() >= DocumentLifecycle::CompositingClean);

    if (action == HitTestForeground) {
        FrameView* childFrameView = toFrameView(widget());
        LayoutView* childRoot = childFrameView->layoutView();

        if (visibleToHitTestRequest(result.hitTestRequest()) && childRoot) {
            LayoutPoint adjustedLocation = accumulatedOffset + location();
            LayoutPoint contentOffset = LayoutPoint(borderLeft() + paddingLeft(), borderTop() + paddingTop()) - LayoutSize(childFrameView->scrollOffset());
            HitTestLocation newHitTestLocation(locationInContainer, -adjustedLocation - contentOffset);
            HitTestRequest newHitTestRequest(result.hitTestRequest().type() | HitTestRequest::ChildFrameHitTest);
            HitTestResult childFrameResult(newHitTestRequest, newHitTestLocation);

            // The frame's layout and style must be up-to-date if we reach here.
            bool isInsideChildFrame = childRoot->hitTestNoLifecycleUpdate(childFrameResult);

            if (result.hitTestRequest().listBased()) {
                result.append(childFrameResult);
            } else if (isInsideChildFrame) {
                // Force the result not to be cacheable because the parent
                // frame should not cache this result; as it won't be notified of
                // changes in the child.
                childFrameResult.setCacheable(false);
                result = childFrameResult;
            }

            // Don't trust |isInsideChildFrame|. For rect-based hit-test, returns
            // true only when the hit test rect is totally within the iframe,
            // i.e. nodeAtPointOverWidget() also returns true.
            // Use a temporary HitTestResult because we don't want to collect the
            // iframe element itself if the hit-test rect is totally within the iframe.
            if (isInsideChildFrame) {
                if (!locationInContainer.isRectBasedTest())
                    return true;
                HitTestResult pointOverWidgetResult = result;
                bool pointOverWidget = nodeAtPointOverWidget(pointOverWidgetResult, locationInContainer, accumulatedOffset, action);
                if (pointOverWidget)
                    return true;
                result = pointOverWidgetResult;
                return false;
            }
        }
    }

    return nodeAtPointOverWidget(result, locationInContainer, accumulatedOffset, action);
}
bool InlineTextBox::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
{
    if (isLineBreak() || m_truncation == cFullTruncation)
        return false;

    LayoutPoint boxOrigin = locationIncludingFlipping();
    boxOrigin.moveBy(accumulatedOffset);
    LayoutRect rect(boxOrigin, size());
    if (visibleToHitTestRequest(result.hitTestRequest()) && locationInContainer.intersects(rect)) {
        getLineLayoutItem().updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset)));
        if (result.addNodeToListBasedTestResult(getLineLayoutItem().node(), locationInContainer, rect) == StopHitTesting)
            return true;
    }
    return false;
}
Example #5
0
bool EllipsisBox::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom)
{
    // FIXME: the call to roundedLayoutPoint() below is temporary and should be removed once
    // the transition to LayoutUnit-based types is complete (crbug.com/321237)
    LayoutPoint adjustedLocation = accumulatedOffset + topLeft();

    LayoutPoint boxOrigin = locationIncludingFlipping();
    boxOrigin.moveBy(accumulatedOffset);
    LayoutRect boundsRect(boxOrigin, size());
    if (visibleToHitTestRequest(result.hitTestRequest()) && boundsRect.intersects(LayoutRect(HitTestLocation::rectForPoint(locationInContainer.point(), 0, 0, 0, 0)))) {
        lineLayoutItem().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
        if (result.addNodeToListBasedTestResult(lineLayoutItem().node(), locationInContainer, boundsRect) == StopHitTesting)
            return true;
    }

    return false;
}
bool InlineTextBox::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
{
    if (isLineBreak())
        return false;

    LayoutPoint boxOrigin = locationIncludingFlipping();
    boxOrigin.moveBy(accumulatedOffset);
    LayoutRect rect(boxOrigin, size());
    // FIXME: both calls to rawValue() below is temporary and should be removed once the transition
    // to LayoutUnit-based types is complete (crbug.com/321237)
    if (m_truncation != cFullTruncation && visibleToHitTestRequest(result.hitTestRequest()) && locationInContainer.intersects(rect)) {
        lineLayoutItem().updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset)));
        if (!result.addNodeToListBasedTestResult(lineLayoutItem().node(), locationInContainer, rect))
            return true;
    }
    return false;
}
// Hit Testing
bool RenderRegion::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
{
    if (!isValid())
        return false;

    LayoutPoint adjustedLocation = accumulatedOffset + location();

    // Check our bounds next. For this purpose always assume that we can only be hit in the
    // foreground phase (which is true for replaced elements like images).
    // FIXME: Once we support overflow, we need to intersect with that and not with the bounds rect.
    LayoutRect boundsRect = borderBoxRectInRegion(locationInContainer.region());
    boundsRect.moveBy(adjustedLocation);
    if (visibleToHitTestRequest(request) && action == HitTestForeground && locationInContainer.intersects(boundsRect)) {
        // Check the contents of the RenderFlowThread.
        if (m_flowThread->hitTestFlowThreadPortionInRegion(this, flowThreadPortionRect(), flowThreadPortionOverflowRect(), request, result, locationInContainer, LayoutPoint(adjustedLocation.x() + borderLeft() + paddingLeft(), adjustedLocation.y() + borderTop() + paddingTop())))
            return true;
        updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
        if (!result.addNodeToRectBasedTestResult(generatingNode(), request, locationInContainer, boundsRect))
            return true;
    }

    return false;
}
Example #8
0
bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
{
    LayoutPoint pointInParent = locationInContainer.point() - toLayoutSize(accumulatedOffset);
    LayoutPoint pointInBorderBox = pointInParent - toLayoutSize(location());

    // Only test SVG content if the point is in our content box.
    // FIXME: This should be an intersection when rect-based hit tests are supported by nodeAtFloatPoint.
    if (contentBoxRect().contains(pointInBorderBox)) {
        FloatPoint localPoint = localToParentTransform().inverse().mapPoint(FloatPoint(pointInParent));

        for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
            // FIXME: nodeAtFloatPoint() doesn't handle rect-based hit tests yet.
            if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) {
                updateHitTestResult(result, pointInBorderBox);
                if (!result.addNodeToRectBasedTestResult(child->node(), request, locationInContainer))
                    return true;
            }
        }
    }

    // If we didn't early exit above, we've just hit the container <svg> element. Unlike SVG 1.1, 2nd Edition allows container elements to be hit.
    if (hitTestAction == HitTestBlockBackground && visibleToHitTestRequest(request)) {
        // Only return true here, if the last hit testing phase 'BlockBackground' is executed. If we'd return true in the 'Foreground' phase,
        // hit testing would stop immediately. For SVG only trees this doesn't matter. Though when we have a <foreignObject> subtree we need
        // to be able to detect hits on the background of a <div> element. If we'd return true here in the 'Foreground' phase, we are not able 
        // to detect these hits anymore.
        LayoutRect boundsRect(accumulatedOffset + location(), size());
        if (locationInContainer.intersects(boundsRect)) {
            updateHitTestResult(result, pointInBorderBox);
            if (!result.addNodeToRectBasedTestResult(node(), request, locationInContainer, boundsRect))
                return true;
        }
    }

    return false;
}
Example #9
0
bool LayoutSVGRoot::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
{
    LayoutPoint pointInParent = locationInContainer.point() - toLayoutSize(accumulatedOffset);
    LayoutPoint pointInBorderBox = pointInParent - toLayoutSize(location());

    // Only test SVG content if the point is in our content box, or in case we
    // don't clip to the viewport, the visual overflow rect.
    // FIXME: This should be an intersection when rect-based hit tests are supported by nodeAtFloatPoint.
    if (contentBoxRect().contains(pointInBorderBox) || (!shouldApplyViewportClip() && visualOverflowRect().contains(pointInBorderBox))) {
        const AffineTransform& localToParentTransform = this->localToParentTransform();
        if (localToParentTransform.isInvertible()) {
            FloatPoint localPoint = localToParentTransform.inverse().mapPoint(FloatPoint(pointInParent));

            for (LayoutObject* child = lastChild(); child; child = child->previousSibling()) {
                // FIXME: nodeAtFloatPoint() doesn't handle rect-based hit tests yet.
                if (child->nodeAtFloatPoint(result, localPoint, hitTestAction)) {
                    updateHitTestResult(result, pointInBorderBox);
                    if (result.addNodeToListBasedTestResult(child->node(), locationInContainer) == StopHitTesting)
                        return true;
                }
            }
        }
    }

    // If we didn't early exit above, we've just hit the container <svg> element. Unlike SVG 1.1, 2nd Edition allows container elements to be hit.
    if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && visibleToHitTestRequest(result.hitTestRequest())) {
        // Only return true here, if the last hit testing phase 'BlockBackground' (or 'ChildBlockBackground' - depending on context) is executed.
        // If we'd return true in the 'Foreground' phase, hit testing would stop immediately. For SVG only trees this doesn't matter.
        // Though when we have a <foreignObject> subtree we need to be able to detect hits on the background of a <div> element.
        // If we'd return true here in the 'Foreground' phase, we are not able to detect these hits anymore.
        LayoutRect boundsRect(accumulatedOffset + location(), size());
        if (locationInContainer.intersects(boundsRect)) {
            updateHitTestResult(result, pointInBorderBox);
            if (result.addNodeToListBasedTestResult(node(), locationInContainer, boundsRect) == StopHitTesting)
                return true;
        }
    }

    return false;
}