WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
209370
REGRESSION: CSS animations inside an embedded SVG image do not animate
https://bugs.webkit.org/show_bug.cgi?id=209370
Summary
REGRESSION: CSS animations inside an embedded SVG image do not animate
tym46383
Reported
2020-03-20 18:21:26 PDT
On this site,
https://css-tricks.com/having-fun-with-link-hover-effects/
, the wavy line a:hover effect is supposed to animate but it doesn't. The rest of the examples provided all seem to animate correctly otherwise. This page mentions its inspiration as coming from
https://theoutline.com/post/5970/unconventional-wisdom-emotional-readiness-is-bullshit
. The hover effects here don't work, either. I thought that this issue might only apply to link states, but none of the decorative lines animate either. They do in Firefox. This happens in the WebKit Nightly as well as on iPadOS 13.4 beta 6. I tried adding the -webkit prefix but the results are the same.
Attachments
Test
(229 bytes, text/html)
2020-04-03 08:36 PDT
,
Antoine Quint
no flags
Details
Patch
(4.89 KB, patch)
2020-04-03 17:22 PDT
,
Said Abou-Hallawa
no flags
Details
Formatted Diff
Diff
Patch
(9.83 KB, patch)
2020-04-03 21:43 PDT
,
Said Abou-Hallawa
no flags
Details
Formatted Diff
Diff
Patch
(15.27 KB, patch)
2020-04-07 01:16 PDT
,
Said Abou-Hallawa
no flags
Details
Formatted Diff
Diff
Patch
(15.19 KB, patch)
2020-04-07 01:29 PDT
,
Said Abou-Hallawa
no flags
Details
Formatted Diff
Diff
Patch
(21.15 KB, patch)
2020-04-07 12:25 PDT
,
Said Abou-Hallawa
no flags
Details
Formatted Diff
Diff
Patch
(19.93 KB, patch)
2020-04-07 15:31 PDT
,
Said Abou-Hallawa
no flags
Details
Formatted Diff
Diff
Patch
(22.78 KB, patch)
2020-04-08 13:07 PDT
,
Said Abou-Hallawa
no flags
Details
Formatted Diff
Diff
Patch
(23.01 KB, patch)
2020-04-08 13:30 PDT
,
Said Abou-Hallawa
no flags
Details
Formatted Diff
Diff
Patch
(26.66 KB, patch)
2020-04-08 21:10 PDT
,
Said Abou-Hallawa
no flags
Details
Formatted Diff
Diff
Patch
(26.52 KB, patch)
2020-04-09 12:03 PDT
,
Said Abou-Hallawa
no flags
Details
Formatted Diff
Diff
Patch
(26.75 KB, patch)
2020-04-09 12:22 PDT
,
Said Abou-Hallawa
no flags
Details
Formatted Diff
Diff
Show Obsolete
(10)
View All
Add attachment
proposed patch, testcase, etc.
tym46383
Comment 1
2020-03-20 18:35:56 PDT
(In reply to tym46383 from
comment #0
)
> On this site,
https://css-tricks.com/having-fun-with-link-hover-effects/
, > the wavy line a:hover effect is supposed to animate but it doesn't. The rest > of the examples provided all seem to animate correctly otherwise. > > This page mentions its inspiration as coming from >
https://theoutline.com/post/5970/unconventional-wisdom-emotional-readiness
- > is-bullshit. The hover effects here don't work, either. I thought that this > issue might only apply to link states, but none of the decorative lines > animate either. They do in Firefox. > > This happens in the WebKit Nightly as well as on iPadOS 13.4 beta 6. I tried > adding the -webkit prefix but the results are the same.
Actually, I just noticed that the horizontal "Border to Background Effect" (
https://codepen.io/geoffgraham/pen/qMbVGv
) fades from orange to bluish-gray in WebKit before fading to white. In Firefox it goes from orange to white. But this and the rest of the examples aren't SVG animations so it's not especially relevant to this bug I suppose.
Radar WebKit Bug Importer
Comment 2
2020-03-21 18:51:38 PDT
<
rdar://problem/60733068
>
Antoine Quint
Comment 3
2020-03-23 10:21:17 PDT
https://theoutline.com/post/5970/unconventional-wisdom-emotional-readiness-is-bullshit
shows the issue without hovering links right at the top of the page where I can see the dividing wavy line animate in Firefox but not in STP 102. This is not new with the Web Animations implementation.
Antoine Quint
Comment 4
2020-03-23 10:28:28 PDT
The animation is performed by a CSS animation in an SVG document,
https://theoutline.com/svg/sq/v?c=ffffff&a=4&f=5&sw=1&anim=true
. You can change the store color by modifying the URL to
https://theoutline.com/svg/sq/v?c=000000&a=4&f=5&sw=1&anim=true
, and this shows the animation working as expected. This is probably an issue where SVG images in background-image don't run animations.
TG
Comment 5
2020-03-29 13:58:12 PDT
Confirming this bug in Safari 13.1 (15609.1.20.111.8) and STP Release 103. SVG keyframe animations on CSS background-image attributes aren't rendering properly, but the animations will render if the SVG is opened/displayed directly in a browser window.
Antoine Quint
Comment 6
2020-04-03 02:12:09 PDT
This is a regression due to Web Animations introduced in Safari 13.1. Looking for a fix now.
Antoine Quint
Comment 7
2020-04-03 05:48:04 PDT
The DocumentTimeline schedules an initial update but its current time never advances.
Antoine Quint
Comment 8
2020-04-03 06:01:26 PDT
In DisplayRefreshMonitorMac::requestRefreshCallback(): CVReturn error = CVDisplayLinkCreateWithCGDisplay(displayID(), &m_displayLink); if (error) return false; We get an error and bail early, never registering for an actual callback.
Antoine Quint
Comment 9
2020-04-03 06:02:29 PDT
The legacy animation engine uses a different codepath presumably, since DisplayRefreshMonitorMac::requestRefreshCallback() is never called.
Antoine Quint
Comment 10
2020-04-03 06:15:46 PDT
The displayID passed to CVDisplayLinkCreateWithCGDisplay is 0, presumably that's an invalid value. Maybe this is because this is the Page for an SVGDocument?
Antoine Quint
Comment 11
2020-04-03 07:13:01 PDT
When I open the SVG file by itself, the code never goes through DisplayRefreshMonitorMac::requestRefreshCallback() in Source/WebCore/platform/graphics/mac/DisplayRefreshMonitorMac.cpp
Antoine Quint
Comment 12
2020-04-03 08:24:31 PDT
This also affects <img> elements pointing to SVG documents.
Antoine Quint
Comment 13
2020-04-03 08:36:00 PDT
A simple reduction: <img src='data:image/svg+xml;utf8,<svg xmlns="
http://www.w3.org/2000/svg
"><style>@keyframes animate { to { opacity: 0 } } rect { animation: animate 0.5s infinite alternate }</style><rect width="100%" height="100%"></rect></svg>'>
Antoine Quint
Comment 14
2020-04-03 08:36:33 PDT
Created
attachment 395379
[details]
Test
Said Abou-Hallawa
Comment 15
2020-04-03 10:59:48 PDT
The CSS animation DocumentTimeline is added to the SVGDocument of the embedded SVGImage. This SVGDocument is not enumerate-able by Page::forEachDocument(), so we never call updateAnimationsAndSendEvents() for it. I am not sure what the right solution is: 1. Should we add the DocumentTimeline to the topDocument? 2. Should we make Page::forEachDocument() enumerate through the SVGDocuments of the embedded SVGImages also?
Antoine Quint
Comment 16
2020-04-03 11:21:31 PDT
(In reply to Said Abou-Hallawa from
comment #15
)
> The CSS animation DocumentTimeline is added to the SVGDocument of the > embedded SVGImage. This SVGDocument is not enumerate-able by > Page::forEachDocument(), so we never call updateAnimationsAndSendEvents() > for it. > > I am not sure what the right solution is: > 1. Should we add the DocumentTimeline to the topDocument? > 2. Should we make Page::forEachDocument() enumerate through the SVGDocuments > of the embedded SVGImages also?
I've been talking about this with Simon and he reckons what we need to do is to make Chrome::displayID() return the hosting page's displayID such that the call to CVDisplayLinkCreateWithCGDisplay doesn't fail.
Simon Fraser (smfr)
Comment 17
2020-04-03 12:33:07 PDT
I think SVGImageChromeClient should implement something that allows the ImageObserver to implement schduleRenderingUpdate.
Said Abou-Hallawa
Comment 18
2020-04-03 13:02:00 PDT
(In reply to Antoine Quint from
comment #16
)
> (In reply to Said Abou-Hallawa from
comment #15
) > > The CSS animation DocumentTimeline is added to the SVGDocument of the > > embedded SVGImage. This SVGDocument is not enumerate-able by > > Page::forEachDocument(), so we never call updateAnimationsAndSendEvents() > > for it. > > > > I am not sure what the right solution is: > > 1. Should we add the DocumentTimeline to the topDocument? > > 2. Should we make Page::forEachDocument() enumerate through the SVGDocuments > > of the embedded SVGImages also? > > I've been talking about this with Simon and he reckons what we need to do is > to make Chrome::displayID() return the hosting page's displayID such that > the call to CVDisplayLinkCreateWithCGDisplay doesn't fail.
DisplayRefreshMonitorMac is only used by WK1 and the bug is happening in WK2 as well.
Said Abou-Hallawa
Comment 19
2020-04-03 17:22:41 PDT
Created
attachment 395420
[details]
Patch
Said Abou-Hallawa
Comment 20
2020-04-03 17:32:46 PDT
Comment on
attachment 395420
[details]
Patch Something is still missing in this patch. WebAnimation should be enabled for top-level SVGDocument but not for the embedded ones.
Simon Fraser (smfr)
Comment 21
2020-04-03 18:07:29 PDT
Comment on
attachment 395420
[details]
Patch This doesn't seem like the right approach (and we also want to eliminate the old animation code eventually).
Said Abou-Hallawa
Comment 22
2020-04-03 21:43:37 PDT
Created
attachment 395432
[details]
Patch
Said Abou-Hallawa
Comment 23
2020-04-03 21:45:35 PDT
(In reply to Said Abou-Hallawa from
comment #22
)
> Created
attachment 395432
[details]
> Patch
This patch is not the right approach. But it is fixes bug and it does not break the top-level case. Besides it has layout tests. Just ignore it for now.
Said Abou-Hallawa
Comment 24
2020-04-07 01:16:30 PDT
Created
attachment 395659
[details]
Patch
Said Abou-Hallawa
Comment 25
2020-04-07 01:29:08 PDT
Created
attachment 395662
[details]
Patch
Said Abou-Hallawa
Comment 26
2020-04-07 10:26:55 PDT
Comment on
attachment 395662
[details]
Patch Two problems with this patch: 1. It fixes the case where the SVG image is embedded in an <img> element. But it does not fix the case where the SVG image is the background of an element. 2. It has to enumerate the RendererImages of every document in each Page::updateRendering() regardless they have SVG images or not.
Said Abou-Hallawa
Comment 27
2020-04-07 12:25:15 PDT
Created
attachment 395723
[details]
Patch
Simon Fraser (smfr)
Comment 28
2020-04-07 12:30:13 PDT
Comment on
attachment 395723
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=395723&action=review
> Source/WebCore/page/Page.cpp:1312 > + if (chrome().client().isSVGImageChromeClient()) > + chrome().client().scheduleRenderingUpdate();
This is weird, because ChromeClient is a virtual interface. Maybe Chrome::scheduleRenderingUpdate() could just return a bool - true if it handled it.
> Source/WebCore/page/Page.cpp:1374 > + for (auto& renderer : descendantsOfType<RenderElement>(*renderView)) > + renderer.updateRendering();
This is a massive tree walk! I think we need to avoid this by storing a list of SVGImages somewhere.
Said Abou-Hallawa
Comment 29
2020-04-07 15:31:21 PDT
Created
attachment 395750
[details]
Patch
Simon Fraser (smfr)
Comment 30
2020-04-07 20:33:28 PDT
Comment on
attachment 395750
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=395750&action=review
> Source/WebCore/dom/Document.cpp:6401 > + for (auto& cachedResourceHandle : m_cachedResourceLoader->allCachedResources().values()) { > + auto* cachedResource = cachedResourceHandle.get(); > + if (!cachedResource || !cachedResource->isImage()) > + continue; > + > + auto* image = downcast<CachedImage>(cachedResource)->image(); > + if (!image || !is<SVGImage>(image)) > + continue; > + > + if (auto* page = downcast<SVGImage>(image)->page()) > + page->updateRendering(); > + }
Please measure how long this takes on some resource-heavy pages (throw in a TimingScope in your local release build). It might be too expensive to do every frame.
> Source/WebCore/page/Page.cpp:1311 > + if (chrome().client().isSVGImageChromeClient()) > + chrome().client().scheduleRenderingUpdate();
Can we do this through virtual functions, as I suggested before?
Said Abou-Hallawa
Comment 31
2020-04-08 13:07:40 PDT
Created
attachment 395859
[details]
Patch
Said Abou-Hallawa
Comment 32
2020-04-08 13:13:39 PDT
Comment on
attachment 395750
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=395750&action=review
>> Source/WebCore/dom/Document.cpp:6401 >> + } > > Please measure how long this takes on some resource-heavy pages (throw in a TimingScope in your local release build). It might be too expensive to do every frame.
I changed that by building a HashSet<String> which contains the URLs of the cached SVGImages when the documentDidFinishLoadEvent fires. This HashSet<> will be used to get the list of the SVGImages in a document instead. So building HashSet<String> happens only once and enumerating this HashSet is cheap. If the HashSet is empty, which is the common case, there should not be any noticeable overhead in the Page::updateRendering().
>> Source/WebCore/page/Page.cpp:1311 >> + chrome().client().scheduleRenderingUpdate(); > > Can we do this through virtual functions, as I suggested before?
Done.
Said Abou-Hallawa
Comment 33
2020-04-08 13:30:26 PDT
Created
attachment 395860
[details]
Patch
Said Abou-Hallawa
Comment 34
2020-04-08 13:42:37 PDT
Comment on
attachment 395860
[details]
Patch This patch does not fix the animation in
https://css-tricks.com/having-fun-with-link-hover-effects/
.
Said Abou-Hallawa
Comment 35
2020-04-08 21:10:31 PDT
Created
attachment 395907
[details]
Patch
Simon Fraser (smfr)
Comment 36
2020-04-09 10:33:50 PDT
Comment on
attachment 395907
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=395907&action=review
> Source/WebCore/loader/cache/CachedResourceLoader.h:121 > + Vector<SVGImage*> allCachedSVGImages() const;
I think this should return Vector<Ref<SVGImage>>
> Source/WebCore/page/ChromeClient.h:319 > + virtual bool scheduleTimedRenderingUpdate() { return false; }
Why do we need to expose the "timed" version here?
> Source/WebCore/page/Page.cpp:1370 > + for (auto* image : document.cachedResourceLoader().allCachedSVGImages()) {
This becomes for (auto image : ...
> Source/WebCore/svg/graphics/SVGImage.h:72 > + Page* page() { return m_page.get(); }
Because this is so special, I would call it internalPage() or something. It's not the Page that the image lives in.
Said Abou-Hallawa
Comment 37
2020-04-09 12:03:43 PDT
Created
attachment 395986
[details]
Patch
Said Abou-Hallawa
Comment 38
2020-04-09 12:10:17 PDT
Comment on
attachment 395907
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=395907&action=review
>> Source/WebCore/loader/cache/CachedResourceLoader.h:121 >> + Vector<SVGImage*> allCachedSVGImages() const; > > I think this should return Vector<Ref<SVGImage>>
Done.
>> Source/WebCore/page/ChromeClient.h:319 >> + virtual bool scheduleTimedRenderingUpdate() { return false; } > > Why do we need to expose the "timed" version here?
Because the immediate scheduleRenderingUpdate() is used by RenderLayerCompositor. All the callers including the WebAnimation use scheduleTimedRenderingUpdate(). The immediate scheduling was implemented to fix many layout test flakiness where waiting for the next frame was producing incorrect results.
>> Source/WebCore/page/Page.cpp:1370 >> + for (auto* image : document.cachedResourceLoader().allCachedSVGImages()) { > > This becomes for (auto image : ...
But I had to make it for (auto& image : ... because Ref<SVGImage> can't be copied.
>> Source/WebCore/svg/graphics/SVGImage.h:72 >> + Page* page() { return m_page.get(); } > > Because this is so special, I would call it internalPage() or something. It's not the Page that the image lives in.
Done: page() => internalPage().
Said Abou-Hallawa
Comment 39
2020-04-09 12:22:51 PDT
Created
attachment 395988
[details]
Patch
EWS
Comment 40
2020-04-09 14:46:02 PDT
Committed
r259830
: <
https://trac.webkit.org/changeset/259830
> All reviewed patches have been landed. Closing bug and clearing flags on
attachment 395988
[details]
.
Said Abou-Hallawa
Comment 41
2020-05-18 20:12:09 PDT
***
Bug 211922
has been marked as a duplicate of this bug. ***
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug