Commit 8454c40e authored by George Steel's avatar George Steel Committed by Commit Bot

Invalidate compositor transform animations with percents on box size.

When looping over transform animations in UpdateTransform, originally to
check whether they preserve axis alignment, we also check for box size
box size dependencies. If such dependencies are found, check whether the
relevant sizes have changed (using a current value stored in the
KeyframeEffect), and if so, restart the animation on the compositor
(note that RestartAnimationOnCompositor is a no-op if the animation is
not already composited).

This makes composited relative transform keyframes (implemented behind a
flag) fully working for CSS boxes, which could potentially be selectively
enabled ahead of doing so for SVG.

Design doc: https://docs.google.com/document/d/1zgr5CHRMpvlqodn1e0eM9J3MjL2eEMfAHrHsZUK7gMM/

Bug: 389359
Change-Id: I9b8189a3f3e002902b5eec58c08bb54644039536
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2492893
Commit-Queue: George Steel <gtsteel@chromium.org>
Reviewed-by: default avatarKevin Ellis <kevers@chromium.org>
Reviewed-by: default avatarXianzhu Wang <wangxianzhu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#820296}
parent 84cc8ac5
......@@ -136,15 +136,17 @@ void ElementAnimations::ClearBaseComputedStyle() {
base_important_set_ = nullptr;
}
bool ElementAnimations::AnimationsPreserveAxisAlignment() const {
for (const auto& entry : animations_) {
const Animation& animation = *entry.key;
if (const auto* effect = DynamicTo<KeyframeEffect>(animation.effect())) {
if (!effect->AnimationsPreserveAxisAlignment())
return false;
bool ElementAnimations::UpdateBoxSizeAndCheckTransformAxisAlignment(
const FloatSize& box_size) {
bool preserves_axis_alignment = true;
for (auto& entry : animations_) {
Animation& animation = *entry.key;
if (auto* effect = DynamicTo<KeyframeEffect>(animation.effect())) {
if (!effect->UpdateBoxSizeAndCheckTransformAxisAlignment(box_size))
preserves_axis_alignment = false;
}
}
return true;
return preserves_axis_alignment;
}
} // namespace blink
......@@ -88,7 +88,7 @@ class CORE_EXPORT ElementAnimations final
std::unique_ptr<CSSBitset> base_important_set);
void ClearBaseComputedStyle();
bool AnimationsPreserveAxisAlignment() const;
bool UpdateBoxSizeAndCheckTransformAxisAlignment(const FloatSize& box_size);
void Trace(Visitor*) const;
......
......@@ -456,24 +456,6 @@ void KeyframeEffect::Trace(Visitor* visitor) const {
AnimationEffect::Trace(visitor);
}
bool KeyframeEffect::AnimationsPreserveAxisAlignment(
const PropertyHandle& property) const {
const auto* keyframes = Model()->GetPropertySpecificKeyframes(property);
if (!keyframes)
return true;
for (const auto& keyframe : *keyframes) {
const auto* value = keyframe->GetCompositorKeyframeValue();
if (!value)
continue;
DCHECK(value->IsTransform());
const auto& transform_operations =
To<CompositorKeyframeTransform>(value)->GetTransformOperations();
if (!transform_operations.PreservesAxisAlignment())
return false;
}
return true;
}
namespace {
static const size_t num_transform_properties = 4;
......@@ -487,14 +469,52 @@ const CSSProperty** TransformProperties() {
} // namespace
bool KeyframeEffect::AnimationsPreserveAxisAlignment() const {
bool KeyframeEffect::UpdateBoxSizeAndCheckTransformAxisAlignment(
const FloatSize& box_size) {
static const auto** properties = TransformProperties();
bool preserves_axis_alignment = true;
bool has_transform = false;
TransformOperation::BoxSizeDependency size_dependencies =
TransformOperation::kDependsNone;
for (size_t i = 0; i < num_transform_properties; i++) {
if (!AnimationsPreserveAxisAlignment(PropertyHandle(*properties[i])))
return false;
const auto* keyframes =
Model()->GetPropertySpecificKeyframes(PropertyHandle(*properties[i]));
if (!keyframes)
continue;
has_transform = true;
for (const auto& keyframe : *keyframes) {
const auto* value = keyframe->GetCompositorKeyframeValue();
if (!value)
continue;
const auto& transform_operations =
To<CompositorKeyframeTransform>(value)->GetTransformOperations();
if (!transform_operations.PreservesAxisAlignment())
preserves_axis_alignment = false;
size_dependencies = TransformOperation::CombineDependencies(
size_dependencies, transform_operations.BoxSizeDependencies());
}
}
return true;
if (!has_transform)
return true;
if (HasAnimation()) {
if (effect_target_size_) {
if ((size_dependencies & TransformOperation::kDependsWidth) &&
(effect_target_size_->Width() != box_size.Width()))
GetAnimation()->RestartAnimationOnCompositor();
else if ((size_dependencies & TransformOperation::kDependsHeight) &&
(effect_target_size_->Width() != box_size.Height()))
GetAnimation()->RestartAnimationOnCompositor();
} else if (size_dependencies) {
GetAnimation()->RestartAnimationOnCompositor();
}
}
effect_target_size_ = box_size;
return preserves_axis_alignment;
}
EffectModel::CompositeOperation KeyframeEffect::CompositeInternal() const {
......
......@@ -31,11 +31,13 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_KEYFRAME_EFFECT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_KEYFRAME_EFFECT_H_
#include "base/optional.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/core/animation/animation_effect.h"
#include "third_party/blink/renderer/core/animation/compositor_animations.h"
#include "third_party/blink/renderer/core/animation/keyframe_effect_model.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/geometry/float_size.h"
namespace blink {
......@@ -133,7 +135,7 @@ class CORE_EXPORT KeyframeEffect final : public AnimationEffect {
void Trace(Visitor*) const override;
bool AnimationsPreserveAxisAlignment() const;
bool UpdateBoxSizeAndCheckTransformAxisAlignment(const FloatSize& box_size);
ActiveInterpolationsMap InterpolationsForCommitStyles();
......@@ -164,8 +166,6 @@ class CORE_EXPORT KeyframeEffect final : public AnimationEffect {
bool HasIncompatibleStyle() const;
bool HasMultipleTransformProperties() const;
bool AnimationsPreserveAxisAlignment(const PropertyHandle&) const;
Member<Element> effect_target_;
Member<Element> target_element_;
String target_pseudo_;
......@@ -177,6 +177,8 @@ class CORE_EXPORT KeyframeEffect final : public AnimationEffect {
Vector<int> compositor_keyframe_model_ids_;
bool ignore_css_keyframes_;
base::Optional<FloatSize> effect_target_size_;
};
template <>
......
......@@ -500,25 +500,27 @@ TEST_F(KeyframeEffectTest, TranslationTransformsPreserveAxisAlignment) {
auto* effect =
GetTwoFrameEffect(CSSPropertyID::kTransform, "translate(10px, 10px)",
"translate(20px, 20px)");
EXPECT_TRUE(effect->AnimationsPreserveAxisAlignment());
EXPECT_TRUE(effect->UpdateBoxSizeAndCheckTransformAxisAlignment(FloatSize()));
}
TEST_F(KeyframeEffectTest, ScaleTransformsPreserveAxisAlignment) {
auto* effect =
GetTwoFrameEffect(CSSPropertyID::kTransform, "scale(2)", "scale(3)");
EXPECT_TRUE(effect->AnimationsPreserveAxisAlignment());
EXPECT_TRUE(effect->UpdateBoxSizeAndCheckTransformAxisAlignment(FloatSize()));
}
TEST_F(KeyframeEffectTest, RotationTransformsDoNotPreserveAxisAlignment) {
auto* effect = GetTwoFrameEffect(CSSPropertyID::kTransform, "rotate(10deg)",
"rotate(20deg)");
EXPECT_FALSE(effect->AnimationsPreserveAxisAlignment());
EXPECT_FALSE(
effect->UpdateBoxSizeAndCheckTransformAxisAlignment(FloatSize()));
}
TEST_F(KeyframeEffectTest, RotationsDoNotPreserveAxisAlignment) {
auto* effect = GetTwoFrameEffect(CSSPropertyID::kRotate, "10deg", "20deg");
EXPECT_FALSE(effect->AnimationsPreserveAxisAlignment());
EXPECT_FALSE(
effect->UpdateBoxSizeAndCheckTransformAxisAlignment(FloatSize()));
}
} // namespace blink
......@@ -844,8 +844,8 @@ static bool NeedsTransform(const LayoutObject& object,
return false;
}
static bool ActiveTransformAnimationIsAxisAligned(
const LayoutObject& object,
static bool UpdateBoxSizeAndCheckActiveAnimationAxisAlignment(
const LayoutBox& object,
CompositingReasons compositing_reasons) {
if (!(compositing_reasons & CompositingReason::kActiveTransformAnimation))
return false;
......@@ -853,9 +853,10 @@ static bool ActiveTransformAnimationIsAxisAligned(
if (!object.GetNode() || !object.GetNode()->IsElementNode())
return false;
const Element* element = To<Element>(object.GetNode());
const auto* animations = element->GetElementAnimations();
auto* animations = element->GetElementAnimations();
DCHECK(animations);
return animations->AnimationsPreserveAxisAlignment();
return animations->UpdateBoxSizeAndCheckTransformAxisAlignment(
FloatSize(object.Size()));
}
void FragmentPaintPropertyTreeBuilder::UpdateTransform() {
......@@ -912,8 +913,8 @@ void FragmentPaintPropertyTreeBuilder::UpdateTransform() {
// calculate most of the compositable animation reasons up front to
// only consider animations which are candidates for compositing.
state.flags.animation_is_axis_aligned =
ActiveTransformAnimationIsAxisAligned(
object_, full_context_.direct_compositing_reasons);
UpdateBoxSizeAndCheckActiveAnimationAxisAlignment(
box, full_context_.direct_compositing_reasons);
}
state.direct_compositing_reasons =
......
......@@ -6355,12 +6355,7 @@ crbug.com/1083605 media/controls-styling-strict.html [ Pass Failure ]
# Transform animation reftests
crbug.com/1133901 virtual/threaded/external/wpt/css/css-transforms/animation/transform-interpolation-translate-em.html [ Failure ]
# Composited Transform animations WIP:
# Existing failure
crbug.com/1133901 virtual/composite-relative-keyframes/external/wpt/css/css-transforms/animation/transform-interpolation-translate-em.html [ Failure ]
# Failures from incomplete implementation
crbug.com/389359 virtual/composite-relative-keyframes/external/wpt/css/css-transforms/animation/transform-interpolation-translate.html [ Failure ]
crbug.com/1136163 [ Linux ] external/wpt/pointerevents/pointerlock/pointerevent_movementxy_with_pointerlock.html [ Failure ]
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment