зеркало из https://github.com/mozilla/pjs.git
Bug 474357, Calls to setCurrentTime, beginElementAt etc. should update the DOM state immediately. r+sr=roc
--HG-- extra : rebase_source : 7c69aae13ee1c1b4fff077a046e042bae9a4970d
This commit is contained in:
Родитель
e36799a8d9
Коммит
03f9d86660
|
@ -64,7 +64,8 @@ const PRUint32 nsSMILAnimationController::kTimerInterval = 22;
|
|||
// ctors, dtors, factory methods
|
||||
|
||||
nsSMILAnimationController::nsSMILAnimationController()
|
||||
: mDocument(nsnull)
|
||||
: mResampleNeeded(PR_FALSE),
|
||||
mDocument(nsnull)
|
||||
{
|
||||
mAnimationElementTable.Init();
|
||||
mChildContainerTable.Init();
|
||||
|
@ -77,11 +78,6 @@ nsSMILAnimationController::~nsSMILAnimationController()
|
|||
mTimer = nsnull;
|
||||
}
|
||||
|
||||
if (mForceSampleEvent) {
|
||||
mForceSampleEvent->Expire();
|
||||
mForceSampleEvent = nsnull;
|
||||
}
|
||||
|
||||
NS_ASSERTION(mAnimationElementTable.Count() == 0,
|
||||
"Animation controller shouldn't be tracking any animation"
|
||||
" elements when it dies.");
|
||||
|
@ -138,7 +134,7 @@ nsSMILAnimationController::Resume(PRUint32 aType)
|
|||
|
||||
nsSMILTimeContainer::Resume(aType);
|
||||
|
||||
if (wasPaused && !mPauseState) {
|
||||
if (wasPaused && !mPauseState && mChildContainerTable.Count()) {
|
||||
StartTimer();
|
||||
}
|
||||
}
|
||||
|
@ -168,38 +164,12 @@ nsSMILAnimationController::UnregisterAnimationElement(
|
|||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsSMILAnimationController methods:
|
||||
|
||||
nsresult
|
||||
nsSMILAnimationController::OnForceSample()
|
||||
{
|
||||
// Make sure this was a queued call
|
||||
NS_ENSURE_TRUE(mForceSampleEvent, NS_ERROR_FAILURE);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (!mPauseState) {
|
||||
// Stop timer-controlled samples first, to avoid race conditions.
|
||||
rv = StopTimer();
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// StartTimer does a synchronous sample before it starts the timer.
|
||||
// This is the sample that we're "forcing" here.
|
||||
rv = StartTimer();
|
||||
}
|
||||
}
|
||||
mForceSampleEvent = nsnull;
|
||||
return rv;
|
||||
}
|
||||
// Resampling methods
|
||||
|
||||
void
|
||||
nsSMILAnimationController::FireForceSampleEvent()
|
||||
nsSMILAnimationController::Resample()
|
||||
{
|
||||
if (!mForceSampleEvent) {
|
||||
mForceSampleEvent = new ForceSampleEvent(*this);
|
||||
if (NS_FAILED(NS_DispatchToCurrentThread(mForceSampleEvent))) {
|
||||
NS_WARNING("Failed to dispatch force sample event");
|
||||
mForceSampleEvent = nsnull;
|
||||
}
|
||||
}
|
||||
DoSample(PR_FALSE);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -242,7 +212,6 @@ nsSMILAnimationController::CompositorTableEntryTraverse(
|
|||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsSMILAnimationController::Unlink()
|
||||
{
|
||||
|
@ -296,14 +265,24 @@ nsSMILAnimationController::StopTimer()
|
|||
void
|
||||
nsSMILAnimationController::DoSample()
|
||||
{
|
||||
DoSample(PR_TRUE); // Skip unchanged time containers
|
||||
}
|
||||
|
||||
void
|
||||
nsSMILAnimationController::DoSample(PRBool aSkipUnchangedContainers)
|
||||
{
|
||||
// Reset resample flag
|
||||
mResampleNeeded = PR_FALSE;
|
||||
|
||||
// STEP 1: Sample the child time containers
|
||||
//
|
||||
// When we sample the child time containers they will simply record the sample
|
||||
// time in document time.
|
||||
TimeContainerHashtable activeContainers;
|
||||
activeContainers.Init(mChildContainerTable.Count());
|
||||
mChildContainerTable.EnumerateEntries(SampleTimeContainers,
|
||||
&activeContainers);
|
||||
SampleTimeContainerParams tcParams = { &activeContainers,
|
||||
aSkipUnchangedContainers };
|
||||
mChildContainerTable.EnumerateEntries(SampleTimeContainer, &tcParams);
|
||||
|
||||
// STEP 2: (i) Sample the timed elements AND
|
||||
// (ii) Create a table of compositors
|
||||
|
@ -332,9 +311,10 @@ nsSMILAnimationController::DoSample()
|
|||
return;
|
||||
currentCompositorTable->Init(0);
|
||||
|
||||
SampleAnimationParams params = { &activeContainers, currentCompositorTable };
|
||||
SampleAnimationParams saParams = { &activeContainers,
|
||||
currentCompositorTable };
|
||||
nsresult rv = mAnimationElementTable.EnumerateEntries(SampleAnimation,
|
||||
¶ms);
|
||||
&saParams);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("SampleAnimationParams failed");
|
||||
}
|
||||
|
@ -356,23 +336,25 @@ nsSMILAnimationController::DoSample()
|
|||
|
||||
// Update last compositor table
|
||||
mLastCompositorTable = currentCompositorTable.forget();
|
||||
|
||||
NS_ASSERTION(!mResampleNeeded, "Resample dirty flag set during sample!");
|
||||
}
|
||||
|
||||
/*static*/ PR_CALLBACK PLDHashOperator
|
||||
nsSMILAnimationController::SampleTimeContainers(TimeContainerPtrKey* aKey,
|
||||
void* aData)
|
||||
nsSMILAnimationController::SampleTimeContainer(TimeContainerPtrKey* aKey,
|
||||
void* aData)
|
||||
{
|
||||
NS_ENSURE_TRUE(aKey, PL_DHASH_NEXT);
|
||||
NS_ENSURE_TRUE(aKey->GetKey(), PL_DHASH_NEXT);
|
||||
NS_ENSURE_TRUE(aData, PL_DHASH_NEXT);
|
||||
|
||||
TimeContainerHashtable* activeContainers
|
||||
= static_cast<TimeContainerHashtable*>(aData);
|
||||
SampleTimeContainerParams* params =
|
||||
static_cast<SampleTimeContainerParams*>(aData);
|
||||
|
||||
nsSMILTimeContainer* container = aKey->GetKey();
|
||||
if (container->NeedsSample()) {
|
||||
if (container->NeedsSample() || !params->mSkipUnchangedContainers) {
|
||||
container->Sample();
|
||||
activeContainers->PutEntry(container);
|
||||
params->mActiveContainers->PutEntry(container);
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
|
@ -410,7 +392,7 @@ nsSMILAnimationController::SampleTimedElement(
|
|||
// return false.
|
||||
//
|
||||
// Instead we build up a hashmap of active time containers during the previous
|
||||
// step (SampleTimeContainers) and then test here if the container for this
|
||||
// step (SampleTimeContainer) and then test here if the container for this
|
||||
// timed element is in the list.
|
||||
if (!aActiveContainers->GetEntry(timeContainer))
|
||||
return;
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
#include "nsITimer.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsThreadUtils.h" // for nsRunnable
|
||||
#include "nsSMILTimeContainer.h"
|
||||
#include "nsSMILCompositorTable.h"
|
||||
|
||||
|
@ -80,17 +79,26 @@ public:
|
|||
void RegisterAnimationElement(nsISMILAnimationElement* aAnimationElement);
|
||||
void UnregisterAnimationElement(nsISMILAnimationElement* aAnimationElement);
|
||||
|
||||
// Methods for forcing synchronous samples
|
||||
nsresult OnForceSample();
|
||||
void FireForceSampleEvent();
|
||||
// Methods for resampling all animations
|
||||
// (A resample performs the same operations as a sample but doesn't advance
|
||||
// the current time and doesn't check if the container is paused)
|
||||
void Resample();
|
||||
void SetResampleNeeded() { mResampleNeeded = PR_TRUE; }
|
||||
void FlushResampleRequests()
|
||||
{
|
||||
if (!mResampleNeeded)
|
||||
return;
|
||||
|
||||
DoSample(PR_FALSE); // Don't skip unchanged time containers--sample them all
|
||||
}
|
||||
|
||||
// Methods for handling page transitions
|
||||
void OnPageShow();
|
||||
void OnPageHide();
|
||||
void OnPageShow();
|
||||
void OnPageHide();
|
||||
|
||||
// Methods for supporting cycle-collection
|
||||
void Traverse(nsCycleCollectionTraversalCallback* aCallback);
|
||||
void Unlink();
|
||||
void Traverse(nsCycleCollectionTraversalCallback* aCallback);
|
||||
void Unlink();
|
||||
|
||||
protected:
|
||||
// Typedefs
|
||||
|
@ -99,22 +107,10 @@ protected:
|
|||
typedef nsPtrHashKey<nsISMILAnimationElement> AnimationElementPtrKey;
|
||||
typedef nsTHashtable<AnimationElementPtrKey> AnimationElementHashtable;
|
||||
|
||||
// Types
|
||||
class ForceSampleEvent : public nsRunnable {
|
||||
public:
|
||||
ForceSampleEvent(nsSMILAnimationController &aAnimationController)
|
||||
: mAnimationController(&aAnimationController) { }
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
if (!mAnimationController)
|
||||
return NS_OK;
|
||||
|
||||
return mAnimationController->OnForceSample();
|
||||
}
|
||||
void Expire() { mAnimationController = nsnull; }
|
||||
|
||||
private:
|
||||
nsSMILAnimationController* mAnimationController;
|
||||
struct SampleTimeContainerParams
|
||||
{
|
||||
TimeContainerHashtable* mActiveContainers;
|
||||
PRBool mSkipUnchangedContainers;
|
||||
};
|
||||
|
||||
struct SampleAnimationParams
|
||||
|
@ -139,7 +135,8 @@ protected:
|
|||
|
||||
// Sample-related callbacks and implementation helpers
|
||||
virtual void DoSample();
|
||||
PR_STATIC_CALLBACK(PLDHashOperator) SampleTimeContainers(
|
||||
void DoSample(PRBool aSkipUnchangedContainers);
|
||||
PR_STATIC_CALLBACK(PLDHashOperator) SampleTimeContainer(
|
||||
TimeContainerPtrKey* aKey, void* aData);
|
||||
PR_STATIC_CALLBACK(PLDHashOperator) SampleAnimation(
|
||||
AnimationElementPtrKey* aKey, void* aData);
|
||||
|
@ -161,7 +158,7 @@ protected:
|
|||
nsCOMPtr<nsITimer> mTimer;
|
||||
AnimationElementHashtable mAnimationElementTable;
|
||||
TimeContainerHashtable mChildContainerTable;
|
||||
nsRefPtr<ForceSampleEvent> mForceSampleEvent;
|
||||
PRPackedBool mResampleNeeded;
|
||||
|
||||
// Store raw ptr to mDocument. It owns the controller, so controller
|
||||
// shouldn't outlive it
|
||||
|
|
|
@ -106,11 +106,40 @@ nsresult
|
|||
nsSMILTimedElement::BeginElementAt(double aOffsetSeconds,
|
||||
const nsSMILTimeContainer* aContainer)
|
||||
{
|
||||
if (!AddInstanceTimeFromCurrentTime(aOffsetSeconds, PR_TRUE, aContainer)) {
|
||||
// Probably we don't have a time container
|
||||
NS_ERROR("Failed to begin element");
|
||||
if (!aContainer)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsSMILTime currentTime = aContainer->GetCurrentTime();
|
||||
|
||||
AddInstanceTimeFromCurrentTime(currentTime, aOffsetSeconds, PR_TRUE);
|
||||
|
||||
// After we've added the instance time we must do a local resample.
|
||||
//
|
||||
// The reason for this can be explained by considering the following sequence
|
||||
// of calls in a script block
|
||||
//
|
||||
// BeginElementAt(0)
|
||||
// BeginElementAt(-1)
|
||||
// GetStartTime() <-- should return the time from the first call to
|
||||
// BeginElementAt
|
||||
//
|
||||
// After BeginElementAt(0) is called a new begin instance time is added to the
|
||||
// list. Depending on the restart mode this may generate a new interval,
|
||||
// possiblying ending the current interval early.
|
||||
//
|
||||
// Intuitively this change should take effect before the subsequent call to
|
||||
// BeginElementAt however to get this to take effect we need to drive the
|
||||
// state engine through it's sequence active-waiting-active by calling Sample.
|
||||
//
|
||||
// When we get the second call to BeginElementAt the element should be in the
|
||||
// active state and hence the new begin instance time will be ignored because
|
||||
// it is before the beginning of the (new) current interval. SMIL says we do
|
||||
// not change the begin of a current interval once it is active.
|
||||
//
|
||||
// See also:
|
||||
// http://www.w3.org/TR/SMIL3/smil-timing.html#Timing-BeginEnd-Restart
|
||||
|
||||
SampleAt(currentTime);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -119,11 +148,12 @@ nsresult
|
|||
nsSMILTimedElement::EndElementAt(double aOffsetSeconds,
|
||||
const nsSMILTimeContainer* aContainer)
|
||||
{
|
||||
if (!AddInstanceTimeFromCurrentTime(aOffsetSeconds, PR_FALSE, aContainer)) {
|
||||
// Probably we don't have a time container
|
||||
NS_ERROR("Failed to end element");
|
||||
if (!aContainer)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsSMILTime currentTime = aContainer->GetCurrentTime();
|
||||
AddInstanceTimeFromCurrentTime(currentTime, aOffsetSeconds, PR_FALSE);
|
||||
SampleAt(currentTime);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -439,6 +469,7 @@ nsSMILTimedElement::SetSimpleDuration(const nsAString& aDurSpec)
|
|||
"Setting unresolved simple duration");
|
||||
|
||||
mSimpleDur = duration;
|
||||
UpdateCurrentInterval();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -549,13 +580,13 @@ nsSMILTimedElement::SetRepeatCount(const nsAString& aRepeatCountSpec)
|
|||
nsresult rv =
|
||||
nsSMILParserUtils::ParseRepeatCount(aRepeatCountSpec, newRepeatCount);
|
||||
|
||||
UpdateCurrentInterval();
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mRepeatCount = newRepeatCount;
|
||||
} else {
|
||||
mRepeatCount.Unset();
|
||||
}
|
||||
|
||||
UpdateCurrentInterval();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -581,9 +612,8 @@ nsSMILTimedElement::SetRepeatDur(const nsAString& aRepeatDurSpec)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
UpdateCurrentInterval();
|
||||
|
||||
mRepeatDur = duration;
|
||||
UpdateCurrentInterval();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -640,6 +670,7 @@ nsSMILTimedElement::SetBeginOrEndSpec(const nsAString& aSpec,
|
|||
|
||||
timeSpecsList.Clear();
|
||||
instancesList.Clear();
|
||||
HardReset(); // XXX Need to take care of time dependents here
|
||||
|
||||
PRInt32 start;
|
||||
PRInt32 end = -1;
|
||||
|
@ -695,7 +726,7 @@ nsSMILTimedElement::GetNextInterval(const nsSMILTimeValue& aBeginAfter,
|
|||
// that has already been used in another interval. See the pseudocode in
|
||||
// SMILANIM 3.6.8 for getFirstInterval.
|
||||
//
|
||||
PRInt32 endMaxPos = 0;
|
||||
PRInt32 endMaxPos = 0;
|
||||
|
||||
if (mRestartMode == RESTART_NEVER && !aFirstInterval)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -1025,27 +1056,16 @@ nsSMILTimedElement::SampleFillValue()
|
|||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSMILTimedElement::AddInstanceTimeFromCurrentTime(double aOffsetSeconds,
|
||||
PRBool aIsBegin, const nsSMILTimeContainer* aContainer)
|
||||
void
|
||||
nsSMILTimedElement::AddInstanceTimeFromCurrentTime(nsSMILTime aCurrentTime,
|
||||
double aOffsetSeconds, PRBool aIsBegin)
|
||||
{
|
||||
/*
|
||||
* SMIL doesn't say what to do if someone calls BeginElement etc. before the
|
||||
* document has started. For now we just fail.
|
||||
*/
|
||||
if (!aContainer)
|
||||
return PR_FALSE;
|
||||
|
||||
double offset = aOffsetSeconds * PR_MSEC_PER_SEC;
|
||||
|
||||
nsSMILTime timeWithOffset =
|
||||
aContainer->GetCurrentTime() + PRInt64(NS_round(offset));
|
||||
nsSMILTime timeWithOffset = aCurrentTime + PRInt64(NS_round(offset));
|
||||
|
||||
nsSMILTimeValue timeVal;
|
||||
timeVal.SetMillis(timeWithOffset);
|
||||
|
||||
nsSMILInstanceTime instanceTime(timeVal, nsnull, PR_TRUE);
|
||||
AddInstanceTime(instanceTime, aIsBegin);
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
|
|
@ -269,8 +269,8 @@ protected:
|
|||
void UpdateCurrentInterval();
|
||||
void SampleSimpleTime(nsSMILTime aActiveTime);
|
||||
void SampleFillValue();
|
||||
PRBool AddInstanceTimeFromCurrentTime(double aOffsetSeconds,
|
||||
PRBool aIsBegin, const nsSMILTimeContainer* aContainer);
|
||||
void AddInstanceTimeFromCurrentTime(nsSMILTime aCurrentTime,
|
||||
double aOffsetSeconds, PRBool aIsBegin);
|
||||
|
||||
// Typedefs
|
||||
typedef nsTArray<nsRefPtr<nsSMILTimeValueSpec> > SMILTimeValueSpecList;
|
||||
|
|
|
@ -46,6 +46,8 @@ include $(topsrcdir)/config/rules.mk
|
|||
_TEST_FILES = test_smilRestart.xhtml \
|
||||
test_smilGetStartTime.xhtml \
|
||||
test_smilGetSimpleDuration.xhtml \
|
||||
test_smilSync.xhtml \
|
||||
test_smilSyncTransform.xhtml \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
|
|
@ -27,8 +27,6 @@ var anim = document.getElementById("anim");
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function main() {
|
||||
// Basic setting and getting
|
||||
|
||||
// indefinite
|
||||
is(anim.getStartTime(), 0, "Unexpected start time with indefinite begin");
|
||||
|
||||
|
@ -44,47 +42,25 @@ function main() {
|
|||
|
||||
// Now test over the lifetime of the animation when there are multiple
|
||||
// intervals
|
||||
//
|
||||
// We do this via a series of setTimeouts because currently we sample (and
|
||||
// update the model) asynchronously after a call to setCurrentTime
|
||||
anim.setAttribute("begin", "1s; 3s");
|
||||
is(anim.getStartTime(), 1, "Unexpected start time with begin=1s; 3s");
|
||||
is(anim.getStartTime(), 1, "Unexpected start time before first interval");
|
||||
|
||||
svg.setCurrentTime(1);
|
||||
setTimeout('checkStartOfFirstInterval()', 0);
|
||||
}
|
||||
is(anim.getStartTime(), 1,
|
||||
"Unexpected start time at start of first interval");
|
||||
|
||||
function checkStartOfFirstInterval() {
|
||||
is(anim.getStartTime(), 1, "Unexpected start time during first interval");
|
||||
svg.setCurrentTime(1.5);
|
||||
setTimeout('checkMidFirstInterval()', 0);
|
||||
}
|
||||
is(anim.getStartTime(), 1, "Unexpected start time during first interval");
|
||||
|
||||
function checkMidFirstInterval() {
|
||||
is(anim.getStartTime(), 1, "Unexpected start time at end of first interval");
|
||||
svg.setCurrentTime(2);
|
||||
setTimeout('checkEndOfFirstInterval()', 0);
|
||||
}
|
||||
is(anim.getStartTime(), 1, "Unexpected start time after first interval");
|
||||
|
||||
function checkEndOfFirstInterval() {
|
||||
is(anim.getStartTime(), 1, "Unexpected start time in active interval");
|
||||
svg.setCurrentTime(2.5);
|
||||
setTimeout('checkAfterFirstInterval()', 0);
|
||||
}
|
||||
|
||||
function checkAfterFirstInterval() {
|
||||
is(anim.getStartTime(), 1, "Unexpected start time while waiting");
|
||||
svg.setCurrentTime(3);
|
||||
setTimeout('checkStartOfSecondInterval()', 0);
|
||||
}
|
||||
is(anim.getStartTime(), 3, "Unexpected start time during second interval");
|
||||
|
||||
function checkStartOfSecondInterval() {
|
||||
is(anim.getStartTime(), 3, "Unexpected start time in second active interval");
|
||||
svg.setCurrentTime(4);
|
||||
setTimeout('checkEndOfSecondInterval()', 0);
|
||||
}
|
||||
is(anim.getStartTime(), 3, "Unexpected start time after second interval");
|
||||
|
||||
function checkEndOfSecondInterval() {
|
||||
is(anim.getStartTime(), 3, "Unexpected start time while postactive");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
|
|
@ -37,67 +37,49 @@ var never = document.getElementById("never");
|
|||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// main: just triggers the first link in the chain of function-calls
|
||||
function tryRestart(elem, state, expected) {
|
||||
var restartTime = svg.getCurrentTime();
|
||||
elem.beginElement();
|
||||
var restart = (elem.getStartTime() === restartTime);
|
||||
if (expected) {
|
||||
var msg = elem.id + " can't restart in " + state + " state";
|
||||
ok(restart, msg);
|
||||
} else {
|
||||
var msg = elem.id + " can restart in " + state + " state";
|
||||
ok(!restart, msg);
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
checkInitialState();
|
||||
}
|
||||
|
||||
function restartAll() {
|
||||
always.beginElement();
|
||||
whenNotActive.beginElement();
|
||||
never.beginElement();
|
||||
}
|
||||
|
||||
function checkInitialState() {
|
||||
// At first everything should be starting at 1s
|
||||
is(always.getStartTime(), 1);
|
||||
is(whenNotActive.getStartTime(), 1);
|
||||
is(never.getStartTime(), 1);
|
||||
|
||||
// Now try to restart everything early, should be allowed by all
|
||||
var restartTime = svg.getCurrentTime();
|
||||
restartAll();
|
||||
setTimeout('doCheckInitialState(' + restartTime + ')',0);
|
||||
}
|
||||
function doCheckInitialState(restartTime) {
|
||||
is(always.getStartTime(), restartTime);
|
||||
is(whenNotActive.getStartTime(), restartTime);
|
||||
is(never.getStartTime(), restartTime);
|
||||
tryRestart(always, "waiting", true);
|
||||
tryRestart(whenNotActive, "waiting", true);
|
||||
tryRestart(never, "waiting", true);
|
||||
|
||||
// Now skip to half-way
|
||||
var newTime = restartTime + 0.5 * always.getSimpleDuration();
|
||||
var newTime = always.getStartTime() + 0.5 * always.getSimpleDuration();
|
||||
svg.setCurrentTime(newTime);
|
||||
setTimeout('checkHalfwayState()', 0);
|
||||
}
|
||||
|
||||
function checkHalfwayState() {
|
||||
// Try to restart half-way through--only 'always' should succeed
|
||||
var restartTime = svg.getCurrentTime();
|
||||
restartAll();
|
||||
setTimeout('doCheckHalfwayState(' + restartTime + ')',0);
|
||||
}
|
||||
function doCheckHalfwayState(restartTime) {
|
||||
is(always.getStartTime(), restartTime);
|
||||
isnot(whenNotActive.getStartTime(), restartTime);
|
||||
isnot(never.getStartTime(), restartTime);
|
||||
// Only 'always' should be able to be restarted
|
||||
tryRestart(always, "active", true);
|
||||
tryRestart(whenNotActive, "active", false);
|
||||
tryRestart(never, "active", false);
|
||||
|
||||
// Now skip to the end
|
||||
var newTime = always.getStartTime() + always.getSimpleDuration() + 1;
|
||||
newTime = always.getStartTime() + always.getSimpleDuration() + 1;
|
||||
svg.setCurrentTime(newTime);
|
||||
setTimeout('checkEndingState()', 0);
|
||||
}
|
||||
|
||||
function checkEndingState() {
|
||||
// Try to restart after all animations have finished--'always' and
|
||||
// 'whenNotActive' should succeed
|
||||
var restartTime = svg.getCurrentTime();
|
||||
restartAll();
|
||||
setTimeout('doCheckEndingState(' + restartTime + ')',0);
|
||||
}
|
||||
function doCheckEndingState(restartTime) {
|
||||
is(always.getStartTime(), restartTime);
|
||||
is(whenNotActive.getStartTime(), restartTime);
|
||||
isnot(never.getStartTime(), restartTime);
|
||||
// All animations have finished, so 'always' and 'whenNotActive' should be
|
||||
// able to be restarted
|
||||
tryRestart(always, "postactive", true);
|
||||
tryRestart(whenNotActive, "postactive", true);
|
||||
tryRestart(never, "postactive", false);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,253 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Test for SMIL sync behaviour </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>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="120px" height="120px">
|
||||
<circle cx="20" cy="20" r="15" fill="blue">
|
||||
<animate attributeName="cx" attributeType="XML" from="20" to="100"
|
||||
begin="indefinite" dur="4s" restart="always" id="anim1"/>
|
||||
</circle>
|
||||
<circle cx="20" cy="20" r="15" fill="blue">
|
||||
<animate attributeName="cx" attributeType="XML" from="0" to="50"
|
||||
begin="0" dur="1s" additive="sum" fill="freeze" id="anim2"/>
|
||||
</circle>
|
||||
<circle cx="20" cy="20" r="15" fill="blue">
|
||||
<animate attributeName="cx" attributeType="XML" from="0" to="50"
|
||||
begin="0" dur="10s" additive="sum" fill="freeze" id="anim3"/>
|
||||
</circle>
|
||||
<circle cx="20" cy="20" r="15" fill="blue">
|
||||
<animate attributeName="cx" attributeType="XML" from="0" to="50"
|
||||
begin="0" dur="10s" additive="sum" fill="freeze" id="anim4"/>
|
||||
</circle>
|
||||
<circle cx="20" cy="20" r="15" fill="blue">
|
||||
<animate attributeName="cx" attributeType="XML" from="0" to="50"
|
||||
begin="0" dur="40s" additive="sum" fill="freeze" id="anim5"/>
|
||||
</circle>
|
||||
<circle cx="20" cy="20" r="15" fill="blue">
|
||||
<animate attributeName="cx" attributeType="XML" from="20" to="100"
|
||||
begin="100s" dur="4s" restart="always" id="anim6"/>
|
||||
</circle>
|
||||
</svg>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
<![CDATA[
|
||||
/** Test for SMIL sync behavior **/
|
||||
|
||||
/* Global Variables */
|
||||
var svg = document.getElementById("svg");
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function main() {
|
||||
testBeginAt(document.getElementById("anim1"));
|
||||
testChangeBaseVal(document.getElementById("anim2"));
|
||||
testChangeWhilePaused(document.getElementById("anim3"));
|
||||
testChangeAnimAttribute(document.getElementById("anim4"));
|
||||
testChangeTimingAttribute(document.getElementById("anim5"));
|
||||
testSetCurrentTime(document.getElementById("anim6"));
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function testBeginAt(anim) {
|
||||
// This (hugely important) test checks that a call to beginElement updates to
|
||||
// the new interval
|
||||
|
||||
// Check some pre-conditions
|
||||
is(anim.getAttribute("restart"), "always");
|
||||
ok(anim.getSimpleDuration() >= 4);
|
||||
|
||||
// First start the animation
|
||||
svg.setCurrentTime(2);
|
||||
anim.beginElement();
|
||||
|
||||
// Then restart it--twice
|
||||
svg.setCurrentTime(4);
|
||||
anim.beginElement();
|
||||
anim.beginElementAt(-1);
|
||||
|
||||
// The first restart should win if the state machine has been successfully
|
||||
// updated. If we get '3' back instead we haven't updated properly.
|
||||
is(anim.getStartTime(), 4);
|
||||
}
|
||||
|
||||
function testChangeBaseVal(anim) {
|
||||
// Check that a change to the base value is updated even after animation is
|
||||
// frozen
|
||||
|
||||
// preconditions -- element should have ended
|
||||
ok(anim.getStartTime() + anim.getSimpleDuration() <= svg.getCurrentTime());
|
||||
|
||||
// check frozen value is applied
|
||||
var target = anim.targetElement;
|
||||
is(target.cx.animVal.value, 70);
|
||||
is(target.cx.baseVal.value, 20);
|
||||
|
||||
// change base val and re-check
|
||||
target.cx.baseVal.value = 30;
|
||||
is(target.cx.animVal.value, 80);
|
||||
is(target.cx.baseVal.value, 30);
|
||||
}
|
||||
|
||||
function testChangeWhilePaused(anim) {
|
||||
// Check that a change to the base value is updated even when the animation is
|
||||
// paused
|
||||
|
||||
svg.pauseAnimations();
|
||||
svg.setCurrentTime(anim.getSimpleDuration() / 2);
|
||||
|
||||
// check paused value is applied
|
||||
var target = anim.targetElement;
|
||||
is(target.cx.animVal.value, 45);
|
||||
is(target.cx.baseVal.value, 20);
|
||||
|
||||
// change base val and re-check
|
||||
target.cx.baseVal.value = 30;
|
||||
is(target.cx.animVal.value, 55);
|
||||
is(target.cx.baseVal.value, 30);
|
||||
}
|
||||
|
||||
function testChangeAnimAttribute(anim) {
|
||||
// Check that a change to an animation attribute causes an update even when
|
||||
// the animation is frozen and paused
|
||||
|
||||
// Make sure animation is paused and frozen
|
||||
svg.pauseAnimations();
|
||||
svg.setCurrentTime(anim.getStartTime() + anim.getSimpleDuration() + 1);
|
||||
|
||||
// Check frozen value is applied
|
||||
var target = anim.targetElement;
|
||||
is(target.cx.animVal.value, 70);
|
||||
is(target.cx.baseVal.value, 20);
|
||||
|
||||
// Make the animation no longer additive
|
||||
anim.removeAttribute("additive");
|
||||
is(target.cx.animVal.value, 50);
|
||||
is(target.cx.baseVal.value, 20);
|
||||
}
|
||||
|
||||
function testChangeTimingAttribute(anim) {
|
||||
// Check that a change to a timing attribute causes an update even when
|
||||
// the animation is paused
|
||||
|
||||
svg.pauseAnimations();
|
||||
svg.setCurrentTime(anim.getSimpleDuration() / 2);
|
||||
|
||||
// Check part-way value is applied
|
||||
var target = anim.targetElement;
|
||||
is(target.cx.animVal.value, 45);
|
||||
is(target.cx.baseVal.value, 20);
|
||||
|
||||
// Make the animation no longer additive
|
||||
anim.setAttribute("dur", String(anim.getSimpleDuration() / 2) + "s");
|
||||
is(target.cx.animVal.value, 70);
|
||||
is(target.cx.baseVal.value, 20);
|
||||
|
||||
// Remove fill
|
||||
anim.removeAttribute("fill");
|
||||
is(target.cx.animVal.value, 20);
|
||||
is(target.cx.baseVal.value, 20);
|
||||
}
|
||||
|
||||
function testSetCurrentTime(anim) {
|
||||
// This test checks that a call to setCurrentTime flushes restarts
|
||||
//
|
||||
// Actually, this same scenario arises in test_smilRestart.xhtml but we
|
||||
// isolate this particular situation here for easier diagnosis if this ever
|
||||
// fails.
|
||||
//
|
||||
// At first we have:
|
||||
// currentTime begin="100s"
|
||||
// v v
|
||||
// Doc time: 0---\/\/\/-------99----------100-------
|
||||
//
|
||||
svg.setCurrentTime(99);
|
||||
is(anim.getStartTime(), 100);
|
||||
|
||||
// Then we restart giving us:
|
||||
//
|
||||
// beginElement begin="100s"
|
||||
// v v
|
||||
// Doc time: 0---\/\/\/-------99----------100-------
|
||||
//
|
||||
// So our current interval is
|
||||
//
|
||||
// begin="100s"
|
||||
// v
|
||||
// +---------------|
|
||||
// Doc time: 0---\/\/\/-------99-100-101-102-103-----
|
||||
//
|
||||
anim.beginElement();
|
||||
is(anim.getStartTime(), svg.getCurrentTime());
|
||||
|
||||
// Then we skip to half-way, i.e.
|
||||
//
|
||||
// currentTime
|
||||
// v
|
||||
// begin="100s"
|
||||
// v
|
||||
// +---------------|
|
||||
// Doc time: 0---\/\/\/-------99-100-101-102-103-----
|
||||
//
|
||||
// At this point we should flush our restarts and early end the first interval
|
||||
// and start the second interval, giving us
|
||||
//
|
||||
// So our timegraph looks like:
|
||||
//
|
||||
// currentTime
|
||||
// v
|
||||
// +---------------|
|
||||
// +---|
|
||||
// Doc time: 0---\/\/\/-------99-100-101-102-103-104-
|
||||
//
|
||||
var newTime = anim.getStartTime() + 0.5 * anim.getSimpleDuration();
|
||||
svg.setCurrentTime(newTime);
|
||||
|
||||
// Finally we call beginElement again giving us
|
||||
//
|
||||
// currentTime
|
||||
// v
|
||||
// +---------------|
|
||||
// +---|
|
||||
// +---|
|
||||
// Doc time: 0---\/\/\/-------99-100-101-102-103-104-105-
|
||||
//
|
||||
// If, however, setCurrentTime failed to flush restarts out starting point
|
||||
// we do come to update the timegraph would be:
|
||||
//
|
||||
// beginElementAt
|
||||
// v
|
||||
// begin="100s"
|
||||
// v
|
||||
// +---------------|
|
||||
// Doc time: 0---\/\/\/-------99-100-101-102-103-----
|
||||
//
|
||||
// And as soon as we encountered the begin="100s" spec we'd do a restart
|
||||
// according to the SMIL algorithms and a restart involves a reset which
|
||||
// clears the instance times created by DOM calls and so we'd end up with
|
||||
// just:
|
||||
//
|
||||
// currentTime
|
||||
// v
|
||||
// +---------------|
|
||||
// +---|
|
||||
// Doc time: 0---\/\/\/-------99-100-101-102-103-104-
|
||||
//
|
||||
// Which is probably not what the author intended.
|
||||
//
|
||||
anim.beginElement();
|
||||
is(anim.getStartTime(), svg.getCurrentTime());
|
||||
}
|
||||
|
||||
window.addEventListener("load", main, false);
|
||||
]]>
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,71 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Test for SMIL sync behaviour for transform types</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>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="120px" height="120px">
|
||||
<circle cx="20" cy="20" r="15" fill="blue">
|
||||
<animateTransform attributeName="transform" type="rotate"
|
||||
from="90" to="180" begin="0s" dur="2s" fill="freeze"
|
||||
additive="sum" id="anim1"/>
|
||||
</circle>
|
||||
<circle cx="20" cy="20" r="15" fill="blue">
|
||||
<animateTransform attributeName="transform" type="scale"
|
||||
from="1" to="2" begin="2s" dur="2s" id="anim2"/>
|
||||
</circle>
|
||||
</svg>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
<![CDATA[
|
||||
/** Test for SMIL sync behavior for transform types **/
|
||||
|
||||
/* Global Variables */
|
||||
var svg = document.getElementById("svg");
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function main() {
|
||||
testChangeBaseVal(document.getElementById("anim1"));
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function testChangeBaseVal(anim) {
|
||||
// Check that a change to the base value is updated even after animation is
|
||||
// frozen
|
||||
|
||||
var target = anim.targetElement;
|
||||
|
||||
// we haven't fully implemented the transform type yet
|
||||
// - when the target isn't animated baseVal and animVal may be the same object
|
||||
// - attempts to change the animVal don't throw exceptions
|
||||
// XXX in the future store the anim val here and query it
|
||||
var transformList = target.transform;
|
||||
|
||||
// make sure element has ended
|
||||
svg.setCurrentTime(anim.getSimpleDuration());
|
||||
|
||||
// check frozen value is applied
|
||||
is(transformList.baseVal.numberOfItems, 0);
|
||||
is(transformList.animVal.numberOfItems, 1);
|
||||
|
||||
// change base val and re-check
|
||||
var newTransform = svg.createSVGTransform();
|
||||
newTransform.setScale(1,2);
|
||||
transformList.baseVal.appendItem(newTransform);
|
||||
is(transformList.baseVal.numberOfItems, 1);
|
||||
// Not done yet
|
||||
todo_is(transformList.animVal.numberOfItems, 2);
|
||||
}
|
||||
|
||||
window.addEventListener("load", main, false);
|
||||
]]>
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -156,6 +156,8 @@ nsSVGAnimationElement::TimedElement()
|
|||
NS_IMETHODIMP
|
||||
nsSVGAnimationElement::GetTargetElement(nsIDOMSVGElement** aTarget)
|
||||
{
|
||||
FlushAnimations();
|
||||
|
||||
// We'll just call the other GetTargetElement method, and QI to the right type
|
||||
nsIContent* targetContent = GetTargetElementContent();
|
||||
|
||||
|
@ -169,6 +171,8 @@ nsSVGAnimationElement::GetTargetElement(nsIDOMSVGElement** aTarget)
|
|||
NS_IMETHODIMP
|
||||
nsSVGAnimationElement::GetStartTime(float* retval)
|
||||
{
|
||||
FlushAnimations();
|
||||
|
||||
nsSMILTimeValue startTime = mTimedElement.GetStartTime();
|
||||
if (startTime.IsResolved()) {
|
||||
*retval = double(startTime.GetMillis()) / PR_MSEC_PER_SEC;
|
||||
|
@ -183,6 +187,8 @@ nsSVGAnimationElement::GetStartTime(float* retval)
|
|||
NS_IMETHODIMP
|
||||
nsSVGAnimationElement::GetCurrentTime(float* retval)
|
||||
{
|
||||
// Not necessary to call FlushAnimations() for this
|
||||
|
||||
nsSMILTimeContainer* root = GetTimeContainer();
|
||||
if (root) {
|
||||
*retval = double(root->GetCurrentTime()) / PR_MSEC_PER_SEC;
|
||||
|
@ -196,6 +202,8 @@ nsSVGAnimationElement::GetCurrentTime(float* retval)
|
|||
NS_IMETHODIMP
|
||||
nsSVGAnimationElement::GetSimpleDuration(float* retval)
|
||||
{
|
||||
// Not necessary to call FlushAnimations() for this
|
||||
|
||||
nsSMILTimeValue simpleDur = mTimedElement.GetSimpleDuration();
|
||||
if (!simpleDur.IsResolved()) {
|
||||
*retval = 0.f;
|
||||
|
@ -246,6 +254,8 @@ nsSVGAnimationElement::BindToTree(nsIDocument* aDocument,
|
|||
}
|
||||
}
|
||||
|
||||
AnimationNeedsResample();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -264,6 +274,8 @@ nsSVGAnimationElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
|
|||
mTimedDocumentRoot = nsnull;
|
||||
}
|
||||
|
||||
AnimationNeedsResample();
|
||||
|
||||
nsSVGAnimationElementBase::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
|
||||
|
@ -281,6 +293,7 @@ nsSVGAnimationElement::ParseAttribute(PRInt32 aNamespaceID,
|
|||
if (aAttribute == nsGkAtoms::attributeName ||
|
||||
aAttribute == nsGkAtoms::attributeType) {
|
||||
aResult.ParseAtom(aValue);
|
||||
AnimationNeedsResample();
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
|
@ -297,6 +310,7 @@ nsSVGAnimationElement::ParseAttribute(PRInt32 aNamespaceID,
|
|||
}
|
||||
|
||||
if (foundMatch) {
|
||||
AnimationNeedsResample();
|
||||
if (NS_FAILED(rv)) {
|
||||
ReportAttributeParseFailure(GetOwnerDoc(), aAttribute, aValue);
|
||||
return PR_FALSE;
|
||||
|
@ -318,8 +332,9 @@ nsSVGAnimationElement::UnsetAttr(PRInt32 aNamespaceID,
|
|||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (!AnimationFunction().UnsetAttr(aAttribute)) {
|
||||
mTimedElement.UnsetAttr(aAttribute);
|
||||
if (AnimationFunction().UnsetAttr(aAttribute) ||
|
||||
mTimedElement.UnsetAttr(aAttribute)) {
|
||||
AnimationNeedsResample();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -380,13 +395,10 @@ nsSVGAnimationElement::BeginElement(void)
|
|||
NS_IMETHODIMP
|
||||
nsSVGAnimationElement::BeginElementAt(float offset)
|
||||
{
|
||||
nsSVGSVGElement *ownerSVG = GetCtx();
|
||||
if (!ownerSVG)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsresult rv = mTimedElement.BeginElementAt(offset, mTimedDocumentRoot);
|
||||
AnimationNeedsResample();
|
||||
|
||||
ownerSVG->RequestSample();
|
||||
|
||||
return mTimedElement.BeginElementAt(offset, mTimedDocumentRoot);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* void endElement (); */
|
||||
|
@ -400,11 +412,8 @@ nsSVGAnimationElement::EndElement(void)
|
|||
NS_IMETHODIMP
|
||||
nsSVGAnimationElement::EndElementAt(float offset)
|
||||
{
|
||||
nsSVGSVGElement *ownerSVG = GetCtx();
|
||||
if (!ownerSVG)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsresult rv = mTimedElement.EndElementAt(offset, mTimedDocumentRoot);
|
||||
AnimationNeedsResample();
|
||||
|
||||
ownerSVG->RequestSample();
|
||||
|
||||
return mTimedElement.EndElementAt(offset, mTimedDocumentRoot);
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -1233,6 +1233,10 @@ nsSVGElement::DidAnimateLength(PRUint8 aAttrEnum)
|
|||
void
|
||||
nsSVGElement::GetAnimatedLengthValues(float *aFirst, ...)
|
||||
{
|
||||
#ifdef MOZ_SMIL
|
||||
FlushAnimations();
|
||||
#endif
|
||||
|
||||
LengthAttributesInfo info = GetLengthInfo();
|
||||
|
||||
NS_ASSERTION(info.mLengthCount > 0,
|
||||
|
@ -1678,4 +1682,28 @@ nsSVGElement::GetAnimatedAttr(const nsIAtom* aName)
|
|||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGElement::AnimationNeedsResample()
|
||||
{
|
||||
nsIDocument* doc = GetCurrentDoc();
|
||||
if (doc) {
|
||||
nsSMILAnimationController* smilController = doc->GetAnimationController();
|
||||
if (smilController) {
|
||||
smilController->SetResampleNeeded();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGElement::FlushAnimations()
|
||||
{
|
||||
nsIDocument* doc = GetCurrentDoc();
|
||||
if (doc) {
|
||||
nsSMILAnimationController* smilController = doc->GetAnimationController();
|
||||
if (smilController) {
|
||||
smilController->FlushResampleRequests();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // MOZ_SMIL
|
||||
|
|
|
@ -155,6 +155,8 @@ public:
|
|||
|
||||
#ifdef MOZ_SMIL
|
||||
virtual nsISMILAttr* GetAnimatedAttr(const nsIAtom* aName);
|
||||
void AnimationNeedsResample();
|
||||
void FlushAnimations();
|
||||
#endif
|
||||
|
||||
virtual void RecompileScriptEventListeners();
|
||||
|
|
|
@ -191,8 +191,8 @@ nsSVGLength2::GetMMPerPixel(nsSVGSVGElement *aCtx) const
|
|||
return mmPerPx;
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGLength2::GetMMPerPixel(nsIFrame *aNonSVGFrame) const
|
||||
/*static*/ float
|
||||
nsSVGLength2::GetMMPerPixel(nsIFrame *aNonSVGFrame)
|
||||
{
|
||||
nsPresContext* presContext = aNonSVGFrame->PresContext();
|
||||
float pixelsPerInch =
|
||||
|
@ -239,9 +239,10 @@ nsSVGLength2::GetAxisLength(nsIFrame *aNonSVGFrame) const
|
|||
}
|
||||
|
||||
float
|
||||
nsSVGLength2::GetUnitScaleFactor(nsSVGElement *aSVGElement) const
|
||||
nsSVGLength2::GetUnitScaleFactor(nsSVGElement *aSVGElement,
|
||||
PRUint8 aUnitType) const
|
||||
{
|
||||
switch (mSpecifiedUnitType) {
|
||||
switch (aUnitType) {
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER:
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_PX:
|
||||
return 1;
|
||||
|
@ -251,13 +252,13 @@ nsSVGLength2::GetUnitScaleFactor(nsSVGElement *aSVGElement) const
|
|||
return 1 / GetExLength(aSVGElement);
|
||||
}
|
||||
|
||||
return GetUnitScaleFactor(aSVGElement->GetCtx());
|
||||
return GetUnitScaleFactor(aSVGElement->GetCtx(), aUnitType);
|
||||
}
|
||||
|
||||
float
|
||||
nsSVGLength2::GetUnitScaleFactor(nsSVGSVGElement *aCtx) const
|
||||
nsSVGLength2::GetUnitScaleFactor(nsSVGSVGElement *aCtx, PRUint8 aUnitType) const
|
||||
{
|
||||
switch (mSpecifiedUnitType) {
|
||||
switch (aUnitType) {
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER:
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_PX:
|
||||
return 1;
|
||||
|
@ -284,13 +285,13 @@ nsSVGLength2::GetUnitScaleFactor(nsSVGSVGElement *aCtx) const
|
|||
}
|
||||
|
||||
float
|
||||
nsSVGLength2::GetUnitScaleFactor(nsIFrame *aFrame) const
|
||||
nsSVGLength2::GetUnitScaleFactor(nsIFrame *aFrame, PRUint8 aUnitType) const
|
||||
{
|
||||
nsIContent* content = aFrame->GetContent();
|
||||
if (content->IsNodeOfType(nsINode::eSVG))
|
||||
return GetUnitScaleFactor(static_cast<nsSVGElement*>(content));
|
||||
return GetUnitScaleFactor(static_cast<nsSVGElement*>(content), aUnitType);
|
||||
|
||||
switch (mSpecifiedUnitType) {
|
||||
switch (aUnitType) {
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER:
|
||||
case nsIDOMSVGLength::SVG_LENGTHTYPE_PX:
|
||||
return 1;
|
||||
|
@ -322,6 +323,12 @@ nsSVGLength2::SetBaseValueInSpecifiedUnits(float aValue,
|
|||
{
|
||||
mBaseVal = aValue;
|
||||
aSVGElement->DidChangeLength(mAttrEnum, PR_TRUE);
|
||||
|
||||
#ifdef MOZ_SMIL
|
||||
if (mIsAnimated) {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -331,7 +338,8 @@ nsSVGLength2::ConvertToSpecifiedUnits(PRUint16 unitType,
|
|||
if (!IsValidUnitType(unitType))
|
||||
return;
|
||||
|
||||
float valueInUserUnits = mBaseVal / GetUnitScaleFactor(aSVGElement);
|
||||
float valueInUserUnits =
|
||||
mBaseVal / GetUnitScaleFactor(aSVGElement, mSpecifiedUnitType);
|
||||
mSpecifiedUnitType = PRUint8(unitType);
|
||||
SetBaseValue(valueInUserUnits, aSVGElement);
|
||||
}
|
||||
|
@ -347,6 +355,12 @@ nsSVGLength2::NewValueSpecifiedUnits(PRUint16 unitType,
|
|||
mBaseVal = mAnimVal = valueInSpecifiedUnits;
|
||||
mSpecifiedUnitType = PRUint8(unitType);
|
||||
aSVGElement->DidChangeLength(mAttrEnum, PR_TRUE);
|
||||
|
||||
#ifdef MOZ_SMIL
|
||||
if (mIsAnimated) {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -390,6 +404,12 @@ nsSVGLength2::SetBaseValueString(const nsAString &aValueAsString,
|
|||
mSpecifiedUnitType = PRUint8(unitType);
|
||||
aSVGElement->DidChangeLength(mAttrEnum, aDoSetAttr);
|
||||
|
||||
#ifdef MOZ_SMIL
|
||||
if (mIsAnimated) {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -408,14 +428,21 @@ nsSVGLength2::GetAnimValueString(nsAString & aValueAsString)
|
|||
void
|
||||
nsSVGLength2::SetBaseValue(float aValue, nsSVGElement *aSVGElement)
|
||||
{
|
||||
mAnimVal = mBaseVal = aValue * GetUnitScaleFactor(aSVGElement);
|
||||
mAnimVal = mBaseVal =
|
||||
aValue * GetUnitScaleFactor(aSVGElement, mSpecifiedUnitType);
|
||||
aSVGElement->DidChangeLength(mAttrEnum, PR_TRUE);
|
||||
#ifdef MOZ_SMIL
|
||||
if (mIsAnimated) {
|
||||
aSVGElement->AnimationNeedsResample();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGLength2::SetAnimValue(float aValue, nsSVGElement *aSVGElement)
|
||||
{
|
||||
mAnimVal = aValue * GetUnitScaleFactor(aSVGElement);
|
||||
mAnimVal = aValue * GetUnitScaleFactor(aSVGElement, mSpecifiedUnitType);
|
||||
mIsAnimated = PR_TRUE;
|
||||
aSVGElement->DidAnimateLength(mAttrEnum);
|
||||
}
|
||||
|
||||
|
@ -443,12 +470,18 @@ nsSVGLength2::SMILLength::ValueFromString(const nsAString& aStr,
|
|||
const nsISMILAnimationElement* /*aSrcElement*/,
|
||||
nsSMILValue& aValue) const
|
||||
{
|
||||
nsSVGLength2 tmp;
|
||||
tmp.SetBaseValueString(aStr, mSVGElement, PR_FALSE);
|
||||
float value;
|
||||
PRUint16 unitType;
|
||||
|
||||
nsresult rv = GetValueFromString(aStr, &value, &unitType);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsSMILValue val(&nsSMILFloatType::sSingleton);
|
||||
val.mU.mDouble = tmp.GetBaseValue(mSVGElement);
|
||||
val.mU.mDouble = value / mVal->GetUnitScaleFactor(mSVGElement, unitType);
|
||||
aValue = val;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -466,7 +499,7 @@ nsSVGLength2::SMILLength::SetAnimValue(const nsSMILValue& aValue)
|
|||
NS_ASSERTION(aValue.mType == &nsSMILFloatType::sSingleton,
|
||||
"Unexpected type to assign animated value");
|
||||
if (aValue.mType == &nsSMILFloatType::sSingleton) {
|
||||
mVal->SetAnimValue((float)aValue.mU.mDouble, mSVGElement);
|
||||
mVal->SetAnimValue(float(aValue.mU.mDouble), mSVGElement);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -73,11 +73,16 @@ public:
|
|||
void GetAnimValueString(nsAString& aValue);
|
||||
|
||||
float GetBaseValue(nsSVGElement* aSVGElement) const
|
||||
{ return mBaseVal / GetUnitScaleFactor(aSVGElement); }
|
||||
{ return mBaseVal / GetUnitScaleFactor(aSVGElement, mSpecifiedUnitType); }
|
||||
float GetAnimValue(nsSVGElement* aSVGElement) const
|
||||
{ return mAnimVal / GetUnitScaleFactor(aSVGElement); }
|
||||
{
|
||||
#ifdef MOZ_SMIL
|
||||
aSVGElement->FlushAnimations();
|
||||
#endif
|
||||
return mAnimVal / GetUnitScaleFactor(aSVGElement, mSpecifiedUnitType);
|
||||
}
|
||||
float GetAnimValue(nsIFrame* aFrame) const
|
||||
{ return mAnimVal / GetUnitScaleFactor(aFrame); }
|
||||
{ return mAnimVal / GetUnitScaleFactor(aFrame, mSpecifiedUnitType); }
|
||||
|
||||
PRUint8 GetCtxType() const { return mCtxType; }
|
||||
PRUint8 GetSpecifiedUnitType() const { return mSpecifiedUnitType; }
|
||||
|
@ -87,9 +92,9 @@ public:
|
|||
float GetBaseValInSpecifiedUnits() const { return mBaseVal; }
|
||||
|
||||
float GetBaseValue(nsSVGSVGElement* aCtx) const
|
||||
{ return mBaseVal / GetUnitScaleFactor(aCtx); }
|
||||
{ return mBaseVal / GetUnitScaleFactor(aCtx, mSpecifiedUnitType); }
|
||||
float GetAnimValue(nsSVGSVGElement* aCtx) const
|
||||
{ return mAnimVal / GetUnitScaleFactor(aCtx); }
|
||||
{ return mAnimVal / GetUnitScaleFactor(aCtx, mSpecifiedUnitType); }
|
||||
|
||||
nsresult ToDOMAnimatedLength(nsIDOMSVGAnimatedLength **aResult,
|
||||
nsSVGElement* aSVGElement);
|
||||
|
@ -107,22 +112,23 @@ private:
|
|||
PRUint8 mCtxType; // X, Y or Unspecified
|
||||
PRPackedBool mIsAnimated;
|
||||
|
||||
float GetMMPerPixel(nsIFrame *aNonSVGFrame) const;
|
||||
static float GetMMPerPixel(nsIFrame *aNonSVGFrame);
|
||||
float GetAxisLength(nsIFrame *aNonSVGFrame) const;
|
||||
float GetEmLength(nsIFrame *aFrame) const
|
||||
static float GetEmLength(nsIFrame *aFrame)
|
||||
{ return nsSVGUtils::GetFontSize(aFrame); }
|
||||
float GetExLength(nsIFrame *aFrame) const
|
||||
static float GetExLength(nsIFrame *aFrame)
|
||||
{ return nsSVGUtils::GetFontXHeight(aFrame); }
|
||||
float GetUnitScaleFactor(nsIFrame *aFrame) const;
|
||||
float GetUnitScaleFactor(nsIFrame *aFrame, PRUint8 aUnitType) const;
|
||||
|
||||
float GetMMPerPixel(nsSVGSVGElement *aCtx) const;
|
||||
float GetAxisLength(nsSVGSVGElement *aCtx) const;
|
||||
float GetEmLength(nsSVGElement *aSVGElement) const
|
||||
static float GetEmLength(nsSVGElement *aSVGElement)
|
||||
{ return nsSVGUtils::GetFontSize(aSVGElement); }
|
||||
float GetExLength(nsSVGElement *aSVGElement) const
|
||||
static float GetExLength(nsSVGElement *aSVGElement)
|
||||
{ return nsSVGUtils::GetFontXHeight(aSVGElement); }
|
||||
float GetUnitScaleFactor(nsSVGElement *aSVGElement) const;
|
||||
float GetUnitScaleFactor(nsSVGSVGElement *aCtx) const;
|
||||
float GetUnitScaleFactor(nsSVGElement *aSVGElement, PRUint8 aUnitType) const;
|
||||
float GetUnitScaleFactor(nsSVGSVGElement *aCtx, PRUint8 aUnitType) const;
|
||||
|
||||
void SetBaseValue(float aValue, nsSVGElement *aSVGElement);
|
||||
void SetBaseValueInSpecifiedUnits(float aValue, nsSVGElement *aSVGElement);
|
||||
void SetAnimValue(float aValue, nsSVGElement *aSVGElement);
|
||||
|
@ -193,22 +199,46 @@ private:
|
|||
nsRefPtr<nsSVGElement> mSVGElement;
|
||||
|
||||
NS_IMETHOD GetUnitType(PRUint16* aResult)
|
||||
{ *aResult = mVal->mSpecifiedUnitType; return NS_OK; }
|
||||
{
|
||||
#ifdef MOZ_SMIL
|
||||
mSVGElement->FlushAnimations();
|
||||
#endif
|
||||
*aResult = mVal->mSpecifiedUnitType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetValue(float* aResult)
|
||||
{ *aResult = mVal->GetAnimValue(mSVGElement); return NS_OK; }
|
||||
{
|
||||
#ifdef MOZ_SMIL
|
||||
mSVGElement->FlushAnimations();
|
||||
#endif
|
||||
*aResult = mVal->GetAnimValue(mSVGElement);
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD SetValue(float aValue)
|
||||
{ return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
|
||||
|
||||
NS_IMETHOD GetValueInSpecifiedUnits(float* aResult)
|
||||
{ *aResult = mVal->mAnimVal; return NS_OK; }
|
||||
{
|
||||
#ifdef MOZ_SMIL
|
||||
mSVGElement->FlushAnimations();
|
||||
#endif
|
||||
*aResult = mVal->mAnimVal;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD SetValueInSpecifiedUnits(float aValue)
|
||||
{ return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
|
||||
|
||||
NS_IMETHOD SetValueAsString(const nsAString& aValue)
|
||||
{ return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
|
||||
NS_IMETHOD GetValueAsString(nsAString& aValue)
|
||||
{ mVal->GetAnimValueString(aValue); return NS_OK; }
|
||||
{
|
||||
#ifdef MOZ_SMIL
|
||||
mSVGElement->FlushAnimations();
|
||||
#endif
|
||||
mVal->GetAnimValueString(aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD NewValueSpecifiedUnits(PRUint16 unitType,
|
||||
float valueInSpecifiedUnits)
|
||||
|
@ -249,7 +279,6 @@ private:
|
|||
nsSVGLength2* mVal;
|
||||
nsSVGElement* mSVGElement;
|
||||
|
||||
|
||||
// nsISMILAttr methods
|
||||
virtual nsresult ValueFromString(const nsAString& aStr,
|
||||
const nsISMILAnimationElement* aSrcElement,
|
||||
|
|
|
@ -555,7 +555,20 @@ nsSVGSVGElement::SetCurrentTime(float seconds)
|
|||
// errors
|
||||
nsSMILTime lMilliseconds = PRInt64(NS_round(fMilliseconds));
|
||||
mTimedDocumentRoot->SetCurrentTime(lMilliseconds);
|
||||
RequestSample();
|
||||
// Force a resample now
|
||||
//
|
||||
// It's not sufficient to just request a resample here because calls to
|
||||
// BeginElement etc. expect to operate on an up-to-date timegraph or else
|
||||
// instance times may be incorrectly discarded.
|
||||
//
|
||||
// See the mochitest: test_smilSync.xhtml:testSetCurrentTime()
|
||||
nsIDocument* doc = GetCurrentDoc();
|
||||
if (doc) {
|
||||
nsSMILAnimationController* smilController = doc->GetAnimationController();
|
||||
if (smilController) {
|
||||
smilController->Resample();
|
||||
}
|
||||
}
|
||||
} // else we're not the outermost <svg> or not bound to a tree, so silently
|
||||
// fail
|
||||
return NS_OK;
|
||||
|
@ -1157,18 +1170,6 @@ nsSVGSVGElement::GetTimedDocumentRoot()
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGSVGElement::RequestSample()
|
||||
{
|
||||
nsIDocument* doc = GetCurrentDoc();
|
||||
if (doc) {
|
||||
nsSMILAnimationController* smilController = doc->GetAnimationController();
|
||||
if (smilController) {
|
||||
smilController->FireForceSampleEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // MOZ_SMIL
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
|
|
@ -137,7 +137,6 @@ public:
|
|||
|
||||
#ifdef MOZ_SMIL
|
||||
nsSMILTimeContainer* GetTimedDocumentRoot();
|
||||
void RequestSample();
|
||||
#endif // MOZ_SMIL
|
||||
|
||||
// nsIContent interface
|
||||
|
|
|
@ -33,7 +33,7 @@ http://www.w3.org/2003/01/REC-SVG11-20030114-errata#getCurrentTime_setCurrentTim
|
|||
document.getElementById('wrong').style.visibility = 'visible';
|
||||
}
|
||||
|
||||
setTimeout('document.documentElement.removeAttribute("class")', 0);
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
]]></script>
|
||||
<circle cx="50" cy="50" r="30" fill="blue">
|
||||
|
|
До Ширина: | Высота: | Размер: 1.8 KiB После Ширина: | Высота: | Размер: 1.8 KiB |
|
@ -6,6 +6,5 @@ function setTimeAndSnapshot(timeInSeconds, pauseFlag) {
|
|||
svg.pauseAnimations();
|
||||
}
|
||||
svg.setCurrentTime(timeInSeconds);
|
||||
// Use setTimeout to allow SMIL to update the animation before snapshot
|
||||
setTimeout('document.documentElement.removeAttribute("class")', 0);
|
||||
svg.removeAttribute("class");
|
||||
}
|
||||
|
|
|
@ -6,12 +6,6 @@
|
|||
var svg = document.documentElement;
|
||||
svg.pauseAnimations();
|
||||
svg.setCurrentTime(timeInSeconds);
|
||||
// Use setTimeout to allow SMIL to update the animation before we check
|
||||
// the values and take a snapshot
|
||||
setTimeout('checkAnimVals()');
|
||||
}
|
||||
function checkAnimVals() {
|
||||
var svg = document.documentElement;
|
||||
var paths = svg.getElementsByTagName("path");
|
||||
for (var i = 0; i < paths.length; i++) {
|
||||
var path = paths[i];
|
||||
|
|
До Ширина: | Высота: | Размер: 7.6 KiB После Ширина: | Высота: | Размер: 7.4 KiB |
Загрузка…
Ссылка в новой задаче