Skip to content

Commit

Permalink
Fix a crash by PaintWorklet + custom property animation
Browse files Browse the repository at this point in the history
https://chromium-review.googlesource.com/c/chromium/src/+/2359370
The above CL made a custom property animation always composited if
it is used by paint worklet, even if the element does not have
"will-change: transform". The approach is that we give a special
ElementId which is uint64_t::max() to the paint worklet element,
and then on the CC side, once we see that element id, we know that
it is an animation associated with paint worklet and we will always
tick that animation.

The problem comes when there are two paint worklet elements.

The short version of the problem is:
CC's animation system doesn't allow two layers with the same
ElementId.

Longer version:
Then these two layers would have the same ElementId when
we try to attach a composited layer with that animation. As a
result, in the AnimationHost::RegisterAnimationForElement(), we
will have two Animation with the same ElementId. Then, the actual
crash happens at ElementAnimations::GetPropertyToElementIdMap(),
at the first DCHECK.

So the solution in this CL is to not DCHECK in certain cases.
The DCHECK actually doesn't make sense in this case where
there is no composited layer. In fact, the callers of the
ElementAnimations::GetPropertyToElementIdMap gives the result
to MutatorHostClient::ElementIsAnimatingChanged, and in there
it only cares about 4 properties. So for the other properties
that it doesn't care, we should not put it in the map.

Bug: 1151755
Change-Id: I5479ccae80f3c89db98d27518ef013dded527ece
  • Loading branch information
xidachen authored and chromium-wpt-export-bot committed Nov 25, 2020
1 parent 63e3b67 commit 6db55e2
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 0 deletions.
14 changes: 14 additions & 0 deletions css/css-paint-api/two-element-custom-property-animation-ref.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<body>
<canvas id ="canvas" width="200" height="400"></canvas>
<script>
var canvas = document.getElementById('canvas');
var context = canvas.getContext("2d");
context.fillStyle = 'green';
context.fillRect(0, 0, 100, 100);
context.fillStyle = 'rgb(128, 128, 0)';
context.fillRect(0, 200, 200, 200);
</script>
</body>
</html>
87 changes: 87 additions & 0 deletions css/css-paint-api/two-element-custom-property-animation.https.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<!DOCTYPE html>
<html class="reftest-wait">
<link rel="help" href="https://drafts.css-houdini.org/css-paint-api/">
<link rel="match" href="two-element-custom-property-animation-ref.html">
<style>
#footainer {
width: 200px;
height: 200px;
}
.fooanimate {
background-image: paint(foo);
animation: expand 5s;
}
#bartainer {
width: 200px;
height: 200px;
}
.baranimate {
background-image: paint(bar);
animation: colorChange 5s;
}
@keyframes expand {
0% { --foo: 0; }
0.01% { --foo: 100; }
99% { --foo: 100; }
100% { --foo: 200; }
}
@keyframes colorChange {
0% { --bar: rgb(255, 0, 0); }
0.01% { --bar: rgb(128, 128, 0); }
99% { --bar: rgb(128, 128, 0); }
100% { --bar: rgb(0, 255, 0); }
}
</style>
<script src="/common/reftest-wait.js"></script>
<script src="/common/worklet-reftest.js"></script>
<body>
<div id="footainer"></div>
<div id="bartainer"></div>

<script id="code" type="text/worklet">
registerPaint('foo', class {
static get inputProperties() { return ['--foo']; }
paint(ctx, geom, properties) {
let fooValue = parseFloat(properties.get('--foo').toString());
ctx.fillStyle = 'green';
ctx.fillRect(0, 0, fooValue, fooValue);
}
});

registerPaint('bar', class {
static get inputProperties() { return ['--bar']; }
paint(ctx, geom, properties) {
ctx.fillStyle = properties.get('--bar').toString();
ctx.fillRect(0, 0, 200, 200);
}
});
</script>

<script type="text/javascript">
CSS.registerProperty({
name: '--foo',
syntax: '<number>',
initialValue: '0',
inherits: false
});
CSS.registerProperty({
name: '--bar',
syntax: '<color>',
initialValue: 'rgb(0, 0, 0)',
inherits: false
});
</script>

<script>
var code = document.getElementById('code').textContent;
var blob = new Blob([code], {type: 'text/javascript'});
CSS.paintWorklet.addModule(URL.createObjectURL(blob)).then(function() {
document.getElementById('footainer').classList.add('fooanimate');
document.getElementById('bartainer').classList.add('baranimate');
requestAnimationFrame(function() {
takeScreenshot();
});
});
</script>
</body>
</html>

0 comments on commit 6db55e2

Please sign in to comment.