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:
Brian Birtles 2009-01-22 14:00:27 +13:00
Родитель e36799a8d9
Коммит 03f9d86660
19 изменённых файлов: 631 добавлений и 254 удалений

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

@ -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,
&params);
&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