Collapse filling script-generated animations
Categories
(Core :: DOM: Animation, defect, P3)
Tracking
()
People
(Reporter: birtles, Assigned: birtles)
References
(Blocks 1 open bug)
Details
(Whiteboard: [layout:backlog:2019q3:69][wptsync upstream])
Attachments
(19 files, 3 obsolete files)
(deleted),
text/plain
|
Details | |
(deleted),
text/html
|
Details | |
(deleted),
image/png
|
Details | |
(deleted),
patch
|
Details | Diff | Splinter Review | |
(deleted),
text/x-phabricator-request
|
Details | |
(deleted),
text/x-phabricator-request
|
Details | |
(deleted),
text/x-phabricator-request
|
Details | |
(deleted),
text/x-phabricator-request
|
Details | |
(deleted),
text/x-phabricator-request
|
Details | |
(deleted),
text/x-phabricator-request
|
Details | |
(deleted),
text/x-phabricator-request
|
Details | |
(deleted),
text/x-phabricator-request
|
Details | |
(deleted),
text/x-phabricator-request
|
Details | |
(deleted),
text/x-phabricator-request
|
Details | |
(deleted),
text/x-phabricator-request
|
Details | |
(deleted),
text/x-phabricator-request
|
Details | |
(deleted),
patch
|
Details | Diff | Splinter Review | |
(deleted),
text/x-phabricator-request
|
Details | |
(deleted),
text/x-phabricator-request
|
Details |
Assignee | ||
Comment 1•9 years ago
|
||
Assignee | ||
Comment 2•9 years ago
|
||
Assignee | ||
Comment 3•8 years ago
|
||
Assignee | ||
Comment 5•7 years ago
|
||
Updated•6 years ago
|
Assignee | ||
Comment 6•6 years ago
|
||
Assignee | ||
Comment 7•6 years ago
|
||
Comment 8•6 years ago
|
||
Assignee | ||
Comment 9•6 years ago
|
||
Assignee | ||
Comment 10•6 years ago
|
||
Assignee | ||
Comment 11•6 years ago
|
||
Assignee | ||
Comment 12•6 years ago
|
||
Assignee | ||
Comment 13•6 years ago
|
||
Assignee | ||
Comment 14•6 years ago
|
||
Assignee | ||
Comment 15•6 years ago
|
||
Assignee | ||
Comment 16•6 years ago
|
||
Assignee | ||
Comment 17•6 years ago
|
||
Assignee | ||
Comment 18•6 years ago
|
||
Assignee | ||
Comment 19•6 years ago
|
||
Assignee | ||
Comment 20•6 years ago
|
||
Assignee | ||
Comment 21•6 years ago
|
||
Assignee | ||
Comment 22•6 years ago
|
||
Assignee | ||
Comment 23•6 years ago
|
||
Assignee | ||
Comment 24•6 years ago
|
||
Assignee | ||
Comment 25•6 years ago
|
||
Assignee | ||
Comment 26•6 years ago
|
||
Assignee | ||
Comment 27•6 years ago
|
||
Assignee | ||
Comment 28•6 years ago
|
||
Assignee | ||
Comment 29•6 years ago
|
||
Assignee | ||
Comment 30•6 years ago
|
||
Assignee | ||
Comment 31•6 years ago
|
||
Assignee | ||
Comment 32•6 years ago
|
||
Assignee | ||
Comment 33•6 years ago
|
||
Assignee | ||
Comment 34•6 years ago
|
||
Assignee | ||
Comment 35•6 years ago
|
||
Assignee | ||
Comment 36•6 years ago
|
||
Assignee | ||
Comment 37•6 years ago
|
||
Assignee | ||
Comment 38•6 years ago
|
||
Assignee | ||
Comment 39•6 years ago
|
||
Assignee | ||
Comment 40•6 years ago
|
||
Hi Boris, I could use some help working out how to approach expando properties in this bug. Specifically, the idea in this bug is that when we do:
const animations = elem.getAnimations();
for any adjacent animations that are filling indefinitely, we lump them together and generate a new FillAnimation
object to represent them. This allows us to internally coalesce these animations in some circumstances and avoid leaking memory.
The proposed spec text for this requires that each time we return a FillAnimation
representing the same set of underlying animations, it returns the same FillAnimation
object.
So, for example, the following should hold (assuming the first animation is a FillAnimation
):
elem.getAnimations()[0] === elem.getAnimations()[0];
(The reason for requiring the same object be returned is that that seems to be the most useful thing for authors. e.g. I expect DevTools might annotate these objects so that it knows which ones it is already rendering and can therefore do a minimal update.)
That said, we want to GC these FillAnimation
s when they're no longer being used so I am expecting to maintain a hashmap of weak pointers to these objects on the Document
, keyed on the set of animations they represent.
However, doing that would make GC observable if the author does:
elem.getAnimations()[0].expandoProp = 'yer';
// ... wait a while ...
const didGC = typeof elem.getAnimations()[0].expandoProp !== 'undefined';
So I am looking at adding another registry to the Document
for mutated FillAnimation
s that simply keeps an owning reference to such animations. FillAnimation
s would then add and remove themselves as their state changes. In order to do that, however, I'd need to detect when such objects have expando properties and when they don't. Ideally, I'd also need some way to detect when that state changes (or else find a suitable place in the GC cycle to check it).
Does that seem possible? I dug through some of the proxy code and users of OverrideBuiltins but I couldn't find anywhere else where we're doing this so I suspect I'm approaching this the wrong way.
Assignee | ||
Comment 41•6 years ago
|
||
I've basically finished implementing this now. There are only three remaining things to do:
- Deal with expando properties (waiting on ni for this).
I've already added a mechanism for preserving the life of FillAnimations that have event handlers etc. so hopefully this is just a matter of hooking into that. - Try making the generated
FillAnimation
s have zero duration so that they report theirplayState
as "finished" rather than "running". - Make DevTools render
FillAnimation
s.
All of those seem quite straightforward. I have the spec text ready (save possible modifications from part 2), web-platform-tests written, and all this work split up into 63 atomic patches that can be landed as four separate bugs (plus the DevTools work which likely needs to be interleaved).
The patch series is here:
https://hg.mozilla.org/try/pushloghtml?changeset=f9c12f30d64f
https://treeherder.mozilla.org/#/jobs?repo=try&revision=f9c12f30d64f6530682ea90ba3b5c3b425239c6d
However... this is still much more complex than I would like.
I've simplified the approach considerably from my initial design, but I'm still deeply concerned that it will make future maintenance more difficult. (I am especially thinking about the impact on implementing GroupEffect
s here since other browser vendors have shown an interest in that recently.)
I've attached the WIP patch so that others can get a feel for the complexity this introduces.
At this stage, the only other approach I think is feasible here is to introduce some hard limit to the number of filling animations in an effect stack (e.g. ~100 per element or something of that sort). Once you go over that limit, the filling animations at the bottom of the stack get automatically canceled.
Comment 42•6 years ago
|
||
The proposed spec text for this requires that each time we return a FillAnimation representing the same
set of underlying animations, it returns the same FillAnimation object.
OK, so it requires you to hold a strong reference to the FillAnimation object... That probably means you need to do that. If you don't want to do that, you might want to push back on the spec that requires it.
we want to GC these FillAnimations when they're no longer being used
Define "no longer being used"? For example, if they are used as weakmap keys, does that count as "used"? Because that would allow them to be gced if they're actually not referenced anywhere, but it sounds like the spec, as written, would require them to be kept alive if they're being used as weakmap keys, because that means they might get returned from this API.
There are probably other upcoming JS APIs (weakrefs, say) that would have similar issues.
One thing you could in theory do is keep strong refs to FillAnimations any time they preserve their wrapper (which means the C++ object is keeping the JS object alive, which we do in various cases like expandos, weakmaps, etc, when we don't want GC to be observable). But wrapper preservation is not really hookable right now; you can tell whether the wrapper is being preserved, but not when it enters that state. We could add yet another virtual call to that code, but that's not great either.
Fundamentally, this sounds like a spec that is going to be really hard to implement interoperably without just keeping the things alive. If it's assuming that they don't actually get kept alive and instead people do something that makes it look like they do, that's likely going to surface as interop bugs. :(
Assignee | ||
Comment 43•6 years ago
|
||
Thanks so much Boris. I only came across the weakref case this morning when looking at a similar issue regarding the Element.pseudo() interface.
Wrapper preservation is indeed the concept I'm looking for here but if there's no way to detect when that happens without significant perf impact this could be a lot more involved.
I'm the author of the proposed spec text and I have serious concerns about it being implemented at all. The spec itself doesn't say "you can GC FillAnimations when they're no longer being used" it's just that the whole feature is designed to allow UAs to avoid leaking memory so they will probably want to do so.
The rationale behind the approach is outlined in the FillAnimation proposal and while I think it's the best option we've considered so far for fixing a difficult problem, I'm more and more persuaded we should do something much simpler, even if it's a little less convenient for authors. Your feedback makes me even more inclined to pursue the simpler approach. Thank you again.
Comment 44•6 years ago
|
||
but if there's no way to detect when that happens without significant perf impact
Well. More precisely, the impact would need to be measured. Maybe it's just not an issue.
Assignee | ||
Comment 45•6 years ago
|
||
For posterity, I've put the patch series to implement the original FillAnimation proposal up on a GitHub branch:
https://github.com/birtles/gecko-dev/commits/fill-animation
It's about 63 patches long. It implements most of that proposal except the issues outline in comment 40 onwards regarding dealing with expando properties, weakrefs etc.
I'm currently working on a much simpler approach which I will put up for review if the spec PR gets merged.
Assignee | ||
Comment 46•6 years ago
|
||
Spec text for this has finally been approved:
https://github.com/w3c/csswg-drafts/commit/db06d5f1c532c20960efa33fae8d0ae869976dde
Assignee | ||
Comment 47•6 years ago
|
||
The in-class initializers are easier to maintain since you don't have to try and
match them up with the constructor initializer list (including matching the
order).
Assignee | ||
Comment 48•6 years ago
|
||
Animation::UpdateTiming takes a SyncNotifyFlag parameter. This is passed to
UpdateFinishedState where it determines how we handle finish actions.
If it is async we queue a microtask where we re-evaluate if the animation is
finished or not before queuing events / resolving promises.
That allows code like the following to not trigger finish events:
const animation = elem.animate({...}, 1000);
animation.currentTime += 1000;
animation.effect.updateTiming({ duration: 2000 });
(Since the check that the animation is finished will run in a microtask after
the call to updateTiming.)
When the flag is "sync" we still don't actually run the finish actions
entirely synchronously: the finished promise is resolved synchronously, but
resolving a promise actually queues a microtask for each callback. Likewise, the
finish event is queued synchronously, but not dispatched.
Since there should be no opportunity for script to run between when we call
Animation::Tick and when we run the next microtask checkpoint (currently at the
end of DocumentTimeline::WillRefresh but that will change slightly in the next
patch in this series) there is no need to introduce the extra "async" microtask
for re-evaluating an animation's finished state. Instead it should be possible
to use the "sync" finishing behavior. Such a change should be unobservable to
Web content but will reduce indirection somewhat.
Depends on D30317
Assignee | ||
Comment 49•6 years ago
|
||
According to the procedure to update animations and send events[1] the UA should
update all timelines first and then run a microtask checkpoint.
As a result, when we run callbacks for the finished promise on an Animation they
should see the fully up-to-date state of all animations, regardless of which
timeline they are attached to.
However, that is currently not the case since we run a microtask checkpoint
after updating each individual timeline.
This difference will become more significant later in this patch series when we
introduce another step--removing replaced animations--that also should happen
before we run the microtask checkpoint (so that the promise callbacks always see
a fully-up-to-date state).
This patch makes our handling a little more in line with the spec. It's not
quite the same because it's possible there may be other refresh driver observers
that trigger a microtask checkpoint in between ticking the different timelines
but that case is expected to be rare and fixing it would require maintaining
a separate queue for timeline observers that we run after all other observers--
so it is probably not necessary to fix that case at this stage.
The test added in this patch fails without the code changes in this patch.
[1] https://drafts.csswg.org/web-animations-1/#update-animations-and-send-events
Depends on D30318
Assignee | ||
Comment 50•6 years ago
|
||
Later in this patch series we will add a HashSet<OwningAnimationTarget> member
to EffectCompositor. This patch provides the necessary definitions to support
that.
Depends on D30319
Assignee | ||
Comment 51•6 years ago
|
||
Depends on D30320
Assignee | ||
Comment 52•6 years ago
|
||
This patch introduces the machinery for dispatching remove events but does not
actually cause removing to do anything to the output of the animation beyond
updating its replaceState member.
The expected behavior is defined in:
https://drafts.csswg.org/web-animations-1/#removing-replaced-animations
And the corresponding IDL members are defined in:
https://drafts.csswg.org/web-animations-1/#animation
https://drafts.csswg.org/web-animations-1/#enumdef-animationreplacestate
Tests for these events are added in the next patch in this series.
Depends on D30321
Assignee | ||
Comment 53•6 years ago
|
||
Depends on D30322
Assignee | ||
Comment 54•6 years ago
|
||
Depends on D30323
Assignee | ||
Comment 55•6 years ago
|
||
https://drafts.csswg.org/web-animations-1/#dom-animation-persist
Depends on D30324
Assignee | ||
Comment 56•6 years ago
|
||
And update the GitHub issue link at the same time since #3947 was duped to
#1837.
Depends on D30325
Assignee | ||
Comment 57•6 years ago
|
||
Depends on D30326
Assignee | ||
Comment 58•6 years ago
|
||
Depends on D30327
Assignee | ||
Comment 59•6 years ago
|
||
After discussion with Apple and Google, we decided to drop the properties
parameter to commitStyles
that allows the author to select which properties to commit. For posterity, here is a patch for implementing that.
Assignee | ||
Comment 60•6 years ago
|
||
Sorry for all the phabricator spam. Due to bug 1549614 we're getting a bunch of bogus coverity spam and each time I update the queue it seems to run again. (The clang-format warnings are legitimate however -- that's due to me disabling the auto-format plugin when it started eating patches a few weeks back.)
Assignee | ||
Comment 61•6 years ago
|
||
Updated•6 years ago
|
Assignee | ||
Comment 62•6 years ago
|
||
Depends on D30327
Updated•6 years ago
|
Updated•6 years ago
|
Updated•6 years ago
|
Comment 63•6 years ago
|
||
Comment 66•6 years ago
|
||
bugherder |
https://hg.mozilla.org/mozilla-central/rev/6e5b24c61e3a
https://hg.mozilla.org/mozilla-central/rev/861caf0b6714
https://hg.mozilla.org/mozilla-central/rev/0e25f7b0790b
https://hg.mozilla.org/mozilla-central/rev/a80ca3b22049
https://hg.mozilla.org/mozilla-central/rev/f0273e033938
https://hg.mozilla.org/mozilla-central/rev/8642d6a60ad9
https://hg.mozilla.org/mozilla-central/rev/25238a996da4
https://hg.mozilla.org/mozilla-central/rev/d540c77bd298
https://hg.mozilla.org/mozilla-central/rev/16dbeeceab38
https://hg.mozilla.org/mozilla-central/rev/b74b84baf717
https://hg.mozilla.org/mozilla-central/rev/180d65431190
https://hg.mozilla.org/mozilla-central/rev/f26b8ea63ae3
https://hg.mozilla.org/mozilla-central/rev/26b7854271e1
https://hg.mozilla.org/mozilla-central/rev/df36c132c6b0
Updated•5 years ago
|
Description
•