Bug 485157: SMIL event timing, part 3 event registration and timing, r=smaug, dholbert; sr=roc, a=roc

This commit is contained in:
Brian Birtles 2010-08-18 19:20:24 +09:00
parent 82b4a7d801
commit f5f57834b2
22 changed files with 493 additions and 68 deletions

View File

@ -44,15 +44,32 @@
#include "nsSMILParserUtils.h"
#include "nsISMILAnimationElement.h"
#include "nsContentUtils.h"
#include "nsIEventListenerManager.h"
#include "nsIDOMEventGroup.h"
#include "nsGUIEvent.h"
#include "nsString.h"
//----------------------------------------------------------------------
// Nested class: EventListener
NS_IMPL_ISUPPORTS1(nsSMILTimeValueSpec::EventListener, nsIDOMEventListener)
NS_IMETHODIMP
nsSMILTimeValueSpec::EventListener::HandleEvent(nsIDOMEvent* aEvent)
{
if (mSpec) {
mSpec->HandleEvent(aEvent);
}
return NS_OK;
}
//----------------------------------------------------------------------
// Implementation
#ifdef _MSC_VER
// Disable "warning C4355: 'this' : used in base member initializer list".
// We can ignore that warning because we know that mTimebase's constructor
// doesn't dereference the pointer passed to it.
// We can ignore that warning because we know that mReferencedElement's
// constructor doesn't dereference the pointer passed to it.
#pragma warning(push)
#pragma warning(disable:4355)
#endif
@ -60,7 +77,7 @@ nsSMILTimeValueSpec::nsSMILTimeValueSpec(nsSMILTimedElement& aOwner,
PRBool aIsBegin)
: mOwner(&aOwner),
mIsBegin(aIsBegin),
mTimebase(this)
mReferencedElement(this)
#ifdef _MSC_VER
#pragma warning(pop)
#endif
@ -69,7 +86,11 @@ nsSMILTimeValueSpec::nsSMILTimeValueSpec(nsSMILTimedElement& aOwner,
nsSMILTimeValueSpec::~nsSMILTimeValueSpec()
{
UnregisterFromTimebase(GetTimebaseElement());
UnregisterFromReferencedElement(mReferencedElement.get());
if (mEventListener) {
mEventListener->Disconnect();
mEventListener = nsnull;
}
}
nsresult
@ -91,11 +112,7 @@ nsSMILTimeValueSpec::SetSpec(const nsAString& aStringSpec,
// "indefinite" in an end list. This value is not removed by a reset.
if (mParams.mType == nsSMILTimeValueSpecParams::OFFSET ||
(!mIsBegin && mParams.mType == nsSMILTimeValueSpecParams::INDEFINITE)) {
nsRefPtr<nsSMILInstanceTime> instance =
new nsSMILInstanceTime(mParams.mOffset);
if (!instance)
return NS_ERROR_OUT_OF_MEMORY;
mOwner->AddInstanceTime(instance, mIsBegin);
mOwner->AddInstanceTime(new nsSMILInstanceTime(mParams.mOffset), mIsBegin);
}
ResolveReferences(aContextNode);
@ -106,7 +123,8 @@ nsSMILTimeValueSpec::SetSpec(const nsAString& aStringSpec,
void
nsSMILTimeValueSpec::ResolveReferences(nsIContent* aContextNode)
{
if (mParams.mType != nsSMILTimeValueSpecParams::SYNCBASE)
if (mParams.mType != nsSMILTimeValueSpecParams::SYNCBASE &&
mParams.mType != nsSMILTimeValueSpecParams::EVENT)
return;
NS_ABORT_IF_FALSE(aContextNode,
@ -118,14 +136,24 @@ nsSMILTimeValueSpec::ResolveReferences(nsIContent* aContextNode)
return;
// Hold ref to the old content so that it isn't destroyed in between resetting
// the timebase and using the pointer to update the timebase.
nsRefPtr<nsIContent> oldTimebaseContent = mTimebase.get();
// the referenced element and using the pointer to update the referenced
// element.
nsRefPtr<nsIContent> oldReferencedContent = mReferencedElement.get();
NS_ABORT_IF_FALSE(mParams.mDependentElemID, "NULL syncbase element id");
// XXX Support default event targets
NS_ABORT_IF_FALSE(mParams.mDependentElemID, "NULL dependent element id");
nsString idStr;
mParams.mDependentElemID->ToString(idStr);
mTimebase.ResetWithID(aContextNode, idStr);
UpdateTimebase(oldTimebaseContent, mTimebase.get());
mReferencedElement.ResetWithID(aContextNode, idStr);
UpdateReferencedElement(oldReferencedContent, mReferencedElement.get());
}
PRBool
nsSMILTimeValueSpec::IsEventBased() const
{
return mParams.mType == nsSMILTimeValueSpecParams::EVENT ||
mParams.mType == nsSMILTimeValueSpecParams::REPEAT ||
mParams.mType == nsSMILTimeValueSpecParams::ACCESSKEY;
}
void
@ -146,9 +174,6 @@ nsSMILTimeValueSpec::HandleNewInterval(nsSMILInterval& aInterval,
nsRefPtr<nsSMILInstanceTime> newInstance =
new nsSMILInstanceTime(newTime, nsSMILInstanceTime::SOURCE_SYNCBASE, this,
&aInterval);
if (!newInstance)
return;
mOwner->AddInstanceTime(newInstance, mIsBegin);
}
@ -196,41 +221,52 @@ nsSMILTimeValueSpec::DependsOnBegin() const
void
nsSMILTimeValueSpec::Traverse(nsCycleCollectionTraversalCallback* aCallback)
{
mTimebase.Traverse(aCallback);
mReferencedElement.Traverse(aCallback);
}
void
nsSMILTimeValueSpec::Unlink()
{
UnregisterFromTimebase(GetTimebaseElement());
mTimebase.Unlink();
UnregisterFromReferencedElement(mReferencedElement.get());
mReferencedElement.Unlink();
}
//----------------------------------------------------------------------
// Implementation helpers
void
nsSMILTimeValueSpec::UpdateTimebase(nsIContent* aFrom, nsIContent* aTo)
nsSMILTimeValueSpec::UpdateReferencedElement(nsIContent* aFrom, nsIContent* aTo)
{
if (aFrom == aTo)
return;
UnregisterFromTimebase(GetTimedElementFromContent(aFrom));
UnregisterFromReferencedElement(aFrom);
nsSMILTimedElement* to = GetTimedElementFromContent(aTo);
if (to) {
to->AddDependent(*this);
if (mParams.mType == nsSMILTimeValueSpecParams::SYNCBASE) {
nsSMILTimedElement* to = GetTimedElementFromContent(aTo);
if (to) {
to->AddDependent(*this);
}
} else if (mParams.mType == nsSMILTimeValueSpecParams::EVENT) {
RegisterEventListener(aTo);
}
}
void
nsSMILTimeValueSpec::UnregisterFromTimebase(nsSMILTimedElement* aTimedElement)
nsSMILTimeValueSpec::UnregisterFromReferencedElement(nsIContent* aContent)
{
if (!aTimedElement)
if (!aContent)
return;
aTimedElement->RemoveDependent(*this);
mOwner->RemoveInstanceTimesForCreator(this, mIsBegin);
if (mParams.mType == nsSMILTimeValueSpecParams::SYNCBASE) {
nsSMILTimedElement* timedElement = GetTimedElementFromContent(aContent);
if (timedElement) {
timedElement->RemoveDependent(*this);
}
mOwner->RemoveInstanceTimesForCreator(this, mIsBegin);
} else if (mParams.mType == nsSMILTimeValueSpecParams::EVENT) {
UnregisterEventListener(aContent);
}
}
nsSMILTimedElement*
@ -246,10 +282,93 @@ nsSMILTimeValueSpec::GetTimedElementFromContent(nsIContent* aContent)
return &animElement->TimedElement();
}
nsSMILTimedElement*
nsSMILTimeValueSpec::GetTimebaseElement()
void
nsSMILTimeValueSpec::RegisterEventListener(nsIContent* aTarget)
{
return GetTimedElementFromContent(mTimebase.get());
NS_ABORT_IF_FALSE(mParams.mType == nsSMILTimeValueSpecParams::EVENT,
"Attempting to register event-listener for non-event nsSMILTimeValueSpec");
NS_ABORT_IF_FALSE(mParams.mEventSymbol,
"Attempting to register event-listener but there is no event name");
// XXX Support default event targets
if (!aTarget)
return;
if (!mEventListener) {
mEventListener = new EventListener(this);
}
nsCOMPtr<nsIDOMEventGroup> sysGroup;
nsIEventListenerManager* elm =
GetEventListenerManager(aTarget, getter_AddRefs(sysGroup));
if (!elm)
return;
elm->AddEventListenerByType(mEventListener,
nsDependentAtomString(mParams.mEventSymbol),
NS_EVENT_FLAG_BUBBLE |
NS_PRIV_EVENT_UNTRUSTED_PERMITTED,
sysGroup);
}
void
nsSMILTimeValueSpec::UnregisterEventListener(nsIContent* aTarget)
{
if (!aTarget || !mEventListener)
return;
nsCOMPtr<nsIDOMEventGroup> sysGroup;
nsIEventListenerManager* elm =
GetEventListenerManager(aTarget, getter_AddRefs(sysGroup));
if (!elm)
return;
elm->RemoveEventListenerByType(mEventListener,
nsDependentAtomString(mParams.mEventSymbol),
NS_EVENT_FLAG_BUBBLE |
NS_PRIV_EVENT_UNTRUSTED_PERMITTED,
sysGroup);
}
nsIEventListenerManager*
nsSMILTimeValueSpec::GetEventListenerManager(nsIContent* aTarget,
nsIDOMEventGroup** aSystemGroup)
{
NS_ABORT_IF_FALSE(aTarget, "null target; can't get EventListenerManager");
NS_ABORT_IF_FALSE(aSystemGroup && !*aSystemGroup,
"Bad out param for system group");
nsIEventListenerManager* elm = aTarget->GetListenerManager(PR_TRUE);
if (!elm)
return nsnull;
aTarget->GetSystemEventGroup(aSystemGroup);
if (!*aSystemGroup)
return nsnull;
return elm;
}
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");
// 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
// time container
nsSMILTimeContainer* container = mOwner->GetTimeContainer();
if (!container)
return;
nsSMILTime currentTime = container->GetCurrentTime();
nsSMILTimeValue newTime(currentTime + mParams.mOffset.GetMillis());
nsRefPtr<nsSMILInstanceTime> newInstance =
new nsSMILInstanceTime(newTime, nsSMILInstanceTime::SOURCE_EVENT);
mOwner->AddInstanceTime(newInstance, mIsBegin);
}
nsSMILTimeValue

View File

@ -41,6 +41,7 @@
#include "nsSMILTimeValueSpecParams.h"
#include "nsReferencedElement.h"
#include "nsAutoPtr.h"
#include "nsIDOMEventListener.h"
class nsAString;
class nsSMILTimeValue;
@ -68,6 +69,7 @@ public:
nsresult SetSpec(const nsAString& aStringSpec, nsIContent* aContextNode);
void ResolveReferences(nsIContent* aContextNode);
PRBool IsEventBased() const;
void HandleNewInterval(nsSMILInterval& aInterval,
const nsSMILTimeContainer* aSrcContainer);
@ -85,10 +87,14 @@ public:
void Unlink();
protected:
void UpdateTimebase(nsIContent* aFrom, nsIContent* aTo);
void UnregisterFromTimebase(nsSMILTimedElement* aTimedElement);
void UpdateReferencedElement(nsIContent* aFrom, nsIContent* aTo);
void UnregisterFromReferencedElement(nsIContent* aContent);
nsSMILTimedElement* GetTimedElementFromContent(nsIContent* aContent);
nsSMILTimedElement* GetTimebaseElement();
void RegisterEventListener(nsIContent* aTarget);
void UnregisterEventListener(nsIContent* aTarget);
nsIEventListenerManager* GetEventListenerManager(nsIContent* aTarget,
nsIDOMEventGroup** aSystemGroup);
void HandleEvent(nsIDOMEvent* aEvent);
nsSMILTimeValue ConvertBetweenTimeContainers(const nsSMILTimeValue& aSrcTime,
const nsSMILTimeContainer* aSrcContainer);
@ -100,21 +106,40 @@ protected:
// the target.
nsSMILTimeValueSpecParams mParams;
class TimebaseElement : public nsReferencedElement {
class TimeReferenceElement : public nsReferencedElement
{
public:
TimebaseElement(nsSMILTimeValueSpec* aOwner) : mSpec(aOwner) { }
TimeReferenceElement(nsSMILTimeValueSpec* aOwner) : mSpec(aOwner) { }
protected:
virtual void ElementChanged(Element* aFrom, Element* aTo) {
virtual void ElementChanged(Element* aFrom, Element* aTo)
{
nsReferencedElement::ElementChanged(aFrom, aTo);
mSpec->UpdateTimebase(aFrom, aTo);
mSpec->UpdateReferencedElement(aFrom, aTo);
}
virtual PRBool IsPersistent() { return PR_TRUE; }
private:
nsSMILTimeValueSpec* mSpec;
};
TimebaseElement mTimebase;
TimeReferenceElement mReferencedElement;
class EventListener : public nsIDOMEventListener
{
public:
EventListener(nsSMILTimeValueSpec* aOwner) : mSpec(aOwner) { }
void Disconnect()
{
mSpec = nsnull;
}
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENTLISTENER
private:
nsSMILTimeValueSpec* mSpec;
};
nsCOMPtr<EventListener> mEventListener;
};
#endif // NS_SMILTIMEVALUESPEC_H_

View File

@ -186,7 +186,6 @@ nsSMILTimedElement::nsSMILTimedElement()
mAnimationElement(nsnull),
mFillMode(FILL_REMOVE),
mRestartMode(RESTART_ALWAYS),
mEndHasEventConditions(PR_FALSE),
mInstanceSerialIndex(0),
mClient(nsnull),
mCurrentInterval(nsnull),
@ -826,9 +825,6 @@ nsSMILTimedElement::SetEndSpec(const nsAString& aEndSpec,
nsIContent* aContextNode,
RemovalTestFunction aRemove)
{
// XXX When implementing events etc., don't forget to ensure
// mEndHasEventConditions is set if the specification contains conditions that
// describe event-values, repeat-values or accessKey-values.
return SetBeginOrEndSpec(aEndSpec, aContextNode, PR_FALSE /*!isBegin*/,
aRemove);
}
@ -1336,17 +1332,6 @@ nsSMILTimedElement::DoPostSeek()
UpdateCurrentInterval();
}
// XXX
// Note that SMIL gives the very cryptic description:
// The associated time for the event is the document time before the seek.
// This action does not resolve any times in the instance times list for end
// times.
//
// The second sentence was added as a clarification in a SMIL 2.0 erratum.
// Presumably the intention is that we fire the event as implemented below but
// don't act on it. This makes sense at least for dependencies within the same
// time container. So we'll probably need to set a flag here to ensure we
// don't actually act on it when we implement event-based timing.
switch (mSeekState)
{
case SEEK_FORWARD_FROM_ACTIVE:
@ -1571,18 +1556,18 @@ nsSMILTimedElement::GetNextInterval(const nsSMILInterval* aPrevInterval,
}
// If all the ends are before the beginning we have a bad interval UNLESS:
// a) We have end events which leave the interval open-ended, OR
// b) We never had any end attribute to begin with (and hence we should
// a) We never had any end attribute to begin with (and hence we should
// just use the active duration after allowing for the possibility of
// an end instance provided by a DOM call)
// c) We have an end attribute but no end instances--this is a special
// an end instance provided by a DOM call), OR
// b) We have an end attribute but no end instances--this is a special
// case that is needed for syncbase timing so that animations of the
// following sort: <animate id="a" end="a.begin+1s" ... /> can be
// resolved (see SVGT 1.2 Test Suite animate-elem-221-t.svg) by first
// establishing an interval of unresolved duration.
PRBool openEndedIntervalOk = mEndHasEventConditions ||
mEndSpecs.IsEmpty() ||
mEndInstances.IsEmpty();
// establishing an interval of unresolved duration, OR
// c) We have end events which leave the interval open-ended.
PRBool openEndedIntervalOk = mEndSpecs.IsEmpty() ||
mEndInstances.IsEmpty() ||
EndHasEventConditions();
if (!tempEnd && !openEndedIntervalOk)
return NS_ERROR_FAILURE; // Bad interval
@ -1928,8 +1913,6 @@ nsSMILTimedElement::AddInstanceTimeFromCurrentTime(nsSMILTime aCurrentTime,
nsSMILTimeValue timeVal(timeWithOffset);
// XXX If we re-use this method for event-based timing we'll need to change it
// so we don't end up setting SOURCE_DOM for event-based times.
nsRefPtr<nsSMILInstanceTime> instanceTime =
new nsSMILInstanceTime(timeVal, nsSMILInstanceTime::SOURCE_DOM);
@ -2106,6 +2089,16 @@ nsSMILTimedElement::GetPreviousInterval() const
: mOldIntervals[mOldIntervals.Length()-1].get();
}
PRBool
nsSMILTimedElement::EndHasEventConditions() const
{
for (PRUint32 i = 0; i < mEndSpecs.Length(); ++i) {
if (mEndSpecs[i]->IsEventBased())
return PR_TRUE;
}
return PR_FALSE;
}
//----------------------------------------------------------------------
// Hashtable callback functions

View File

@ -492,6 +492,7 @@ protected:
const nsSMILInstanceTime* GetEffectiveBeginInstance() const;
const nsSMILInterval* GetPreviousInterval() const;
PRBool HasPlayed() const { return !mOldIntervals.IsEmpty(); }
PRBool EndHasEventConditions() const;
// Hashtable callback methods
PR_STATIC_CALLBACK(PLDHashOperator) NotifyNewIntervalCallback(
@ -530,8 +531,6 @@ protected:
nsSMILRestartMode mRestartMode;
static nsAttrValue::EnumTable sRestartModeTable[];
PRPackedBool mEndHasEventConditions;
InstanceTimeList mBeginInstances;
InstanceTimeList mEndInstances;
PRUint32 mInstanceSerialIndex;

View File

@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="
document.documentElement.pauseAnimations();
document.documentElement.setCurrentTime(0);
click('circle');
delayedSnapshot(2)">
<script xlink:href="event-util.js" type="text/javascript"/>
<circle id="circle" r="10"/>
<rect width="100" height="100" fill="red">
<set attributeName="fill" attributeType="CSS"
to="green"
begin="circle.click" dur="4s"/>
</rect>
</svg>

After

Width:  |  Height:  |  Size: 546 B

View File

@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait" id="svg"
onload="
document.documentElement.pauseAnimations();
document.documentElement.setCurrentTime(0);
delayedSnapshot(2)">
<script xlink:href="event-util.js" type="text/javascript"/>
<rect width="100" height="100" fill="red">
<set attributeName="fill" attributeType="CSS"
to="green"
begin="svg.SVGLoad" dur="4s"/>
</rect>
</svg>

After

Width:  |  Height:  |  Size: 498 B

View File

@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="
document.documentElement.pauseAnimations();
document.documentElement.setCurrentTime(0);
click('circle');
delayedSnapshot(6)">
<script xlink:href="event-util.js" type="text/javascript"/>
<circle id="circle" r="10"/>
<rect width="100" height="100" fill="red">
<set attributeName="fill" attributeType="CSS"
to="green"
begin="circle.click+4s" dur="4s"/>
</rect>
</svg>

After

Width:  |  Height:  |  Size: 549 B

View File

@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="
document.documentElement.pauseAnimations();
document.documentElement.setCurrentTime(4);
click('circle');
delayedSnapshot(4)">
<script xlink:href="event-util.js" type="text/javascript"/>
<circle id="circle" r="10"/>
<rect width="100" height="100" fill="red">
<animate attributeName="fill" attributeType="CSS"
values="orange; green" calcMode="discrete"
begin="circle.click-4s" dur="8s"/>
</rect>
</svg>

After

Width:  |  Height:  |  Size: 585 B

View File

@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="
document.documentElement.pauseAnimations();
document.documentElement.setCurrentTime(0);
/* Make sure the event gets fired */
document.documentElement.setCurrentTime(0.1);
delayedSnapshot(2)">
<script xlink:href="event-util.js" type="text/javascript"/>
<rect width="100" height="100" fill="red">
<set attributeName="x" to="0" begin="0s" id="a"/>
<set attributeName="fill" attributeType="CSS"
to="green"
begin="a.beginEvent" dur="4s"/>
</rect>
</svg>

After

Width:  |  Height:  |  Size: 643 B

View File

@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="
document.documentElement.pauseAnimations();
document.documentElement.setCurrentTime(0);
/* Make sure the event gets fired */
document.documentElement.setCurrentTime(0.1);
document.documentElement.setCurrentTime(0.6);
delayedSnapshot(2.5)">
<script xlink:href="event-util.js" type="text/javascript"/>
<rect width="100" height="100" fill="red">
<set attributeName="x" to="0" begin="0s" dur="0.5s" id="a"/>
<set attributeName="fill" attributeType="CSS"
to="green"
begin="a.endEvent" dur="4s"/>
</rect>
</svg>

After

Width:  |  Height:  |  Size: 708 B

View File

@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="
document.documentElement.pauseAnimations();
document.documentElement.setCurrentTime(0.499);
document.documentElement.unpauseAnimations();
window.setTimeout(finish, 100, 2);">
<script xlink:href="event-util.js" type="text/javascript"/>
<rect width="100" height="100" fill="red">
<set attributeName="x" to="0" begin="0s" dur="0.5s" repeatCount="2" id="a"/>
<set attributeName="fill" attributeType="CSS"
to="green"
begin="a.repeatEvent" dur="4s"/>
</rect>
</svg>

After

Width:  |  Height:  |  Size: 646 B

View File

@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="
document.documentElement.pauseAnimations();
document.documentElement.setCurrentTime(0);
click('circle');
delayedSnapshot(2)">
<script xlink:href="event-util.js" type="text/javascript"/>
<g id="g">
<circle id="circle" r="10"/>
</g>
<rect width="100" height="100" fill="red">
<set attributeName="fill" attributeType="CSS"
to="green"
begin="g.click" dur="4s"/>
</rect>
</svg>

After

Width:  |  Height:  |  Size: 563 B

View File

@ -0,0 +1,26 @@
<!-- Tests support for custom events -->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="sendEvent()">
<script xlink:href="event-util.js" type="text/javascript"/>
<script type="text/javascript">
function sendEvent()
{
document.documentElement.pauseAnimations();
document.documentElement.setCurrentTime(0);
var evt = document.createEvent("SVGEvents");
evt.initEvent("user.defined", false, false);
var target = document.getElementById('rect');
target.dispatchEvent(evt);
delayedSnapshot(2);
}
</script>
<rect width="100" height="100" fill="red" id="rect">
<!-- SMIL allows periods to be embedded in the event name by escaping them
with a backslash. (Otherwise the part before the period would be
treated as an ID reference.) Test that we support that. -->
<set attributeName="fill" attributeType="CSS" to="green"
begin="rect.user\.defined" dur="4s"/>
</rect>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="
document.documentElement.pauseAnimations();
document.documentElement.setCurrentTime(2);
click('circle');
delayedSnapshot(3)">
<script xlink:href="event-util.js" type="text/javascript"/>
<circle id="circle" r="10"/>
<rect width="100" height="100" fill="green">
<set attributeName="fill" attributeType="CSS"
to="red"
begin="1s" end="circle.click" dur="4s"/>
</rect>
</svg>

After

Width:  |  Height:  |  Size: 555 B

View File

@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="
document.documentElement.pauseAnimations();
document.documentElement.setCurrentTime(0);
/* Click event should be ignored since the element is inactive as per
* SMIL's event sensitivity rules */
click('circle');
delayedSnapshot(3)">
<script xlink:href="event-util.js" type="text/javascript"/>
<circle id="circle" r="10"/>
<rect width="100" height="100" fill="red">
<set attributeName="fill" attributeType="CSS"
to="green"
begin="1s" end="circle.click+2s" dur="4s"/>
</rect>
</svg>

After

Width:  |  Height:  |  Size: 681 B

View File

@ -0,0 +1,20 @@
<!--
Generally speaking, when constructing intervals if all the end instance times
are before the next begin time there's no valid interval.
However, SMIL specifically makes an exception when the end attribute has event
conditions in which case an unresolved end is used.
-->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="
document.documentElement.pauseAnimations();
document.documentElement.setCurrentTime(2);
document.documentElement.removeAttribute('class')">
<circle id="circle" r="10"/>
<rect width="100" height="100" fill="red">
<set attributeName="fill" attributeType="CSS" to="green"
begin="0s; 2s" end="1s; circle.click"/>
</rect>
</svg>

After

Width:  |  Height:  |  Size: 778 B

View File

@ -0,0 +1,16 @@
<!-- Calling preventDefault on the event should have no effect -->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="
document.documentElement.pauseAnimations();
document.documentElement.setCurrentTime(0);
click('circle');
delayedSnapshot(2)">
<script xlink:href="event-util.js" type="text/javascript"/>
<circle id="circle" r="10" onclick="evt.preventDefault()"/>
<rect width="100" height="100" fill="red">
<set attributeName="fill" attributeType="CSS"
to="green" begin="circle.click" dur="4s"/>
</rect>
</svg>

After

Width:  |  Height:  |  Size: 638 B

View File

@ -0,0 +1,19 @@
<!-- Test a backwards seek with an event-generated time -->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
id="svg"
class="reftest-wait"
onload="window.setTimeout(seek, 10)">
<script xlink:href="event-util.js" type="text/javascript"/>
<script type="text/javascript">
function seek()
{
document.documentElement.setCurrentTime(40);
finish(30);
}
</script>
<rect width="100" height="100" fill="red">
<set attributeName="fill" attributeType="CSS" to="green"
begin="svg.SVGLoad+20s"/>
</rect>
</svg>

After

Width:  |  Height:  |  Size: 595 B

View File

@ -0,0 +1,21 @@
// Allows a moment for events to be processed then performs a seek and runs
// a snapshot.
function delayedSnapshot(seekTimeInSeconds) {
// Allow time for events to be processed
window.setTimeout(finish, 10, seekTimeInSeconds);
}
function finish(seekTimeInSeconds) {
document.documentElement.pauseAnimations();
if (seekTimeInSeconds)
document.documentElement.setCurrentTime(seekTimeInSeconds);
document.documentElement.removeAttribute("class");
}
function click(targetId) {
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent("click", true, true, window,
0, 0, 0, 0, 0, false, false, false, false, 0, null);
var target = document.getElementById(targetId);
target.dispatchEvent(evt);
}

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg">
<rect width="100" height="100" fill="green"/>
</svg>

After

Width:  |  Height:  |  Size: 96 B

View File

@ -0,0 +1,16 @@
# Tests related to SVG Animation (using SMIL) that use event timing.
== event-begin-1.svg green-box-ref.svg
== event-begin-offset-1.svg green-box-ref.svg
== event-begin-offset-2.svg green-box-ref.svg
== event-begin-timeevent-1.svg green-box-ref.svg
== event-begin-timeevent-2.svg green-box-ref.svg
== event-begin-timeevent-3.svg green-box-ref.svg
== event-begin-load-1.svg green-box-ref.svg
== event-bubble-1.svg green-box-ref.svg
== event-custom-1.svg green-box-ref.svg
== event-end-1.svg green-box-ref.svg
== event-end-2.svg green-box-ref.svg
== event-end-open-1.svg green-box-ref.svg
== event-preventDefault-1.svg green-box-ref.svg
== event-seek-1.svg green-box-ref.svg

View File

@ -50,6 +50,9 @@ include syncbase/reftest.list
# seek tests
include seek/reftest.list
# event tests
include event/reftest.list
# General tests
== anim-discrete-values-1.svg anim-standard-ref.svg
== anim-discrete-replace-sum-1.svg anim-standard-ref.svg