/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is AnimationCommon, common animation code for transitions * and animations. * * The Initial Developer of the Original Code is the Mozilla Foundation. * Portions created by the Initial Developer are Copyright (C) 2011 * the Initial Developer. All Rights Reserved. * * Contributor(s): * L. David Baron , Mozilla Corporation (original author) * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "AnimationCommon.h" #include "nsRuleData.h" #include "nsCSSValue.h" #include "nsStyleContext.h" namespace mozilla { namespace css { CommonAnimationManager::CommonAnimationManager(nsPresContext *aPresContext) : mPresContext(aPresContext) { PR_INIT_CLIST(&mElementData); } CommonAnimationManager::~CommonAnimationManager() { NS_ABORT_IF_FALSE(!mPresContext, "Disconnect should have been called"); } void CommonAnimationManager::Disconnect() { // Content nodes might outlive the transition or animation manager. RemoveAllElementData(); mPresContext = nsnull; } void CommonAnimationManager::AddElementData(CommonElementAnimationData* aData) { if (PR_CLIST_IS_EMPTY(&mElementData)) { // We need to observe the refresh driver. nsRefreshDriver *rd = mPresContext->RefreshDriver(); rd->AddRefreshObserver(this, Flush_Style); } PR_INSERT_BEFORE(aData, &mElementData); } void CommonAnimationManager::ElementDataRemoved() { // If we have no transitions or animations left, remove ourselves from // the refresh driver. if (PR_CLIST_IS_EMPTY(&mElementData)) { mPresContext->RefreshDriver()->RemoveRefreshObserver(this, Flush_Style); } } void CommonAnimationManager::RemoveAllElementData() { while (!PR_CLIST_IS_EMPTY(&mElementData)) { CommonElementAnimationData *head = static_cast(PR_LIST_HEAD(&mElementData)); head->Destroy(); } } /* * nsISupports implementation */ NS_IMPL_ISUPPORTS1(CommonAnimationManager, nsIStyleRuleProcessor) nsRestyleHint CommonAnimationManager::HasStateDependentStyle(StateRuleProcessorData* aData) { return nsRestyleHint(0); } bool CommonAnimationManager::HasDocumentStateDependentStyle(StateRuleProcessorData* aData) { return false; } nsRestyleHint CommonAnimationManager::HasAttributeDependentStyle(AttributeRuleProcessorData* aData) { return nsRestyleHint(0); } /* virtual */ bool CommonAnimationManager::MediumFeaturesChanged(nsPresContext* aPresContext) { return false; } /* virtual */ size_t CommonAnimationManager::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const { // XXX: could measure mProperytValuePairs here. Bug 671299 may do this. return 0; } /* virtual */ size_t CommonAnimationManager::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const { return aMallocSizeOf(this, sizeof(CommonAnimationManager)) + SizeOfExcludingThis(aMallocSizeOf); } /* static */ bool CommonAnimationManager::ExtractComputedValueForTransition( nsCSSProperty aProperty, nsStyleContext* aStyleContext, nsStyleAnimation::Value& aComputedValue) { bool result = nsStyleAnimation::ExtractComputedValue(aProperty, aStyleContext, aComputedValue); if (aProperty == eCSSProperty_visibility) { NS_ABORT_IF_FALSE(aComputedValue.GetUnit() == nsStyleAnimation::eUnit_Enumerated, "unexpected unit"); aComputedValue.SetIntValue(aComputedValue.GetIntValue(), nsStyleAnimation::eUnit_Visibility); } return result; } NS_IMPL_ISUPPORTS1(AnimValuesStyleRule, nsIStyleRule) /* virtual */ void AnimValuesStyleRule::MapRuleInfoInto(nsRuleData* aRuleData) { nsStyleContext *contextParent = aRuleData->mStyleContext->GetParent(); if (contextParent && contextParent->HasPseudoElementData()) { // Don't apply transitions or animations to things inside of // pseudo-elements. // FIXME (Bug 522599): Add tests for this. return; } for (PRUint32 i = 0, i_end = mPropertyValuePairs.Length(); i < i_end; ++i) { PropertyValuePair &cv = mPropertyValuePairs[i]; if (aRuleData->mSIDs & nsCachedStyleData::GetBitForSID( nsCSSProps::kSIDTable[cv.mProperty])) { nsCSSValue *prop = aRuleData->ValueFor(cv.mProperty); if (prop->GetUnit() == eCSSUnit_Null) { #ifdef DEBUG bool ok = #endif nsStyleAnimation::UncomputeValue(cv.mProperty, aRuleData->mPresContext, cv.mValue, *prop); NS_ABORT_IF_FALSE(ok, "could not store computed value"); } } } } #ifdef DEBUG /* virtual */ void AnimValuesStyleRule::List(FILE* out, PRInt32 aIndent) const { // WRITE ME? } #endif void ComputedTimingFunction::Init(const nsTimingFunction &aFunction) { mType = aFunction.mType; if (mType == nsTimingFunction::Function) { mTimingFunction.Init(aFunction.mFunc.mX1, aFunction.mFunc.mY1, aFunction.mFunc.mX2, aFunction.mFunc.mY2); } else { mSteps = aFunction.mSteps; } } static inline double StepEnd(PRUint32 aSteps, double aPortion) { NS_ABORT_IF_FALSE(0.0 <= aPortion && aPortion <= 1.0, "out of range"); PRUint32 step = PRUint32(aPortion * aSteps); // floor return double(step) / double(aSteps); } double ComputedTimingFunction::GetValue(double aPortion) const { switch (mType) { case nsTimingFunction::Function: return mTimingFunction.GetSplineValue(aPortion); case nsTimingFunction::StepStart: // There are diagrams in the spec that seem to suggest this check // and the bounds point should not be symmetric with StepEnd, but // should actually step up at rather than immediately after the // fraction points. However, we rely on rounding negative values // up to zero, so we can't do that. And it's not clear the spec // really meant it. return 1.0 - StepEnd(mSteps, 1.0 - aPortion); default: NS_ABORT_IF_FALSE(false, "bad type"); // fall through case nsTimingFunction::StepEnd: return StepEnd(mSteps, aPortion); } } } }