Title: [260445] trunk
Revision
260445
Author
simon.fra...@apple.com
Date
2020-04-21 11:17:10 -0700 (Tue, 21 Apr 2020)

Log Message

Horizontal overflow overlay scrollbar is misplaced in RTL
https://bugs.webkit.org/show_bug.cgi?id=210673
<rdar://problem/61950751>

Reviewed by Antti Koivisto.
Source/WebCore:

Code for positioning RenderLayer overflow controls (scrollbars and scroll corner)
was scattered across lots of different functions, making it hard to follow,
and prone to bugs.

Fix by making one source of truth, overflowControlsRects(), which computes
rects for the two scrollbars, the "scroll corner" (the square in the corner which
shows, only for non-overlay scrollbars, when both scrollbars or the resize control
is visible), and the resize control which shows when style specifies the "resize" property.

Call this function in all the places that need to know about overflow control
geometry. RenderLayer::hitTestResizerInFragments() is a little tricky because it wants
the resize control relative to the fragment rect; achieve this by computing the position
of the resizer rect relative to the border box, then shifting it into position relative
to the fragment bounds (which include border).

Test: compositing/overflow/rtl-scrollbar-layer-positioning.html

* page/EventHandler.cpp:
(WebCore::EventHandler::selectCursor):
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::scrollCornerRect const):
(WebCore::RenderLayer::overflowControlsRects const):
(WebCore::RenderLayer::scrollbarOffset const):
(WebCore::RenderLayer::invalidateScrollbarRect):
(WebCore::RenderLayer::positionOverflowControls):
(WebCore::RenderLayer::overflowControlsIntersectRect const):
(WebCore::RenderLayer::paintResizer):
(WebCore::RenderLayer::isPointInResizeControl const):
(WebCore::RenderLayer::hitTestOverflowControls):
(WebCore::RenderLayer::hitTestResizerInFragments const):
(WebCore::cornerStart): Deleted.
(WebCore::cornerRect): Deleted.
(WebCore::resizerCornerRect): Deleted.
(WebCore::RenderLayer::scrollCornerAndResizerRect const): Deleted.
(WebCore::RenderLayer::rectForHorizontalScrollbar const): Deleted.
(WebCore::RenderLayer::rectForVerticalScrollbar const): Deleted.
(WebCore::RenderLayer::verticalScrollbarStart const): Deleted.
(WebCore::RenderLayer::horizontalScrollbarStart const): Deleted.
* rendering/RenderLayer.h:
* rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::requiresScrollCornerLayer const):
(WebCore::RenderLayerBacking::positionOverflowControlsLayers):
(WebCore::RenderLayerBacking::paintContents):

LayoutTests:

* compositing/overflow/rtl-scrollbar-layer-positioning-expected.txt: Added.
* compositing/overflow/rtl-scrollbar-layer-positioning.html: Added.
* platform/ios-wk2/compositing/overflow/rtl-scrollbar-layer-positioning-expected.txt: Added.
* platform/mac-wk1/compositing/overflow/rtl-scrollbar-layer-positioning-expected.txt: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (260444 => 260445)


--- trunk/LayoutTests/ChangeLog	2020-04-21 18:13:36 UTC (rev 260444)
+++ trunk/LayoutTests/ChangeLog	2020-04-21 18:17:10 UTC (rev 260445)
@@ -1,3 +1,16 @@
+2020-04-20  Simon Fraser  <simon.fra...@apple.com>
+
+        Horizontal overflow overlay scrollbar is misplaced in RTL
+        https://bugs.webkit.org/show_bug.cgi?id=210673
+        <rdar://problem/61950751>
+
+        Reviewed by Antti Koivisto.
+
+        * compositing/overflow/rtl-scrollbar-layer-positioning-expected.txt: Added.
+        * compositing/overflow/rtl-scrollbar-layer-positioning.html: Added.
+        * platform/ios-wk2/compositing/overflow/rtl-scrollbar-layer-positioning-expected.txt: Added.
+        * platform/mac-wk1/compositing/overflow/rtl-scrollbar-layer-positioning-expected.txt: Added.
+
 2020-04-21  Sergio Villar Senin  <svil...@igalia.com>
 
         Unreviewed, reverting r260432.

Added: trunk/LayoutTests/compositing/overflow/rtl-scrollbar-layer-positioning-expected.txt (0 => 260445)


--- trunk/LayoutTests/compositing/overflow/rtl-scrollbar-layer-positioning-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/compositing/overflow/rtl-scrollbar-layer-positioning-expected.txt	2020-04-21 18:17:10 UTC (rev 260445)
@@ -0,0 +1,50 @@
+(GraphicsLayer
+  (anchor 0.00 0.00)
+  (bounds 800.00 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (contentsOpaque 1)
+      (children 1
+        (GraphicsLayer
+          (offsetFromRenderer width=-10 height=-10)
+          (position 18.00 10.00)
+          (bounds 362.00 362.00)
+          (drawsContent 1)
+          (children 2
+            (GraphicsLayer
+              (offsetFromRenderer width=13 height=13)
+              (position 23.00 23.00)
+              (bounds origin 292.00 0.00)
+              (bounds 316.00 316.00)
+              (children 1
+                (GraphicsLayer
+                  (offsetFromRenderer width=13 height=13)
+                  (scrollOffset (292,0))
+                  (anchor 0.00 0.00)
+                  (bounds 608.00 616.00)
+                )
+              )
+            )
+            (GraphicsLayer
+              (position 23.00 23.00)
+              (bounds 316.00 316.00)
+              (children 2
+                (GraphicsLayer
+                  (position 0.00 301.00)
+                  (bounds 316.00 15.00)
+                  (drawsContent 1)
+                )
+                (GraphicsLayer
+                  (bounds 15.00 316.00)
+                  (drawsContent 1)
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+)
+

Added: trunk/LayoutTests/compositing/overflow/rtl-scrollbar-layer-positioning.html (0 => 260445)


--- trunk/LayoutTests/compositing/overflow/rtl-scrollbar-layer-positioning.html	                        (rev 0)
+++ trunk/LayoutTests/compositing/overflow/rtl-scrollbar-layer-positioning.html	2020-04-21 18:17:10 UTC (rev 260445)
@@ -0,0 +1,41 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ internal:AsyncOverflowScrollingEnabled=true ] -->
+<html>
+<head>
+    <title>Layer tree dump RTL overflow with composited scrollbars</title>
+    <style>
+        #scroller {
+            overflow-y: scroll;
+            height: 300px;
+            width: 300px;
+            margin: 20px;
+            border: 13px solid black;
+            box-shadow: 0 0 7px black;
+            padding: 8px;
+        }
+
+        .content {
+            height: 200%;
+            width: 200%;
+        }
+    </style>
+    <script>
+        if (window.testRunner)
+            testRunner.dumpAsText();
+
+        if (window.internals)
+            internals.setUsesOverlayScrollbars(true)
+
+        window.addEventListener('load', () => {
+            if (window.internals)
+                document.getElementById('layers').innerText = window.internals.layerTreeAsText(document);
+        }, false);
+    </script>
+</head>
+<body>
+    <div id="scroller" dir="rtl">
+        <div class="content"></div>
+    </div>
+<pre id="layers"></pre>
+</body>
+</html>
+

Added: trunk/LayoutTests/platform/ios-wk2/compositing/overflow/rtl-scrollbar-layer-positioning-expected.txt (0 => 260445)


--- trunk/LayoutTests/platform/ios-wk2/compositing/overflow/rtl-scrollbar-layer-positioning-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/platform/ios-wk2/compositing/overflow/rtl-scrollbar-layer-positioning-expected.txt	2020-04-21 18:17:10 UTC (rev 260445)
@@ -0,0 +1,51 @@
+(GraphicsLayer
+  (anchor 0.00 0.00)
+  (bounds 800.00 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (contentsOpaque 1)
+      (children 1
+        (GraphicsLayer
+          (offsetFromRenderer width=-10 height=-10)
+          (position 18.00 10.00)
+          (bounds 362.00 362.00)
+          (drawsContent 1)
+          (children 2
+            (GraphicsLayer
+              (offsetFromRenderer width=13 height=13)
+              (position 23.00 23.00)
+              (bounds origin 292.00 0.00)
+              (bounds 316.00 316.00)
+              (children 1
+                (GraphicsLayer
+                  (offsetFromRenderer width=13 height=13)
+                  (scrollOffset (292,0))
+                  (anchor 0.00 0.00)
+                  (bounds 608.00 616.00)
+                )
+              )
+            )
+            (GraphicsLayer
+              (position 23.00 23.00)
+              (bounds 316.00 316.00)
+              (children 2
+                (GraphicsLayer
+                  (position 0.00 301.00)
+                  (bounds 316.00 15.00)
+                  (drawsContent 1)
+                )
+                (GraphicsLayer
+                  (position 301.00 0.00)
+                  (bounds 15.00 316.00)
+                  (drawsContent 1)
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+)
+

Added: trunk/LayoutTests/platform/mac-wk1/compositing/overflow/rtl-scrollbar-layer-positioning-expected.txt (0 => 260445)


--- trunk/LayoutTests/platform/mac-wk1/compositing/overflow/rtl-scrollbar-layer-positioning-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/platform/mac-wk1/compositing/overflow/rtl-scrollbar-layer-positioning-expected.txt	2020-04-21 18:17:10 UTC (rev 260445)
@@ -0,0 +1 @@
+

Modified: trunk/Source/WebCore/ChangeLog (260444 => 260445)


--- trunk/Source/WebCore/ChangeLog	2020-04-21 18:13:36 UTC (rev 260444)
+++ trunk/Source/WebCore/ChangeLog	2020-04-21 18:17:10 UTC (rev 260445)
@@ -1,3 +1,55 @@
+2020-04-20  Simon Fraser  <simon.fra...@apple.com>
+
+        Horizontal overflow overlay scrollbar is misplaced in RTL
+        https://bugs.webkit.org/show_bug.cgi?id=210673
+        <rdar://problem/61950751>
+
+        Reviewed by Antti Koivisto.
+        
+        Code for positioning RenderLayer overflow controls (scrollbars and scroll corner)
+        was scattered across lots of different functions, making it hard to follow,
+        and prone to bugs.
+
+        Fix by making one source of truth, overflowControlsRects(), which computes
+        rects for the two scrollbars, the "scroll corner" (the square in the corner which
+        shows, only for non-overlay scrollbars, when both scrollbars or the resize control
+        is visible), and the resize control which shows when style specifies the "resize" property.
+        
+        Call this function in all the places that need to know about overflow control
+        geometry. RenderLayer::hitTestResizerInFragments() is a little tricky because it wants
+        the resize control relative to the fragment rect; achieve this by computing the position
+        of the resizer rect relative to the border box, then shifting it into position relative
+        to the fragment bounds (which include border).
+
+        Test: compositing/overflow/rtl-scrollbar-layer-positioning.html
+
+        * page/EventHandler.cpp:
+        (WebCore::EventHandler::selectCursor):
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::scrollCornerRect const):
+        (WebCore::RenderLayer::overflowControlsRects const):
+        (WebCore::RenderLayer::scrollbarOffset const):
+        (WebCore::RenderLayer::invalidateScrollbarRect):
+        (WebCore::RenderLayer::positionOverflowControls):
+        (WebCore::RenderLayer::overflowControlsIntersectRect const):
+        (WebCore::RenderLayer::paintResizer):
+        (WebCore::RenderLayer::isPointInResizeControl const):
+        (WebCore::RenderLayer::hitTestOverflowControls):
+        (WebCore::RenderLayer::hitTestResizerInFragments const):
+        (WebCore::cornerStart): Deleted.
+        (WebCore::cornerRect): Deleted.
+        (WebCore::resizerCornerRect): Deleted.
+        (WebCore::RenderLayer::scrollCornerAndResizerRect const): Deleted.
+        (WebCore::RenderLayer::rectForHorizontalScrollbar const): Deleted.
+        (WebCore::RenderLayer::rectForVerticalScrollbar const): Deleted.
+        (WebCore::RenderLayer::verticalScrollbarStart const): Deleted.
+        (WebCore::RenderLayer::horizontalScrollbarStart const): Deleted.
+        * rendering/RenderLayer.h:
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::RenderLayerBacking::requiresScrollCornerLayer const):
+        (WebCore::RenderLayerBacking::positionOverflowControlsLayers):
+        (WebCore::RenderLayerBacking::paintContents):
+
 2020-04-21  Sergio Villar Senin  <svil...@igalia.com>
 
         Unreviewed, reverting r260432.

Modified: trunk/Source/WebCore/page/EventHandler.cpp (260444 => 260445)


--- trunk/Source/WebCore/page/EventHandler.cpp	2020-04-21 18:13:36 UTC (rev 260444)
+++ trunk/Source/WebCore/page/EventHandler.cpp	2020-04-21 18:17:10 UTC (rev 260445)
@@ -1545,7 +1545,7 @@
         if (renderer) {
             if (RenderLayer* layer = renderer->enclosingLayer()) {
                 if (FrameView* view = m_frame.view())
-                    inResizer = layer->isPointInResizeControl(view->windowToContents(roundedIntPoint(result.localPoint())));
+                    inResizer = layer->isPointInResizeControl(view->windowToContents(roundedIntPoint(result.localPoint()))); // This coordinate conversion is wrong: webkit.org/b/210778.
             }
         }
 

Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (260444 => 260445)


--- trunk/Source/WebCore/rendering/RenderLayer.cpp	2020-04-21 18:13:36 UTC (rev 260444)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp	2020-04-21 18:17:10 UTC (rev 260445)
@@ -3179,71 +3179,11 @@
     return page().focusController().isActive();
 }
 
-static int cornerStart(const RenderLayer& layer, int minX, int maxX, int thickness)
-{
-    if (layer.shouldPlaceBlockDirectionScrollbarOnLeft())
-        return minX + layer.renderer().style().borderLeftWidth();
-    return maxX - thickness - layer.renderer().style().borderRightWidth();
-}
-
-static LayoutRect cornerRect(const RenderLayer& layer, const LayoutRect& bounds)
-{
-    int horizontalThickness;
-    int verticalThickness;
-    if (!layer.verticalScrollbar() && !layer.horizontalScrollbar()) {
-        // FIXME: This isn't right.  We need to know the thickness of custom scrollbars
-        // even when they don't exist in order to set the resizer square size properly.
-        horizontalThickness = ScrollbarTheme::theme().scrollbarThickness();
-        verticalThickness = horizontalThickness;
-    } else if (layer.verticalScrollbar() && !layer.horizontalScrollbar()) {
-        horizontalThickness = layer.verticalScrollbar()->width();
-        verticalThickness = horizontalThickness;
-    } else if (layer.horizontalScrollbar() && !layer.verticalScrollbar()) {
-        verticalThickness = layer.horizontalScrollbar()->height();
-        horizontalThickness = verticalThickness;
-    } else {
-        horizontalThickness = layer.verticalScrollbar()->width();
-        verticalThickness = layer.horizontalScrollbar()->height();
-    }
-    return LayoutRect(cornerStart(layer, bounds.x(), bounds.maxX(), horizontalThickness),
-        bounds.maxY() - verticalThickness - layer.renderer().style().borderBottomWidth(),
-        horizontalThickness, verticalThickness);
-}
-
 IntRect RenderLayer::scrollCornerRect() const
 {
-    // We have a scrollbar corner when a non overlay scrollbar is visible and not filling the entire length of the box.
-    // This happens when:
-    // (a) A resizer is present and at least one non overlay scrollbar is present
-    // (b) Both non overlay scrollbars are present.
-    // Overlay scrollbars always fill the entire length of the box so we never have scroll corner in that case.
-    bool hasHorizontalBar = m_hBar && !m_hBar->isOverlayScrollbar();
-    bool hasVerticalBar = m_vBar && !m_vBar->isOverlayScrollbar();
-    bool hasResizer = renderer().style().resize() != Resize::None;
-    if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar)))
-        return snappedIntRect(cornerRect(*this, renderBox()->borderBoxRect()));
-    return IntRect();
+    return overflowControlsRects().scrollCorner;
 }
 
-static LayoutRect resizerCornerRect(const RenderLayer& layer, const LayoutRect& bounds)
-{
-    ASSERT(layer.renderer().isBox());
-    if (layer.renderer().style().resize() == Resize::None)
-        return LayoutRect();
-    return cornerRect(layer, bounds);
-}
-
-LayoutRect RenderLayer::scrollCornerAndResizerRect() const
-{
-    RenderBox* box = renderBox();
-    if (!box)
-        return LayoutRect();
-    LayoutRect scrollCornerAndResizer = scrollCornerRect();
-    if (scrollCornerAndResizer.isEmpty())
-        scrollCornerAndResizer = resizerCornerRect(*this, box->borderBoxRect());
-    return scrollCornerAndResizer;
-}
-
 bool RenderLayer::isScrollCornerVisible() const
 {
     ASSERT(renderer().isBox());
@@ -3350,63 +3290,98 @@
     return renderer().frame().eventHandler().isHandlingWheelEvent();
 }
 
-IntRect RenderLayer::rectForHorizontalScrollbar(const IntRect& borderBoxRect) const
+RenderLayer::OverflowControlRects RenderLayer::overflowControlsRects() const
 {
-    if (!m_hBar)
-        return IntRect();
+    ASSERT(is<RenderBox>(renderer()));
+    auto& renderBox = downcast<RenderBox>(renderer());
+    // Scrollbars sit inside the border box.
+    auto overflowControlsPositioningRect = snappedIntRect(renderBox.paddingBoxRectIncludingScrollbar());
 
-    const RenderBox* box = renderBox();
-    const IntRect& scrollCorner = scrollCornerRect();
+    auto horizontalScrollbarHeight = m_hBar ? m_hBar->height() : 0;
+    auto verticalScrollbarWidth = m_vBar ? m_vBar->width() : 0;
 
-    return IntRect(horizontalScrollbarStart(borderBoxRect.x()),
-        borderBoxRect.maxY() - box->borderBottom() - m_hBar->height(),
-        borderBoxRect.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(),
-        m_hBar->height());
-}
+    auto isNonOverlayScrollbar = [](const Scrollbar* scrollbar) {
+        return scrollbar && !scrollbar->isOverlayScrollbar();
+    };
 
-IntRect RenderLayer::rectForVerticalScrollbar(const IntRect& borderBoxRect) const
-{
-    if (!m_vBar)
-        return IntRect();
+    bool haveNonOverlayHorizontalScrollbar = isNonOverlayScrollbar(m_hBar.get());
+    bool haveNonOverlayVerticalScrollbar = isNonOverlayScrollbar(m_vBar.get());
+    bool placeVerticalScrollbarOnTheLeft = shouldPlaceBlockDirectionScrollbarOnLeft();
+    bool haveResizer = renderer().style().resize() != Resize::None;
+    bool scrollbarsAvoidCorner = (haveNonOverlayHorizontalScrollbar && haveNonOverlayVerticalScrollbar) || (haveResizer && (haveNonOverlayHorizontalScrollbar || haveNonOverlayVerticalScrollbar));
 
-    const RenderBox* box = renderBox();
-    const IntRect& scrollCorner = scrollCornerRect();
+    IntSize cornerSize;
+    if (scrollbarsAvoidCorner) {
+        // If only one scrollbar is present, the corner is square.
+        cornerSize = IntSize {
+            verticalScrollbarWidth ? verticalScrollbarWidth : horizontalScrollbarHeight,
+            horizontalScrollbarHeight ? horizontalScrollbarHeight : verticalScrollbarWidth
+        };
+    }
 
-    return IntRect(verticalScrollbarStart(borderBoxRect.x(), borderBoxRect.maxX()),
-        borderBoxRect.y() + box->borderTop(),
-        m_vBar->width(),
-        borderBoxRect.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height());
-}
+    OverflowControlRects result;
 
-LayoutUnit RenderLayer::verticalScrollbarStart(int minX, int maxX) const
-{
-    const RenderBox* box = renderBox();
-    if (shouldPlaceBlockDirectionScrollbarOnLeft())
-        return minX + box->borderLeft();
-    return maxX - box->borderRight() - m_vBar->width();
-}
+    if (m_hBar) {
+        auto barRect = overflowControlsPositioningRect;
+        barRect.shiftYEdgeTo(barRect.maxY() - horizontalScrollbarHeight);
+        if (scrollbarsAvoidCorner) {
+            if (placeVerticalScrollbarOnTheLeft)
+                barRect.shiftXEdgeTo(barRect.x() + cornerSize.width());
+            else
+                barRect.contract(cornerSize.width(), 0);
+        }
 
-LayoutUnit RenderLayer::horizontalScrollbarStart(int minX) const
-{
-    const RenderBox* box = renderBox();
-    int x = minX + box->borderLeft();
-    if (shouldPlaceBlockDirectionScrollbarOnLeft())
-        x += m_vBar ? m_vBar->width() : roundToInt(resizerCornerRect(*this, box->borderBoxRect()).width());
-    return x;
+        result.horizontalScrollbar = barRect;
+    }
+
+    if (m_vBar) {
+        auto barRect = overflowControlsPositioningRect;
+        if (placeVerticalScrollbarOnTheLeft)
+            barRect.setWidth(verticalScrollbarWidth);
+        else
+            barRect.shiftXEdgeTo(barRect.maxX() - verticalScrollbarWidth);
+
+        if (scrollbarsAvoidCorner)
+            barRect.contract(0, cornerSize.height());
+
+        result.verticalScrollbar = barRect;
+    }
+
+    auto cornerRect = [&](IntSize cornerSize) {
+        if (placeVerticalScrollbarOnTheLeft) {
+            auto bottomLeftCorner = overflowControlsPositioningRect.minXMaxYCorner();
+            return IntRect { { bottomLeftCorner.x(), bottomLeftCorner.y() - cornerSize.height(), }, cornerSize };
+        }
+        return IntRect { overflowControlsPositioningRect.maxXMaxYCorner() - cornerSize, cornerSize };
+    };
+
+    if (scrollbarsAvoidCorner)
+        result.scrollCorner = cornerRect(cornerSize);
+
+    if (haveResizer) {
+        if (scrollbarsAvoidCorner)
+            result.resizer = result.scrollCorner;
+        else {
+            auto scrollbarThickness = ScrollbarTheme::theme().scrollbarThickness();
+            result.resizer = cornerRect({ scrollbarThickness, scrollbarThickness });
+        }
+    }
+
+    return result;
 }
 
 IntSize RenderLayer::scrollbarOffset(const Scrollbar& scrollbar) const
 {
-    RenderBox* box = renderBox();
+    auto rects = overflowControlsRects();
 
     if (&scrollbar == m_vBar.get())
-        return IntSize(verticalScrollbarStart(0, box->width()), box->borderTop());
+        return toIntSize(rects.verticalScrollbar.location());
 
     if (&scrollbar == m_hBar.get())
-        return IntSize(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar.height());
+        return toIntSize(rects.horizontalScrollbar.location());
     
     ASSERT_NOT_REACHED();
-    return IntSize();
+    return { };
 }
 
 void RenderLayer::invalidateScrollbarRect(Scrollbar& scrollbar, const IntRect& rect)
@@ -3426,7 +3401,7 @@
         }
     }
 
-    IntRect scrollRect = rect;
+    auto scrollRect = rect;
     RenderBox* box = renderBox();
     ASSERT(box);
     // If we are not yet inserted into the tree, there is no need to repaint.
@@ -3433,10 +3408,13 @@
     if (!box->parent())
         return;
 
+    auto rects = overflowControlsRects();
+
     if (&scrollbar == m_vBar.get())
-        scrollRect.move(verticalScrollbarStart(0, box->width()), box->borderTop());
+        scrollRect.moveBy(rects.verticalScrollbar.location());
     else
-        scrollRect.move(horizontalScrollbarStart(0), box->height() - box->borderBottom() - scrollbar.height());
+        scrollRect.moveBy(rects.horizontalScrollbar.location());
+
     LayoutRect repaintRect = scrollRect;
     renderBox()->flipForWritingMode(repaintRect);
     renderer().repaintRectangle(repaintRect);
@@ -3706,30 +3684,27 @@
 {
     if (!m_hBar && !m_vBar && !canResize())
         return;
-    
-    RenderBox* box = renderBox();
-    if (!box)
+
+    if (!renderBox())
         return;
 
-    const IntRect borderBox = snappedIntRect(box->borderBoxRect());
-    const IntRect& scrollCorner = scrollCornerRect();
-    IntRect absBounds(borderBox.location() + offsetFromRoot, borderBox.size());
+    auto rects = overflowControlsRects();
+
     if (m_vBar) {
-        IntRect vBarRect = rectForVerticalScrollbar(borderBox);
-        vBarRect.move(offsetFromRoot);
-        m_vBar->setFrameRect(vBarRect);
+        rects.verticalScrollbar.move(offsetFromRoot);
+        m_vBar->setFrameRect(rects.verticalScrollbar);
     }
     
     if (m_hBar) {
-        IntRect hBarRect = rectForHorizontalScrollbar(borderBox);
-        hBarRect.move(offsetFromRoot);
-        m_hBar->setFrameRect(hBarRect);
+        rects.horizontalScrollbar.move(offsetFromRoot);
+        m_hBar->setFrameRect(rects.horizontalScrollbar);
     }
-    
+
     if (m_scrollCorner)
-        m_scrollCorner->setFrameRect(scrollCorner);
+        m_scrollCorner->setFrameRect(rects.scrollCorner);
+
     if (m_resizer)
-        m_resizer->setFrameRect(resizerCornerRect(*this, borderBox));
+        m_resizer->setFrameRect(rects.resizer);
 }
 
 int RenderLayer::scrollWidth() const
@@ -3961,18 +3936,18 @@
 
 bool RenderLayer::overflowControlsIntersectRect(const IntRect& localRect) const
 {
-    const IntRect borderBox = snappedIntRect(renderBox()->borderBoxRect());
+    auto rects = overflowControlsRects();
 
-    if (rectForHorizontalScrollbar(borderBox).intersects(localRect))
+    if (rects.horizontalScrollbar.intersects(localRect))
         return true;
 
-    if (rectForVerticalScrollbar(borderBox).intersects(localRect))
+    if (rects.verticalScrollbar.intersects(localRect))
         return true;
 
-    if (scrollCornerRect().intersects(localRect))
+    if (rects.scrollCorner.intersects(localRect))
         return true;
-    
-    if (resizerCornerRect(*this, borderBox).intersects(localRect))
+
+    if (rects.resizer.intersects(localRect))
         return true;
 
     return false;
@@ -4111,12 +4086,11 @@
     if (renderer().style().resize() == Resize::None)
         return;
 
-    RenderBox* box = renderBox();
-    ASSERT(box);
+    auto rects = overflowControlsRects();
 
-    LayoutRect absRect = resizerCornerRect(*this, box->borderBoxRect());
-    absRect.moveBy(paintOffset);
-    if (!absRect.intersects(damageRect))
+    LayoutRect resizerAbsRect = rects.resizer;
+    resizerAbsRect.moveBy(paintOffset);
+    if (!resizerAbsRect.intersects(damageRect))
         return;
 
     if (context.invalidatingControlTints()) {
@@ -4125,18 +4099,18 @@
     }
     
     if (m_resizer) {
-        m_resizer->paintIntoRect(context, paintOffset, absRect);
+        m_resizer->paintIntoRect(context, paintOffset, resizerAbsRect);
         return;
     }
 
-    drawPlatformResizerImage(context, absRect);
+    drawPlatformResizerImage(context, resizerAbsRect);
 
     // Draw a frame around the resizer (1px grey line) if there are any scrollbars present.
     // Clipping will exclude the right and bottom edges of this frame.
     if (!hasOverlayScrollbars() && (m_vBar || m_hBar)) {
         GraphicsContextStateSaver stateSaver(context);
-        context.clip(absRect);
-        LayoutRect largerCorner = absRect;
+        context.clip(resizerAbsRect);
+        LayoutRect largerCorner = resizerAbsRect;
         largerCorner.setSize(LayoutSize(largerCorner.width() + 1_lu, largerCorner.height() + 1_lu));
         context.setStrokeColor(Color(makeRGB(217, 217, 217)));
         context.setStrokeThickness(1.0f);
@@ -4149,14 +4123,11 @@
 {
     if (!canResize())
         return false;
-    
-    RenderBox* box = renderBox();
-    ASSERT(box);
 
+    auto rects = overflowControlsRects();
+
     IntPoint localPoint = roundedIntPoint(absoluteToContents(absolutePoint));
-
-    IntRect localBounds(IntPoint(), snappedIntRect(box->frameRect()).size());
-    return resizerCornerRect(*this, localBounds).contains(localPoint);
+    return rects.resizer.contains(localPoint);
 }
 
 bool RenderLayer::hitTestOverflowControls(HitTestResult& result, const IntPoint& localPoint)
@@ -4164,38 +4135,24 @@
     if (!m_hBar && !m_vBar && !canResize())
         return false;
 
-    RenderBox* box = renderBox();
-    ASSERT(box);
-    
+    auto rects = overflowControlsRects();
+
     IntRect resizeControlRect;
     if (renderer().style().resize() != Resize::None) {
-        resizeControlRect = snappedIntRect(resizerCornerRect(*this, box->borderBoxRect()));
-        if (resizeControlRect.contains(localPoint))
+        if (rects.resizer.contains(localPoint))
             return true;
     }
 
-    int resizeControlSize = std::max(resizeControlRect.height(), 0);
-
     // FIXME: We should hit test the m_scrollCorner and pass it back through the result.
-
     if (m_vBar && m_vBar->shouldParticipateInHitTesting()) {
-        LayoutRect vBarRect(verticalScrollbarStart(0, box->width()),
-                            box->borderTop(),
-                            m_vBar->width(),
-                            box->height() - (box->borderTop() + box->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize));
-        if (vBarRect.contains(localPoint)) {
+        if (rects.verticalScrollbar.contains(localPoint)) {
             result.setScrollbar(m_vBar.get());
             return true;
         }
     }
 
-    resizeControlSize = std::max(resizeControlRect.width(), 0);
     if (m_hBar && m_hBar->shouldParticipateInHitTesting()) {
-        LayoutRect hBarRect(horizontalScrollbarStart(0),
-                            box->height() - box->borderBottom() - m_hBar->height(),
-                            box->width() - (box->borderLeft() + box->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize),
-                            m_hBar->height());
-        if (hBarRect.contains(localPoint)) {
+        if (rects.horizontalScrollbar.contains(localPoint)) {
             result.setScrollbar(m_hBar.get());
             return true;
         }
@@ -5569,9 +5526,22 @@
     if (layerFragments.isEmpty())
         return false;
 
+    auto borderBoxRect = snappedIntRect(downcast<RenderBox>(renderer()).borderBoxRect());
+    auto rects = overflowControlsRects();
+
+    auto cornerRectInFragment = [&](const IntRect& fragmentBounds, const IntRect& resizerRect) {
+        if (shouldPlaceBlockDirectionScrollbarOnLeft()) {
+            IntSize offsetFromBottomLeft = borderBoxRect.minXMaxYCorner() - resizerRect.minXMaxYCorner();
+            return IntRect { fragmentBounds.minXMaxYCorner() - offsetFromBottomLeft - IntSize { 0, resizerRect.height() }, resizerRect.size() };
+        }
+        IntSize offsetFromBottomRight = borderBoxRect.maxXMaxYCorner() - resizerRect.maxXMaxYCorner();
+        return IntRect { fragmentBounds.maxXMaxYCorner() - offsetFromBottomRight - resizerRect.size(), resizerRect.size() };
+    };
+
     for (int i = layerFragments.size() - 1; i >= 0; --i) {
         const LayerFragment& fragment = layerFragments.at(i);
-        if (fragment.backgroundRect.intersects(hitTestLocation) && resizerCornerRect(*this, snappedIntRect(fragment.layerBounds)).contains(hitTestLocation.roundedPoint()))
+        auto resizerRectInFragment = cornerRectInFragment(snappedIntRect(fragment.layerBounds), rects.resizer);
+        if (fragment.backgroundRect.intersects(hitTestLocation) && resizerRectInFragment.contains(hitTestLocation.roundedPoint()))
             return true;
     }
     

Modified: trunk/Source/WebCore/rendering/RenderLayer.h (260444 => 260445)


--- trunk/Source/WebCore/rendering/RenderLayer.h	2020-04-21 18:13:36 UTC (rev 260444)
+++ trunk/Source/WebCore/rendering/RenderLayer.h	2020-04-21 18:17:10 UTC (rev 260445)
@@ -1142,9 +1142,6 @@
     void unregisterAsTouchEventListenerForScrolling();
 #endif
 
-    // Rectangle encompassing the scroll corner and resizer rect.
-    LayoutRect scrollCornerAndResizerRect() const;
-
     // NOTE: This should only be called by the overridden setScrollOffset from ScrollableArea.
     void scrollTo(const ScrollPosition&);
     void updateCompositingLayersAfterScroll();
@@ -1210,12 +1207,18 @@
     LayoutUnit overflowLeft() const;
     LayoutUnit overflowRight() const;
 
-    IntRect rectForHorizontalScrollbar(const IntRect& borderBoxRect) const;
-    IntRect rectForVerticalScrollbar(const IntRect& borderBoxRect) const;
+    struct OverflowControlRects {
+        IntRect horizontalScrollbar;
+        IntRect verticalScrollbar;
+        IntRect scrollCorner;
+        IntRect resizer;
+        IntRect scrollCornerOrResizerRect() const
+        {
+            return !scrollCorner.isEmpty() ? scrollCorner : resizer;
+        }
+    };
+    OverflowControlRects overflowControlsRects() const;
 
-    LayoutUnit verticalScrollbarStart(int minX, int maxX) const;
-    LayoutUnit horizontalScrollbarStart(int minX) const;
-
     bool overflowControlsIntersectRect(const IntRect& localRect) const;
 
     OptionSet<Compositing> m_compositingDirtyBits;

Modified: trunk/Source/WebCore/rendering/RenderLayerBacking.cpp (260444 => 260445)


--- trunk/Source/WebCore/rendering/RenderLayerBacking.cpp	2020-04-21 18:13:36 UTC (rev 260444)
+++ trunk/Source/WebCore/rendering/RenderLayerBacking.cpp	2020-04-21 18:17:10 UTC (rev 260445)
@@ -1829,9 +1829,13 @@
 
 bool RenderLayerBacking::requiresScrollCornerLayer() const
 {
-    if (m_owningLayer.scrollCornerAndResizerRect().isEmpty())
+    if (!is<RenderBox>(m_owningLayer.renderer()))
         return false;
 
+    auto cornerRect = m_owningLayer.overflowControlsRects().scrollCornerOrResizerRect();
+    if (cornerRect.isEmpty())
+        return false;
+
     auto verticalScrollbar = m_owningLayer.verticalScrollbar();
     auto scrollbar = verticalScrollbar ? verticalScrollbar : m_owningLayer.horizontalScrollbar();
     return requiresLayerForScrollbar(scrollbar);
@@ -1901,21 +1905,24 @@
         }
     };
 
+    // These rects are relative to the borderBoxRect.
+    auto rects = m_owningLayer.overflowControlsRects();
+
     if (auto* layer = layerForHorizontalScrollbar()) {
-        positionScrollbarLayer(*layer, m_owningLayer.rectForHorizontalScrollbar(borderBox), paddingBoxInset);
+        positionScrollbarLayer(*layer, rects.horizontalScrollbar, paddingBoxInset);
         layer->setDrawsContent(m_owningLayer.horizontalScrollbar() && !layer->usesContentsLayer());
     }
 
     if (auto* layer = layerForVerticalScrollbar()) {
-        positionScrollbarLayer(*layer, m_owningLayer.rectForVerticalScrollbar(borderBox), paddingBoxInset);
+        positionScrollbarLayer(*layer, rects.verticalScrollbar, paddingBoxInset);
         layer->setDrawsContent(m_owningLayer.verticalScrollbar() && !layer->usesContentsLayer());
     }
 
     if (auto* layer = layerForScrollCorner()) {
-        const LayoutRect& scrollCornerAndResizer = m_owningLayer.scrollCornerAndResizerRect();
-        layer->setPosition(scrollCornerAndResizer.location() - paddingBoxInset);
-        layer->setSize(scrollCornerAndResizer.size());
-        layer->setDrawsContent(!scrollCornerAndResizer.isEmpty());
+        auto cornerRect = rects.scrollCornerOrResizerRect();
+        layer->setPosition(cornerRect.location() - paddingBoxInset);
+        layer->setSize(cornerRect.size());
+        layer->setDrawsContent(!cornerRect.isEmpty());
     }
 }
 
@@ -3184,11 +3191,11 @@
     } else if (graphicsLayer == layerForVerticalScrollbar()) {
         paintScrollbar(m_owningLayer.verticalScrollbar(), context, dirtyRect);
     } else if (graphicsLayer == layerForScrollCorner()) {
-        const LayoutRect& scrollCornerAndResizer = m_owningLayer.scrollCornerAndResizerRect();
+        auto cornerRect = m_owningLayer.overflowControlsRects().scrollCornerOrResizerRect();
         GraphicsContextStateSaver stateSaver(context);
-        context.translate(-scrollCornerAndResizer.location());
+        context.translate(-cornerRect.location());
         LayoutRect transformedClip = LayoutRect(clip);
-        transformedClip.moveBy(scrollCornerAndResizer.location());
+        transformedClip.moveBy(cornerRect.location());
         m_owningLayer.paintScrollCorner(context, IntPoint(), snappedIntRect(transformedClip));
         m_owningLayer.paintResizer(context, IntPoint(), transformedClip);
     }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to