Title: [272749] trunk
Revision
272749
Author
[email protected]
Date
2021-02-11 13:57:38 -0800 (Thu, 11 Feb 2021)

Log Message

[iOS] Some checkboxes and radio buttons are clipped on top
https://bugs.webkit.org/show_bug.cgi?id=221736
<rdar://problem/73956812>

Reviewed by Simon Fraser.

Source/WebCore:

The clipping occurs due to integral rounding of the paint rect in
both RenderBox::paintBoxDecorations, as well as using the integral
rect in RenderTheme::paint. To fix, use FloatRect and the device
pixel snapped rect when painting these elements.

Tests: fast/forms/ios/form-control-refresh/checkbox/subpixel-clipping.html
       fast/forms/ios/form-control-refresh/radio/subpixel-clipping.html

* rendering/RenderBox.cpp:
(WebCore::RenderBox::paintBoxDecorations):

Moved into RenderTheme to avoid duplication.

* rendering/RenderElement.cpp:
(WebCore::RenderElement::paintOutline):

Moved into RenderTheme to avoid duplication.

* rendering/RenderTheme.cpp:
(WebCore::RenderTheme::paint):

Use the device pixel snapped rect when painting checkboxes and radio
buttons.

* rendering/RenderTheme.h:
(WebCore::RenderTheme::adjustedPaintRect):

On most platforms, no adjustment is performed.

(WebCore::RenderTheme::paintCheckbox):
(WebCore::RenderTheme::paintRadio):
* rendering/RenderThemeIOS.h:
* rendering/RenderThemeIOS.mm:
(WebCore::RenderThemeIOS::adjustedPaintRect):

On iOS, radio buttons and checkboxes always have a square painting
rect. Updated to use FloatRect, rather than IntRect, to avoid
clipping.

(WebCore::RenderThemeIOS::paintCheckbox):
(WebCore::RenderThemeIOS::paintRadio):
* rendering/RenderThemeWin.h:

LayoutTests:

Added reference mismatch tests to verify that the clipping no longer
occurs. The tests work by drawing an overlay smaller than the actual
size of the checkbox/radio input. If the input is clipped, only the
overlay will be visible, matching the "-expected-mismatch.html".
However, if the input is drawn correctly, the overlay will not cover
the entire input, and a mismatch will occur.

* fast/forms/ios/form-control-refresh/checkbox/subpixel-clipping-expected-mismatch.html: Added.
* fast/forms/ios/form-control-refresh/checkbox/subpixel-clipping.html: Added.
* fast/forms/ios/form-control-refresh/radio/subpixel-clipping-expected-mismatch.html: Added.
* fast/forms/ios/form-control-refresh/radio/subpixel-clipping.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (272748 => 272749)


--- trunk/LayoutTests/ChangeLog	2021-02-11 21:49:12 UTC (rev 272748)
+++ trunk/LayoutTests/ChangeLog	2021-02-11 21:57:38 UTC (rev 272749)
@@ -1,3 +1,23 @@
+2021-02-11  Aditya Keerthi  <[email protected]>
+
+        [iOS] Some checkboxes and radio buttons are clipped on top
+        https://bugs.webkit.org/show_bug.cgi?id=221736
+        <rdar://problem/73956812>
+
+        Reviewed by Simon Fraser.
+
+        Added reference mismatch tests to verify that the clipping no longer
+        occurs. The tests work by drawing an overlay smaller than the actual
+        size of the checkbox/radio input. If the input is clipped, only the
+        overlay will be visible, matching the "-expected-mismatch.html".
+        However, if the input is drawn correctly, the overlay will not cover
+        the entire input, and a mismatch will occur.
+
+        * fast/forms/ios/form-control-refresh/checkbox/subpixel-clipping-expected-mismatch.html: Added.
+        * fast/forms/ios/form-control-refresh/checkbox/subpixel-clipping.html: Added.
+        * fast/forms/ios/form-control-refresh/radio/subpixel-clipping-expected-mismatch.html: Added.
+        * fast/forms/ios/form-control-refresh/radio/subpixel-clipping.html: Added.
+
 2021-02-11  Chris Dumez  <[email protected]>
 
         [ MacOS Debug wk2] imported/w3c/web-platform-tests/worklets/animation-worklet-service-worker-interception.https.html is a flakey text failure

Added: trunk/LayoutTests/fast/forms/ios/form-control-refresh/checkbox/subpixel-clipping-expected-mismatch.html (0 => 272749)


--- trunk/LayoutTests/fast/forms/ios/form-control-refresh/checkbox/subpixel-clipping-expected-mismatch.html	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/ios/form-control-refresh/checkbox/subpixel-clipping-expected-mismatch.html	2021-02-11 21:57:38 UTC (rev 272749)
@@ -0,0 +1,20 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ IOSFormControlRefreshEnabled=true ] -->
+<html>
+<head>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<style>
+    #overlay {
+        position: absolute;
+        top: 1.5px;
+        left: 0px;
+        height: 15.5px;
+        width: 16px;
+        margin: 0px;
+        background-color: red;
+    }
+</style>
+</head>
+<body>
+<div id="overlay"></div>
+</body>
+</html>

Added: trunk/LayoutTests/fast/forms/ios/form-control-refresh/checkbox/subpixel-clipping.html (0 => 272749)


--- trunk/LayoutTests/fast/forms/ios/form-control-refresh/checkbox/subpixel-clipping.html	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/ios/form-control-refresh/checkbox/subpixel-clipping.html	2021-02-11 21:57:38 UTC (rev 272749)
@@ -0,0 +1,30 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ IOSFormControlRefreshEnabled=true ] -->
+<html>
+<head>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<style>
+    input {
+        position: absolute;
+        top: 1.5px;
+        left: 0px;
+        height: 16px;
+        width: 16px;
+        margin: 0px;
+    }
+
+    #overlay {
+        position: absolute;
+        top: 1.5px;
+        left: 0px;
+        height: 15.5px;
+        width: 16px;
+        margin: 0px;
+        background-color: red;
+    }
+</style>
+</head>
+<body>
+<input type="checkbox" checked disabled>
+<div id="overlay"></div>
+</body>
+</html>

Added: trunk/LayoutTests/fast/forms/ios/form-control-refresh/radio/subpixel-clipping-expected-mismatch.html (0 => 272749)


--- trunk/LayoutTests/fast/forms/ios/form-control-refresh/radio/subpixel-clipping-expected-mismatch.html	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/ios/form-control-refresh/radio/subpixel-clipping-expected-mismatch.html	2021-02-11 21:57:38 UTC (rev 272749)
@@ -0,0 +1,20 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ IOSFormControlRefreshEnabled=true ] -->
+<html>
+<head>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<style>
+    #overlay {
+        position: absolute;
+        top: 1.5px;
+        left: 0px;
+        height: 15.5px;
+        width: 16px;
+        margin: 0px;
+        background-color: red;
+    }
+</style>
+</head>
+<body>
+<div id="overlay"></div>
+</body>
+</html>

Added: trunk/LayoutTests/fast/forms/ios/form-control-refresh/radio/subpixel-clipping.html (0 => 272749)


--- trunk/LayoutTests/fast/forms/ios/form-control-refresh/radio/subpixel-clipping.html	                        (rev 0)
+++ trunk/LayoutTests/fast/forms/ios/form-control-refresh/radio/subpixel-clipping.html	2021-02-11 21:57:38 UTC (rev 272749)
@@ -0,0 +1,30 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ IOSFormControlRefreshEnabled=true ] -->
+<html>
+<head>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<style>
+    input {
+        position: absolute;
+        top: 1.5px;
+        left: 0px;
+        height: 16px;
+        width: 16px;
+        margin: 0px;
+    }
+
+    #overlay {
+        position: absolute;
+        top: 1.5px;
+        left: 0px;
+        height: 15.5px;
+        width: 16px;
+        margin: 0px;
+        background-color: red;
+    }
+</style>
+</head>
+<body>
+<input type="radio" checked disabled>
+<div id="overlay"></div>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (272748 => 272749)


--- trunk/Source/WebCore/ChangeLog	2021-02-11 21:49:12 UTC (rev 272748)
+++ trunk/Source/WebCore/ChangeLog	2021-02-11 21:57:38 UTC (rev 272749)
@@ -1,3 +1,54 @@
+2021-02-11  Aditya Keerthi  <[email protected]>
+
+        [iOS] Some checkboxes and radio buttons are clipped on top
+        https://bugs.webkit.org/show_bug.cgi?id=221736
+        <rdar://problem/73956812>
+
+        Reviewed by Simon Fraser.
+
+        The clipping occurs due to integral rounding of the paint rect in
+        both RenderBox::paintBoxDecorations, as well as using the integral
+        rect in RenderTheme::paint. To fix, use FloatRect and the device
+        pixel snapped rect when painting these elements.
+
+        Tests: fast/forms/ios/form-control-refresh/checkbox/subpixel-clipping.html
+               fast/forms/ios/form-control-refresh/radio/subpixel-clipping.html
+
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::paintBoxDecorations):
+
+        Moved into RenderTheme to avoid duplication.
+
+        * rendering/RenderElement.cpp:
+        (WebCore::RenderElement::paintOutline):
+
+        Moved into RenderTheme to avoid duplication.
+
+        * rendering/RenderTheme.cpp:
+        (WebCore::RenderTheme::paint):
+
+        Use the device pixel snapped rect when painting checkboxes and radio
+        buttons.
+
+        * rendering/RenderTheme.h:
+        (WebCore::RenderTheme::adjustedPaintRect):
+
+        On most platforms, no adjustment is performed.
+
+        (WebCore::RenderTheme::paintCheckbox):
+        (WebCore::RenderTheme::paintRadio):
+        * rendering/RenderThemeIOS.h:
+        * rendering/RenderThemeIOS.mm:
+        (WebCore::RenderThemeIOS::adjustedPaintRect):
+
+        On iOS, radio buttons and checkboxes always have a square painting
+        rect. Updated to use FloatRect, rather than IntRect, to avoid
+        clipping.
+
+        (WebCore::RenderThemeIOS::paintCheckbox):
+        (WebCore::RenderThemeIOS::paintRadio):
+        * rendering/RenderThemeWin.h:
+
 2021-02-11  Jer Noble  <[email protected]>
 
         [Cocoa][GPUP] Move RemoteCommandListener into the GPU Process

Modified: trunk/Source/WebCore/rendering/RenderBox.cpp (272748 => 272749)


--- trunk/Source/WebCore/rendering/RenderBox.cpp	2021-02-11 21:49:12 UTC (rev 272748)
+++ trunk/Source/WebCore/rendering/RenderBox.cpp	2021-02-11 21:57:38 UTC (rev 272749)
@@ -1425,15 +1425,7 @@
     paintRect.moveBy(paintOffset);
     adjustBorderBoxRectForPainting(paintRect);
 
-#if PLATFORM(IOS_FAMILY)
-    // Workaround for <rdar://problem/6209763>. Force the painting bounds of checkboxes and radio controls to be square.
-    // FIXME: Consolidate this code with the same code in RenderElement::paintOutline(). See <https://bugs.webkit.org/show_bug.cgi?id=194781>.
-    if (style().appearance() == CheckboxPart || style().appearance() == RadioPart) {
-        int width = std::min(paintRect.width(), paintRect.height());
-        int height = width;
-        paintRect = IntRect { paintRect.x(), paintRect.y() + (this->height() - height) / 2, width, height }; // Vertically center the checkbox, like on desktop
-    }
-#endif
+    paintRect = theme().adjustedPaintRect(*this, paintRect);
     BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance(paintInfo.context());
 
     // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have

Modified: trunk/Source/WebCore/rendering/RenderElement.cpp (272748 => 272749)


--- trunk/Source/WebCore/rendering/RenderElement.cpp	2021-02-11 21:49:12 UTC (rev 272748)
+++ trunk/Source/WebCore/rendering/RenderElement.cpp	2021-02-11 21:57:38 UTC (rev 272749)
@@ -2047,15 +2047,8 @@
     if (styleToUse.outlineStyleIsAuto() == OutlineIsAuto::On && !theme().supportsFocusRing(styleToUse)) {
         Vector<LayoutRect> focusRingRects;
         LayoutRect paintRectToUse { paintRect };
-#if PLATFORM(IOS_FAMILY)
-        // Workaround for <rdar://problem/6209763>. Force the painting bounds of checkboxes and radio controls to be square.
-        // FIXME: Consolidate this code with the same code in RenderBox::paintBoxDecorations(). See <https://bugs.webkit.org/show_bug.cgi?id=194781>.
-        if (style().appearance() == CheckboxPart || style().appearance() == RadioPart) {
-            int width = std::min(paintRect.width(), paintRect.height());
-            int height = width;
-            paintRectToUse = IntRect { paintRect.x(), paintRect.y() + (downcast<RenderBox>(*this).height() - height) / 2, width, height }; // Vertically center the checkbox, like on desktop
-        }
-#endif
+        if (is<RenderBox>(*this))
+            paintRectToUse = theme().adjustedPaintRect(downcast<RenderBox>(*this), paintRectToUse);
         addFocusRingRects(focusRingRects, paintRectToUse.location(), paintInfo.paintContainer);
         paintFocusRing(paintInfo, styleToUse, focusRingRects);
     }

Modified: trunk/Source/WebCore/rendering/RenderTheme.cpp (272748 => 272749)


--- trunk/Source/WebCore/rendering/RenderTheme.cpp	2021-02-11 21:49:12 UTC (rev 272748)
+++ trunk/Source/WebCore/rendering/RenderTheme.cpp	2021-02-11 21:57:38 UTC (rev 272749)
@@ -324,9 +324,9 @@
     switch (part) {
 #if !USE(NEW_THEME)
     case CheckboxPart:
-        return paintCheckbox(box, paintInfo, integralSnappedRect);
+        return paintCheckbox(box, paintInfo, devicePixelSnappedRect);
     case RadioPart:
-        return paintRadio(box, paintInfo, integralSnappedRect);
+        return paintRadio(box, paintInfo, devicePixelSnappedRect);
 #if ENABLE(INPUT_TYPE_COLOR)
     case ColorWellPart:
         return paintColorWell(box, paintInfo, integralSnappedRect);

Modified: trunk/Source/WebCore/rendering/RenderTheme.h (272748 => 272749)


--- trunk/Source/WebCore/rendering/RenderTheme.h	2021-02-11 21:49:12 UTC (rev 272748)
+++ trunk/Source/WebCore/rendering/RenderTheme.h	2021-02-11 21:57:38 UTC (rev 272749)
@@ -101,6 +101,8 @@
     virtual String colorInputStyleSheet(const Settings&) const;
 #endif
 
+    virtual LayoutRect adjustedPaintRect(const RenderBox&, const LayoutRect& paintRect) const { return paintRect; }
+
     // A method to obtain the baseline position for a "leaf" control.  This will only be used if a baseline
     // position cannot be determined by examining child content. Checkboxes and radio buttons are examples of
     // controls that need to do this.
@@ -287,11 +289,11 @@
 #if !USE(NEW_THEME)
     // Methods for each appearance value.
     virtual void adjustCheckboxStyle(RenderStyle&, const Element*) const;
-    virtual bool paintCheckbox(const RenderObject&, const PaintInfo&, const IntRect&) { return true; }
+    virtual bool paintCheckbox(const RenderObject&, const PaintInfo&, const FloatRect&) { return true; }
     virtual void setCheckboxSize(RenderStyle&) const { }
 
     virtual void adjustRadioStyle(RenderStyle&, const Element*) const;
-    virtual bool paintRadio(const RenderObject&, const PaintInfo&, const IntRect&) { return true; }
+    virtual bool paintRadio(const RenderObject&, const PaintInfo&, const FloatRect&) { return true; }
     virtual void setRadioSize(RenderStyle&) const { }
 
     virtual void adjustButtonStyle(RenderStyle&, const Element*) const;

Modified: trunk/Source/WebCore/rendering/RenderThemeIOS.h (272748 => 272749)


--- trunk/Source/WebCore/rendering/RenderThemeIOS.h	2021-02-11 21:49:12 UTC (rev 272748)
+++ trunk/Source/WebCore/rendering/RenderThemeIOS.h	2021-02-11 21:57:38 UTC (rev 272749)
@@ -72,6 +72,8 @@
 
     LengthBox popupInternalPaddingBox(const RenderStyle&, const Settings&) const override;
 
+    LayoutRect adjustedPaintRect(const RenderBox&, const LayoutRect&) const override;
+
     int baselinePosition(const RenderBox&) const override;
 
     bool isControlStyled(const RenderStyle&, const RenderStyle& userAgentStyle) const override;
@@ -112,8 +114,8 @@
     void paintSearchFieldDecorations(const RenderObject&, const PaintInfo&, const IntRect&) override;
 
 #if ENABLE(IOS_FORM_CONTROL_REFRESH)
-    bool paintCheckbox(const RenderObject&, const PaintInfo&, const IntRect&) override;
-    bool paintRadio(const RenderObject&, const PaintInfo&, const IntRect&) override;
+    bool paintCheckbox(const RenderObject&, const PaintInfo&, const FloatRect&) override;
+    bool paintRadio(const RenderObject&, const PaintInfo&, const FloatRect&) override;
 
     Seconds animationRepeatIntervalForProgressBar(const RenderProgress&) const final;
 

Modified: trunk/Source/WebCore/rendering/RenderThemeIOS.mm (272748 => 272749)


--- trunk/Source/WebCore/rendering/RenderThemeIOS.mm	2021-02-11 21:49:12 UTC (rev 272748)
+++ trunk/Source/WebCore/rendering/RenderThemeIOS.mm	2021-02-11 21:57:38 UTC (rev 272749)
@@ -453,6 +453,18 @@
     }
 }
 
+LayoutRect RenderThemeIOS::adjustedPaintRect(const RenderBox& box, const LayoutRect& paintRect) const
+{
+    // Workaround for <rdar://problem/6209763>. Force the painting bounds of checkboxes and radio controls to be square.
+    if (box.style().appearance() == CheckboxPart || box.style().appearance() == RadioPart) {
+        float width = std::min(paintRect.width(), paintRect.height());
+        float height = width;
+        return enclosingLayoutRect(FloatRect(paintRect.x(), paintRect.y() + (box.height() - height) / 2, width, height)); // Vertically center the checkbox, like on desktop
+    }
+
+    return paintRect;
+}
+
 int RenderThemeIOS::baselinePosition(const RenderBox& box) const
 {
     if (box.style().appearance() == CheckboxPart || box.style().appearance() == RadioPart)
@@ -2050,7 +2062,7 @@
 
 constexpr auto menulistButtonColor = SRGBA<uint8_t> { 97, 172, 255 };
 
-bool RenderThemeIOS::paintCheckbox(const RenderObject& box, const PaintInfo& paintInfo, const IntRect& rect)
+bool RenderThemeIOS::paintCheckbox(const RenderObject& box, const PaintInfo& paintInfo, const FloatRect& rect)
 {
     if (!box.settings().iOSFormControlRefreshEnabled())
         return true;
@@ -2108,7 +2120,7 @@
     return false;
 }
 
-bool RenderThemeIOS::paintRadio(const RenderObject& box, const PaintInfo& paintInfo, const IntRect& rect)
+bool RenderThemeIOS::paintRadio(const RenderObject& box, const PaintInfo& paintInfo, const FloatRect& rect)
 {
     if (!box.settings().iOSFormControlRefreshEnabled())
         return true;

Modified: trunk/Source/WebCore/rendering/RenderThemeWin.h (272748 => 272749)


--- trunk/Source/WebCore/rendering/RenderThemeWin.h	2021-02-11 21:49:12 UTC (rev 272748)
+++ trunk/Source/WebCore/rendering/RenderThemeWin.h	2021-02-11 21:57:38 UTC (rev 272749)
@@ -61,12 +61,12 @@
 
     Color systemColor(CSSValueID, OptionSet<StyleColor::Options>) const override;
 
-    bool paintCheckbox(const RenderObject& o, const PaintInfo& i, const IntRect& r) override
-    { return paintButton(o, i, r); }
+    bool paintCheckbox(const RenderObject& o, const PaintInfo& i, const FloatRect& r) override
+    { return paintButton(o, i, IntRect(r)); }
     void setCheckboxSize(RenderStyle&) const override;
 
-    bool paintRadio(const RenderObject& o, const PaintInfo& i, const IntRect& r) override
-    { return paintButton(o, i, r); }
+    bool paintRadio(const RenderObject& o, const PaintInfo& i, const FloatRect& r) override
+    { return paintButton(o, i, IntRect(r)); }
     void setRadioSize(RenderStyle& style) const override
     { return setCheckboxSize(style); }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to