RESOLVED FIXED310804
[threaded-animations] animating `offset-path` with a percentage-based `offset-distance` value fails
https://bugs.webkit.org/show_bug.cgi?id=310804
Summary [threaded-animations] animating `offset-path` with a percentage-based `offset...
Antoine Quint
Reported 2026-03-26 04:16:13 PDT
Created attachment 478803 [details] Test A keyframe such as this one: ``` @keyframes move { from { offset-path: rect(0px 100px 100px 0px) } to { offset-distance: 100% } } ``` … fails a debug assertion for `PrimitiveNumeric`: ``` IPCData ipcData() const { return WTF::switchOn(m_value, [](const Dimension& dimension) -> IPCData { return dimension; }, [](const Percentage& percentage) -> IPCData { return percentage; }, [](const Calc&) -> IPCData { ASSERT_NOT_REACHED(); return Dimension { 0 }; } // <<<< HERE ); } ``` I find it surprising since we're not using `calc()` anywhere here.
Attachments
Test (257 bytes, text/html)
2026-03-26 04:16 PDT, Antoine Quint
no flags
Antoine Quint
Comment 1 2026-03-26 09:16:12 PDT
Once we fix this, we'll crash in the blending code which needs to fix this way: ``` diff --git a/Source/WebCore/platform/animation/AcceleratedEffect.cpp b/Source/WebCore/platform/animation/AcceleratedEffect.cpp index d72a1b1433b8..741a4cb602a4 100644 --- a/Source/WebCore/platform/animation/AcceleratedEffect.cpp +++ b/Source/WebCore/platform/animation/AcceleratedEffect.cpp @@ -366,8 +366,12 @@ static void blend(AcceleratedEffectProperty property, AcceleratedEffectValues& o output.offsetDistance = blend(from.offsetDistance, to.offsetDistance, blendingContext); break; case AcceleratedEffectProperty::OffsetPath: - if (auto& fromOffsetPath = from.offsetPath) - output.offsetPath = fromOffsetPath->blend(to.offsetPath.get(), blendingContext); + if (!from.offsetPath || !to.offsetPath) { + blendingContext.isDiscrete = true; + blendingContext.normalizeProgress(); + output.offsetPath = blendingContext.progress ? to.offsetPath : from.offsetPath; + } else + output.offsetPath = from.offsetPath->blend(to.offsetPath.get(), blendingContext); break; case AcceleratedEffectProperty::OffsetPosition: if (!canBlend(from.offsetPosition, to.offsetPosition)) { ```
Sam Weinig
Comment 2 2026-03-26 13:22:45 PDT
The reason there is a calc() here is that the `rect()` in `offset-path: rect(0px 100px 100px 0px)` gets converted to its "inset" form during style building, which introduces the calcs. rect(0px 100px 100px 0px) -> inset(0px calc(100% - 100px) calc(100% - 100px) 0px)
Antoine Quint
Comment 3 2026-03-28 01:27:22 PDT
Will likely be fixed by bug 310943.
Sam Weinig
Comment 4 2026-03-29 14:02:19 PDT
When https://bugs.webkit.org/show_bug.cgi?id=310943 lands, this no longer asserts, but the animation doesn't match the behavior when threaded animations are disabled. To illustrate why it still doesn't match, I am going to make the values a bit more explicit in the example: ``` @keyframes move { from { offset-path: rect(0px 100px 100px 0px); offset-distance: 0%; } to { offset-path: none; offset-distance: 100%; } } ``` When converted to AcceleratedEffectValues these become: from -> AcceleratedEffectValues { offset-path: {some path} offset-distance: 0; } to -> AcceleratedEffectValues { offset-path: none offset-distance: 0; } ``` Importantly, `offset-distance` stays `0`. This happens for two reasons. 1. Because `offset-distance` is only calculated at all if there is an `offset-path` (we can fix this one by just unconditionally evaluated the `offset-distance`) 2. Because percentage/calc `offset-distance` values are evaluated with respect to the length `offset-path`. Due to #2, the lack of `offset-path` makes the `offset-distance: 100%` incalculable. -- So what should we do? We need to ensure that we don't use the accelerated animation path for keyframe pairs where: - The length of `offset-path` is changing (this probably boils down to if "`offset-path` is changing" at all). and - The value of `offset-distance` is percentage or calc for either keyframe. We should also change it so calculate values for all the `offset-*` properties regardless of whether `tryPath()` succeeds (except, of course, `offset-distance` when it is percentage or calc), so that they can properly interpolate even when one keyframe does not have a valid `offset-path`.
Radar WebKit Bug Importer
Comment 5 2026-04-02 04:17:13 PDT
Antoine Quint
Comment 6 2026-04-13 07:43:56 PDT
Retitling given that the original issue was fixed by 310943.
Antoine Quint
Comment 7 2026-04-13 08:22:21 PDT
EWS
Comment 8 2026-04-14 13:28:25 PDT
Committed 311224@main (89607e24306f): <https://commits.webkit.org/311224@main> Reviewed commits have been landed. Closing PR #62638 and removing active labels.
Note You need to log in before you can comment on or make changes to this bug.