Commit f65c1e27 authored by haozhe's avatar haozhe Committed by Commit Bot

getAnimations from the Document instead of from Timeline

Per the spec, Document::getAnimations() must report all Animations whose
target effect is the given document.

Spec:
https://drafts.csswg.org/web-animations/#extensions-to-the-documentorshadowroot-interface-mixin

Bug: 828585
Change-Id: I92a5cab69d0b9869fea0238e2cfb8e98d995a3b9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2024539
Commit-Queue: Hao Sheng <haozhes@chromium.org>
Reviewed-by: default avatarRobert Flack <flackr@chromium.org>
Reviewed-by: default avatarKevin Ellis <kevers@chromium.org>
Cr-Commit-Position: refs/heads/master@{#741473}
parent 8d9325b5
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
#include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/page_animator.h"
namespace blink { namespace blink {
...@@ -121,8 +123,29 @@ HeapVector<Member<Animation>> DocumentAnimations::getAnimations() { ...@@ -121,8 +123,29 @@ HeapVector<Member<Animation>> DocumentAnimations::getAnimations() {
// This method implements the Document::getAnimations method defined in the // This method implements the Document::getAnimations method defined in the
// web-animations-1 spec. // web-animations-1 spec.
// https://drafts.csswg.org/web-animations-1/#dom-document-getanimations // https://drafts.csswg.org/web-animations-1/#dom-document-getanimations
// TODO(crbug.com/1046916): refactoring work to create a shared implementation
// of getAnimations for Documents and ShadowRoots.
document_->UpdateStyleAndLayoutTree(); document_->UpdateStyleAndLayoutTree();
HeapVector<Member<Animation>> animations; HeapVector<Member<Animation>> animations;
if (document_->GetPage())
animations = document_->GetPage()->Animator().GetAnimations(document_);
else
GetAnimationsTargetingDocument(document_, animations);
std::sort(animations.begin(), animations.end(), CompareAnimations);
return animations;
}
void DocumentAnimations::Trace(blink::Visitor* visitor) {
visitor->Trace(document_);
visitor->Trace(timelines_);
}
void DocumentAnimations::GetAnimationsTargetingDocument(
Document* document_,
HeapVector<Member<Animation>>& animations) {
// This method follows the timelines in a given docmuent and append all the
// animations to the reference animations.
for (auto& timeline : timelines_) { for (auto& timeline : timelines_) {
for (const auto& animation : timeline->GetAnimations()) { for (const auto& animation : timeline->GetAnimations()) {
if (animation->ReplaceStateRemoved()) if (animation->ReplaceStateRemoved())
...@@ -141,13 +164,5 @@ HeapVector<Member<Animation>> DocumentAnimations::getAnimations() { ...@@ -141,13 +164,5 @@ HeapVector<Member<Animation>> DocumentAnimations::getAnimations() {
animations.push_back(animation); animations.push_back(animation);
} }
} }
std::sort(animations.begin(), animations.end(), CompareAnimations);
return animations;
}
void DocumentAnimations::Trace(Visitor* visitor) {
visitor->Trace(document_);
visitor->Trace(timelines_);
} }
} // namespace blink } // namespace blink
...@@ -51,6 +51,8 @@ class CORE_EXPORT DocumentAnimations final ...@@ -51,6 +51,8 @@ class CORE_EXPORT DocumentAnimations final
void UpdateAnimationTimingForAnimationFrame(); void UpdateAnimationTimingForAnimationFrame();
bool NeedsAnimationTimingUpdate(); bool NeedsAnimationTimingUpdate();
void UpdateAnimationTimingIfNeeded(); void UpdateAnimationTimingIfNeeded();
void GetAnimationsTargetingDocument(Document*,
HeapVector<Member<Animation>>&);
// Updates existing animations as part of generating a new (document // Updates existing animations as part of generating a new (document
// lifecycle) frame. Note that this considers and updates state for // lifecycle) frame. Note that this considers and updates state for
......
...@@ -19,6 +19,22 @@ ...@@ -19,6 +19,22 @@
namespace blink { namespace blink {
namespace {
typedef HeapVector<Member<Document>, 32> DocumentsVector;
// We walk through all the frames in DOM tree order and get all the documents
DocumentsVector GetAllDocuments(Frame* main_frame) {
DocumentsVector documents;
for (Frame* frame = main_frame; frame; frame = frame->Tree().TraverseNext()) {
if (auto* local_frame = DynamicTo<LocalFrame>(frame))
documents.push_back(local_frame->GetDocument());
}
return documents;
}
} // namespace
PageAnimator::PageAnimator(Page& page) PageAnimator::PageAnimator(Page& page)
: page_(page), : page_(page),
servicing_animations_(false), servicing_animations_(false),
...@@ -37,12 +53,7 @@ void PageAnimator::ServiceScriptedAnimations( ...@@ -37,12 +53,7 @@ void PageAnimator::ServiceScriptedAnimations(
Clock().SetAllowedToDynamicallyUpdateTime(false); Clock().SetAllowedToDynamicallyUpdateTime(false);
Clock().UpdateTime(monotonic_animation_start_time); Clock().UpdateTime(monotonic_animation_start_time);
HeapVector<Member<Document>, 32> documents; DocumentsVector documents = GetAllDocuments(page_->MainFrame());
for (Frame* frame = page_->MainFrame(); frame;
frame = frame->Tree().TraverseNext()) {
if (auto* local_frame = DynamicTo<LocalFrame>(frame))
documents.push_back(local_frame->GetDocument());
}
for (auto& document : documents) { for (auto& document : documents) {
ScopedFrameBlamer frame_blamer(document->GetFrame()); ScopedFrameBlamer frame_blamer(document->GetFrame());
...@@ -90,7 +101,7 @@ void PageAnimator::ServiceScriptedAnimations( ...@@ -90,7 +101,7 @@ void PageAnimator::ServiceScriptedAnimations(
} }
void PageAnimator::PostAnimate() { void PageAnimator::PostAnimate() {
HeapVector<Member<Document>, 32> documents; DocumentsVector documents;
for (Frame* frame = page_->MainFrame(); frame; for (Frame* frame = page_->MainFrame(); frame;
frame = frame->Tree().TraverseNext()) { frame = frame->Tree().TraverseNext()) {
if (frame->IsLocalFrame()) if (frame->IsLocalFrame())
...@@ -171,4 +182,14 @@ void PageAnimator::UpdateHitTestOcclusionData(LocalFrame& root_frame) { ...@@ -171,4 +182,14 @@ void PageAnimator::UpdateHitTestOcclusionData(LocalFrame& root_frame) {
} }
} }
HeapVector<Member<Animation>> PageAnimator::GetAnimations(Document* document_) {
HeapVector<Member<Animation>> animations;
DocumentsVector documents = GetAllDocuments(page_->MainFrame());
for (auto& document : documents) {
document->GetDocumentAnimations().GetAnimationsTargetingDocument(
document_, animations);
}
return animations;
}
} // namespace blink } // namespace blink
...@@ -6,8 +6,11 @@ ...@@ -6,8 +6,11 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_PAGE_ANIMATOR_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_PAGE_PAGE_ANIMATOR_H_
#include "third_party/blink/public/common/metrics/document_update_reason.h" #include "third_party/blink/public/common/metrics/document_update_reason.h"
#include "third_party/blink/renderer/core/animation/animation.h"
#include "third_party/blink/renderer/core/animation/animation_clock.h" #include "third_party/blink/renderer/core/animation/animation_clock.h"
#include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/document_lifecycle.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/heap/handle.h"
namespace blink { namespace blink {
...@@ -41,6 +44,7 @@ class CORE_EXPORT PageAnimator final : public GarbageCollected<PageAnimator> { ...@@ -41,6 +44,7 @@ class CORE_EXPORT PageAnimator final : public GarbageCollected<PageAnimator> {
void UpdateLifecycleToLayoutClean(LocalFrame& root_frame, void UpdateLifecycleToLayoutClean(LocalFrame& root_frame,
DocumentUpdateReason reason); DocumentUpdateReason reason);
AnimationClock& Clock() { return animation_clock_; } AnimationClock& Clock() { return animation_clock_; }
HeapVector<Member<Animation>> GetAnimations(Document*);
private: private:
void UpdateHitTestOcclusionData(LocalFrame& root_frame); void UpdateHitTestOcclusionData(LocalFrame& root_frame);
......
...@@ -4,7 +4,8 @@ PASS Document.getAnimations() returns script-generated animations ...@@ -4,7 +4,8 @@ PASS Document.getAnimations() returns script-generated animations
PASS Document.getAnimations() returns script-generated animations in the order they were created PASS Document.getAnimations() returns script-generated animations in the order they were created
PASS Document.getAnimations() does not return a disconnected node PASS Document.getAnimations() does not return a disconnected node
PASS Document.getAnimations() does not return an animation with a null target PASS Document.getAnimations() does not return an animation with a null target
FAIL Document.getAnimations() returns animations on elements inside same-origin iframes assert_equals: expected 1 but got 0 PASS Document.getAnimations() returns animations on elements inside same-origin iframes
PASS iframe.contentDocument.getAnimations() returns animations on elements inside same-origin Document
FAIL ShadowRoot.getAnimations() return all animations in the shadow tree div.shadowRoot.getAnimations is not a function FAIL ShadowRoot.getAnimations() return all animations in the shadow tree div.shadowRoot.getAnimations is not a function
FAIL Document.getAnimations() does NOT return animations in shadow trees assert_array_equals: getAnimations() called on Document does not return animations from shadow trees lengths differ, expected array [] length 0, got [object "[object Animation]"] length 1 FAIL Document.getAnimations() does NOT return animations in shadow trees assert_array_equals: getAnimations() called on Document does not return animations from shadow trees lengths differ, expected array [] length 0, got [object "[object Animation]"] length 1
PASS Document.getAnimations() triggers a style change event PASS Document.getAnimations() triggers a style change event
......
...@@ -13,6 +13,16 @@ ...@@ -13,6 +13,16 @@
const gKeyFrames = { 'marginLeft': ['100px', '200px'] }; const gKeyFrames = { 'marginLeft': ['100px', '200px'] };
async function insert_frame_and_await_load(test, iframe, document) {
const eventWatcher = new EventWatcher(test, iframe, ['load']);
const event_promise = eventWatcher.wait_for('load');
document.body.appendChild(iframe);
test.add_cleanup(() => { document.body.removeChild(iframe); });
await event_promise;
}
test(t => { test(t => {
assert_equals(document.getAnimations().length, 0, assert_equals(document.getAnimations().length, 0,
'getAnimations returns an empty sequence for a document ' + 'getAnimations returns an empty sequence for a document ' +
...@@ -68,14 +78,7 @@ test(t => { ...@@ -68,14 +78,7 @@ test(t => {
promise_test(async t => { promise_test(async t => {
const iframe = document.createElement('iframe'); const iframe = document.createElement('iframe');
insert_frame_and_await_load(t, iframe, document)
const eventWatcher = new EventWatcher(t, iframe, ['load']);
const event_promise = eventWatcher.wait_for('load');
document.body.appendChild(iframe);
t.add_cleanup(() => { document.body.removeChild(iframe); });
await event_promise;
const div = createDiv(t, iframe.contentDocument) const div = createDiv(t, iframe.contentDocument)
const effect = new KeyframeEffect(div, null, 100 * MS_PER_SEC); const effect = new KeyframeEffect(div, null, 100 * MS_PER_SEC);
...@@ -91,6 +94,52 @@ promise_test(async t => { ...@@ -91,6 +94,52 @@ promise_test(async t => {
}, 'Document.getAnimations() returns animations on elements inside same-origin' }, 'Document.getAnimations() returns animations on elements inside same-origin'
+ ' iframes'); + ' iframes');
promise_test(async t => {
const iframe1 = document.createElement('iframe');
const iframe2 = document.createElement('iframe');
insert_frame_and_await_load(t, iframe1, document);
insert_frame_and_await_load(t, iframe2, document);
const div_frame1 = createDiv(t, iframe1.contentDocument)
const div_main_frame = createDiv(t)
const effect1 = new KeyframeEffect(div_frame1, null, 100 * MS_PER_SEC);
const anim1 = new Animation(effect1, document.timeline);
anim1.play();
// Animation of div_frame1 is in iframe with main timeline.
// The animation's timeline is from the iframe, but the effect's target
// element is part of the iframe's document.
assert_equals(document.getAnimations().length, 0);
assert_equals(iframe1.contentDocument.getAnimations().length, 1);
anim1.finish();
// animation of div_frame1 in iframe1 with iframe timeline
const effect2 = new KeyframeEffect(div_frame1, null, 100 * MS_PER_SEC);
const anim2 = new Animation(effect2, iframe1.contentDocument.timeline);
anim2.play();
assert_equals(document.getAnimations().length, 0);
assert_equals(iframe1.contentDocument.getAnimations().length, 1);
anim2.finish();
//animation of div_main_frame in main frame with iframe timeline
const effect3 = new KeyframeEffect(div_main_frame, null, 100 * MS_PER_SEC);
const anim3 = new Animation(effect3, iframe1.contentDocument.timeline);
anim3.play();
assert_equals(document.getAnimations().length, 1);
assert_equals(iframe1.contentDocument.getAnimations().length, 0);
anim3.finish();
//animation of div_frame1 in iframe1 with another iframe's timeline
const effect4 = new KeyframeEffect(div_frame1, null, 100 * MS_PER_SEC);
const anim4 = new Animation(effect4, iframe2.contentDocument.timeline);
anim4.play();
assert_equals(document.getAnimations().length, 0);
assert_equals(iframe1.contentDocument.getAnimations().length, 1);
assert_equals(iframe2.contentDocument.getAnimations().length, 0);
anim4.finish();
}, 'iframe.contentDocument.getAnimations() returns animations on elements '
+ 'inside same-origin Document');
test(t => { test(t => {
const div = createDiv(t); const div = createDiv(t);
const shadow = div.attachShadow({ mode: 'open' }); const shadow = div.attachShadow({ mode: 'open' });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment