Bug 1032573 part 5 - Add GetAnimationPlayers to Element; r=bz
authorBrian Birtles <birtles@gmail.com>
Wed, 16 Jul 2014 09:02:31 +0900
changeset 216193 e672d5bffa8f0b3635c2cd1ff7811376e5a377f7
parent 216192 08f2190d7e40f18e738b6c32a83dc07fb45af29d
child 216194 f681694c9df1cd5c23fd05ed0d92cacfd1cfd789
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1032573
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1032573 part 5 - Add GetAnimationPlayers to Element; r=bz This patch adds the WebIDL definitions and implementation of getAnimationPlayers on Element. It does not include the full definition of AnimationPlayer but only readonly versions of the currentTime and startTime attributes since these are easy to implement and enable identifying the different animations that are returned for the sake of testing. Web Animations defines getAnimationPlayers as only returning the animations that are either running or will run in the future (known as "current" animations). This will likely change since it seems desirable to be able query animations that have finished but are applying a forwards fill. For now, however, this patch makes us only return animations that have not finished. This patch also removes an assertion in ElementAnimation::GetLocalTime that would fail if called on a finished transition. This assertion is no longer necessary since an earlier patch in this series removed the overloading of the animation start time that meant calling this on a finished transition was unsafe. Furthermore, this assertion, if it were not removed, would fail if script holds onto a transition and queries its start time after it completed.
content/base/public/Element.h
content/base/src/Element.cpp
content/base/src/nsINode.cpp
dom/bindings/Bindings.conf
dom/webidl/Animatable.webidl
dom/webidl/AnimationPlayer.webidl
dom/webidl/Element.webidl
dom/webidl/moz.build
layout/style/AnimationCommon.cpp
layout/style/AnimationCommon.h
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -96,16 +96,17 @@ enum {
 };
 
 #undef ELEMENT_FLAG_BIT
 
 // Make sure we have space for our bits
 ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET);
 
 namespace mozilla {
+class ElementAnimation;
 class EventChainPostVisitor;
 class EventChainPreVisitor;
 class EventChainVisitor;
 class EventListenerManager;
 class EventStateManager;
 
 namespace dom {
 
@@ -778,16 +779,18 @@ public:
   {
     return false;
   }
 
   virtual void SetUndoScope(bool aUndoScope, ErrorResult& aError)
   {
   }
 
+  void GetAnimationPlayers(nsTArray<nsRefPtr<ElementAnimation> >& aPlayers);
+
   NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML);
   virtual void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
   void GetOuterHTML(nsAString& aOuterHTML);
   void SetOuterHTML(const nsAString& aOuterHTML, ErrorResult& aError);
   void InsertAdjacentHTML(const nsAString& aPosition, const nsAString& aText,
                           ErrorResult& aError);
 
   //----------------------------------------
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -7,16 +7,17 @@
 /*
  * Base class for all element classes; this provides an implementation
  * of DOM Core's nsIDOMElement, implements nsIContent, provides
  * utility methods for subclasses, and so forth.
  */
 
 #include "mozilla/dom/ElementInlines.h"
 
+#include "AnimationCommon.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/dom/Attr.h"
 #include "nsDOMAttributeMap.h"
 #include "nsIAtom.h"
 #include "nsIContentInlines.h"
 #include "mozilla/dom/NodeInfo.h"
 #include "nsIDocumentInlines.h"
 #include "nsIDOMNodeList.h"
@@ -2859,16 +2860,46 @@ Element::MozRequestFullScreen()
 }
 
 void
 Element::MozRequestPointerLock()
 {
   OwnerDoc()->RequestPointerLock(this);
 }
 
+void
+Element::GetAnimationPlayers(nsTArray<nsRefPtr<ElementAnimation> >& aPlayers)
+{
+  mozilla::TimeStamp now = OwnerDoc()->Timeline()->GetCurrentTimeStamp();
+  if (now.IsNull()) {
+    // If the timeline doesn't have a current time, return an empty list.
+    return;
+  }
+
+  nsIAtom* properties[] = { nsGkAtoms::transitionsProperty,
+                            nsGkAtoms::animationsProperty };
+  for (size_t propIdx = 0; propIdx < MOZ_ARRAY_LENGTH(properties);
+       propIdx++) {
+    ElementAnimationCollection* collection =
+      static_cast<ElementAnimationCollection*>(
+        GetProperty(properties[propIdx]));
+    if (!collection) {
+      continue;
+    }
+    for (size_t animIdx = 0;
+         animIdx < collection->mAnimations.Length();
+         animIdx++) {
+      ElementAnimation* anim = collection->mAnimations[animIdx];
+      if (anim->IsCurrentAt(now)) {
+        aPlayers.AppendElement(anim);
+      }
+    }
+  }
+}
+
 NS_IMETHODIMP
 Element::GetInnerHTML(nsAString& aInnerHTML)
 {
   GetMarkup(false, aInnerHTML);
   return NS_OK;
 }
 
 void
--- a/content/base/src/nsINode.cpp
+++ b/content/base/src/nsINode.cpp
@@ -16,16 +16,17 @@
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/CORSMode.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Telemetry.h"
+#include "mozilla/TimeStamp.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "nsAttrValueOrString.h"
 #include "nsBindingManager.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsContentList.h"
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -131,16 +131,21 @@ DOMInterfaces = {
         'channelInterpretation': 'channelInterpretationValue',
     },
 },
 
 'AudioProcessingEvent' : {
     'resultNotAddRefed': [ 'inputBuffer', 'outputBuffer' ],
 },
 
+'AnimationPlayer' : {
+    'nativeType': 'mozilla::ElementAnimation',
+    'headerFile': 'AnimationCommon.h',
+},
+
 'BarProp': {
     'headerFile': 'mozilla/dom/BarProps.h',
 },
 
 'BiquadFilterNode': {
     'resultNotAddRefed': [ 'frequency', 'detune', 'q', 'gain' ],
 },
 
new file mode 100644
--- /dev/null
+++ b/dom/webidl/Animatable.webidl
@@ -0,0 +1,17 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://dev.w3.org/fxtf/web-animations/#the-animatable-interface
+ *
+ * Copyright © 2014 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+[NoInterfaceObject]
+interface Animatable {
+  [Pref="dom.animations-api.core.enabled"]
+  sequence<AnimationPlayer> getAnimationPlayers();
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/AnimationPlayer.webidl
@@ -0,0 +1,17 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://dev.w3.org/fxtf/web-animations/#the-animationtimeline-interface
+ *
+ * Copyright © 2014 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+[Pref="dom.animations-api.core.enabled"]
+interface AnimationPlayer {
+  [Pure] readonly attribute double startTime;
+  readonly attribute double currentTime;
+};
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -207,8 +207,9 @@ partial interface Element {
   NodeList getDestinationInsertionPoints();
   [Func="nsDocument::IsWebComponentsEnabled"]
   readonly attribute ShadowRoot? shadowRoot;
 };
 
 Element implements ChildNode;
 Element implements NonDocumentTypeChildNode;
 Element implements ParentNode;
+Element implements Animatable;
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -14,17 +14,19 @@ PREPROCESSED_WEBIDL_FILES = [
     'Window.webidl',
 ]
 
 WEBIDL_FILES = [
     'AbstractWorker.webidl',
     'ActivityRequestHandler.webidl',
     'AlarmsManager.webidl',
     'AnalyserNode.webidl',
+    'Animatable.webidl',
     'AnimationEvent.webidl',
+    'AnimationPlayer.webidl',
     'AnimationTimeline.webidl',
     'AppInfo.webidl',
     'AppNotificationServiceOptions.webidl',
     'APZTestData.webidl',
     'ArchiveReader.webidl',
     'ArchiveRequest.webidl',
     'Attr.webidl',
     'AudioBuffer.webidl',
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AnimationCommon.h"
 #include "nsTransitionManager.h"
 #include "nsAnimationManager.h"
 
+#include "mozilla/dom/AnimationPlayerBinding.h"
 #include "ActiveLayerTracker.h"
 #include "gfxPlatform.h"
 #include "nsRuleData.h"
 #include "nsCSSPropertySet.h"
 #include "nsCSSValue.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsStyleContext.h"
 #include "nsIFrame.h"
@@ -402,20 +403,56 @@ ComputedTimingFunction::GetValue(double 
 
 } /* end sub-namespace css */
 
 // In the Web Animations model, the time fraction can be outside the range
 // [0.0, 1.0] but it shouldn't be Infinity.
 const double ComputedTiming::kNullTimeFraction =
   mozilla::PositiveInfinity<double>();
 
-NS_IMPL_CYCLE_COLLECTION(ElementAnimation, mTimeline)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ElementAnimation, mTimeline)
+
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(ElementAnimation, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(ElementAnimation, Release)
 
+JSObject*
+ElementAnimation::WrapObject(JSContext* aCx)
+{
+  return dom::AnimationPlayerBinding::Wrap(aCx, this);
+}
+
+double
+ElementAnimation::StartTime() const
+{
+  Nullable<double> startTime = mTimeline->ToTimelineTime(mStartTime);
+  return startTime.IsNull() ? 0.0 : startTime.Value();
+}
+
+double
+ElementAnimation::CurrentTime() const
+{
+  TimeStamp now = mTimeline->GetCurrentTimeStamp();
+  // |now| should only be null when we don't have a refresh driver.
+  //
+  // If we previously had a refresh driver, the correct thing would be to store
+  // the last refresh time in the AnimationTimeline, return that from
+  // GetCurrentTimeStamp and use that here.
+  //
+  // If we never had a refresh driver then any start times would be null we can
+  // do here is return 0 (that is, until we allow returning a null start time).
+  //
+  // Since we don't yet record the last refresh time we just return 0 in both
+  // cases.
+  if (now.IsNull()) {
+    return 0.0;
+  }
+
+  return GetLocalTimeAt(now).ToMilliseconds();
+}
+
 bool
 ElementAnimation::IsRunningAt(TimeStamp aTime) const
 {
   if (IsPaused() || IsFinishedTransition()) {
     return false;
   }
 
   ComputedTiming computedTiming =
--- a/layout/style/AnimationCommon.h
+++ b/layout/style/AnimationCommon.h
@@ -21,16 +21,20 @@
 #include "mozilla/FloatingPoint.h"
 #include "nsCSSPseudoElements.h"
 #include "nsCycleCollectionParticipant.h"
 
 class nsIFrame;
 class nsPresContext;
 class nsStyleChangeList;
 
+// X11 has a #define for CurrentTime.
+#ifdef CurrentTime
+#undef CurrentTime
+#endif
 
 namespace mozilla {
 
 class StyleAnimationValue;
 struct ElementPropertyTransition;
 struct ElementAnimationCollection;
 
 namespace css {
@@ -302,32 +306,40 @@ struct ComputedTiming
     AnimationPhase_After
   } mPhase;
 };
 
 /**
  * Data about one animation (i.e., one of the values of
  * 'animation-name') running on an element.
  */
-struct ElementAnimation
+class ElementAnimation : public nsWrapperCache
 {
 protected:
   virtual ~ElementAnimation() { }
 
 public:
   explicit ElementAnimation(dom::AnimationTimeline* aTimeline)
     : mIsRunningOnCompositor(false)
     , mIsFinishedTransition(false)
     , mLastNotification(LAST_NOTIFICATION_NONE)
     , mTimeline(aTimeline)
   {
+    SetIsDOMBinding();
   }
 
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(ElementAnimation)
-  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ElementAnimation)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(ElementAnimation)
+
+  mozilla::dom::AnimationTimeline* GetParentObject() const { return mTimeline; }
+  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+
+  // AnimationPlayer methods
+  double StartTime() const;
+  double CurrentTime() const;
 
   // FIXME: If we succeed in moving transition-specific code to a type of
   // AnimationEffect (as per the Web Animations API) we should remove these
   // virtual methods.
   virtual ElementPropertyTransition* AsTransition() { return nullptr; }
   virtual const ElementPropertyTransition* AsTransition() const {
     return nullptr;
   }
@@ -352,18 +364,16 @@ public:
   bool IsRunningAt(mozilla::TimeStamp aTime) const;
   bool IsCurrentAt(mozilla::TimeStamp aTime) const;
 
   // Return the duration at aTime (or, if paused, mPauseStart) since
   // the start of the delay period.  May be negative.
   mozilla::TimeDuration GetLocalTimeAt(mozilla::TimeStamp aTime) const {
     MOZ_ASSERT(!IsPaused() || aTime >= mPauseStart,
                "if paused, aTime must be at least mPauseStart");
-    MOZ_ASSERT(!IsFinishedTransition(),
-               "GetLocalTimeAt should not be called on a finished transition");
     return (IsPaused() ? mPauseStart : aTime) - mStartTime;
   }
 
   // Return the duration from the start the active interval to the point where
   // the animation begins playback. This is zero unless the animation has
   // a negative delay in which case it is the absolute value of the delay.
   // This is used for setting the elapsedTime member of AnimationEvents.
   mozilla::TimeDuration InitialAdvance() const {