diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index e1b1145a5a6..f736fffeb57 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -1320,6 +1320,7 @@ GK_ATOM(onrepeat, "onrepeat") GK_ATOM(onrepeatEvent, "onrepeatEvent") GK_ATOM(repeatCount, "repeatCount") GK_ATOM(repeatDur, "repeatDur") +GK_ATOM(repeatEvent, "repeatEvent") GK_ATOM(restart, "restart") GK_ATOM(to, "to") GK_ATOM(XML, "XML") diff --git a/content/smil/nsSMILParserUtils.cpp b/content/smil/nsSMILParserUtils.cpp index 4eb0bf9a374..5c9f1a69c2d 100644 --- a/content/smil/nsSMILParserUtils.cpp +++ b/content/smil/nsSMILParserUtils.cpp @@ -60,7 +60,9 @@ const PRUint32 MSEC_PER_MIN = 1000 * 60; const PRUint32 MSEC_PER_HOUR = 1000 * 60 * 60; const PRInt32 DECIMAL_BASE = 10; -#define ACCESSKEY_PREFIX NS_LITERAL_STRING("accesskey(") +// XXX SVG/SMIL Animation use 'accessKey' whilst SMIL3 uses 'accesskey' +// We should allow both +#define ACCESSKEY_PREFIX NS_LITERAL_STRING("accessKey(") #define REPEAT_PREFIX NS_LITERAL_STRING("repeat(") #define WALLCLOCK_PREFIX NS_LITERAL_STRING("wallclock(") @@ -363,6 +365,9 @@ ParseElementBaseTimeValueSpec(const nsAString& aSpec, // element-name.repeat(3) // event\.name // + // Technically `repeat(3)' is permitted but the behaviour in this case is not + // defined (for SMIL Animation) so we don't support it here. + // const PRUnichar* tokenStart = aSpec.BeginReading(); const PRUnichar* tokenEnd = GetTokenEnd(aSpec, PR_TRUE); diff --git a/content/smil/nsSMILTimeValueSpec.cpp b/content/smil/nsSMILTimeValueSpec.cpp index 421d52df99b..d2d78dc9f6d 100644 --- a/content/smil/nsSMILTimeValueSpec.cpp +++ b/content/smil/nsSMILTimeValueSpec.cpp @@ -47,6 +47,7 @@ #include "nsIEventListenerManager.h" #include "nsIDOMEventGroup.h" #include "nsGUIEvent.h" +#include "nsIDOMTimeEvent.h" #include "nsString.h" using namespace mozilla::dom; @@ -117,6 +118,11 @@ nsSMILTimeValueSpec::SetSpec(const nsAString& aStringSpec, mOwner->AddInstanceTime(new nsSMILInstanceTime(mParams.mOffset), mIsBegin); } + // Fill in the event symbol to simplify handling later + if (mParams.mType == nsSMILTimeValueSpecParams::REPEAT) { + mParams.mEventSymbol = nsGkAtoms::repeatEvent; + } + ResolveReferences(aContextNode); return rv; @@ -126,7 +132,8 @@ void nsSMILTimeValueSpec::ResolveReferences(nsIContent* aContextNode) { if (mParams.mType != nsSMILTimeValueSpecParams::SYNCBASE && - !IsEventBased()) + mParams.mType != nsSMILTimeValueSpecParams::EVENT && + mParams.mType != nsSMILTimeValueSpecParams::REPEAT) return; NS_ABORT_IF_FALSE(aContextNode, @@ -145,11 +152,11 @@ nsSMILTimeValueSpec::ResolveReferences(nsIContent* aContextNode) if (mParams.mDependentElemID) { mReferencedElement.ResetWithID(aContextNode, nsDependentAtomString(mParams.mDependentElemID)); - } else if (IsEventBased()) { + } else if (mParams.mType == nsSMILTimeValueSpecParams::EVENT) { Element* target = mOwner->GetTargetElement(); mReferencedElement.ResetWithElement(target); } else { - NS_ABORT_IF_FALSE(PR_FALSE, "Syncbase element without ID"); + NS_ABORT_IF_FALSE(PR_FALSE, "Syncbase or repeat spec without ID"); } UpdateReferencedElement(oldReferencedElement, mReferencedElement.get()); } @@ -257,13 +264,25 @@ nsSMILTimeValueSpec::UpdateReferencedElement(Element* aFrom, Element* aTo) UnregisterFromReferencedElement(aFrom); - if (mParams.mType == nsSMILTimeValueSpecParams::SYNCBASE) { - nsSMILTimedElement* to = GetTimedElement(aTo); - if (to) { - to->AddDependent(*this); + switch (mParams.mType) + { + case nsSMILTimeValueSpecParams::SYNCBASE: + { + nsSMILTimedElement* to = GetTimedElement(aTo); + if (to) { + to->AddDependent(*this); + } } - } else if (mParams.mType == nsSMILTimeValueSpecParams::EVENT) { + break; + + case nsSMILTimeValueSpecParams::EVENT: + case nsSMILTimeValueSpecParams::REPEAT: RegisterEventListener(aTo); + break; + + default: + // not a referencing-type or not yet supported + break; } } @@ -279,7 +298,7 @@ nsSMILTimeValueSpec::UnregisterFromReferencedElement(Element* aElement) timedElement->RemoveDependent(*this); } mOwner->RemoveInstanceTimesForCreator(this, mIsBegin); - } else if (mParams.mType == nsSMILTimeValueSpecParams::EVENT) { + } else if (IsEventBased()) { UnregisterEventListener(aElement); } } @@ -300,8 +319,10 @@ nsSMILTimeValueSpec::GetTimedElement(Element* aElement) void nsSMILTimeValueSpec::RegisterEventListener(Element* aTarget) { - NS_ABORT_IF_FALSE(mParams.mType == nsSMILTimeValueSpecParams::EVENT, - "Attempting to register event-listener for non-event nsSMILTimeValueSpec"); + NS_ABORT_IF_FALSE(mParams.mType == nsSMILTimeValueSpecParams::EVENT || + mParams.mType == nsSMILTimeValueSpecParams::REPEAT, + "Attempting to register event-listener for unexpected nsSMILTimeValueSpec" + " type"); NS_ABORT_IF_FALSE(mParams.mEventSymbol, "Attempting to register event-listener but there is no event name"); @@ -367,8 +388,9 @@ void nsSMILTimeValueSpec::HandleEvent(nsIDOMEvent* aEvent) { NS_ABORT_IF_FALSE(mEventListener, "Got event without an event listener"); - NS_ABORT_IF_FALSE(mParams.mType == nsSMILTimeValueSpecParams::EVENT, - "Got event for non-event nsSMILTimeValueSpec"); + NS_ABORT_IF_FALSE(IsEventBased(), + "Got event for non-event nsSMILTimeValueSpec"); + NS_ABORT_IF_FALSE(aEvent, "No event supplied"); // XXX In the long run we should get the time from the event itself which will // store the time in global document time which we'll need to convert to our @@ -377,6 +399,9 @@ nsSMILTimeValueSpec::HandleEvent(nsIDOMEvent* aEvent) if (!container) return; + if (!CheckEventDetail(aEvent)) + return; + nsSMILTime currentTime = container->GetCurrentTime(); nsSMILTimeValue newTime(currentTime + mParams.mOffset.GetMillis()); @@ -385,6 +410,23 @@ nsSMILTimeValueSpec::HandleEvent(nsIDOMEvent* aEvent) mOwner->AddInstanceTime(newInstance, mIsBegin); } +PRBool +nsSMILTimeValueSpec::CheckEventDetail(nsIDOMEvent *aEvent) +{ + if (mParams.mType != nsSMILTimeValueSpecParams::REPEAT) + return PR_TRUE; + + nsCOMPtr timeEvent = do_QueryInterface(aEvent); + if (!timeEvent) { + NS_WARNING("Received a repeat event that was not a DOMTimeEvent"); + return PR_FALSE; + } + + PRInt32 detail; + timeEvent->GetDetail(&detail); + return detail == mParams.mRepeatIterationOrAccessKey; +} + nsSMILTimeValue nsSMILTimeValueSpec::ConvertBetweenTimeContainers( const nsSMILTimeValue& aSrcTime, diff --git a/content/smil/nsSMILTimeValueSpec.h b/content/smil/nsSMILTimeValueSpec.h index 4f1ec968b17..ed14c21fb48 100644 --- a/content/smil/nsSMILTimeValueSpec.h +++ b/content/smil/nsSMILTimeValueSpec.h @@ -98,6 +98,7 @@ protected: nsIEventListenerManager* GetEventListenerManager(Element* aElement, nsIDOMEventGroup** aSystemGroup); void HandleEvent(nsIDOMEvent* aEvent); + PRBool CheckEventDetail(nsIDOMEvent* aEvent); nsSMILTimeValue ConvertBetweenTimeContainers(const nsSMILTimeValue& aSrcTime, const nsSMILTimeContainer* aSrcContainer); diff --git a/content/smil/test/Makefile.in b/content/smil/test/Makefile.in index 77e4640a4cf..a687182746e 100644 --- a/content/smil/test/Makefile.in +++ b/content/smil/test/Makefile.in @@ -77,6 +77,7 @@ _TEST_FILES = \ test_smilGetSimpleDuration.xhtml \ test_smilKeySplines.xhtml \ test_smilKeyTimesPacedMode.xhtml \ + test_smilRepeatTiming.xhtml \ test_smilSetCurrentTime.xhtml \ test_smilSync.xhtml \ test_smilSyncbaseTarget.xhtml \ diff --git a/content/smil/test/test_smilRepeatTiming.xhtml b/content/smil/test/test_smilRepeatTiming.xhtml new file mode 100644 index 00000000000..89c67d280de --- /dev/null +++ b/content/smil/test/test_smilRepeatTiming.xhtml @@ -0,0 +1,96 @@ + + + + Test repeat timing + + + + + +Mozilla Bug + 485157 +

+ +
+
+
+ +