1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/smil/nsSMILCompositor.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,186 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsSMILCompositor.h" 1.10 +#include "nsSMILCSSProperty.h" 1.11 +#include "nsCSSProps.h" 1.12 +#include "nsHashKeys.h" 1.13 + 1.14 +// PLDHashEntryHdr methods 1.15 +bool 1.16 +nsSMILCompositor::KeyEquals(KeyTypePointer aKey) const 1.17 +{ 1.18 + return aKey && aKey->Equals(mKey); 1.19 +} 1.20 + 1.21 +/*static*/ PLDHashNumber 1.22 +nsSMILCompositor::HashKey(KeyTypePointer aKey) 1.23 +{ 1.24 + // Combine the 3 values into one numeric value, which will be hashed. 1.25 + // NOTE: We right-shift one of the pointers by 2 to get some randomness in 1.26 + // its 2 lowest-order bits. (Those shifted-off bits will always be 0 since 1.27 + // our pointers will be word-aligned.) 1.28 + return (NS_PTR_TO_UINT32(aKey->mElement.get()) >> 2) + 1.29 + NS_PTR_TO_UINT32(aKey->mAttributeName.get()) + 1.30 + (aKey->mIsCSS ? 1 : 0); 1.31 +} 1.32 + 1.33 +// Cycle-collection support 1.34 +void 1.35 +nsSMILCompositor::Traverse(nsCycleCollectionTraversalCallback* aCallback) 1.36 +{ 1.37 + if (!mKey.mElement) 1.38 + return; 1.39 + 1.40 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback, "Compositor mKey.mElement"); 1.41 + aCallback->NoteXPCOMChild(mKey.mElement); 1.42 +} 1.43 + 1.44 +// Other methods 1.45 +void 1.46 +nsSMILCompositor::AddAnimationFunction(nsSMILAnimationFunction* aFunc) 1.47 +{ 1.48 + if (aFunc) { 1.49 + mAnimationFunctions.AppendElement(aFunc); 1.50 + } 1.51 +} 1.52 + 1.53 +void 1.54 +nsSMILCompositor::ComposeAttribute() 1.55 +{ 1.56 + if (!mKey.mElement) 1.57 + return; 1.58 + 1.59 + // FIRST: Get the nsISMILAttr (to grab base value from, and to eventually 1.60 + // give animated value to) 1.61 + nsAutoPtr<nsISMILAttr> smilAttr(CreateSMILAttr()); 1.62 + if (!smilAttr) { 1.63 + // Target attribute not found (or, out of memory) 1.64 + return; 1.65 + } 1.66 + if (mAnimationFunctions.IsEmpty()) { 1.67 + // No active animation functions. (We can still have a nsSMILCompositor in 1.68 + // that case if an animation function has *just* become inactive) 1.69 + smilAttr->ClearAnimValue(); 1.70 + return; 1.71 + } 1.72 + 1.73 + // SECOND: Sort the animationFunctions, to prepare for compositing. 1.74 + nsSMILAnimationFunction::Comparator comparator; 1.75 + mAnimationFunctions.Sort(comparator); 1.76 + 1.77 + // THIRD: Step backwards through animation functions to find out 1.78 + // which ones we actually care about. 1.79 + uint32_t firstFuncToCompose = GetFirstFuncToAffectSandwich(); 1.80 + 1.81 + // FOURTH: Get & cache base value 1.82 + nsSMILValue sandwichResultValue; 1.83 + if (!mAnimationFunctions[firstFuncToCompose]->WillReplace()) { 1.84 + sandwichResultValue = smilAttr->GetBaseValue(); 1.85 + } 1.86 + UpdateCachedBaseValue(sandwichResultValue); 1.87 + 1.88 + if (!mForceCompositing) { 1.89 + return; 1.90 + } 1.91 + 1.92 + // FIFTH: Compose animation functions 1.93 + uint32_t length = mAnimationFunctions.Length(); 1.94 + for (uint32_t i = firstFuncToCompose; i < length; ++i) { 1.95 + mAnimationFunctions[i]->ComposeResult(*smilAttr, sandwichResultValue); 1.96 + } 1.97 + if (sandwichResultValue.IsNull()) { 1.98 + smilAttr->ClearAnimValue(); 1.99 + return; 1.100 + } 1.101 + 1.102 + // SIXTH: Set the animated value to the final composited result. 1.103 + nsresult rv = smilAttr->SetAnimValue(sandwichResultValue); 1.104 + if (NS_FAILED(rv)) { 1.105 + NS_WARNING("nsISMILAttr::SetAnimValue failed"); 1.106 + } 1.107 +} 1.108 + 1.109 +void 1.110 +nsSMILCompositor::ClearAnimationEffects() 1.111 +{ 1.112 + if (!mKey.mElement || !mKey.mAttributeName) 1.113 + return; 1.114 + 1.115 + nsAutoPtr<nsISMILAttr> smilAttr(CreateSMILAttr()); 1.116 + if (!smilAttr) { 1.117 + // Target attribute not found (or, out of memory) 1.118 + return; 1.119 + } 1.120 + smilAttr->ClearAnimValue(); 1.121 +} 1.122 + 1.123 +// Protected Helper Functions 1.124 +// -------------------------- 1.125 +nsISMILAttr* 1.126 +nsSMILCompositor::CreateSMILAttr() 1.127 +{ 1.128 + if (mKey.mIsCSS) { 1.129 + nsCSSProperty propId = 1.130 + nsCSSProps::LookupProperty(nsDependentAtomString(mKey.mAttributeName), 1.131 + nsCSSProps::eEnabledForAllContent); 1.132 + if (nsSMILCSSProperty::IsPropertyAnimatable(propId)) { 1.133 + return new nsSMILCSSProperty(propId, mKey.mElement.get()); 1.134 + } 1.135 + } else { 1.136 + return mKey.mElement->GetAnimatedAttr(mKey.mAttributeNamespaceID, 1.137 + mKey.mAttributeName); 1.138 + } 1.139 + return nullptr; 1.140 +} 1.141 + 1.142 +uint32_t 1.143 +nsSMILCompositor::GetFirstFuncToAffectSandwich() 1.144 +{ 1.145 + uint32_t i; 1.146 + for (i = mAnimationFunctions.Length(); i > 0; --i) { 1.147 + nsSMILAnimationFunction* curAnimFunc = mAnimationFunctions[i-1]; 1.148 + // In the following, the lack of short-circuit behavior of |= means that we 1.149 + // will ALWAYS run UpdateCachedTarget (even if mForceCompositing is true) 1.150 + // but only call HasChanged and WasSkippedInPrevSample if necessary. This 1.151 + // is important since we need UpdateCachedTarget to run in order to detect 1.152 + // changes to the target in subsequent samples. 1.153 + mForceCompositing |= 1.154 + curAnimFunc->UpdateCachedTarget(mKey) || 1.155 + curAnimFunc->HasChanged() || 1.156 + curAnimFunc->WasSkippedInPrevSample(); 1.157 + 1.158 + if (curAnimFunc->WillReplace()) { 1.159 + --i; 1.160 + break; 1.161 + } 1.162 + } 1.163 + // Mark remaining animation functions as having been skipped so if we later 1.164 + // use them we'll know to force compositing. 1.165 + // Note that we only really need to do this if something has changed 1.166 + // (otherwise we would have set the flag on a previous sample) and if 1.167 + // something has changed mForceCompositing will be true. 1.168 + if (mForceCompositing) { 1.169 + for (uint32_t j = i; j > 0; --j) { 1.170 + mAnimationFunctions[j-1]->SetWasSkipped(); 1.171 + } 1.172 + } 1.173 + return i; 1.174 +} 1.175 + 1.176 +void 1.177 +nsSMILCompositor::UpdateCachedBaseValue(const nsSMILValue& aBaseValue) 1.178 +{ 1.179 + if (!mCachedBaseValue) { 1.180 + // We don't have last sample's base value cached. Assume it's changed. 1.181 + mCachedBaseValue = new nsSMILValue(aBaseValue); 1.182 + NS_WARN_IF_FALSE(mCachedBaseValue, "failed to cache base value (OOM?)"); 1.183 + mForceCompositing = true; 1.184 + } else if (*mCachedBaseValue != aBaseValue) { 1.185 + // Base value has changed since last sample. 1.186 + *mCachedBaseValue = aBaseValue; 1.187 + mForceCompositing = true; 1.188 + } 1.189 +}