Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 3adec8e64df0536e4d34c37902714552fbc0057d
https://github.com/WebKit/WebKit/commit/3adec8e64df0536e4d34c37902714552fbc0057d
Author: Ahmad Saleem <[email protected]>
Date: 2026-08-15 (Sat, 15 Aug 2026)
Changed paths:
M LayoutTests/fast/borders/hidpi-outline-hairline-painting-expected.html
A LayoutTests/fast/css/outline-offset-used-value-zoom-rounding-expected.txt
A LayoutTests/fast/css/outline-offset-used-value-zoom-rounding.html
M
LayoutTests/imported/w3c/web-platform-tests/css/css-borders/outline-offset-rounding.tentative-expected.txt
M
LayoutTests/imported/w3c/web-platform-tests/css/css-borders/outline-offset-rounding.tentative.html
A
LayoutTests/imported/w3c/web-platform-tests/css/css-ui/animation/outline-offset-interpolation-rounding.tentative-expected.txt
A
LayoutTests/imported/w3c/web-platform-tests/css/css-ui/animation/outline-offset-interpolation-rounding.tentative.html
M Source/WebCore/Headers.cmake
M Source/WebCore/Sources.txt
M Source/WebCore/WebCore.xcodeproj/project.pbxproj
M Source/WebCore/accessibility/AccessibilityRenderObject.cpp
M Source/WebCore/rendering/OutlinePainter.cpp
M Source/WebCore/rendering/RenderElement.cpp
M Source/WebCore/rendering/cocoa/RenderThemeCocoa.mm
M Source/WebCore/style/computed/StyleComputedStyle.cpp
M Source/WebCore/style/computed/StyleComputedStyle.h
M Source/WebCore/style/computed/StyleComputedStyleBase.h
M Source/WebCore/style/values/backgrounds/StyleLineWidth.cpp
M Source/WebCore/style/values/backgrounds/StyleLineWidth.h
A Source/WebCore/style/values/outline/StyleOutlineOffset.cpp
M Source/WebCore/style/values/outline/StyleOutlineOffset.h
A Source/WebCore/style/values/primitives/StyleSnapLengthAsBorderWidth.cpp
A
Source/WebCore/style/values/primitives/StyleSnapLengthAsBorderWidth.h
M Source/WebCore/testing/Internals.cpp
Log Message:
-----------
[css-ui] outline-offset computed value should be snapped as a line width
https://bugs.webkit.org/show_bug.cgi?id=317427
rdar://180054053
Reviewed by Sam Weinig and Darin Adler.
This patch aligns WebKit with Gecko / Firefox and Blink / Chromium.
The CSSWG resolved that `outline-offset` should be snapped to an integer number
of
device pixels the same way `outline-width` and `border-width` are
(w3c/csswg-drafts#12906). WebKit used the raw, unsnapped length, so
getComputedStyle().outlineOffset returned values like "0.1px" instead of "1px".
Move "snap a length as a border width"
(https://drafts.csswg.org/css-values-4/#snap-a-length-as-a-border-width) out of
`LineWidth` into its own file, exposing the `float` overload directly and adding
signed overloads for lengths that may be negative, which snap the magnitude
and
restore the sign: zero is unchanged, a magnitude below 1 device pixel rounds
away
from zero, a larger magnitude rounds toward zero.
`outline-offset` now snaps in the same three places `outline-width` does:
- `CSSValueConversion<OutlineOffset>` snaps the computed value.
- `Blending<OutlineOffset>` re-snaps blended values, keeping animations on
device
pixels. It also has to supply `canBlend()`, since a full specialization
replaces
the generic `ValueOrKeyword` one, which is what makes `inset` interpolate
discretely against a length rather than blending as an empty value.
- `Evaluation<UsedOutlineOffset>` re-snaps after zoom is applied, keeping the
used
value on device pixels at any page zoom. `ComputedStyle::usedOutlineOffset()`
returns `Style::UsedOutlineOffset` so that evaluating it requires a device
scale
factor, and its callers pass one.
The manual `floorToDevicePixel()` in RenderThemeCocoa is subsumed by that
used-value
snapping. It is
not quite equivalent: for a magnitude below one device pixel, `floor`
gave 0 while snapping rounds away from zero to 1 device pixel, so an iOS focus
ring
at a zoom below 1 now scales by the offset instead of ignoring it. That is the
behavior `outline-width` already has.
`inset` resolves to the negated used `outline-width`, and snapping both after
zoom
makes them cancel exactly, which they previously did not at fractional zoom.
* LayoutTests/fast/borders/hidpi-outline-hairline-painting-expected.html:
Rebaselined.
This reference was authored against unsnapped offsets, and at the 2x device
scale factor
this test runs at, snapping the offset changes the painted outline geometry.
* LayoutTests/fast/css/outline-offset-used-value-zoom-rounding-expected.txt:
Added.
* LayoutTests/fast/css/outline-offset-used-value-zoom-rounding.html: Added.
Covers the
used value after zoom, which needs `internals` since it is not web-exposed.
*
LayoutTests/imported/w3c/web-platform-tests/css/css-borders/outline-offset-rounding.tentative.html:
The test as imported hard-codes expectations that assume 1 device pixel is 1
CSS pixel, so its
sub-pixel sub-tests reported FAIL at any other device scale factor even though
the engine was
behaving as specified. Derive the expectations from window.devicePixelRatio
instead, and add
sub-tests that cross-check outline-offset against outline-width for the same
input, which is a
direct statement of the CSSWG resolution and holds at any device scale factor.
Verified all 30
sub-tests pass at 1x, 2x and 3x. To be upstreamed.
*
LayoutTests/imported/w3c/web-platform-tests/css/css-borders/outline-offset-rounding.tentative-expected.txt:
Progression
*
LayoutTests/imported/w3c/web-platform-tests/css/css-ui/animation/outline-offset-interpolation-rounding.tentative-expected.txt:
Added.
*
LayoutTests/imported/w3c/web-platform-tests/css/css-ui/animation/outline-offset-interpolation-rounding.tentative.html:
Added.
Covers snapping of blended values, deriving expectations from
window.devicePixelRatio so they hold
at any device scale factor. The `inset` sub-test is gated on CSS.supports(),
since Chromium and
Gecko do not implement it yet and drop the keyframe. To be upstreamed.
* Source/WebCore/Headers.cmake:
* Source/WebCore/Sources.txt:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::elementPath const):
* Source/WebCore/rendering/OutlinePainter.cpp:
(WebCore::OutlinePainter::paintOutline const):
(WebCore::OutlinePainter::paintOutlineWithLineRects const):
(WebCore::OutlinePainter::paintFocusRing const):
* Source/WebCore/rendering/RenderElement.cpp:
(WebCore::RenderElement::repaintAfterLayoutIfNeeded):
*
Source/WebCore/rendering/cocoa/RenderThemeCocoa.mm:
(WebCore::drawFocusRingForPathForVectorBasedControls):
* Source/WebCore/style/computed/StyleComputedStyle.cpp:
(WebCore::Style::ComputedStyle::usedOutlineOffset const):
(WebCore::Style::ComputedStyle::usedOutlineSize const):
* Source/WebCore/style/computed/StyleComputedStyle.h:
* Source/WebCore/style/computed/StyleComputedStyleBase.h:
* Source/WebCore/style/values/backgrounds/StyleLineWidth.cpp:
(WebCore::Style::snapLengthAsBorderWidth): Deleted.
(WebCore::Style::LineWidth::snapLengthAsBorderWidth): Deleted.
* Source/WebCore/style/values/backgrounds/StyleLineWidth.h:
* Source/WebCore/style/values/outline/StyleOutlineOffset.cpp:
(WebCore::Style::CSSValueConversion<OutlineOffset>::operator()):
(WebCore::Style::Blending<OutlineOffset>::canBlend):
(WebCore::Style::Blending<OutlineOffset>::blend):
(WebCore::Style::Evaluation<UsedOutlineOffset, float>::operator()):
(WebCore::Style::Evaluation<UsedOutlineOffset,
LayoutUnit>::operator()):
* Source/WebCore/style/values/outline/StyleOutlineOffset.h:
* Source/WebCore/style/values/primitives/StyleSnapLengthAsBorderWidth.cpp:
Added.
(WebCore::Style::snapLengthAsBorderWidth):
(WebCore::Style::snapSignedLengthAsBorderWidth):
* Source/WebCore/style/values/primitives/StyleSnapLengthAsBorderWidth.h: Added.
* Source/WebCore/testing/Internals.cpp:
(WebCore::Internals::usedOutlineOffset):
Canonical link:
https://flagged.apple.com:443/proxy?t2=Dh3n1i1Fv9&o=aHR0cHM6Ly9jb21taXRzLndlYmtpdC5vcmcvMzE5MjM2QG1haW4=&emid=ff31d39f-26a4-4a58-9746-489113a7a11e&c=11
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications