⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 278343 in webkit


Ignore:
Timestamp:
Jun 2, 2021, 1:28:32 AM (5 years ago)
Author:
graouts@webkit.org
Message:

Hit-testing does not account for clip-path on <iframe>
https://bugs.webkit.org/show_bug.cgi?id=226380
<rdar://problem/78621486>

Reviewed by Antti Koivisto.

Source/WebCore:

The logic to account for the clip-path property during hit-testing was only found in RenderBlock::nodeAtPoint()
although other types of RenderBox objects may need this, such as RenderIFrame. So we move some of the logic
from RenderBlock::nodeAtPoint() to dedicated methods on RenderBox such that RenderBox::nodeAtPoint() may call them
but also allow for RenderBlock::nodeAtPoint() to call them.

Test: css3/masking/clip-path-hit-test-iframe.html

css3/masking/clip-path-hit-test-img.html

  • rendering/RenderBlock.cpp:

(WebCore::RenderBlock::nodeAtPoint):

  • rendering/RenderBox.cpp:

(WebCore::RenderBox::hitTestVisualOverflow const):
(WebCore::RenderBox::hitTestClipPath const):
(WebCore::RenderBox::hitTestBorderRadius const):
(WebCore::RenderBox::nodeAtPoint):

  • rendering/RenderBox.h:

LayoutTests:

Add a new test which checks that we hit-test correctly in part of an
<iframe> or <img> clipped by the clip-path property.

  • css3/masking/clip-path-hit-test-iframe-expected.txt: Added.
  • css3/masking/clip-path-hit-test-iframe.html: Added.
  • css3/masking/clip-path-hit-test-img-expected.txt: Added.
  • css3/masking/clip-path-hit-test-img.html: Added.
Location:
trunk
Files:
4 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r278337 r278343  
     12021-05-28  Antoine Quint  <graouts@webkit.org>
     2
     3        Hit-testing does not account for clip-path on <iframe>
     4        https://bugs.webkit.org/show_bug.cgi?id=226380
     5        <rdar://problem/78621486>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        Add a new test which checks that we hit-test correctly in part of an
     10        <iframe> or <img> clipped by the clip-path property.
     11
     12        * css3/masking/clip-path-hit-test-iframe-expected.txt: Added.
     13        * css3/masking/clip-path-hit-test-iframe.html: Added.
     14        * css3/masking/clip-path-hit-test-img-expected.txt: Added.
     15        * css3/masking/clip-path-hit-test-img.html: Added.
     16
    1172021-06-01  Lauro Moura  <lmoura@igalia.com>
    218
  • trunk/Source/WebCore/ChangeLog

    r278341 r278343  
     12021-05-28  Antoine Quint  <graouts@webkit.org>
     2
     3        Hit-testing does not account for clip-path on <iframe>
     4        https://bugs.webkit.org/show_bug.cgi?id=226380
     5        <rdar://problem/78621486>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        The logic to account for the clip-path property during hit-testing was only found in RenderBlock::nodeAtPoint()
     10        although other types of RenderBox objects may need this, such as RenderIFrame. So we move some of the logic
     11        from RenderBlock::nodeAtPoint() to dedicated methods on RenderBox such that RenderBox::nodeAtPoint() may call them
     12        but also allow for RenderBlock::nodeAtPoint() to call them.
     13
     14        Test: css3/masking/clip-path-hit-test-iframe.html
     15              css3/masking/clip-path-hit-test-img.html
     16
     17        * rendering/RenderBlock.cpp:
     18        (WebCore::RenderBlock::nodeAtPoint):
     19        * rendering/RenderBox.cpp:
     20        (WebCore::RenderBox::hitTestVisualOverflow const):
     21        (WebCore::RenderBox::hitTestClipPath const):
     22        (WebCore::RenderBox::hitTestBorderRadius const):
     23        (WebCore::RenderBox::nodeAtPoint):
     24        * rendering/RenderBox.h:
     25
    1262021-06-02  Youenn Fablet  <youenn@apple.com>
    227
  • trunk/Source/WebCore/rendering/RenderBlock.cpp

    r278340 r278343  
    6464#include "RenderListMarker.h"
    6565#include "RenderMenuList.h"
    66 #include "RenderSVGResourceClipper.h"
    6766#include "RenderSVGRoot.h"
    6867#include "RenderTableCell.h"
     
    20632062    const LayoutSize localOffset = toLayoutSize(adjustedLocation);
    20642063
    2065     if (!isRenderView()) {
    2066         // Check if we need to do anything at all.
    2067         LayoutRect overflowBox = visualOverflowRect();
    2068         flipForWritingMode(overflowBox);
    2069         overflowBox.moveBy(adjustedLocation);
    2070         if (!locationInContainer.intersects(overflowBox))
    2071             return false;
    2072     }
     2064    // Check if we need to do anything at all.
     2065    if (!hitTestVisualOverflow(locationInContainer, accumulatedOffset))
     2066        return false;
    20732067
    20742068    if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && isPointInOverflowControl(result, locationInContainer.point(), adjustedLocation)) {
     
    20792073    }
    20802074
    2081     if (style().clipPath()) {
    2082         switch (style().clipPath()->type()) {
    2083         case ClipPathOperation::Shape: {
    2084             auto& clipPath = downcast<ShapeClipPathOperation>(*style().clipPath());
    2085             auto referenceBoxRect = referenceBox(clipPath.referenceBox());
    2086             if (!clipPath.pathForReferenceRect(referenceBoxRect).contains(locationInContainer.point() - localOffset, clipPath.windRule()))
    2087                 return false;
    2088             break;
    2089         }
    2090         case ClipPathOperation::Reference: {
    2091             const auto& referenceClipPathOperation = downcast<ReferenceClipPathOperation>(*style().clipPath());
    2092             auto* element = document().getElementById(referenceClipPathOperation.fragment());
    2093             if (!element || !element->renderer())
    2094                 break;
    2095             if (!is<SVGClipPathElement>(*element))
    2096                 break;
    2097             auto& clipper = downcast<RenderSVGResourceClipper>(*element->renderer());
    2098             if (!clipper.hitTestClipContent(FloatRect(borderBoxRect()), FloatPoint(locationInContainer.point() - localOffset)))
    2099                 return false;
    2100             break;
    2101         }
    2102         case ClipPathOperation::Box:
    2103             break;
    2104         }
    2105     }
     2075    if (!hitTestClipPath(locationInContainer, accumulatedOffset))
     2076        return false;
    21062077
    21072078    // If we have clipping, then we can't have any spillout.
     
    21142085        return true;
    21152086
    2116     // Check if the point is outside radii.
    2117     if (!isRenderView() && style().hasBorderRadius()) {
    2118         LayoutRect borderRect = borderBoxRect();
    2119         borderRect.moveBy(adjustedLocation);
    2120         RoundedRect border = style().getRoundedBorderFor(borderRect);
    2121         if (!locationInContainer.intersects(border))
    2122             return false;
    2123     }
     2087    if (!hitTestBorderRadius(locationInContainer, accumulatedOffset))
     2088        return false;
    21242089
    21252090    // Now hit test our background
  • trunk/Source/WebCore/rendering/RenderBox.cpp

    r278253 r278343  
    2727
    2828#include "CSSFontSelector.h"
     29#include "ClipPathOperation.h"
    2930#include "ControlStates.h"
    3031#include "Document.h"
     
    6768#include "RenderLayoutState.h"
    6869#include "RenderMultiColumnFlow.h"
     70#include "RenderSVGResourceClipper.h"
    6971#include "RenderTableCell.h"
    7072#include "RenderTheme.h"
    7173#include "RenderView.h"
    7274#include "RuntimeApplicationChecks.h"
     75#include "SVGClipPathElement.h"
    7376#include "ScrollAnimator.h"
    7477#include "ScrollbarTheme.h"
     
    13401343
    13411344// Hit Testing
     1345bool RenderBox::hitTestVisualOverflow(const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const
     1346{
     1347    if (isRenderView())
     1348        return true;
     1349
     1350    LayoutPoint adjustedLocation = accumulatedOffset + location();
     1351    LayoutRect overflowBox = visualOverflowRect();
     1352    flipForWritingMode(overflowBox);
     1353    overflowBox.moveBy(adjustedLocation);
     1354    return locationInContainer.intersects(overflowBox);
     1355}
     1356
     1357bool RenderBox::hitTestClipPath(const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const
     1358{
     1359    if (!style().clipPath())
     1360        return true;
     1361
     1362    LayoutPoint adjustedLocation = accumulatedOffset + location();
     1363    const LayoutSize localOffset = toLayoutSize(adjustedLocation);
     1364
     1365    switch (style().clipPath()->type()) {
     1366    case ClipPathOperation::Shape: {
     1367        auto& clipPath = downcast<ShapeClipPathOperation>(*style().clipPath());
     1368        auto referenceBoxRect = referenceBox(clipPath.referenceBox());
     1369        if (!clipPath.pathForReferenceRect(referenceBoxRect).contains(locationInContainer.point() - localOffset, clipPath.windRule()))
     1370            return false;
     1371        break;
     1372    }
     1373    case ClipPathOperation::Reference: {
     1374        const auto& referenceClipPathOperation = downcast<ReferenceClipPathOperation>(*style().clipPath());
     1375        auto* element = document().getElementById(referenceClipPathOperation.fragment());
     1376        if (!element || !element->renderer())
     1377            break;
     1378        if (!is<SVGClipPathElement>(*element))
     1379            break;
     1380        auto& clipper = downcast<RenderSVGResourceClipper>(*element->renderer());
     1381        if (!clipper.hitTestClipContent(FloatRect(borderBoxRect()), FloatPoint(locationInContainer.point() - localOffset)))
     1382            return false;
     1383        break;
     1384    }
     1385    case ClipPathOperation::Box:
     1386        break;
     1387    }
     1388
     1389    return true;
     1390}
     1391
     1392bool RenderBox::hitTestBorderRadius(const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const
     1393{
     1394    if (isRenderView() || !style().hasBorderRadius())
     1395        return true;
     1396
     1397    LayoutPoint adjustedLocation = accumulatedOffset + location();
     1398    LayoutRect borderRect = borderBoxRect();
     1399    borderRect.moveBy(adjustedLocation);
     1400    RoundedRect border = style().getRoundedBorderFor(borderRect);
     1401    return locationInContainer.intersects(border);
     1402}
     1403
    13421404bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
    13431405{
     
    13571419    boundsRect.moveBy(adjustedLocation);
    13581420    if (visibleToHitTesting(request) && action == HitTestForeground && locationInContainer.intersects(boundsRect)) {
     1421        if (!hitTestVisualOverflow(locationInContainer, accumulatedOffset))
     1422            return false;
     1423
     1424        if (!hitTestClipPath(locationInContainer, accumulatedOffset))
     1425            return false;
     1426
     1427        if (!hitTestBorderRadius(locationInContainer, accumulatedOffset))
     1428            return false;
     1429
    13591430        updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
    13601431        if (result.addNodeToListBasedTestResult(nodeForHitTest(), request, locationInContainer, boundsRect) == HitTestProgress::Stop)
     
    13621433    }
    13631434
    1364     return false;
     1435    return RenderBoxModelObject::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action);
    13651436}
    13661437
  • trunk/Source/WebCore/rendering/RenderBox.h

    r278253 r278343  
    307307    void layout() override;
    308308    bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override;
     309    bool hitTestVisualOverflow(const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const;
     310    bool hitTestClipPath(const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const;
     311    bool hitTestBorderRadius(const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const;
    309312
    310313    LayoutUnit minPreferredLogicalWidth() const override;
Note: See TracChangeset for help on using the changeset viewer.