Bug 533291 Patch D: Cache base value with each SMIL compositor, since we need to recompose when base value changes. r=roc

This commit is contained in:
Daniel Holbert 2010-02-20 13:13:11 -08:00
parent d022ff95c3
commit 0185ff4ef3
4 changed files with 118 additions and 52 deletions

View File

@ -255,6 +255,22 @@ nsSMILAnimationController::StopTimer()
//----------------------------------------------------------------------
// Sample-related methods and callbacks
PR_CALLBACK PLDHashOperator
TransferCachedBaseValue(nsSMILCompositor* aCompositor,
void* aData)
{
nsSMILCompositorTable* lastCompositorTable =
static_cast<nsSMILCompositorTable*>(aData);
nsSMILCompositor* lastCompositor =
lastCompositorTable->GetEntry(aCompositor->GetKey());
if (lastCompositor) {
aCompositor->StealCachedBaseValue(lastCompositor);
}
return PL_DHASH_NEXT;
}
PR_CALLBACK PLDHashOperator
RemoveCompositorFromTable(nsSMILCompositor* aCompositor,
void* aData)
@ -339,8 +355,14 @@ nsSMILAnimationController::DoSample(PRBool aSkipUnchangedContainers)
&saParams);
activeContainers.Clear();
// STEP 4: Remove animation effects from any no-longer-animated elems/attrs
// STEP 4: Compare previous sample's compositors against this sample's.
// (Transfer cached base values across, & remove animation effects from
// no-longer-animated targets.)
if (mLastCompositorTable) {
// * Transfer over cached base values, from last sample's compositors
currentCompositorTable->EnumerateEntries(TransferCachedBaseValue,
mLastCompositorTable);
// * For each compositor in current sample's hash table, remove entry from
// prev sample's hash table -- we don't need to clear animation
// effects of those compositors, since they're still being animated.

View File

@ -351,8 +351,8 @@ nsSMILAnimationFunction::WillReplace() const
* here we return false for to animation as it builds on the underlying value
* unless its a frozen to animation.
*/
return !(IsAdditive() || IsToAnimation()) ||
(IsToAnimation() && mIsFrozen && !mHasChanged);
return !mErrorFlags && (!(IsAdditive() || IsToAnimation()) ||
(IsToAnimation() && mIsFrozen && !mHasChanged));
}
PRBool

View File

@ -78,22 +78,6 @@ nsSMILCompositor::AddAnimationFunction(nsSMILAnimationFunction* aFunc)
}
}
nsISMILAttr*
nsSMILCompositor::CreateSMILAttr()
{
if (mKey.mIsCSS) {
nsAutoString name;
mKey.mAttributeName->ToString(name);
nsCSSProperty propId = nsCSSProps::LookupProperty(name);
if (nsSMILCSSProperty::IsPropertyAnimatable(propId)) {
return new nsSMILCSSProperty(propId, mKey.mElement.get());
}
} else {
return mKey.mElement->GetAnimatedAttr(mKey.mAttributeName);
}
return nsnull;
}
void
nsSMILCompositor::ComposeAttribute()
{
@ -120,42 +104,29 @@ nsSMILCompositor::ComposeAttribute()
// THIRD: Step backwards through animation functions to find out
// which ones we actually care about.
PRBool changed = mForceCompositing;
PRUint32 length = mAnimationFunctions.Length();
PRUint32 i;
for (i = length; i > 0; --i) {
nsSMILAnimationFunction* curAnimFunc = mAnimationFunctions[i-1];
if (curAnimFunc->UpdateCachedTarget(mKey) ||
(!changed && curAnimFunc->HasChanged())) {
changed = PR_TRUE;
}
PRUint32 firstFuncToCompose = GetFirstFuncToAffectSandwich();
if (curAnimFunc->WillReplace()) {
--i;
break;
}
}
// NOTE: 'i' is now the index of the first animation function that we need
// to use in compositing.
// if (!changed) // XXXdholbert Still need to enable this optimization
// return;
// FOURTH: Compose animation functions (starting with base value)
nsSMILValue resultValue = smilAttr->GetBaseValue();
if (resultValue.IsNull()) {
// FOURTH: Get & cache base value
nsSMILValue sandwichResultValue = smilAttr->GetBaseValue();
if (sandwichResultValue.IsNull()) {
NS_WARNING("nsISMILAttr::GetBaseValue failed");
return;
}
for (; i < length; ++i) {
nsSMILAnimationFunction* curAnimFunc = mAnimationFunctions[i];
if (curAnimFunc) {
curAnimFunc->ComposeResult(*smilAttr, resultValue);
}
UpdateCachedBaseValue(sandwichResultValue);
// if (!mForceCompositing) {
// XXXdholbert Still need to enable this optimization
// return;
// }
// FIFTH: Compose animation functions
PRUint32 length = mAnimationFunctions.Length();
for (PRUint32 i = firstFuncToCompose; i < length; ++i) {
mAnimationFunctions[i]->ComposeResult(*smilAttr, sandwichResultValue);
}
// FIFTH: Set the animated value to the final composited result.
nsresult rv = smilAttr->SetAnimValue(resultValue);
// SIXTH: Set the animated value to the final composited result.
nsresult rv = smilAttr->SetAnimValue(sandwichResultValue);
if (NS_FAILED(rv)) {
NS_WARNING("nsISMILAttr::SetAnimValue failed");
}
@ -175,3 +146,54 @@ nsSMILCompositor::ClearAnimationEffects()
smilAttr->ClearAnimValue();
}
// Protected Helper Functions
// --------------------------
nsISMILAttr*
nsSMILCompositor::CreateSMILAttr()
{
if (mKey.mIsCSS) {
nsAutoString name;
mKey.mAttributeName->ToString(name);
nsCSSProperty propId = nsCSSProps::LookupProperty(name);
if (nsSMILCSSProperty::IsPropertyAnimatable(propId)) {
return new nsSMILCSSProperty(propId, mKey.mElement.get());
}
} else {
return mKey.mElement->GetAnimatedAttr(mKey.mAttributeName);
}
return nsnull;
}
PRUint32
nsSMILCompositor::GetFirstFuncToAffectSandwich()
{
PRUint32 i;
for (i = mAnimationFunctions.Length(); i > 0; --i) {
nsSMILAnimationFunction* curAnimFunc = mAnimationFunctions[i-1];
if (curAnimFunc->UpdateCachedTarget(mKey) ||
(!mForceCompositing && curAnimFunc->HasChanged())) {
mForceCompositing = PR_TRUE;
}
if (curAnimFunc->WillReplace()) {
--i;
break;
}
}
return i;
}
void
nsSMILCompositor::UpdateCachedBaseValue(const nsSMILValue& aBaseValue)
{
if (!mCachedBaseValue) {
// We don't have last sample's base value cached. Assume it's changed.
mCachedBaseValue = new nsSMILValue(aBaseValue);
NS_WARN_IF_FALSE(mCachedBaseValue, "failed to cache base value (OOM?)");
mForceCompositing = PR_TRUE;
} else if (*mCachedBaseValue != aBaseValue) {
// Base value has changed since last sample.
*mCachedBaseValue = aBaseValue;
mForceCompositing = PR_TRUE;
}
}

View File

@ -95,10 +95,24 @@ public:
// optimizations) when we hit ComposeAttribute.
void ToggleForceCompositing() { mForceCompositing = PR_TRUE; }
// Transfers |aOther|'s mCachedBaseValue to |this|
void StealCachedBaseValue(nsSMILCompositor* aOther) {
mCachedBaseValue = aOther->mCachedBaseValue;
}
private:
// Create a nsISMILAttr for my target, on the heap. Caller is responsible
// for deallocating the returned object.
nsISMILAttr* CreateSMILAttr();
// Finds the index of the first function that will affect our animation
// sandwich. Also toggles the 'mForceCompositing' flag if it finds that any
// (used) functions have changed.
PRUint32 GetFirstFuncToAffectSandwich();
// If the passed-in base value differs from our cached base value, this
// method updates the cached value (and toggles the 'mForceCompositing' flag)
void UpdateCachedBaseValue(const nsSMILValue& aBaseValue);
// Static callback methods
PR_STATIC_CALLBACK(PLDHashOperator) DoComposeAttribute(
@ -107,11 +121,19 @@ public:
// The hash key (tuple of element/attributeName/attributeType)
KeyType mKey;
// Hash Value: List of animation functions that animate the specified
// attribute
// ---------------------------------------------------------------
// Hash Value: List of animation functions that animate the specified attr
nsTArray<nsSMILAnimationFunction*> mAnimationFunctions;
// Member data for detecting when we need to force-recompose
// ---------------------------------------------------------
// Flag for tracking whether we need to compose. Initialized to PR_FALSE, but
// gets flipped to PR_TRUE if we detect that something has changed.
PRPackedBool mForceCompositing;
// Cached base value, so we can detect & force-recompose when it changes
// from one sample to the next. (nsSMILAnimationController copies this
// forward from the previous sample's compositor.)
nsAutoPtr<nsSMILValue> mCachedBaseValue;
};
#endif // NS_SMILCOMPOSITOR_H_