Bug 485157: SMIL event timing, part 6 repeat timing, r=dholbert, sr=roc, a=roc

This commit is contained in:
Brian Birtles 2010-08-18 19:20:24 +09:00
Родитель 9896ec8948
Коммит a146a4eac7
6 изменённых файлов: 160 добавлений и 14 удалений

Просмотреть файл

@ -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")

Просмотреть файл

@ -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);

Просмотреть файл

@ -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<nsIDOMTimeEvent> 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,

Просмотреть файл

@ -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);

Просмотреть файл

@ -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 \

Просмотреть файл

@ -0,0 +1,96 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=485157
-->
<head>
<title>Test repeat timing</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=485157">Mozilla Bug
485157</a>
<p id="display"></p>
<div id="content" style="display: none">
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="100px" height="100px">
<rect width="100" height="100" fill="green">
<set attributeName="width" to="100" dur="20s" repeatCount="5" begin="0s"
id="a" onrepeat="startWaiting(evt)"/>
<set attributeName="fill" attributeType="CSS" to="green"
begin="a.repeat(1)" onbegin="expectedBegin()" dur="20s"/>
<set attributeName="x" to="100"
begin="a.repeat(2)" onbegin="unexpectedBegin(this)" dur="20s"/>
<set attributeName="y" to="100"
begin="a.repeat(0)" onbegin="unexpectedBegin(this)" dur="20s"/>
<set attributeName="width" to="100"
begin="a.repeat(-1)" onbegin="unexpectedBegin(this)" dur="20s"/>
<set attributeName="height" to="100"
begin="a.repeat(a)" onbegin="unexpectedBegin(this)" dur="20s"/>
</rect>
</svg>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
<![CDATA[
/** Test SMIL repeat timing **/
/* Global Variables */
const gTimeoutDur = 5000; // Time until we give up waiting for events in ms
var gSvg = document.getElementById('svg');
var gRect = document.getElementById('circle');
var gTimeoutID;
var gGotBegin = false;
SimpleTest.waitForExplicitFinish();
function testBegin()
{
gSvg.setCurrentTime(19.999);
}
function startWaiting(evt)
{
is(evt.detail, 1, "Unexpected repeat event received: test broken");
if (gGotBegin)
return;
gTimeoutID = setTimeout(timeoutFail, gTimeoutDur);
}
function timeoutFail()
{
ok(false, "Timed out waiting for begin event");
finish();
}
function expectedBegin()
{
is(gGotBegin, false,
"Got begin event more than once for non-repeating animation");
gGotBegin = true;
clearTimeout(gTimeoutID);
// Wait a moment before finishing in case there are erroneous events waiting
// to be processed.
setTimeout(finish, 10);
}
function unexpectedBegin(elem)
{
ok(false, "Got unexpected begin from animation with spec: " +
elem.getAttribute('begin'));
}
function finish()
{
gSvg.pauseAnimations();
SimpleTest.finish();
}
window.addEventListener("load", testBegin, false);
]]>
</script>
</pre>
</body>
</html>