1 /*
2 * Copyright (c) 2013, Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "third_party/blink/renderer/core/animation/compositor_animations.h"
32
33 #include <limits>
34 #include <memory>
35 #include <utility>
36
37 #include "base/memory/ptr_util.h"
38 #include "base/memory/scoped_refptr.h"
39 #include "cc/animation/animation_host.h"
40 #include "cc/layers/picture_layer.h"
41 #include "cc/trees/transform_node.h"
42 #include "testing/gtest/include/gtest/gtest.h"
43 #include "third_party/blink/public/web/web_settings.h"
44 #include "third_party/blink/renderer/core/animation/animation.h"
45 #include "third_party/blink/renderer/core/animation/css/compositor_keyframe_double.h"
46 #include "third_party/blink/renderer/core/animation/document_timeline.h"
47 #include "third_party/blink/renderer/core/animation/element_animations.h"
48 #include "third_party/blink/renderer/core/animation/keyframe_effect.h"
49 #include "third_party/blink/renderer/core/animation/pending_animations.h"
50 #include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
51 #include "third_party/blink/renderer/core/css/css_paint_value.h"
52 #include "third_party/blink/renderer/core/css/css_syntax_definition.h"
53 #include "third_party/blink/renderer/core/css/css_test_helpers.h"
54 #include "third_party/blink/renderer/core/css/mock_css_paint_image_generator.h"
55 #include "third_party/blink/renderer/core/dom/document.h"
56 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
57 #include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
58 #include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
59 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
60 #include "third_party/blink/renderer/core/layout/layout_object.h"
61 #include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
62 #include "third_party/blink/renderer/core/paint/object_paint_properties.h"
63 #include "third_party/blink/renderer/core/paint/paint_layer.h"
64 #include "third_party/blink/renderer/core/style/computed_style.h"
65 #include "third_party/blink/renderer/core/style/filter_operations.h"
66 #include "third_party/blink/renderer/core/style/style_generated_image.h"
67 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
68 #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
69 #include "third_party/blink/renderer/platform/animation/compositor_color_animation_curve.h"
70 #include "third_party/blink/renderer/platform/animation/compositor_float_animation_curve.h"
71 #include "third_party/blink/renderer/platform/animation/compositor_float_keyframe.h"
72 #include "third_party/blink/renderer/platform/animation/compositor_keyframe_model.h"
73 #include "third_party/blink/renderer/platform/geometry/float_box.h"
74 #include "third_party/blink/renderer/platform/geometry/int_size.h"
75 #include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
76 #include "third_party/blink/renderer/platform/heap/heap.h"
77 #include "third_party/blink/renderer/platform/testing/histogram_tester.h"
78 #include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
79 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
80 #include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
81 #include "third_party/blink/renderer/platform/transforms/transform_operations.h"
82 #include "third_party/blink/renderer/platform/transforms/translate_transform_operation.h"
83 #include "third_party/blink/renderer/platform/wtf/hash_functions.h"
84 #include "third_party/skia/include/core/SkColor.h"
85
86 using testing::_;
87 using testing::NiceMock;
88 using testing::Return;
89 using testing::ReturnRef;
90 using testing::Values;
91
92 namespace blink {
93
94 namespace {
95 // CSSPaintImageGenerator requires that CSSPaintImageGeneratorCreateFunction be
96 // a static method. As such, it cannot access a class member and so instead we
97 // store a pointer to the overriding generator globally.
98 MockCSSPaintImageGenerator* g_override_generator = nullptr;
ProvideOverrideGenerator(const String &,const Document &,CSSPaintImageGenerator::Observer *)99 CSSPaintImageGenerator* ProvideOverrideGenerator(
100 const String&,
101 const Document&,
102 CSSPaintImageGenerator::Observer*) {
103 return g_override_generator;
104 }
105 } // namespace
106
107 using css_test_helpers::RegisterProperty;
108
109 class AnimationCompositorAnimationsTest : public PaintTestConfigurations,
110 public RenderingTest {
111 protected:
112 scoped_refptr<TimingFunction> linear_timing_function_;
113 scoped_refptr<TimingFunction> cubic_ease_timing_function_;
114 scoped_refptr<TimingFunction> cubic_custom_timing_function_;
115 scoped_refptr<TimingFunction> step_timing_function_;
116
117 Timing timing_;
118 CompositorAnimations::CompositorTiming compositor_timing_;
119 Persistent<HeapVector<Member<StringKeyframe>>> keyframe_vector2_;
120 Persistent<StringKeyframeEffectModel> keyframe_animation_effect2_;
121 Persistent<HeapVector<Member<StringKeyframe>>> keyframe_vector5_;
122 Persistent<StringKeyframeEffectModel> keyframe_animation_effect5_;
123
124 Persistent<Element> element_;
125 Persistent<Element> inline_;
126 Persistent<DocumentTimeline> timeline_;
127
SetUp()128 void SetUp() override {
129 EnableCompositing();
130 RenderingTest::SetUp();
131 linear_timing_function_ = LinearTimingFunction::Shared();
132 cubic_ease_timing_function_ = CubicBezierTimingFunction::Preset(
133 CubicBezierTimingFunction::EaseType::EASE);
134 cubic_custom_timing_function_ =
135 CubicBezierTimingFunction::Create(1, 2, 3, 4);
136 step_timing_function_ =
137 StepsTimingFunction::Create(1, StepsTimingFunction::StepPosition::END);
138
139 timing_ = CreateCompositableTiming();
140 compositor_timing_ = CompositorAnimations::CompositorTiming();
141 // Make sure the CompositableTiming is really compositable, otherwise
142 // most other tests will fail.
143 ASSERT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
144
145 keyframe_vector2_ = CreateCompositableFloatKeyframeVector(2);
146 keyframe_animation_effect2_ =
147 MakeGarbageCollected<StringKeyframeEffectModel>(*keyframe_vector2_);
148
149 keyframe_vector5_ = CreateCompositableFloatKeyframeVector(5);
150 keyframe_animation_effect5_ =
151 MakeGarbageCollected<StringKeyframeEffectModel>(*keyframe_vector5_);
152
153 GetAnimationClock().ResetTimeForTesting();
154
155 timeline_ = GetDocument().Timeline();
156 timeline_->ResetForTesting();
157
158 // Using will-change ensures that this object will need paint properties.
159 // Having an animation would normally ensure this but these tests don't
160 // explicitly construct a full animation on the element.
161 SetBodyInnerHTML(R"HTML(
162 <div id='test' style='will-change: opacity,filter,transform; height:100px; background: green;'></div>
163 <span id='inline' style='will-change: opacity,filter,transform;'>text</div>
164 )HTML");
165 element_ = GetDocument().getElementById("test");
166 inline_ = GetDocument().getElementById("inline");
167
168 helper_.Initialize(nullptr, nullptr, nullptr);
169 base_url_ = "http://www.test.com/";
170 }
171
172 public:
ConvertTimingForCompositor(const Timing & t,CompositorAnimations::CompositorTiming & out)173 bool ConvertTimingForCompositor(const Timing& t,
174 CompositorAnimations::CompositorTiming& out) {
175 return CompositorAnimations::ConvertTimingForCompositor(
176 t, base::TimeDelta(), out, 1);
177 }
178
CanStartEffectOnCompositor(const Timing & timing,const KeyframeEffectModelBase & effect)179 CompositorAnimations::FailureReasons CanStartEffectOnCompositor(
180 const Timing& timing,
181 const KeyframeEffectModelBase& effect) {
182 // TODO(crbug.com/725385): Remove once compositor uses InterpolationTypes.
183 auto style = GetDocument().EnsureStyleResolver().StyleForElement(element_);
184 effect.SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(), *style,
185 nullptr);
186 return CheckCanStartEffectOnCompositor(timing, *element_.Get(), nullptr,
187 effect);
188 }
CheckCanStartEffectOnCompositor(const Timing & timing,const Element & element,const Animation * animation,const EffectModel & effect_model)189 CompositorAnimations::FailureReasons CheckCanStartEffectOnCompositor(
190 const Timing& timing,
191 const Element& element,
192 const Animation* animation,
193 const EffectModel& effect_model) {
194 const PaintArtifactCompositor* paint_artifact_compositor =
195 GetDocument().View()->GetPaintArtifactCompositor();
196 return CompositorAnimations::CheckCanStartEffectOnCompositor(
197 timing, element, animation, effect_model, paint_artifact_compositor, 1);
198 }
199
CheckCanStartElementOnCompositor(const Element & element)200 CompositorAnimations::FailureReasons CheckCanStartElementOnCompositor(
201 const Element& element) {
202 return CompositorAnimations::CheckCanStartElementOnCompositor(element);
203 }
204
GetAnimationOnCompositor(Timing & timing,StringKeyframeEffectModel & effect,Vector<std::unique_ptr<CompositorKeyframeModel>> & keyframe_models,double animation_playback_rate)205 void GetAnimationOnCompositor(
206 Timing& timing,
207 StringKeyframeEffectModel& effect,
208 Vector<std::unique_ptr<CompositorKeyframeModel>>& keyframe_models,
209 double animation_playback_rate) {
210 CompositorAnimations::GetAnimationOnCompositor(
211 *element_, timing, 0, base::nullopt, base::TimeDelta(), effect,
212 keyframe_models, animation_playback_rate);
213 }
214
215 CompositorAnimations::FailureReasons
DuplicateSingleKeyframeAndTestIsCandidateOnResult(StringKeyframe * frame)216 DuplicateSingleKeyframeAndTestIsCandidateOnResult(StringKeyframe* frame) {
217 EXPECT_EQ(frame->CheckedOffset(), 0);
218 StringKeyframeVector frames;
219 Keyframe* second = frame->CloneWithOffset(1);
220
221 frames.push_back(frame);
222 frames.push_back(To<StringKeyframe>(second));
223 return CanStartEffectOnCompositor(
224 timing_, *MakeGarbageCollected<StringKeyframeEffectModel>(frames));
225 }
226
227 // -------------------------------------------------------------------
228
CreateCompositableTiming()229 Timing CreateCompositableTiming() {
230 Timing timing;
231 timing.start_delay = 0;
232 timing.fill_mode = Timing::FillMode::NONE;
233 timing.iteration_start = 0;
234 timing.iteration_count = 1;
235 timing.iteration_duration = AnimationTimeDelta::FromSecondsD(1);
236 timing.direction = Timing::PlaybackDirection::NORMAL;
237 timing.timing_function = linear_timing_function_;
238 return timing;
239 }
240
CreateReplaceOpKeyframe(CSSPropertyID id,const String & value,double offset=0)241 StringKeyframe* CreateReplaceOpKeyframe(CSSPropertyID id,
242 const String& value,
243 double offset = 0) {
244 auto* keyframe = MakeGarbageCollected<StringKeyframe>();
245 keyframe->SetCSSPropertyValue(id, value,
246 SecureContextMode::kInsecureContext, nullptr);
247 keyframe->SetComposite(EffectModel::kCompositeReplace);
248 keyframe->SetOffset(offset);
249 keyframe->SetEasing(LinearTimingFunction::Shared());
250 return keyframe;
251 }
252
CreateReplaceOpKeyframe(const String & property_name,const String & value,double offset=0)253 StringKeyframe* CreateReplaceOpKeyframe(const String& property_name,
254 const String& value,
255 double offset = 0) {
256 auto* keyframe = MakeGarbageCollected<StringKeyframe>();
257 keyframe->SetCSSPropertyValue(AtomicString(property_name), value,
258 GetDocument().GetSecureContextMode(),
259 GetDocument().ElementSheet().Contents());
260 keyframe->SetComposite(EffectModel::kCompositeReplace);
261 keyframe->SetOffset(offset);
262 keyframe->SetEasing(LinearTimingFunction::Shared());
263 return keyframe;
264 }
265
CreateDefaultKeyframe(CSSPropertyID id,EffectModel::CompositeOperation op,double offset=0)266 StringKeyframe* CreateDefaultKeyframe(CSSPropertyID id,
267 EffectModel::CompositeOperation op,
268 double offset = 0) {
269 String value = "0.1";
270 if (id == CSSPropertyID::kTransform)
271 value = "none";
272 else if (id == CSSPropertyID::kColor)
273 value = "red";
274
275 StringKeyframe* keyframe = CreateReplaceOpKeyframe(id, value, offset);
276 keyframe->SetComposite(op);
277 return keyframe;
278 }
279
CreateCompositableFloatKeyframeVector(size_t n)280 HeapVector<Member<StringKeyframe>>* CreateCompositableFloatKeyframeVector(
281 size_t n) {
282 Vector<double> values;
283 for (size_t i = 0; i < n; i++) {
284 values.push_back(static_cast<double>(i));
285 }
286 return CreateCompositableFloatKeyframeVector(values);
287 }
288
CreateCompositableFloatKeyframeVector(Vector<double> & values)289 HeapVector<Member<StringKeyframe>>* CreateCompositableFloatKeyframeVector(
290 Vector<double>& values) {
291 HeapVector<Member<StringKeyframe>>* frames =
292 MakeGarbageCollected<HeapVector<Member<StringKeyframe>>>();
293 for (wtf_size_t i = 0; i < values.size(); i++) {
294 double offset = 1.0 / (values.size() - 1) * i;
295 String value = String::Number(values[i]);
296 frames->push_back(
297 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, value, offset));
298 }
299 return frames;
300 }
301
SetCustomProperty(const String & name,const String & value)302 void SetCustomProperty(const String& name, const String& value) {
303 DummyExceptionStateForTesting exception_state;
304 element_->style()->setProperty(GetDocument().GetExecutionContext(), name,
305 value, g_empty_string, exception_state);
306 EXPECT_FALSE(exception_state.HadException());
307 EXPECT_TRUE(element_->style()->getPropertyValue(name));
308 }
309
310 // This class exists to dodge the interlock between creating compositor
311 // keyframe values iff we can animate them on the compositor, and hence can
312 // start their animations on it. i.e. two far away switch statements have
313 // matching non-default values, preventing us from testing the default.
314 class MockStringKeyframe : public StringKeyframe {
315 public:
Create(double offset)316 static StringKeyframe* Create(double offset) {
317 return MakeGarbageCollected<MockStringKeyframe>(offset);
318 }
319
MockStringKeyframe(double offset)320 MockStringKeyframe(double offset)
321 : StringKeyframe(),
322 property_specific_(
323 MakeGarbageCollected<MockPropertySpecificStringKeyframe>(
324 offset)) {
325 SetOffset(offset);
326 }
327
CreatePropertySpecificKeyframe(const PropertyHandle &,EffectModel::CompositeOperation,double) const328 Keyframe::PropertySpecificKeyframe* CreatePropertySpecificKeyframe(
329 const PropertyHandle&,
330 EffectModel::CompositeOperation,
331 double) const final {
332 return property_specific_; // We know a shortcut.
333 }
334
Trace(Visitor * visitor)335 void Trace(Visitor* visitor) override {
336 visitor->Trace(property_specific_);
337 StringKeyframe::Trace(visitor);
338 }
339
340 private:
341 class MockPropertySpecificStringKeyframe : public PropertySpecificKeyframe {
342 public:
343 // Pretend to have a compositor keyframe value. Pick the offset for pure
344 // convenience: it matters not what it is.
MockPropertySpecificStringKeyframe(double offset)345 MockPropertySpecificStringKeyframe(double offset)
346 : PropertySpecificKeyframe(offset,
347 LinearTimingFunction::Shared(),
348 EffectModel::kCompositeReplace),
349 compositor_keyframe_value_(
350 MakeGarbageCollected<CompositorKeyframeDouble>(offset)) {}
IsNeutral() const351 bool IsNeutral() const final { return true; }
CloneWithOffset(double) const352 PropertySpecificKeyframe* CloneWithOffset(double) const final {
353 NOTREACHED();
354 return nullptr;
355 }
PopulateCompositorKeyframeValue(const PropertyHandle &,Element &,const ComputedStyle & base_style,const ComputedStyle * parent_style) const356 bool PopulateCompositorKeyframeValue(
357 const PropertyHandle&,
358 Element&,
359 const ComputedStyle& base_style,
360 const ComputedStyle* parent_style) const final {
361 return true;
362 }
GetCompositorKeyframeValue() const363 const CompositorKeyframeValue* GetCompositorKeyframeValue() const final {
364 return compositor_keyframe_value_;
365 }
NeutralKeyframe(double,scoped_refptr<TimingFunction>) const366 PropertySpecificKeyframe* NeutralKeyframe(
367 double,
368 scoped_refptr<TimingFunction>) const final {
369 NOTREACHED();
370 return nullptr;
371 }
372
Trace(Visitor * visitor)373 void Trace(Visitor* visitor) override {
374 visitor->Trace(compositor_keyframe_value_);
375 PropertySpecificKeyframe::Trace(visitor);
376 }
377
378 private:
379 Member<CompositorKeyframeDouble> compositor_keyframe_value_;
380 };
381
382 Member<PropertySpecificKeyframe> property_specific_;
383 };
384
CreateMockReplaceKeyframe(CSSPropertyID id,const String & value,double offset)385 StringKeyframe* CreateMockReplaceKeyframe(CSSPropertyID id,
386 const String& value,
387 double offset) {
388 StringKeyframe* keyframe = MockStringKeyframe::Create(offset);
389 keyframe->SetCSSPropertyValue(id, value,
390 SecureContextMode::kInsecureContext, nullptr);
391 keyframe->SetComposite(EffectModel::kCompositeReplace);
392 keyframe->SetEasing(LinearTimingFunction::Shared());
393
394 return keyframe;
395 }
396
CreateSVGKeyframe(const QualifiedName & name,const String & value,double offset)397 StringKeyframe* CreateSVGKeyframe(const QualifiedName& name,
398 const String& value,
399 double offset) {
400 auto* keyframe = MakeGarbageCollected<StringKeyframe>();
401 keyframe->SetSVGAttributeValue(name, value);
402 keyframe->SetComposite(EffectModel::kCompositeReplace);
403 keyframe->SetOffset(offset);
404 keyframe->SetEasing(LinearTimingFunction::Shared());
405
406 return keyframe;
407 }
408
CreateKeyframeEffectModel(StringKeyframe * from,StringKeyframe * to,StringKeyframe * c=nullptr,StringKeyframe * d=nullptr)409 StringKeyframeEffectModel* CreateKeyframeEffectModel(
410 StringKeyframe* from,
411 StringKeyframe* to,
412 StringKeyframe* c = nullptr,
413 StringKeyframe* d = nullptr) {
414 EXPECT_EQ(from->CheckedOffset(), 0);
415 StringKeyframeVector frames;
416 frames.push_back(from);
417 EXPECT_LE(from->Offset(), to->Offset());
418 frames.push_back(to);
419 if (c) {
420 EXPECT_LE(to->Offset(), c->Offset());
421 frames.push_back(c);
422 }
423 if (d) {
424 frames.push_back(d);
425 EXPECT_LE(c->Offset(), d->Offset());
426 EXPECT_EQ(d->CheckedOffset(), 1.0);
427 } else {
428 EXPECT_EQ(to->CheckedOffset(), 1.0);
429 }
430 if (!HasFatalFailure()) {
431 return MakeGarbageCollected<StringKeyframeEffectModel>(frames);
432 }
433 return nullptr;
434 }
435
SimulateFrame(double time)436 void SimulateFrame(double time) {
437 GetAnimationClock().UpdateTime(base::TimeTicks() +
438 base::TimeDelta::FromSecondsD(time));
439 GetPendingAnimations().Update(nullptr, false);
440 timeline_->ServiceAnimations(kTimingUpdateForAnimationFrame);
441 }
442
ConvertToCompositorAnimation(StringKeyframeEffectModel & effect,double animation_playback_rate)443 std::unique_ptr<CompositorKeyframeModel> ConvertToCompositorAnimation(
444 StringKeyframeEffectModel& effect,
445 double animation_playback_rate) {
446 // As the compositor code only understands CompositorKeyframeValues, we must
447 // snapshot the effect to make those available.
448 // TODO(crbug.com/725385): Remove once compositor uses InterpolationTypes.
449 auto style = GetDocument().EnsureStyleResolver().StyleForElement(element_);
450 effect.SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(), *style,
451 nullptr);
452
453 Vector<std::unique_ptr<CompositorKeyframeModel>> result;
454 GetAnimationOnCompositor(timing_, effect, result, animation_playback_rate);
455 DCHECK_EQ(1U, result.size());
456 return std::move(result[0]);
457 }
458
ConvertToCompositorAnimation(StringKeyframeEffectModel & effect)459 std::unique_ptr<CompositorKeyframeModel> ConvertToCompositorAnimation(
460 StringKeyframeEffectModel& effect) {
461 return ConvertToCompositorAnimation(effect, 1.0);
462 }
463
ExpectKeyframeTimingFunctionCubic(const CompositorFloatKeyframe & keyframe,const CubicBezierTimingFunction::EaseType ease_type)464 void ExpectKeyframeTimingFunctionCubic(
465 const CompositorFloatKeyframe& keyframe,
466 const CubicBezierTimingFunction::EaseType ease_type) {
467 auto keyframe_timing_function = keyframe.GetTimingFunctionForTesting();
468 DCHECK_EQ(keyframe_timing_function->GetType(),
469 TimingFunction::Type::CUBIC_BEZIER);
470 const auto& cubic_timing_function =
471 To<CubicBezierTimingFunction>(*keyframe_timing_function);
472 EXPECT_EQ(cubic_timing_function.GetEaseType(), ease_type);
473 }
474
LoadTestData(const std::string & file_name)475 void LoadTestData(const std::string& file_name) {
476 String testing_path =
477 test::BlinkRootDir() + "/renderer/core/animation/test_data/";
478 WebURL url = url_test_helpers::RegisterMockedURLLoadFromBase(
479 WebString::FromUTF8(base_url_), testing_path,
480 WebString::FromUTF8(file_name));
481 frame_test_helpers::LoadFrame(helper_.GetWebView()->MainFrameImpl(),
482 base_url_ + file_name);
483 ForceFullCompositingUpdate();
484 url_test_helpers::RegisterMockedURLUnregister(url);
485 }
486
GetFrame() const487 LocalFrame* GetFrame() const { return helper_.LocalMainFrame()->GetFrame(); }
488
BeginFrame()489 void BeginFrame() {
490 helper_.GetWebView()
491 ->MainFrameWidgetBase()
492 ->SynchronouslyCompositeForTesting(base::TimeTicks::Now());
493 }
494
ForceFullCompositingUpdate()495 void ForceFullCompositingUpdate() {
496 helper_.GetWebView()->MainFrameWidget()->UpdateAllLifecyclePhases(
497 DocumentUpdateReason::kTest);
498 }
499
500 private:
501 frame_test_helpers::WebViewHelper helper_;
502 std::string base_url_;
503 };
504
505 class LayoutObjectProxy : public LayoutObject {
506 public:
Create(Node * node)507 static LayoutObjectProxy* Create(Node* node) {
508 return new LayoutObjectProxy(node);
509 }
510
Dispose(LayoutObjectProxy * proxy)511 static void Dispose(LayoutObjectProxy* proxy) { proxy->Destroy(); }
512
GetName() const513 const char* GetName() const override { return nullptr; }
UpdateLayout()514 void UpdateLayout() override {}
LocalBoundingBoxRectForAccessibility() const515 FloatRect LocalBoundingBoxRectForAccessibility() const override {
516 return FloatRect();
517 }
518
EnsureIdForTestingProxy()519 void EnsureIdForTestingProxy() {
520 // We need Ids of proxies to be valid.
521 EnsureIdForTesting();
522 }
523
524 private:
LayoutObjectProxy(Node * node)525 explicit LayoutObjectProxy(Node* node) : LayoutObject(node) {}
526 };
527
528 // -----------------------------------------------------------------------
529 // -----------------------------------------------------------------------
530
531 INSTANTIATE_PAINT_TEST_SUITE_P(AnimationCompositorAnimationsTest);
532
TEST_P(AnimationCompositorAnimationsTest,CanStartEffectOnCompositorKeyframeMultipleCSSProperties)533 TEST_P(AnimationCompositorAnimationsTest,
534 CanStartEffectOnCompositorKeyframeMultipleCSSProperties) {
535 StringKeyframe* keyframe_good_multiple = CreateDefaultKeyframe(
536 CSSPropertyID::kOpacity, EffectModel::kCompositeReplace);
537 keyframe_good_multiple->SetCSSPropertyValue(
538 CSSPropertyID::kTransform, "none", SecureContextMode::kInsecureContext,
539 nullptr);
540 EXPECT_EQ(
541 DuplicateSingleKeyframeAndTestIsCandidateOnResult(keyframe_good_multiple),
542 CompositorAnimations::kNoFailure);
543
544 StringKeyframe* keyframe_bad_multiple_id = CreateDefaultKeyframe(
545 CSSPropertyID::kColor, EffectModel::kCompositeReplace);
546 keyframe_bad_multiple_id->SetCSSPropertyValue(
547 CSSPropertyID::kOpacity, "0.1", SecureContextMode::kInsecureContext,
548 nullptr);
549 EXPECT_TRUE(DuplicateSingleKeyframeAndTestIsCandidateOnResult(
550 keyframe_bad_multiple_id) &
551 CompositorAnimations::kUnsupportedCSSProperty);
552 }
553
TEST_P(AnimationCompositorAnimationsTest,IsNotCandidateForCompositorAnimationTransformDependsOnBoxSize)554 TEST_P(AnimationCompositorAnimationsTest,
555 IsNotCandidateForCompositorAnimationTransformDependsOnBoxSize) {
556 // Absolute transforms can be animated on the compositor.
557 String transform = "translateX(2px) translateY(2px)";
558 StringKeyframe* good_keyframe =
559 CreateReplaceOpKeyframe(CSSPropertyID::kTransform, transform);
560 EXPECT_EQ(DuplicateSingleKeyframeAndTestIsCandidateOnResult(good_keyframe),
561 CompositorAnimations::kNoFailure);
562
563 // Transforms that rely on the box size, such as percent calculations, cannot
564 // be animated on the compositor (as the box size may change).
565 String transform2 = "translateX(50%) translateY(2px)";
566 StringKeyframe* bad_keyframe =
567 CreateReplaceOpKeyframe(CSSPropertyID::kTransform, transform2);
568 EXPECT_TRUE(DuplicateSingleKeyframeAndTestIsCandidateOnResult(bad_keyframe) &
569 CompositorAnimations::kTransformRelatedPropertyDependsOnBoxSize);
570
571 // Similarly, calc transforms cannot be animated on the compositor.
572 String transform3 = "translateX(calc(100% + (0.5 * 100px)))";
573 StringKeyframe* bad_keyframe2 =
574 CreateReplaceOpKeyframe(CSSPropertyID::kTransform, transform3);
575 EXPECT_TRUE(DuplicateSingleKeyframeAndTestIsCandidateOnResult(bad_keyframe2) &
576 CompositorAnimations::kTransformRelatedPropertyDependsOnBoxSize);
577 }
578
TEST_P(AnimationCompositorAnimationsTest,CanStartEffectOnCompositorKeyframeEffectModel)579 TEST_P(AnimationCompositorAnimationsTest,
580 CanStartEffectOnCompositorKeyframeEffectModel) {
581 StringKeyframeVector frames_same;
582 frames_same.push_back(CreateDefaultKeyframe(
583 CSSPropertyID::kColor, EffectModel::kCompositeReplace, 0.0));
584 frames_same.push_back(CreateDefaultKeyframe(
585 CSSPropertyID::kColor, EffectModel::kCompositeReplace, 1.0));
586 EXPECT_TRUE(CanStartEffectOnCompositor(
587 timing_, *MakeGarbageCollected<StringKeyframeEffectModel>(
588 frames_same)) &
589 CompositorAnimations::kUnsupportedCSSProperty);
590
591 StringKeyframeVector frames_mixed_properties;
592 auto* keyframe = MakeGarbageCollected<StringKeyframe>();
593 keyframe->SetOffset(0);
594 keyframe->SetCSSPropertyValue(CSSPropertyID::kColor, "red",
595 SecureContextMode::kInsecureContext, nullptr);
596 keyframe->SetCSSPropertyValue(CSSPropertyID::kOpacity, "0",
597 SecureContextMode::kInsecureContext, nullptr);
598 frames_mixed_properties.push_back(keyframe);
599 keyframe = MakeGarbageCollected<StringKeyframe>();
600 keyframe->SetOffset(1);
601 keyframe->SetCSSPropertyValue(CSSPropertyID::kColor, "green",
602 SecureContextMode::kInsecureContext, nullptr);
603 keyframe->SetCSSPropertyValue(CSSPropertyID::kOpacity, "1",
604 SecureContextMode::kInsecureContext, nullptr);
605 frames_mixed_properties.push_back(keyframe);
606 EXPECT_TRUE(CanStartEffectOnCompositor(
607 timing_, *MakeGarbageCollected<StringKeyframeEffectModel>(
608 frames_mixed_properties)) &
609 CompositorAnimations::kUnsupportedCSSProperty);
610 }
611
TEST_P(AnimationCompositorAnimationsTest,CanStartEffectOnCompositorCustomCssProperty)612 TEST_P(AnimationCompositorAnimationsTest,
613 CanStartEffectOnCompositorCustomCssProperty) {
614 ScopedOffMainThreadCSSPaintForTest off_main_thread_css_paint(true);
615 RegisterProperty(GetDocument(), "--foo", "<number>", "0", false);
616 RegisterProperty(GetDocument(), "--bar", "<length>", "10px", false);
617 RegisterProperty(GetDocument(), "--loo", "<color>", "rgb(0, 0, 0)", false);
618 RegisterProperty(GetDocument(), "--x", "<number>", "0", false);
619 SetCustomProperty("--foo", "10");
620 SetCustomProperty("--bar", "10px");
621 SetCustomProperty("--loo", "rgb(0, 255, 0)");
622 SetCustomProperty("--x", "5");
623
624 auto style = GetDocument().EnsureStyleResolver().StyleForElement(element_);
625 EXPECT_TRUE(style->NonInheritedVariables());
626 EXPECT_TRUE(style->NonInheritedVariables()
627 ->GetData(AtomicString("--foo"))
628 .value_or(nullptr));
629 EXPECT_TRUE(style->NonInheritedVariables()
630 ->GetData(AtomicString("--bar"))
631 .value_or(nullptr));
632 EXPECT_TRUE(style->NonInheritedVariables()
633 ->GetData(AtomicString("--loo"))
634 .value_or(nullptr));
635 EXPECT_TRUE(style->NonInheritedVariables()
636 ->GetData(AtomicString("--x"))
637 .value_or(nullptr));
638
639 NiceMock<MockCSSPaintImageGenerator>* mock_generator =
640 MakeGarbageCollected<NiceMock<MockCSSPaintImageGenerator>>();
641 base::AutoReset<MockCSSPaintImageGenerator*> scoped_override_generator(
642 &g_override_generator, mock_generator);
643 base::AutoReset<CSSPaintImageGenerator::CSSPaintImageGeneratorCreateFunction>
644 scoped_create_function(
645 CSSPaintImageGenerator::GetCreateFunctionForTesting(),
646 ProvideOverrideGenerator);
647
648 mock_generator->AddCustomProperty("--foo");
649 mock_generator->AddCustomProperty("--bar");
650 mock_generator->AddCustomProperty("--loo");
651 auto* ident = MakeGarbageCollected<CSSCustomIdentValue>("foopainter");
652 CSSPaintValue* paint_value = MakeGarbageCollected<CSSPaintValue>(ident);
653 paint_value->CreateGeneratorForTesting(GetDocument());
654 StyleGeneratedImage* style_image =
655 MakeGarbageCollected<StyleGeneratedImage>(*paint_value);
656 style->AddPaintImage(style_image);
657 element_->GetLayoutObject()->SetStyle(style);
658 // The image is added for testing off-thread paint worklet supporting
659 // custom property animation case. The style doesn't have a real
660 // PaintImage, so we cannot call UpdateAllLifecyclePhasesForTest. But the
661 // PaintArtifactCompositor requires NeedsUpdate to be false.
662 // In the real world when a PaintImage does exist in the style, the life
663 // cycle will be updated automatically and we don't have to worry about
664 // this.
665 auto* paint_artifact_compositor =
666 GetDocument().View()->GetPaintArtifactCompositor();
667 paint_artifact_compositor->ClearNeedsUpdateForTesting();
668
669 ON_CALL(*mock_generator, IsImageGeneratorReady()).WillByDefault(Return(true));
670 StringKeyframe* keyframe = CreateReplaceOpKeyframe("--foo", "10");
671 EXPECT_EQ(DuplicateSingleKeyframeAndTestIsCandidateOnResult(keyframe),
672 CompositorAnimations::kNoFailure);
673
674 // Color-valued properties are supported
675 StringKeyframe* color_keyframe =
676 CreateReplaceOpKeyframe("--loo", "rgb(0, 255, 0)");
677 EXPECT_EQ(DuplicateSingleKeyframeAndTestIsCandidateOnResult(color_keyframe),
678 CompositorAnimations::kNoFailure);
679
680 // Length-valued properties are not compositable.
681 StringKeyframe* non_animatable_keyframe =
682 CreateReplaceOpKeyframe("--bar", "10px");
683 EXPECT_TRUE(DuplicateSingleKeyframeAndTestIsCandidateOnResult(
684 non_animatable_keyframe) &
685 CompositorAnimations::kUnsupportedCSSProperty);
686
687 // Cannot composite due to side effect.
688 SetCustomProperty("opacity", "var(--foo)");
689 EXPECT_TRUE(DuplicateSingleKeyframeAndTestIsCandidateOnResult(keyframe) &
690 CompositorAnimations::kUnsupportedCSSProperty);
691
692 // Cannot composite because "--x" is not used by the paint worklet.
693 StringKeyframe* non_used_keyframe = CreateReplaceOpKeyframe("--x", "5");
694 EXPECT_EQ(
695 DuplicateSingleKeyframeAndTestIsCandidateOnResult(non_used_keyframe),
696 CompositorAnimations::kUnsupportedCSSProperty);
697 }
698
TEST_P(AnimationCompositorAnimationsTest,ConvertTimingForCompositorStartDelay)699 TEST_P(AnimationCompositorAnimationsTest,
700 ConvertTimingForCompositorStartDelay) {
701 timing_.iteration_duration = AnimationTimeDelta::FromSecondsD(20);
702
703 timing_.start_delay = 2.0;
704 EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
705 EXPECT_DOUBLE_EQ(-2.0, compositor_timing_.scaled_time_offset.InSecondsF());
706
707 timing_.start_delay = -2.0;
708 EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
709 EXPECT_DOUBLE_EQ(2.0, compositor_timing_.scaled_time_offset.InSecondsF());
710 }
711
TEST_P(AnimationCompositorAnimationsTest,ConvertTimingForCompositorIterationStart)712 TEST_P(AnimationCompositorAnimationsTest,
713 ConvertTimingForCompositorIterationStart) {
714 timing_.iteration_start = 2.2;
715 EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
716 }
717
TEST_P(AnimationCompositorAnimationsTest,ConvertTimingForCompositorIterationCount)718 TEST_P(AnimationCompositorAnimationsTest,
719 ConvertTimingForCompositorIterationCount) {
720 timing_.iteration_count = 5.0;
721 EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
722 EXPECT_EQ(5, compositor_timing_.adjusted_iteration_count);
723
724 timing_.iteration_count = 5.5;
725 EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
726 EXPECT_EQ(5.5, compositor_timing_.adjusted_iteration_count);
727
728 timing_.iteration_count = std::numeric_limits<double>::infinity();
729 EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
730 EXPECT_EQ(std::numeric_limits<double>::infinity(),
731 compositor_timing_.adjusted_iteration_count);
732
733 timing_.iteration_count = std::numeric_limits<double>::infinity();
734 timing_.iteration_duration = AnimationTimeDelta::FromSecondsD(5);
735 timing_.start_delay = -6.0;
736 EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
737 EXPECT_DOUBLE_EQ(6.0, compositor_timing_.scaled_time_offset.InSecondsF());
738 EXPECT_EQ(std::numeric_limits<double>::infinity(),
739 compositor_timing_.adjusted_iteration_count);
740 }
741
TEST_P(AnimationCompositorAnimationsTest,ConvertTimingForCompositorIterationsAndStartDelay)742 TEST_P(AnimationCompositorAnimationsTest,
743 ConvertTimingForCompositorIterationsAndStartDelay) {
744 timing_.iteration_count = 4.0;
745 timing_.iteration_duration = AnimationTimeDelta::FromSecondsD(5);
746
747 timing_.start_delay = 6.0;
748 EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
749 EXPECT_DOUBLE_EQ(-6.0, compositor_timing_.scaled_time_offset.InSecondsF());
750 EXPECT_DOUBLE_EQ(4.0, compositor_timing_.adjusted_iteration_count);
751
752 timing_.start_delay = -6.0;
753 EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
754 EXPECT_DOUBLE_EQ(6.0, compositor_timing_.scaled_time_offset.InSecondsF());
755 EXPECT_DOUBLE_EQ(4.0, compositor_timing_.adjusted_iteration_count);
756
757 timing_.start_delay = 21.0;
758 EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
759 }
760
TEST_P(AnimationCompositorAnimationsTest,ConvertTimingForCompositorDirection)761 TEST_P(AnimationCompositorAnimationsTest, ConvertTimingForCompositorDirection) {
762 timing_.direction = Timing::PlaybackDirection::NORMAL;
763 EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
764 EXPECT_EQ(compositor_timing_.direction, Timing::PlaybackDirection::NORMAL);
765
766 timing_.direction = Timing::PlaybackDirection::ALTERNATE_NORMAL;
767 EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
768 EXPECT_EQ(compositor_timing_.direction,
769 Timing::PlaybackDirection::ALTERNATE_NORMAL);
770
771 timing_.direction = Timing::PlaybackDirection::ALTERNATE_REVERSE;
772 EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
773 EXPECT_EQ(compositor_timing_.direction,
774 Timing::PlaybackDirection::ALTERNATE_REVERSE);
775
776 timing_.direction = Timing::PlaybackDirection::REVERSE;
777 EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
778 EXPECT_EQ(compositor_timing_.direction, Timing::PlaybackDirection::REVERSE);
779 }
780
TEST_P(AnimationCompositorAnimationsTest,ConvertTimingForCompositorDirectionIterationsAndStartDelay)781 TEST_P(AnimationCompositorAnimationsTest,
782 ConvertTimingForCompositorDirectionIterationsAndStartDelay) {
783 timing_.direction = Timing::PlaybackDirection::ALTERNATE_NORMAL;
784 timing_.iteration_count = 4.0;
785 timing_.iteration_duration = AnimationTimeDelta::FromSecondsD(5);
786 timing_.start_delay = -6.0;
787 EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
788 EXPECT_DOUBLE_EQ(6.0, compositor_timing_.scaled_time_offset.InSecondsF());
789 EXPECT_EQ(4, compositor_timing_.adjusted_iteration_count);
790 EXPECT_EQ(compositor_timing_.direction,
791 Timing::PlaybackDirection::ALTERNATE_NORMAL);
792
793 timing_.direction = Timing::PlaybackDirection::ALTERNATE_NORMAL;
794 timing_.iteration_count = 4.0;
795 timing_.iteration_duration = AnimationTimeDelta::FromSecondsD(5);
796 timing_.start_delay = -11.0;
797 EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
798 EXPECT_DOUBLE_EQ(11.0, compositor_timing_.scaled_time_offset.InSecondsF());
799 EXPECT_EQ(4, compositor_timing_.adjusted_iteration_count);
800 EXPECT_EQ(compositor_timing_.direction,
801 Timing::PlaybackDirection::ALTERNATE_NORMAL);
802
803 timing_.direction = Timing::PlaybackDirection::ALTERNATE_REVERSE;
804 timing_.iteration_count = 4.0;
805 timing_.iteration_duration = AnimationTimeDelta::FromSecondsD(5);
806 timing_.start_delay = -6.0;
807 EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
808 EXPECT_DOUBLE_EQ(6.0, compositor_timing_.scaled_time_offset.InSecondsF());
809 EXPECT_EQ(4, compositor_timing_.adjusted_iteration_count);
810 EXPECT_EQ(compositor_timing_.direction,
811 Timing::PlaybackDirection::ALTERNATE_REVERSE);
812
813 timing_.direction = Timing::PlaybackDirection::ALTERNATE_REVERSE;
814 timing_.iteration_count = 4.0;
815 timing_.iteration_duration = AnimationTimeDelta::FromSecondsD(5);
816 timing_.start_delay = -11.0;
817 EXPECT_TRUE(ConvertTimingForCompositor(timing_, compositor_timing_));
818 EXPECT_DOUBLE_EQ(11.0, compositor_timing_.scaled_time_offset.InSecondsF());
819 EXPECT_EQ(4, compositor_timing_.adjusted_iteration_count);
820 EXPECT_EQ(compositor_timing_.direction,
821 Timing::PlaybackDirection::ALTERNATE_REVERSE);
822 }
823
TEST_P(AnimationCompositorAnimationsTest,CanStartEffectOnCompositorTimingFunctionLinear)824 TEST_P(AnimationCompositorAnimationsTest,
825 CanStartEffectOnCompositorTimingFunctionLinear) {
826 timing_.timing_function = linear_timing_function_;
827 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect2_),
828 CompositorAnimations::kNoFailure);
829 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_),
830 CompositorAnimations::kNoFailure);
831 }
832
TEST_P(AnimationCompositorAnimationsTest,CanStartEffectOnCompositorTimingFunctionCubic)833 TEST_P(AnimationCompositorAnimationsTest,
834 CanStartEffectOnCompositorTimingFunctionCubic) {
835 timing_.timing_function = cubic_ease_timing_function_;
836 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect2_),
837 CompositorAnimations::kNoFailure);
838 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_),
839 CompositorAnimations::kNoFailure);
840
841 timing_.timing_function = cubic_custom_timing_function_;
842 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect2_),
843 CompositorAnimations::kNoFailure);
844 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_),
845 CompositorAnimations::kNoFailure);
846 }
847
TEST_P(AnimationCompositorAnimationsTest,CanStartEffectOnCompositorTimingFunctionSteps)848 TEST_P(AnimationCompositorAnimationsTest,
849 CanStartEffectOnCompositorTimingFunctionSteps) {
850 timing_.timing_function = step_timing_function_;
851 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect2_),
852 CompositorAnimations::kNoFailure);
853 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_),
854 CompositorAnimations::kNoFailure);
855 }
856
TEST_P(AnimationCompositorAnimationsTest,CanStartEffectOnCompositorTimingFunctionChainedLinear)857 TEST_P(AnimationCompositorAnimationsTest,
858 CanStartEffectOnCompositorTimingFunctionChainedLinear) {
859 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect2_),
860 CompositorAnimations::kNoFailure);
861 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_),
862 CompositorAnimations::kNoFailure);
863 }
864
TEST_P(AnimationCompositorAnimationsTest,CanStartEffectOnCompositorNonLinearTimingFunctionOnFirstOrLastFrame)865 TEST_P(AnimationCompositorAnimationsTest,
866 CanStartEffectOnCompositorNonLinearTimingFunctionOnFirstOrLastFrame) {
867 keyframe_vector2_->at(0)->SetEasing(cubic_ease_timing_function_.get());
868 keyframe_animation_effect2_ =
869 MakeGarbageCollected<StringKeyframeEffectModel>(*keyframe_vector2_);
870
871 keyframe_vector5_->at(3)->SetEasing(cubic_ease_timing_function_.get());
872 keyframe_animation_effect5_ =
873 MakeGarbageCollected<StringKeyframeEffectModel>(*keyframe_vector5_);
874
875 timing_.timing_function = cubic_ease_timing_function_;
876 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect2_),
877 CompositorAnimations::kNoFailure);
878 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_),
879 CompositorAnimations::kNoFailure);
880
881 timing_.timing_function = cubic_custom_timing_function_;
882 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect2_),
883 CompositorAnimations::kNoFailure);
884 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_),
885 CompositorAnimations::kNoFailure);
886 }
887
TEST_P(AnimationCompositorAnimationsTest,CanStartElementOnCompositorEffectOpacity)888 TEST_P(AnimationCompositorAnimationsTest,
889 CanStartElementOnCompositorEffectOpacity) {
890 // Check that we got something effectively different.
891 StringKeyframeVector key_frames;
892 key_frames.push_back(CreateDefaultKeyframe(
893 CSSPropertyID::kOpacity, EffectModel::kCompositeReplace, 0.0));
894 key_frames.push_back(CreateDefaultKeyframe(
895 CSSPropertyID::kOpacity, EffectModel::kCompositeReplace, 1.0));
896 KeyframeEffectModelBase* animation_effect =
897 MakeGarbageCollected<StringKeyframeEffectModel>(key_frames);
898
899 Timing timing;
900 timing.iteration_duration = AnimationTimeDelta::FromSecondsD(1);
901
902 // The first animation for opacity is ok to run on compositor.
903 auto* keyframe_effect1 =
904 MakeGarbageCollected<KeyframeEffect>(element_, animation_effect, timing);
905 Animation* animation = timeline_->Play(keyframe_effect1);
906 auto style = ComputedStyle::Create();
907 animation_effect->SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(),
908 *style, nullptr);
909
910 // Now we can check that we are set up correctly.
911 EXPECT_EQ(CheckCanStartEffectOnCompositor(timing, *element_.Get(), animation,
912 *animation_effect),
913 CompositorAnimations::kNoFailure);
914
915 // Timings have to be convertible for compositor.
916 EXPECT_EQ(CheckCanStartEffectOnCompositor(timing, *element_.Get(), animation,
917 *animation_effect),
918 CompositorAnimations::kNoFailure);
919 timing.end_delay = 1.0;
920 EXPECT_TRUE(CheckCanStartEffectOnCompositor(timing, *element_.Get(),
921 animation, *animation_effect) &
922 CompositorAnimations::kEffectHasUnsupportedTimingParameters);
923 EXPECT_TRUE(CheckCanStartEffectOnCompositor(timing, *element_.Get(),
924 animation, *animation_effect) &
925 (CompositorAnimations::kTargetHasInvalidCompositingState |
926 CompositorAnimations::kEffectHasUnsupportedTimingParameters));
927 }
928
TEST_P(AnimationCompositorAnimationsTest,CanStartElementOnCompositorEffectInvalid)929 TEST_P(AnimationCompositorAnimationsTest,
930 CanStartElementOnCompositorEffectInvalid) {
931 auto style = ComputedStyle::Create();
932
933 // Check that we notice the value is not animatable correctly.
934 const CSSProperty& target_property1(GetCSSPropertyOutlineStyle());
935 PropertyHandle target_property1h(target_property1);
936 StringKeyframeEffectModel* effect1 = CreateKeyframeEffectModel(
937 CreateReplaceOpKeyframe(target_property1.PropertyID(), "dotted", 0),
938 CreateReplaceOpKeyframe(target_property1.PropertyID(), "dashed", 1.0));
939
940 auto* keyframe_effect1 =
941 MakeGarbageCollected<KeyframeEffect>(element_.Get(), effect1, timing_);
942
943 Animation* animation1 = timeline_->Play(keyframe_effect1);
944 effect1->SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(), *style,
945 nullptr);
946
947 const auto& keyframes1 =
948 *effect1->GetPropertySpecificKeyframes(target_property1h);
949 EXPECT_EQ(2u, keyframes1.size());
950 EXPECT_FALSE(keyframes1[0]->GetCompositorKeyframeValue());
951 EXPECT_EQ(1u, effect1->Properties().size());
952 EXPECT_TRUE(CheckCanStartEffectOnCompositor(timing_, *element_.Get(),
953 animation1, *effect1) &
954 CompositorAnimations::kUnsupportedCSSProperty);
955
956 // Check that we notice transform is not animatable correctly on an inline.
957 const CSSProperty& target_property2(GetCSSPropertyScale());
958 PropertyHandle target_property2h(target_property2);
959 StringKeyframeEffectModel* effect2 = CreateKeyframeEffectModel(
960 CreateReplaceOpKeyframe(target_property2.PropertyID(), "1", 0),
961 CreateReplaceOpKeyframe(target_property2.PropertyID(), "3", 1.0));
962
963 auto* keyframe_effect2 =
964 MakeGarbageCollected<KeyframeEffect>(inline_.Get(), effect2, timing_);
965
966 Animation* animation2 = timeline_->Play(keyframe_effect2);
967 effect2->SnapshotAllCompositorKeyframesIfNecessary(*inline_.Get(), *style,
968 nullptr);
969
970 const auto& keyframes2 =
971 *effect2->GetPropertySpecificKeyframes(target_property2h);
972 EXPECT_EQ(2u, keyframes2.size());
973 EXPECT_TRUE(keyframes2[0]->GetCompositorKeyframeValue());
974 EXPECT_EQ(1u, effect2->Properties().size());
975 EXPECT_TRUE(CheckCanStartEffectOnCompositor(timing_, *inline_.Get(),
976 animation2, *effect2) &
977 CompositorAnimations::
978 kTransformRelatedPropertyCannotBeAcceleratedOnTarget);
979
980 // Check that we notice the Property is not animatable correctly.
981 // These ones claim to have animatable values, but we can't composite
982 // the property. We also don't know the ID domain.
983 const CSSProperty& target_property3(GetCSSPropertyWidth());
984 PropertyHandle target_property3h(target_property3);
985 StringKeyframeEffectModel* effect3 = CreateKeyframeEffectModel(
986 CreateMockReplaceKeyframe(target_property3.PropertyID(), "10px", 0.0),
987 CreateMockReplaceKeyframe(target_property3.PropertyID(), "20px", 1.0));
988
989 auto* keyframe_effect3 =
990 MakeGarbageCollected<KeyframeEffect>(element_.Get(), effect3, timing_);
991
992 Animation* animation3 = timeline_->Play(keyframe_effect3);
993 effect3->SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(), *style,
994 nullptr);
995
996 const auto& keyframes3 =
997 *effect3->GetPropertySpecificKeyframes(target_property3h);
998 EXPECT_EQ(2u, keyframes3.size());
999 EXPECT_TRUE(keyframes3[0]->GetCompositorKeyframeValue());
1000 EXPECT_EQ(1u, effect3->Properties().size());
1001 EXPECT_TRUE(CheckCanStartEffectOnCompositor(timing_, *element_.Get(),
1002 animation3, *effect3) &
1003 CompositorAnimations::kUnsupportedCSSProperty);
1004 }
1005
TEST_P(AnimationCompositorAnimationsTest,CanStartElementOnCompositorEffectFilter)1006 TEST_P(AnimationCompositorAnimationsTest,
1007 CanStartElementOnCompositorEffectFilter) {
1008 // TODO(https://crbug.com/960953): Create a filter effect node when
1009 // will-change: filter is specified so that filter effects can be tested
1010 // without compositing changes.
1011 if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
1012 return;
1013
1014 // Filter Properties use a different ID namespace
1015 StringKeyframeEffectModel* effect1 = CreateKeyframeEffectModel(
1016 CreateReplaceOpKeyframe(CSSPropertyID::kFilter, "none", 0),
1017 CreateReplaceOpKeyframe(CSSPropertyID::kFilter, "sepia(50%)", 1.0));
1018
1019 auto* keyframe_effect1 =
1020 MakeGarbageCollected<KeyframeEffect>(element_.Get(), effect1, timing_);
1021
1022 Animation* animation1 = timeline_->Play(keyframe_effect1);
1023 auto style = ComputedStyle::Create();
1024 effect1->SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(), *style,
1025 nullptr);
1026
1027 // Now we can check that we are set up correctly.
1028 EXPECT_EQ(CheckCanStartEffectOnCompositor(timing_, *element_.Get(),
1029 animation1, *effect1),
1030 CompositorAnimations::kNoFailure);
1031
1032 // Filters that affect neighboring pixels can't be composited.
1033 StringKeyframeEffectModel* effect2 = CreateKeyframeEffectModel(
1034 CreateReplaceOpKeyframe(CSSPropertyID::kFilter, "none", 0),
1035 CreateReplaceOpKeyframe(CSSPropertyID::kFilter, "blur(10px)", 1.0));
1036
1037 auto* keyframe_effect2 =
1038 MakeGarbageCollected<KeyframeEffect>(element_.Get(), effect2, timing_);
1039
1040 Animation* animation2 = timeline_->Play(keyframe_effect2);
1041 effect2->SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(), *style,
1042 nullptr);
1043 EXPECT_TRUE(CheckCanStartEffectOnCompositor(timing_, *element_.Get(),
1044 animation2, *effect2) &
1045 CompositorAnimations::kFilterRelatedPropertyMayMovePixels);
1046
1047 EXPECT_TRUE(CheckCanStartEffectOnCompositor(timing_, *element_.Get(),
1048 animation2, *effect2) &
1049 (CompositorAnimations::kFilterRelatedPropertyMayMovePixels |
1050 CompositorAnimations::kTargetHasInvalidCompositingState));
1051 }
1052
TEST_P(AnimationCompositorAnimationsTest,CanStartElementOnCompositorEffectTransform)1053 TEST_P(AnimationCompositorAnimationsTest,
1054 CanStartElementOnCompositorEffectTransform) {
1055 auto style = ComputedStyle::Create();
1056
1057 StringKeyframeEffectModel* effect1 = CreateKeyframeEffectModel(
1058 CreateReplaceOpKeyframe(CSSPropertyID::kTransform, "none", 0),
1059 CreateReplaceOpKeyframe(CSSPropertyID::kTransform, "rotate(45deg)", 1.0));
1060
1061 auto* keyframe_effect1 =
1062 MakeGarbageCollected<KeyframeEffect>(element_.Get(), effect1, timing_);
1063
1064 Animation* animation1 = timeline_->Play(keyframe_effect1);
1065 effect1->SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(), *style,
1066 nullptr);
1067
1068 // Check if our layout object is not TransformApplicable
1069 EXPECT_TRUE(CheckCanStartEffectOnCompositor(timing_, *inline_.Get(),
1070 animation1, *effect1) &
1071 CompositorAnimations::
1072 kTransformRelatedPropertyCannotBeAcceleratedOnTarget);
1073
1074 StringKeyframeEffectModel* effect2 = CreateKeyframeEffectModel(
1075 CreateReplaceOpKeyframe(CSSPropertyID::kTransform, "translateX(-45px)",
1076 0),
1077 CreateReplaceOpKeyframe(CSSPropertyID::kRotate, "none", 0),
1078 CreateReplaceOpKeyframe(CSSPropertyID::kTransform, "translateX(45px)",
1079 1.0),
1080 CreateReplaceOpKeyframe(CSSPropertyID::kRotate, "45deg", 1.0));
1081
1082 auto* keyframe_effect2 =
1083 MakeGarbageCollected<KeyframeEffect>(element_.Get(), effect2, timing_);
1084
1085 Animation* animation2 = timeline_->Play(keyframe_effect2);
1086 effect2->SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(), *style,
1087 nullptr);
1088
1089 EXPECT_TRUE(CheckCanStartEffectOnCompositor(timing_, *element_.Get(),
1090 animation2, *effect2) &
1091 CompositorAnimations::kMultipleTransformAnimationsOnSameTarget);
1092 }
1093
TEST_P(AnimationCompositorAnimationsTest,CanStartEffectOnCompositorTimingFunctionChainedCubicMatchingOffsets)1094 TEST_P(AnimationCompositorAnimationsTest,
1095 CanStartEffectOnCompositorTimingFunctionChainedCubicMatchingOffsets) {
1096 keyframe_vector2_->at(0)->SetEasing(cubic_ease_timing_function_.get());
1097 keyframe_animation_effect2_ =
1098 MakeGarbageCollected<StringKeyframeEffectModel>(*keyframe_vector2_);
1099 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect2_),
1100 CompositorAnimations::kNoFailure);
1101
1102 keyframe_vector2_->at(0)->SetEasing(cubic_custom_timing_function_.get());
1103 keyframe_animation_effect2_ =
1104 MakeGarbageCollected<StringKeyframeEffectModel>(*keyframe_vector2_);
1105 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect2_),
1106 CompositorAnimations::kNoFailure);
1107
1108 keyframe_vector5_->at(0)->SetEasing(cubic_ease_timing_function_.get());
1109 keyframe_vector5_->at(1)->SetEasing(cubic_custom_timing_function_.get());
1110 keyframe_vector5_->at(2)->SetEasing(cubic_custom_timing_function_.get());
1111 keyframe_vector5_->at(3)->SetEasing(cubic_custom_timing_function_.get());
1112 keyframe_animation_effect5_ =
1113 MakeGarbageCollected<StringKeyframeEffectModel>(*keyframe_vector5_);
1114 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_),
1115 CompositorAnimations::kNoFailure);
1116 }
1117
TEST_P(AnimationCompositorAnimationsTest,CanStartEffectOnCompositorTimingFunctionMixedGood)1118 TEST_P(AnimationCompositorAnimationsTest,
1119 CanStartEffectOnCompositorTimingFunctionMixedGood) {
1120 keyframe_vector5_->at(0)->SetEasing(linear_timing_function_.get());
1121 keyframe_vector5_->at(1)->SetEasing(cubic_ease_timing_function_.get());
1122 keyframe_vector5_->at(2)->SetEasing(cubic_ease_timing_function_.get());
1123 keyframe_vector5_->at(3)->SetEasing(linear_timing_function_.get());
1124 keyframe_animation_effect5_ =
1125 MakeGarbageCollected<StringKeyframeEffectModel>(*keyframe_vector5_);
1126 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_),
1127 CompositorAnimations::kNoFailure);
1128 }
1129
TEST_P(AnimationCompositorAnimationsTest,CanStartEffectOnCompositorTimingFunctionWithStepOrFrameOkay)1130 TEST_P(AnimationCompositorAnimationsTest,
1131 CanStartEffectOnCompositorTimingFunctionWithStepOrFrameOkay) {
1132 keyframe_vector2_->at(0)->SetEasing(step_timing_function_.get());
1133 keyframe_animation_effect2_ =
1134 MakeGarbageCollected<StringKeyframeEffectModel>(*keyframe_vector2_);
1135 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect2_),
1136 CompositorAnimations::kNoFailure);
1137
1138 keyframe_vector5_->at(0)->SetEasing(step_timing_function_.get());
1139 keyframe_vector5_->at(1)->SetEasing(linear_timing_function_.get());
1140 keyframe_vector5_->at(2)->SetEasing(cubic_ease_timing_function_.get());
1141 keyframe_animation_effect5_ =
1142 MakeGarbageCollected<StringKeyframeEffectModel>(*keyframe_vector5_);
1143 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_),
1144 CompositorAnimations::kNoFailure);
1145
1146 keyframe_vector5_->at(1)->SetEasing(step_timing_function_.get());
1147 keyframe_vector5_->at(2)->SetEasing(cubic_ease_timing_function_.get());
1148 keyframe_vector5_->at(3)->SetEasing(linear_timing_function_.get());
1149 keyframe_animation_effect5_ =
1150 MakeGarbageCollected<StringKeyframeEffectModel>(*keyframe_vector5_);
1151 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_),
1152 CompositorAnimations::kNoFailure);
1153
1154 keyframe_vector5_->at(0)->SetEasing(linear_timing_function_.get());
1155 keyframe_vector5_->at(2)->SetEasing(cubic_ease_timing_function_.get());
1156 keyframe_vector5_->at(3)->SetEasing(step_timing_function_.get());
1157 keyframe_animation_effect5_ =
1158 MakeGarbageCollected<StringKeyframeEffectModel>(*keyframe_vector5_);
1159 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *keyframe_animation_effect5_),
1160 CompositorAnimations::kNoFailure);
1161 }
1162
TEST_P(AnimationCompositorAnimationsTest,CanStartEffectOnCompositorBasic)1163 TEST_P(AnimationCompositorAnimationsTest, CanStartEffectOnCompositorBasic) {
1164 StringKeyframeVector basic_frames_vector;
1165 basic_frames_vector.push_back(CreateDefaultKeyframe(
1166 CSSPropertyID::kOpacity, EffectModel::kCompositeReplace, 0.0));
1167 basic_frames_vector.push_back(CreateDefaultKeyframe(
1168 CSSPropertyID::kOpacity, EffectModel::kCompositeReplace, 1.0));
1169
1170 StringKeyframeVector non_basic_frames_vector;
1171 non_basic_frames_vector.push_back(CreateDefaultKeyframe(
1172 CSSPropertyID::kOpacity, EffectModel::kCompositeReplace, 0.0));
1173 non_basic_frames_vector.push_back(CreateDefaultKeyframe(
1174 CSSPropertyID::kOpacity, EffectModel::kCompositeReplace, 0.5));
1175 non_basic_frames_vector.push_back(CreateDefaultKeyframe(
1176 CSSPropertyID::kOpacity, EffectModel::kCompositeReplace, 1.0));
1177
1178 basic_frames_vector[0]->SetEasing(linear_timing_function_.get());
1179 auto* basic_frames =
1180 MakeGarbageCollected<StringKeyframeEffectModel>(basic_frames_vector);
1181 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *basic_frames),
1182 CompositorAnimations::kNoFailure);
1183
1184 basic_frames_vector[0]->SetEasing(CubicBezierTimingFunction::Preset(
1185 CubicBezierTimingFunction::EaseType::EASE_IN));
1186 basic_frames =
1187 MakeGarbageCollected<StringKeyframeEffectModel>(basic_frames_vector);
1188 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *basic_frames),
1189 CompositorAnimations::kNoFailure);
1190
1191 non_basic_frames_vector[0]->SetEasing(linear_timing_function_.get());
1192 non_basic_frames_vector[1]->SetEasing(CubicBezierTimingFunction::Preset(
1193 CubicBezierTimingFunction::EaseType::EASE_IN));
1194 auto* non_basic_frames =
1195 MakeGarbageCollected<StringKeyframeEffectModel>(non_basic_frames_vector);
1196 EXPECT_EQ(CanStartEffectOnCompositor(timing_, *non_basic_frames),
1197 CompositorAnimations::kNoFailure);
1198
1199 StringKeyframeVector non_allowed_frames_vector;
1200 non_allowed_frames_vector.push_back(CreateDefaultKeyframe(
1201 CSSPropertyID::kOpacity, EffectModel::kCompositeAdd, 0.1));
1202 non_allowed_frames_vector.push_back(CreateDefaultKeyframe(
1203 CSSPropertyID::kOpacity, EffectModel::kCompositeAdd, 0.25));
1204 auto* non_allowed_frames = MakeGarbageCollected<StringKeyframeEffectModel>(
1205 non_allowed_frames_vector);
1206 EXPECT_TRUE(CanStartEffectOnCompositor(timing_, *non_allowed_frames) &
1207 CompositorAnimations::kEffectHasNonReplaceCompositeMode);
1208
1209 // Set SVGAttribute keeps a pointer to this thing for the lifespan of
1210 // the Keyframe. This is ugly but sufficient to work around it.
1211 QualifiedName fake_name("prefix", "local", "uri");
1212
1213 StringKeyframeVector non_css_frames_vector;
1214 non_css_frames_vector.push_back(CreateSVGKeyframe(fake_name, "cargo", 0.0));
1215 non_css_frames_vector.push_back(CreateSVGKeyframe(fake_name, "cargo", 1.0));
1216 auto* non_css_frames =
1217 MakeGarbageCollected<StringKeyframeEffectModel>(non_css_frames_vector);
1218 EXPECT_TRUE(CanStartEffectOnCompositor(timing_, *non_css_frames) &
1219 CompositorAnimations::kAnimationAffectsNonCSSProperties);
1220 // NB: Important that non_css_frames_vector goes away and cleans up
1221 // before fake_name.
1222 }
1223
1224 // -----------------------------------------------------------------------
1225 // -----------------------------------------------------------------------
1226
TEST_P(AnimationCompositorAnimationsTest,CreateSimpleOpacityAnimation)1227 TEST_P(AnimationCompositorAnimationsTest, CreateSimpleOpacityAnimation) {
1228 // KeyframeEffect to convert
1229 StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
1230 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.2", 0),
1231 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.5", 1.0));
1232
1233 std::unique_ptr<CompositorKeyframeModel> keyframe_model =
1234 ConvertToCompositorAnimation(*effect);
1235 EXPECT_EQ(compositor_target_property::OPACITY,
1236 keyframe_model->TargetProperty());
1237 EXPECT_EQ(1.0, keyframe_model->Iterations());
1238 EXPECT_EQ(0, keyframe_model->TimeOffset());
1239 EXPECT_EQ(CompositorKeyframeModel::Direction::NORMAL,
1240 keyframe_model->GetDirection());
1241 EXPECT_EQ(1.0, keyframe_model->PlaybackRate());
1242
1243 std::unique_ptr<CompositorFloatAnimationCurve> keyframed_float_curve =
1244 keyframe_model->FloatCurveForTesting();
1245
1246 CompositorFloatAnimationCurve::Keyframes keyframes =
1247 keyframed_float_curve->KeyframesForTesting();
1248 ASSERT_EQ(2UL, keyframes.size());
1249
1250 EXPECT_EQ(0, keyframes[0]->Time());
1251 EXPECT_EQ(0.2f, keyframes[0]->Value());
1252 EXPECT_EQ(TimingFunction::Type::LINEAR,
1253 keyframes[0]->GetTimingFunctionForTesting()->GetType());
1254
1255 EXPECT_EQ(1.0, keyframes[1]->Time());
1256 EXPECT_EQ(0.5f, keyframes[1]->Value());
1257 EXPECT_EQ(TimingFunction::Type::LINEAR,
1258 keyframes[1]->GetTimingFunctionForTesting()->GetType());
1259 }
1260
TEST_P(AnimationCompositorAnimationsTest,CreateSimpleOpacityAnimationDuration)1261 TEST_P(AnimationCompositorAnimationsTest,
1262 CreateSimpleOpacityAnimationDuration) {
1263 // KeyframeEffect to convert
1264 StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
1265 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.2", 0),
1266 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.5", 1.0));
1267
1268 const AnimationTimeDelta kDuration = AnimationTimeDelta::FromSecondsD(10);
1269 timing_.iteration_duration = kDuration;
1270
1271 std::unique_ptr<CompositorKeyframeModel> keyframe_model =
1272 ConvertToCompositorAnimation(*effect);
1273 std::unique_ptr<CompositorFloatAnimationCurve> keyframed_float_curve =
1274 keyframe_model->FloatCurveForTesting();
1275
1276 CompositorFloatAnimationCurve::Keyframes keyframes =
1277 keyframed_float_curve->KeyframesForTesting();
1278 ASSERT_EQ(2UL, keyframes.size());
1279
1280 EXPECT_EQ(kDuration, keyframes[1]->Time() * kDuration);
1281 }
1282
TEST_P(AnimationCompositorAnimationsTest,CreateMultipleKeyframeOpacityAnimationLinear)1283 TEST_P(AnimationCompositorAnimationsTest,
1284 CreateMultipleKeyframeOpacityAnimationLinear) {
1285 // KeyframeEffect to convert
1286 StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
1287 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.2", 0),
1288 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.0", 0.25),
1289 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.25", 0.5),
1290 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.5", 1.0));
1291
1292 timing_.iteration_count = 5;
1293 timing_.direction = Timing::PlaybackDirection::ALTERNATE_NORMAL;
1294
1295 std::unique_ptr<CompositorKeyframeModel> keyframe_model =
1296 ConvertToCompositorAnimation(*effect, 2.0);
1297 EXPECT_EQ(compositor_target_property::OPACITY,
1298 keyframe_model->TargetProperty());
1299 EXPECT_EQ(5.0, keyframe_model->Iterations());
1300 EXPECT_EQ(0, keyframe_model->TimeOffset());
1301 EXPECT_EQ(CompositorKeyframeModel::Direction::ALTERNATE_NORMAL,
1302 keyframe_model->GetDirection());
1303 EXPECT_EQ(2.0, keyframe_model->PlaybackRate());
1304
1305 std::unique_ptr<CompositorFloatAnimationCurve> keyframed_float_curve =
1306 keyframe_model->FloatCurveForTesting();
1307
1308 CompositorFloatAnimationCurve::Keyframes keyframes =
1309 keyframed_float_curve->KeyframesForTesting();
1310 ASSERT_EQ(4UL, keyframes.size());
1311
1312 EXPECT_EQ(0, keyframes[0]->Time());
1313 EXPECT_EQ(0.2f, keyframes[0]->Value());
1314 EXPECT_EQ(TimingFunction::Type::LINEAR,
1315 keyframes[0]->GetTimingFunctionForTesting()->GetType());
1316
1317 EXPECT_EQ(0.25, keyframes[1]->Time());
1318 EXPECT_EQ(0, keyframes[1]->Value());
1319 EXPECT_EQ(TimingFunction::Type::LINEAR,
1320 keyframes[1]->GetTimingFunctionForTesting()->GetType());
1321
1322 EXPECT_EQ(0.5, keyframes[2]->Time());
1323 EXPECT_EQ(0.25f, keyframes[2]->Value());
1324 EXPECT_EQ(TimingFunction::Type::LINEAR,
1325 keyframes[2]->GetTimingFunctionForTesting()->GetType());
1326
1327 EXPECT_EQ(1.0, keyframes[3]->Time());
1328 EXPECT_EQ(0.5f, keyframes[3]->Value());
1329 EXPECT_EQ(TimingFunction::Type::LINEAR,
1330 keyframes[3]->GetTimingFunctionForTesting()->GetType());
1331 }
1332
TEST_P(AnimationCompositorAnimationsTest,CreateSimpleOpacityAnimationStartDelay)1333 TEST_P(AnimationCompositorAnimationsTest,
1334 CreateSimpleOpacityAnimationStartDelay) {
1335 // KeyframeEffect to convert
1336 StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
1337 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.2", 0),
1338 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.5", 1.0));
1339
1340 const double kStartDelay = 3.25;
1341
1342 timing_.iteration_count = 5.0;
1343 timing_.iteration_duration = AnimationTimeDelta::FromSecondsD(1.75);
1344 timing_.start_delay = kStartDelay;
1345
1346 std::unique_ptr<CompositorKeyframeModel> keyframe_model =
1347 ConvertToCompositorAnimation(*effect);
1348
1349 EXPECT_EQ(compositor_target_property::OPACITY,
1350 keyframe_model->TargetProperty());
1351 EXPECT_EQ(5.0, keyframe_model->Iterations());
1352 EXPECT_EQ(-kStartDelay, keyframe_model->TimeOffset());
1353
1354 std::unique_ptr<CompositorFloatAnimationCurve> keyframed_float_curve =
1355 keyframe_model->FloatCurveForTesting();
1356
1357 CompositorFloatAnimationCurve::Keyframes keyframes =
1358 keyframed_float_curve->KeyframesForTesting();
1359 ASSERT_EQ(2UL, keyframes.size());
1360
1361 EXPECT_EQ(1.75,
1362 keyframes[1]->Time() * timing_.iteration_duration->InSecondsF());
1363 EXPECT_EQ(0.5f, keyframes[1]->Value());
1364 }
1365
TEST_P(AnimationCompositorAnimationsTest,CreateMultipleKeyframeOpacityAnimationChained)1366 TEST_P(AnimationCompositorAnimationsTest,
1367 CreateMultipleKeyframeOpacityAnimationChained) {
1368 // KeyframeEffect to convert
1369 StringKeyframeVector frames;
1370 frames.push_back(CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.2", 0));
1371 frames.push_back(
1372 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.0", 0.25));
1373 frames.push_back(
1374 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.35", 0.5));
1375 frames.push_back(
1376 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.5", 1.0));
1377 frames[0]->SetEasing(cubic_ease_timing_function_.get());
1378 frames[1]->SetEasing(linear_timing_function_.get());
1379 frames[2]->SetEasing(cubic_custom_timing_function_.get());
1380 auto* effect = MakeGarbageCollected<StringKeyframeEffectModel>(frames);
1381
1382 timing_.timing_function = linear_timing_function_.get();
1383 timing_.iteration_duration = AnimationTimeDelta::FromSecondsD(2);
1384 timing_.iteration_count = 10;
1385 timing_.direction = Timing::PlaybackDirection::ALTERNATE_NORMAL;
1386
1387 std::unique_ptr<CompositorKeyframeModel> keyframe_model =
1388 ConvertToCompositorAnimation(*effect);
1389 EXPECT_EQ(compositor_target_property::OPACITY,
1390 keyframe_model->TargetProperty());
1391 EXPECT_EQ(10.0, keyframe_model->Iterations());
1392 EXPECT_EQ(0, keyframe_model->TimeOffset());
1393 EXPECT_EQ(CompositorKeyframeModel::Direction::ALTERNATE_NORMAL,
1394 keyframe_model->GetDirection());
1395 EXPECT_EQ(1.0, keyframe_model->PlaybackRate());
1396
1397 std::unique_ptr<CompositorFloatAnimationCurve> keyframed_float_curve =
1398 keyframe_model->FloatCurveForTesting();
1399
1400 CompositorFloatAnimationCurve::Keyframes keyframes =
1401 keyframed_float_curve->KeyframesForTesting();
1402 ASSERT_EQ(4UL, keyframes.size());
1403
1404 EXPECT_EQ(0, keyframes[0]->Time() * timing_.iteration_duration->InSecondsF());
1405 EXPECT_EQ(0.2f, keyframes[0]->Value());
1406 ExpectKeyframeTimingFunctionCubic(*keyframes[0],
1407 CubicBezierTimingFunction::EaseType::EASE);
1408
1409 EXPECT_EQ(0.5,
1410 keyframes[1]->Time() * timing_.iteration_duration->InSecondsF());
1411 EXPECT_EQ(0, keyframes[1]->Value());
1412 EXPECT_EQ(TimingFunction::Type::LINEAR,
1413 keyframes[1]->GetTimingFunctionForTesting()->GetType());
1414
1415 EXPECT_EQ(1.0,
1416 keyframes[2]->Time() * timing_.iteration_duration->InSecondsF());
1417 EXPECT_EQ(0.35f, keyframes[2]->Value());
1418 ExpectKeyframeTimingFunctionCubic(
1419 *keyframes[2], CubicBezierTimingFunction::EaseType::CUSTOM);
1420
1421 EXPECT_EQ(2.0,
1422 keyframes[3]->Time() * timing_.iteration_duration->InSecondsF());
1423 EXPECT_EQ(0.5f, keyframes[3]->Value());
1424 EXPECT_EQ(TimingFunction::Type::LINEAR,
1425 keyframes[3]->GetTimingFunctionForTesting()->GetType());
1426 }
1427
TEST_P(AnimationCompositorAnimationsTest,CreateReversedOpacityAnimation)1428 TEST_P(AnimationCompositorAnimationsTest, CreateReversedOpacityAnimation) {
1429 scoped_refptr<TimingFunction> cubic_easy_flip_timing_function =
1430 CubicBezierTimingFunction::Create(0.0, 0.0, 0.0, 1.0);
1431
1432 // KeyframeEffect to convert
1433 StringKeyframeVector frames;
1434 frames.push_back(CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.2", 0));
1435 frames.push_back(
1436 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.0", 0.25));
1437 frames.push_back(
1438 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.25", 0.5));
1439 frames.push_back(
1440 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.5", 1.0));
1441 frames[0]->SetEasing(CubicBezierTimingFunction::Preset(
1442 CubicBezierTimingFunction::EaseType::EASE_IN));
1443 frames[1]->SetEasing(linear_timing_function_.get());
1444 frames[2]->SetEasing(cubic_easy_flip_timing_function.get());
1445 auto* effect = MakeGarbageCollected<StringKeyframeEffectModel>(frames);
1446
1447 timing_.timing_function = linear_timing_function_.get();
1448 timing_.iteration_count = 10;
1449 timing_.direction = Timing::PlaybackDirection::ALTERNATE_REVERSE;
1450
1451 std::unique_ptr<CompositorKeyframeModel> keyframe_model =
1452 ConvertToCompositorAnimation(*effect);
1453 EXPECT_EQ(compositor_target_property::OPACITY,
1454 keyframe_model->TargetProperty());
1455 EXPECT_EQ(10.0, keyframe_model->Iterations());
1456 EXPECT_EQ(0, keyframe_model->TimeOffset());
1457 EXPECT_EQ(CompositorKeyframeModel::Direction::ALTERNATE_REVERSE,
1458 keyframe_model->GetDirection());
1459 EXPECT_EQ(1.0, keyframe_model->PlaybackRate());
1460
1461 std::unique_ptr<CompositorFloatAnimationCurve> keyframed_float_curve =
1462 keyframe_model->FloatCurveForTesting();
1463
1464 CompositorFloatAnimationCurve::Keyframes keyframes =
1465 keyframed_float_curve->KeyframesForTesting();
1466 ASSERT_EQ(4UL, keyframes.size());
1467
1468 EXPECT_EQ(keyframed_float_curve->GetTimingFunctionForTesting()->GetType(),
1469 TimingFunction::Type::LINEAR);
1470
1471 EXPECT_EQ(0, keyframes[0]->Time());
1472 EXPECT_EQ(0.2f, keyframes[0]->Value());
1473 ExpectKeyframeTimingFunctionCubic(
1474 *keyframes[0], CubicBezierTimingFunction::EaseType::EASE_IN);
1475
1476 EXPECT_EQ(0.25, keyframes[1]->Time());
1477 EXPECT_EQ(0, keyframes[1]->Value());
1478 EXPECT_EQ(TimingFunction::Type::LINEAR,
1479 keyframes[1]->GetTimingFunctionForTesting()->GetType());
1480
1481 EXPECT_EQ(0.5, keyframes[2]->Time());
1482 EXPECT_EQ(0.25f, keyframes[2]->Value());
1483 ExpectKeyframeTimingFunctionCubic(
1484 *keyframes[2], CubicBezierTimingFunction::EaseType::CUSTOM);
1485
1486 EXPECT_EQ(1.0, keyframes[3]->Time());
1487 EXPECT_EQ(0.5f, keyframes[3]->Value());
1488 EXPECT_EQ(TimingFunction::Type::LINEAR,
1489 keyframes[3]->GetTimingFunctionForTesting()->GetType());
1490 }
1491
TEST_P(AnimationCompositorAnimationsTest,CreateReversedOpacityAnimationNegativeStartDelay)1492 TEST_P(AnimationCompositorAnimationsTest,
1493 CreateReversedOpacityAnimationNegativeStartDelay) {
1494 // KeyframeEffect to convert
1495 StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
1496 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.2", 0),
1497 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.5", 1.0));
1498
1499 const double kNegativeStartDelay = -3;
1500
1501 timing_.iteration_count = 5.0;
1502 timing_.iteration_duration = AnimationTimeDelta::FromSecondsD(1.5);
1503 timing_.start_delay = kNegativeStartDelay;
1504 timing_.direction = Timing::PlaybackDirection::ALTERNATE_REVERSE;
1505
1506 std::unique_ptr<CompositorKeyframeModel> keyframe_model =
1507 ConvertToCompositorAnimation(*effect);
1508 EXPECT_EQ(compositor_target_property::OPACITY,
1509 keyframe_model->TargetProperty());
1510 EXPECT_EQ(5.0, keyframe_model->Iterations());
1511 EXPECT_EQ(-kNegativeStartDelay, keyframe_model->TimeOffset());
1512 EXPECT_EQ(CompositorKeyframeModel::Direction::ALTERNATE_REVERSE,
1513 keyframe_model->GetDirection());
1514 EXPECT_EQ(1.0, keyframe_model->PlaybackRate());
1515
1516 std::unique_ptr<CompositorFloatAnimationCurve> keyframed_float_curve =
1517 keyframe_model->FloatCurveForTesting();
1518
1519 CompositorFloatAnimationCurve::Keyframes keyframes =
1520 keyframed_float_curve->KeyframesForTesting();
1521 ASSERT_EQ(2UL, keyframes.size());
1522 }
1523
TEST_P(AnimationCompositorAnimationsTest,CreateSimpleOpacityAnimationFillModeNone)1524 TEST_P(AnimationCompositorAnimationsTest,
1525 CreateSimpleOpacityAnimationFillModeNone) {
1526 // KeyframeEffect to convert
1527 StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
1528 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.2", 0),
1529 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.5", 1.0));
1530
1531 timing_.fill_mode = Timing::FillMode::NONE;
1532
1533 std::unique_ptr<CompositorKeyframeModel> keyframe_model =
1534 ConvertToCompositorAnimation(*effect);
1535 EXPECT_EQ(CompositorKeyframeModel::FillMode::NONE,
1536 keyframe_model->GetFillMode());
1537 }
1538
TEST_P(AnimationCompositorAnimationsTest,CreateSimpleOpacityAnimationFillModeAuto)1539 TEST_P(AnimationCompositorAnimationsTest,
1540 CreateSimpleOpacityAnimationFillModeAuto) {
1541 // KeyframeEffect to convert
1542 StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
1543 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.2", 0),
1544 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.5", 1.0));
1545
1546 timing_.fill_mode = Timing::FillMode::AUTO;
1547
1548 std::unique_ptr<CompositorKeyframeModel> keyframe_model =
1549 ConvertToCompositorAnimation(*effect);
1550 EXPECT_EQ(compositor_target_property::OPACITY,
1551 keyframe_model->TargetProperty());
1552 EXPECT_EQ(1.0, keyframe_model->Iterations());
1553 EXPECT_EQ(0, keyframe_model->TimeOffset());
1554 EXPECT_EQ(CompositorKeyframeModel::Direction::NORMAL,
1555 keyframe_model->GetDirection());
1556 EXPECT_EQ(1.0, keyframe_model->PlaybackRate());
1557 EXPECT_EQ(CompositorKeyframeModel::FillMode::NONE,
1558 keyframe_model->GetFillMode());
1559 }
1560
TEST_P(AnimationCompositorAnimationsTest,CreateSimpleOpacityAnimationWithTimingFunction)1561 TEST_P(AnimationCompositorAnimationsTest,
1562 CreateSimpleOpacityAnimationWithTimingFunction) {
1563 // KeyframeEffect to convert
1564 StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
1565 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.2", 0),
1566 CreateReplaceOpKeyframe(CSSPropertyID::kOpacity, "0.5", 1.0));
1567
1568 timing_.timing_function = cubic_custom_timing_function_;
1569
1570 std::unique_ptr<CompositorKeyframeModel> keyframe_model =
1571 ConvertToCompositorAnimation(*effect);
1572
1573 std::unique_ptr<CompositorFloatAnimationCurve> keyframed_float_curve =
1574 keyframe_model->FloatCurveForTesting();
1575
1576 auto curve_timing_function =
1577 keyframed_float_curve->GetTimingFunctionForTesting();
1578 EXPECT_EQ(curve_timing_function->GetType(),
1579 TimingFunction::Type::CUBIC_BEZIER);
1580 const auto& cubic_timing_function =
1581 To<CubicBezierTimingFunction>(*curve_timing_function);
1582 EXPECT_EQ(cubic_timing_function.GetEaseType(),
1583 CubicBezierTimingFunction::EaseType::CUSTOM);
1584 EXPECT_EQ(cubic_timing_function.X1(), 1.0);
1585 EXPECT_EQ(cubic_timing_function.Y1(), 2.0);
1586 EXPECT_EQ(cubic_timing_function.X2(), 3.0);
1587 EXPECT_EQ(cubic_timing_function.Y2(), 4.0);
1588
1589 CompositorFloatAnimationCurve::Keyframes keyframes =
1590 keyframed_float_curve->KeyframesForTesting();
1591 ASSERT_EQ(2UL, keyframes.size());
1592
1593 EXPECT_EQ(0, keyframes[0]->Time());
1594 EXPECT_EQ(0.2f, keyframes[0]->Value());
1595 EXPECT_EQ(TimingFunction::Type::LINEAR,
1596 keyframes[0]->GetTimingFunctionForTesting()->GetType());
1597
1598 EXPECT_EQ(1.0, keyframes[1]->Time());
1599 EXPECT_EQ(0.5f, keyframes[1]->Value());
1600 EXPECT_EQ(TimingFunction::Type::LINEAR,
1601 keyframes[1]->GetTimingFunctionForTesting()->GetType());
1602 }
1603
TEST_P(AnimationCompositorAnimationsTest,CreateCustomFloatPropertyAnimationWithNonAsciiName)1604 TEST_P(AnimationCompositorAnimationsTest,
1605 CreateCustomFloatPropertyAnimationWithNonAsciiName) {
1606 ScopedOffMainThreadCSSPaintForTest off_main_thread_css_paint(true);
1607
1608 String property_name = "--東京都";
1609 RegisterProperty(GetDocument(), property_name, "<number>", "0", false);
1610 SetCustomProperty(property_name, "10");
1611
1612 StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
1613 CreateReplaceOpKeyframe(property_name, "10", 0),
1614 CreateReplaceOpKeyframe(property_name, "20", 1.0));
1615
1616 std::unique_ptr<CompositorKeyframeModel> keyframe_model =
1617 ConvertToCompositorAnimation(*effect);
1618 EXPECT_EQ(compositor_target_property::CSS_CUSTOM_PROPERTY,
1619 keyframe_model->TargetProperty());
1620 EXPECT_EQ(keyframe_model->GetCustomPropertyNameForTesting(),
1621 property_name.Utf8().data());
1622 }
1623
TEST_P(AnimationCompositorAnimationsTest,CreateSimpleCustomFloatPropertyAnimation)1624 TEST_P(AnimationCompositorAnimationsTest,
1625 CreateSimpleCustomFloatPropertyAnimation) {
1626 ScopedOffMainThreadCSSPaintForTest off_main_thread_css_paint(true);
1627
1628 RegisterProperty(GetDocument(), "--foo", "<number>", "0", false);
1629 SetCustomProperty("--foo", "10");
1630
1631 StringKeyframeEffectModel* effect =
1632 CreateKeyframeEffectModel(CreateReplaceOpKeyframe("--foo", "10", 0),
1633 CreateReplaceOpKeyframe("--foo", "20", 1.0));
1634
1635 std::unique_ptr<CompositorKeyframeModel> keyframe_model =
1636 ConvertToCompositorAnimation(*effect);
1637 EXPECT_EQ(compositor_target_property::CSS_CUSTOM_PROPERTY,
1638 keyframe_model->TargetProperty());
1639
1640 std::unique_ptr<CompositorFloatAnimationCurve> keyframed_float_curve =
1641 keyframe_model->FloatCurveForTesting();
1642
1643 CompositorFloatAnimationCurve::Keyframes keyframes =
1644 keyframed_float_curve->KeyframesForTesting();
1645 ASSERT_EQ(2UL, keyframes.size());
1646
1647 EXPECT_EQ(0, keyframes[0]->Time());
1648 EXPECT_EQ(10, keyframes[0]->Value());
1649 EXPECT_EQ(TimingFunction::Type::LINEAR,
1650 keyframes[0]->GetTimingFunctionForTesting()->GetType());
1651
1652 EXPECT_EQ(1.0, keyframes[1]->Time());
1653 EXPECT_EQ(20, keyframes[1]->Value());
1654 EXPECT_EQ(TimingFunction::Type::LINEAR,
1655 keyframes[1]->GetTimingFunctionForTesting()->GetType());
1656 }
1657
TEST_P(AnimationCompositorAnimationsTest,CreateSimpleCustomColorPropertyAnimation)1658 TEST_P(AnimationCompositorAnimationsTest,
1659 CreateSimpleCustomColorPropertyAnimation) {
1660 ScopedOffMainThreadCSSPaintForTest off_main_thread_css_paint(true);
1661
1662 RegisterProperty(GetDocument(), "--foo", "<color>", "rgb(0, 0, 0)", false);
1663 SetCustomProperty("--foo", "rgb(0, 0, 0)");
1664
1665 StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
1666 CreateReplaceOpKeyframe("--foo", "rgb(0, 0, 0)", 0),
1667 CreateReplaceOpKeyframe("--foo", "rgb(0, 255, 0)", 1.0));
1668
1669 std::unique_ptr<CompositorKeyframeModel> keyframe_model =
1670 ConvertToCompositorAnimation(*effect);
1671 EXPECT_EQ(compositor_target_property::CSS_CUSTOM_PROPERTY,
1672 keyframe_model->TargetProperty());
1673
1674 std::unique_ptr<CompositorColorAnimationCurve> keyframed_color_curve =
1675 keyframe_model->ColorCurveForTesting();
1676
1677 CompositorColorAnimationCurve::Keyframes keyframes =
1678 keyframed_color_curve->KeyframesForTesting();
1679 ASSERT_EQ(2UL, keyframes.size());
1680
1681 EXPECT_EQ(0, keyframes[0]->Time());
1682 EXPECT_EQ(SkColorSetRGB(0, 0, 0), keyframes[0]->Value());
1683 EXPECT_EQ(TimingFunction::Type::LINEAR,
1684 keyframes[0]->GetTimingFunctionForTesting()->GetType());
1685
1686 EXPECT_EQ(1.0, keyframes[1]->Time());
1687 EXPECT_EQ(SkColorSetRGB(0, 0xFF, 0), keyframes[1]->Value());
1688 EXPECT_EQ(TimingFunction::Type::LINEAR,
1689 keyframes[1]->GetTimingFunctionForTesting()->GetType());
1690 }
1691
TEST_P(AnimationCompositorAnimationsTest,MixedCustomPropertyAnimation)1692 TEST_P(AnimationCompositorAnimationsTest, MixedCustomPropertyAnimation) {
1693 ScopedOffMainThreadCSSPaintForTest off_main_thread_css_paint(true);
1694
1695 RegisterProperty(GetDocument(), "--foo", "<number> | <color>", "0", false);
1696 SetCustomProperty("--foo", "0");
1697
1698 StringKeyframeEffectModel* effect = CreateKeyframeEffectModel(
1699 CreateReplaceOpKeyframe("--foo", "20", 0),
1700 CreateReplaceOpKeyframe("--foo", "rgb(0, 255, 0)", 1.0));
1701
1702 EXPECT_TRUE(CanStartEffectOnCompositor(timing_, *effect) &
1703 CompositorAnimations::kMixedKeyframeValueTypes);
1704 }
1705
TEST_P(AnimationCompositorAnimationsTest,CancelIncompatibleCompositorAnimations)1706 TEST_P(AnimationCompositorAnimationsTest,
1707 CancelIncompatibleCompositorAnimations) {
1708 Persistent<HeapVector<Member<StringKeyframe>>> key_frames =
1709 MakeGarbageCollected<HeapVector<Member<StringKeyframe>>>();
1710 key_frames->push_back(CreateDefaultKeyframe(
1711 CSSPropertyID::kOpacity, EffectModel::kCompositeReplace, 0.0));
1712 key_frames->push_back(CreateDefaultKeyframe(
1713 CSSPropertyID::kOpacity, EffectModel::kCompositeReplace, 1.0));
1714 KeyframeEffectModelBase* animation_effect1 =
1715 MakeGarbageCollected<StringKeyframeEffectModel>(*key_frames);
1716 KeyframeEffectModelBase* animation_effect2 =
1717 MakeGarbageCollected<StringKeyframeEffectModel>(*key_frames);
1718
1719 Timing timing;
1720 timing.iteration_duration = AnimationTimeDelta::FromSecondsD(1);
1721
1722 // The first animation for opacity is ok to run on compositor.
1723 auto* keyframe_effect1 = MakeGarbageCollected<KeyframeEffect>(
1724 element_.Get(), animation_effect1, timing);
1725 Animation* animation1 = timeline_->Play(keyframe_effect1);
1726 auto style = ComputedStyle::Create();
1727 animation_effect1->SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(),
1728 *style, nullptr);
1729 EXPECT_EQ(CheckCanStartEffectOnCompositor(timing, *element_.Get(), animation1,
1730 *animation_effect1),
1731 CompositorAnimations::kNoFailure);
1732
1733 // The second animation for opacity is not ok to run on compositor.
1734 auto* keyframe_effect2 = MakeGarbageCollected<KeyframeEffect>(
1735 element_.Get(), animation_effect2, timing);
1736 Animation* animation2 = timeline_->Play(keyframe_effect2);
1737 animation_effect2->SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(),
1738 *style, nullptr);
1739 EXPECT_TRUE(CheckCanStartEffectOnCompositor(timing, *element_.Get(),
1740 animation2, *animation_effect2) &
1741 CompositorAnimations::kTargetHasIncompatibleAnimations);
1742 EXPECT_FALSE(animation2->HasActiveAnimationsOnCompositor());
1743
1744 // A fallback to blink implementation needed, so cancel all compositor-side
1745 // opacity animations for this element.
1746 animation2->CancelIncompatibleAnimationsOnCompositor();
1747
1748 EXPECT_FALSE(animation1->HasActiveAnimationsOnCompositor());
1749 EXPECT_FALSE(animation2->HasActiveAnimationsOnCompositor());
1750
1751 SimulateFrame(0);
1752 EXPECT_EQ(2U, element_->GetElementAnimations()->Animations().size());
1753
1754 // After finishing and collecting garbage there should be no
1755 // ElementAnimations on the element.
1756 SimulateFrame(1.);
1757 ThreadState::Current()->CollectAllGarbageForTesting();
1758 EXPECT_TRUE(element_->GetElementAnimations()->Animations().IsEmpty());
1759 }
1760
1761 namespace {
1762
UpdateDummyTransformNode(ObjectPaintProperties & properties,CompositingReasons reasons)1763 void UpdateDummyTransformNode(ObjectPaintProperties& properties,
1764 CompositingReasons reasons) {
1765 // Initialize with TransformationMatrix() to avoid 2d translation optimization
1766 // in case of transform animation.
1767 TransformPaintPropertyNode::State state{TransformationMatrix()};
1768 state.direct_compositing_reasons = reasons;
1769 properties.UpdateTransform(TransformPaintPropertyNode::Root(),
1770 std::move(state));
1771 }
1772
UpdateDummyEffectNode(ObjectPaintProperties & properties,CompositingReasons reasons)1773 void UpdateDummyEffectNode(ObjectPaintProperties& properties,
1774 CompositingReasons reasons) {
1775 EffectPaintPropertyNode::State state;
1776 state.direct_compositing_reasons = reasons;
1777 properties.UpdateEffect(EffectPaintPropertyNode::Root(), std::move(state));
1778 }
1779
1780 } // namespace
1781
TEST_P(AnimationCompositorAnimationsTest,CanStartElementOnCompositorTransformBasedOnPaintProperties)1782 TEST_P(AnimationCompositorAnimationsTest,
1783 CanStartElementOnCompositorTransformBasedOnPaintProperties) {
1784 Persistent<Element> element = GetDocument().CreateElementForBinding("shared");
1785 LayoutObjectProxy* layout_object = LayoutObjectProxy::Create(element.Get());
1786 layout_object->EnsureIdForTestingProxy();
1787 element->SetLayoutObject(layout_object);
1788
1789 auto& properties = layout_object->GetMutableForPainting()
1790 .FirstFragment()
1791 .EnsurePaintProperties();
1792
1793 // Add a transform with a compositing reason, which should allow starting
1794 // animation.
1795 UpdateDummyTransformNode(properties,
1796 CompositingReason::kActiveTransformAnimation);
1797 EXPECT_EQ(CheckCanStartElementOnCompositor(*element),
1798 CompositorAnimations::kNoFailure);
1799
1800 // Setting to CompositingReasonNone should produce false.
1801 UpdateDummyTransformNode(properties, CompositingReason::kNone);
1802 EXPECT_TRUE(CheckCanStartElementOnCompositor(*element) &
1803 CompositorAnimations::kTargetHasInvalidCompositingState);
1804
1805 // Clearing the transform node entirely should also produce false.
1806 properties.ClearTransform();
1807 EXPECT_TRUE(CheckCanStartElementOnCompositor(*element) &
1808 CompositorAnimations::kTargetHasInvalidCompositingState);
1809
1810 element->SetLayoutObject(nullptr);
1811 LayoutObjectProxy::Dispose(layout_object);
1812 }
1813
TEST_P(AnimationCompositorAnimationsTest,CanStartElementOnCompositorEffectBasedOnPaintProperties)1814 TEST_P(AnimationCompositorAnimationsTest,
1815 CanStartElementOnCompositorEffectBasedOnPaintProperties) {
1816 Persistent<Element> element = GetDocument().CreateElementForBinding("shared");
1817 LayoutObjectProxy* layout_object = LayoutObjectProxy::Create(element.Get());
1818 layout_object->EnsureIdForTestingProxy();
1819 element->SetLayoutObject(layout_object);
1820
1821 auto& properties = layout_object->GetMutableForPainting()
1822 .FirstFragment()
1823 .EnsurePaintProperties();
1824
1825 // Add an effect with a compositing reason, which should allow starting
1826 // animation.
1827 UpdateDummyEffectNode(properties,
1828 CompositingReason::kActiveTransformAnimation);
1829 EXPECT_EQ(CheckCanStartElementOnCompositor(*element),
1830 CompositorAnimations::kNoFailure);
1831
1832 // Setting to CompositingReasonNone should produce false.
1833 UpdateDummyEffectNode(properties, CompositingReason::kNone);
1834 EXPECT_TRUE(CheckCanStartElementOnCompositor(*element) &
1835 CompositorAnimations::kTargetHasInvalidCompositingState);
1836
1837 // Clearing the effect node entirely should also produce false.
1838 properties.ClearEffect();
1839 EXPECT_TRUE(CheckCanStartElementOnCompositor(*element) &
1840 CompositorAnimations::kTargetHasInvalidCompositingState);
1841
1842 element->SetLayoutObject(nullptr);
1843 LayoutObjectProxy::Dispose(layout_object);
1844 }
1845
TEST_P(AnimationCompositorAnimationsTest,TrackRafAnimation)1846 TEST_P(AnimationCompositorAnimationsTest, TrackRafAnimation) {
1847 LoadTestData("raf-countdown.html");
1848
1849 cc::AnimationHost* host =
1850 GetFrame()->GetDocument()->View()->GetCompositorAnimationHost();
1851
1852 // The test file registers two rAF 'animations'; one which ends after 5
1853 // iterations and the other that ends after 10.
1854 for (int i = 0; i < 9; i++) {
1855 BeginFrame();
1856 EXPECT_TRUE(host->CurrentFrameHadRAF());
1857 EXPECT_TRUE(host->NextFrameHasPendingRAF());
1858 }
1859
1860 // On the 10th iteration, there should be a current rAF, but no more pending
1861 // rAFs.
1862 BeginFrame();
1863 EXPECT_TRUE(host->CurrentFrameHadRAF());
1864 EXPECT_FALSE(host->NextFrameHasPendingRAF());
1865
1866 // On the 11th iteration, there should be no more rAFs firing.
1867 BeginFrame();
1868 EXPECT_FALSE(host->CurrentFrameHadRAF());
1869 EXPECT_FALSE(host->NextFrameHasPendingRAF());
1870 }
1871
TEST_P(AnimationCompositorAnimationsTest,TrackRafAnimationTimeout)1872 TEST_P(AnimationCompositorAnimationsTest, TrackRafAnimationTimeout) {
1873 LoadTestData("raf-timeout.html");
1874
1875 cc::AnimationHost* host =
1876 GetFrame()->GetDocument()->View()->GetCompositorAnimationHost();
1877
1878 // The test file executes a rAF, which fires a setTimeout for the next rAF.
1879 // Even with setTimeout(func, 0), the next rAF is not considered pending.
1880 BeginFrame();
1881 EXPECT_TRUE(host->CurrentFrameHadRAF());
1882 EXPECT_FALSE(host->NextFrameHasPendingRAF());
1883 }
1884
TEST_P(AnimationCompositorAnimationsTest,TrackRafAnimationNoneRegistered)1885 TEST_P(AnimationCompositorAnimationsTest, TrackRafAnimationNoneRegistered) {
1886 SetBodyInnerHTML("<div id='box'></div>");
1887
1888 // Run a full frame after loading the test data so that scripted animations
1889 // are serviced and data propagated.
1890 BeginFrame();
1891
1892 // The HTML does not have any rAFs.
1893 cc::AnimationHost* host =
1894 GetFrame()->GetDocument()->View()->GetCompositorAnimationHost();
1895 EXPECT_FALSE(host->CurrentFrameHadRAF());
1896 EXPECT_FALSE(host->NextFrameHasPendingRAF());
1897
1898 // And still shouldn't after another frame.
1899 BeginFrame();
1900 EXPECT_FALSE(host->CurrentFrameHadRAF());
1901 EXPECT_FALSE(host->NextFrameHasPendingRAF());
1902 }
1903
TEST_P(AnimationCompositorAnimationsTest,CompositedTransformAnimation)1904 TEST_P(AnimationCompositorAnimationsTest, CompositedTransformAnimation) {
1905 // TODO(wangxianzhu): Fix this test for CompositeAfterPaint.
1906 if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
1907 return;
1908
1909 LoadTestData("transform-animation.html");
1910 Document* document = GetFrame()->GetDocument();
1911 Element* target = document->getElementById("target");
1912 const ObjectPaintProperties* properties =
1913 target->GetLayoutObject()->FirstFragment().PaintProperties();
1914 ASSERT_NE(nullptr, properties);
1915 const auto* transform = properties->Transform();
1916 ASSERT_NE(nullptr, transform);
1917 EXPECT_TRUE(transform->HasDirectCompositingReasons());
1918 EXPECT_TRUE(transform->HasActiveTransformAnimation());
1919
1920 // Make sure the animation state is initialized in paint properties.
1921 auto* property_trees =
1922 document->View()->RootCcLayer()->layer_tree_host()->property_trees();
1923 auto* cc_transform = property_trees->transform_tree.Node(
1924 property_trees->element_id_to_transform_node_index
1925 [transform->GetCompositorElementId()]);
1926 ASSERT_NE(nullptr, cc_transform);
1927 EXPECT_TRUE(cc_transform->has_potential_animation);
1928 EXPECT_TRUE(cc_transform->is_currently_animating);
1929 EXPECT_EQ(cc::kNotScaled, cc_transform->starting_animation_scale);
1930 EXPECT_EQ(cc::kNotScaled, cc_transform->maximum_animation_scale);
1931
1932 // Make sure the animation is started on the compositor.
1933 EXPECT_EQ(CheckCanStartElementOnCompositor(*target),
1934 CompositorAnimations::kNoFailure);
1935 EXPECT_EQ(document->Timeline().AnimationsNeedingUpdateCount(), 1u);
1936 cc::AnimationHost* host = document->View()->GetCompositorAnimationHost();
1937 EXPECT_EQ(host->MainThreadAnimationsCount(), 0u);
1938 EXPECT_EQ(host->CompositedAnimationsCount(), 1u);
1939 }
1940
TEST_P(AnimationCompositorAnimationsTest,CompositedScaleAnimation)1941 TEST_P(AnimationCompositorAnimationsTest, CompositedScaleAnimation) {
1942 // TODO(wangxianzhu): Fix this test for CompositeAfterPaint.
1943 if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
1944 return;
1945
1946 LoadTestData("scale-animation.html");
1947 Document* document = GetFrame()->GetDocument();
1948 Element* target = document->getElementById("target");
1949 const ObjectPaintProperties* properties =
1950 target->GetLayoutObject()->FirstFragment().PaintProperties();
1951 ASSERT_NE(nullptr, properties);
1952 const auto* transform = properties->Transform();
1953 ASSERT_NE(nullptr, transform);
1954 EXPECT_TRUE(transform->HasDirectCompositingReasons());
1955 EXPECT_TRUE(transform->HasActiveTransformAnimation());
1956
1957 // Make sure the animation state is initialized in paint properties.
1958 auto* property_trees =
1959 document->View()->RootCcLayer()->layer_tree_host()->property_trees();
1960 auto* cc_transform = property_trees->transform_tree.Node(
1961 property_trees->element_id_to_transform_node_index
1962 [transform->GetCompositorElementId()]);
1963 ASSERT_NE(nullptr, cc_transform);
1964 EXPECT_TRUE(cc_transform->has_potential_animation);
1965 EXPECT_TRUE(cc_transform->is_currently_animating);
1966 EXPECT_EQ(2.f, cc_transform->starting_animation_scale);
1967 EXPECT_EQ(5.f, cc_transform->maximum_animation_scale);
1968
1969 // Make sure the animation is started on the compositor.
1970 EXPECT_EQ(CheckCanStartElementOnCompositor(*target),
1971 CompositorAnimations::kNoFailure);
1972 EXPECT_EQ(document->Timeline().AnimationsNeedingUpdateCount(), 1u);
1973 cc::AnimationHost* host = document->View()->GetCompositorAnimationHost();
1974 EXPECT_EQ(host->MainThreadAnimationsCount(), 0u);
1975 EXPECT_EQ(host->CompositedAnimationsCount(), 1u);
1976 }
1977
TEST_P(AnimationCompositorAnimationsTest,NonAnimatedTransformPropertyChangeGetsUpdated)1978 TEST_P(AnimationCompositorAnimationsTest,
1979 NonAnimatedTransformPropertyChangeGetsUpdated) {
1980 // TODO(wangxianzhu): Fix this test for CompositeAfterPaint.
1981 if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
1982 return;
1983
1984 LoadTestData("transform-animation-update.html");
1985 Document* document = GetFrame()->GetDocument();
1986 Element* target = document->getElementById("target");
1987 const ObjectPaintProperties* properties =
1988 target->GetLayoutObject()->FirstFragment().PaintProperties();
1989 ASSERT_NE(nullptr, properties);
1990 const auto* transform = properties->Transform();
1991 ASSERT_NE(nullptr, transform);
1992 // Make sure composited animation is running on #target.
1993 EXPECT_TRUE(transform->HasDirectCompositingReasons());
1994 EXPECT_TRUE(transform->HasActiveTransformAnimation());
1995 EXPECT_EQ(CheckCanStartElementOnCompositor(*target),
1996 CompositorAnimations::kNoFailure);
1997 // Make sure the animation state is initialized in paint properties.
1998 auto* property_trees =
1999 document->View()->RootCcLayer()->layer_tree_host()->property_trees();
2000 auto* cc_transform = property_trees->transform_tree.Node(
2001 property_trees->element_id_to_transform_node_index
2002 [transform->GetCompositorElementId()]);
2003 ASSERT_NE(nullptr, cc_transform);
2004 EXPECT_TRUE(cc_transform->has_potential_animation);
2005 EXPECT_TRUE(cc_transform->is_currently_animating);
2006 // Make sure the animation is started on the compositor.
2007 EXPECT_EQ(document->Timeline().AnimationsNeedingUpdateCount(), 1u);
2008 cc::AnimationHost* host = document->View()->GetCompositorAnimationHost();
2009 EXPECT_EQ(host->MainThreadAnimationsCount(), 0u);
2010 EXPECT_EQ(host->CompositedAnimationsCount(), 1u);
2011 // Make sure the backface-visibility is correctly set, both in blink and on
2012 // the cc::Layer.
2013 EXPECT_FALSE(transform->Matrix().IsIdentity()); // Rotated
2014 EXPECT_EQ(transform->GetBackfaceVisibilityForTesting(),
2015 TransformPaintPropertyNode::BackfaceVisibility::kVisible);
2016 const CompositedLayerMapping* composited_layer_mapping =
2017 ToLayoutBoxModelObject(target->GetLayoutObject())
2018 ->Layer()
2019 ->GetCompositedLayerMapping();
2020 ASSERT_NE(nullptr, composited_layer_mapping);
2021 const cc::PictureLayer* layer =
2022 composited_layer_mapping->MainGraphicsLayer()->CcLayer();
2023 ASSERT_NE(nullptr, layer);
2024 EXPECT_TRUE(layer->double_sided());
2025
2026 // Change the backface visibility, while the compositor animation is
2027 // happening.
2028 target->setAttribute(html_names::kClassAttr, "backface-hidden");
2029 ForceFullCompositingUpdate();
2030 // Make sure the setting made it to both blink and all the way to CC.
2031 EXPECT_EQ(transform->GetBackfaceVisibilityForTesting(),
2032 TransformPaintPropertyNode::BackfaceVisibility::kHidden);
2033 EXPECT_FALSE(layer->double_sided())
2034 << "Change to hidden did not get propagated to CC";
2035 // Make sure the animation state is initialized in paint properties after
2036 // blink pushing new paint properties without animation state change.
2037 property_trees =
2038 document->View()->RootCcLayer()->layer_tree_host()->property_trees();
2039 cc_transform = property_trees->transform_tree.Node(
2040 property_trees->element_id_to_transform_node_index
2041 [transform->GetCompositorElementId()]);
2042 ASSERT_NE(nullptr, cc_transform);
2043 EXPECT_TRUE(cc_transform->has_potential_animation);
2044 EXPECT_TRUE(cc_transform->is_currently_animating);
2045 }
2046
2047 // Regression test for https://crbug.com/781305. When we have a transform
2048 // animation on a SVG element, the effect can be started on compositor but the
2049 // element itself cannot.
TEST_P(AnimationCompositorAnimationsTest,CannotStartElementOnCompositorEffectSVG)2050 TEST_P(AnimationCompositorAnimationsTest,
2051 CannotStartElementOnCompositorEffectSVG) {
2052 LoadTestData("transform-animation-on-svg.html");
2053 Document* document = GetFrame()->GetDocument();
2054 Element* target = document->getElementById("dots");
2055 EXPECT_TRUE(CheckCanStartElementOnCompositor(*target) &
2056 CompositorAnimations::kTargetHasInvalidCompositingState);
2057 EXPECT_EQ(document->Timeline().AnimationsNeedingUpdateCount(), 4u);
2058 cc::AnimationHost* host = document->View()->GetCompositorAnimationHost();
2059 EXPECT_EQ(host->MainThreadAnimationsCount(), 4u);
2060 EXPECT_EQ(host->CompositedAnimationsCount(), 0u);
2061 }
2062
2063 // Regression test for https://crbug.com/999333. We were relying on the Document
2064 // always having Settings, which will not be the case if it is not attached to a
2065 // Frame.
TEST_P(AnimationCompositorAnimationsTest,DocumentWithoutSettingShouldNotCauseCrash)2066 TEST_P(AnimationCompositorAnimationsTest,
2067 DocumentWithoutSettingShouldNotCauseCrash) {
2068 SetBodyInnerHTML("<div id='target'></div>");
2069 Element* target = GetElementById("target");
2070 ASSERT_TRUE(target);
2071
2072 // Move the target element to another Document, that does not have a frame
2073 // (and thus no Settings).
2074 Document* another_document = MakeGarbageCollected<Document>();
2075 ASSERT_FALSE(another_document->GetSettings());
2076
2077 another_document->adoptNode(target, ASSERT_NO_EXCEPTION);
2078
2079 // This should not crash.
2080 EXPECT_NE(CheckCanStartElementOnCompositor(*target),
2081 CompositorAnimations::kNoFailure);
2082 }
2083
2084 } // namespace blink
2085