diff options
Diffstat (limited to 'dom/svg/nsSVGNumberPair.cpp')
-rw-r--r-- | dom/svg/nsSVGNumberPair.cpp | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/dom/svg/nsSVGNumberPair.cpp b/dom/svg/nsSVGNumberPair.cpp new file mode 100644 index 000000000..fd1532546 --- /dev/null +++ b/dom/svg/nsSVGNumberPair.cpp @@ -0,0 +1,230 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsSVGNumberPair.h" +#include "nsSVGAttrTearoffTable.h" +#include "nsCharSeparatedTokenizer.h" +#include "nsSMILValue.h" +#include "SVGContentUtils.h" +#include "SVGNumberPairSMILType.h" + +using namespace mozilla; +using namespace mozilla::dom; + +static nsSVGAttrTearoffTable<nsSVGNumberPair, nsSVGNumberPair::DOMAnimatedNumber> + sSVGFirstAnimatedNumberTearoffTable; +static nsSVGAttrTearoffTable<nsSVGNumberPair, nsSVGNumberPair::DOMAnimatedNumber> + sSVGSecondAnimatedNumberTearoffTable; + +static nsresult +ParseNumberOptionalNumber(const nsAString& aValue, + float aValues[2]) +{ + nsCharSeparatedTokenizerTemplate<IsSVGWhitespace> + tokenizer(aValue, ',', + nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL); + if (tokenizer.whitespaceBeforeFirstToken()) { + return NS_ERROR_DOM_SYNTAX_ERR; + } + + uint32_t i; + for (i = 0; i < 2 && tokenizer.hasMoreTokens(); ++i) { + if (!SVGContentUtils::ParseNumber(tokenizer.nextToken(), aValues[i])) { + return NS_ERROR_DOM_SYNTAX_ERR; + } + } + if (i == 1) { + aValues[1] = aValues[0]; + } + + if (i == 0 || // Too few values. + tokenizer.hasMoreTokens() || // Too many values. + tokenizer.whitespaceAfterCurrentToken() || // Trailing whitespace. + tokenizer.separatorAfterCurrentToken()) { // Trailing comma. + return NS_ERROR_DOM_SYNTAX_ERR; + } + + return NS_OK; +} + +nsresult +nsSVGNumberPair::SetBaseValueString(const nsAString &aValueAsString, + nsSVGElement *aSVGElement) +{ + float val[2]; + + nsresult rv = ParseNumberOptionalNumber(aValueAsString, val); + if (NS_FAILED(rv)) { + return rv; + } + + mBaseVal[0] = val[0]; + mBaseVal[1] = val[1]; + mIsBaseSet = true; + if (!mIsAnimated) { + mAnimVal[0] = mBaseVal[0]; + mAnimVal[1] = mBaseVal[1]; + } + else { + aSVGElement->AnimationNeedsResample(); + } + + // We don't need to call Will/DidChange* here - we're only called by + // nsSVGElement::ParseAttribute under Element::SetAttr, + // which takes care of notifying. + return NS_OK; +} + +void +nsSVGNumberPair::GetBaseValueString(nsAString &aValueAsString) const +{ + aValueAsString.Truncate(); + aValueAsString.AppendFloat(mBaseVal[0]); + if (mBaseVal[0] != mBaseVal[1]) { + aValueAsString.AppendLiteral(", "); + aValueAsString.AppendFloat(mBaseVal[1]); + } +} + +void +nsSVGNumberPair::SetBaseValue(float aValue, PairIndex aPairIndex, + nsSVGElement *aSVGElement) +{ + uint32_t index = (aPairIndex == eFirst ? 0 : 1); + if (mIsBaseSet && mBaseVal[index] == aValue) { + return; + } + nsAttrValue emptyOrOldValue = aSVGElement->WillChangeNumberPair(mAttrEnum); + mBaseVal[index] = aValue; + mIsBaseSet = true; + if (!mIsAnimated) { + mAnimVal[index] = aValue; + } + else { + aSVGElement->AnimationNeedsResample(); + } + aSVGElement->DidChangeNumberPair(mAttrEnum, emptyOrOldValue); +} + +void +nsSVGNumberPair::SetBaseValues(float aValue1, float aValue2, + nsSVGElement *aSVGElement) +{ + if (mIsBaseSet && mBaseVal[0] == aValue1 && mBaseVal[1] == aValue2) { + return; + } + nsAttrValue emptyOrOldValue = aSVGElement->WillChangeNumberPair(mAttrEnum); + mBaseVal[0] = aValue1; + mBaseVal[1] = aValue2; + mIsBaseSet = true; + if (!mIsAnimated) { + mAnimVal[0] = aValue1; + mAnimVal[1] = aValue2; + } + else { + aSVGElement->AnimationNeedsResample(); + } + aSVGElement->DidChangeNumberPair(mAttrEnum, emptyOrOldValue); +} + +void +nsSVGNumberPair::SetAnimValue(const float aValue[2], nsSVGElement *aSVGElement) +{ + if (mIsAnimated && mAnimVal[0] == aValue[0] && mAnimVal[1] == aValue[1]) { + return; + } + mAnimVal[0] = aValue[0]; + mAnimVal[1] = aValue[1]; + mIsAnimated = true; + aSVGElement->DidAnimateNumberPair(mAttrEnum); +} + +already_AddRefed<SVGAnimatedNumber> +nsSVGNumberPair::ToDOMAnimatedNumber(PairIndex aIndex, + nsSVGElement* aSVGElement) +{ + RefPtr<DOMAnimatedNumber> domAnimatedNumber = + aIndex == eFirst ? sSVGFirstAnimatedNumberTearoffTable.GetTearoff(this) : + sSVGSecondAnimatedNumberTearoffTable.GetTearoff(this); + if (!domAnimatedNumber) { + domAnimatedNumber = new DOMAnimatedNumber(this, aIndex, aSVGElement); + if (aIndex == eFirst) { + sSVGFirstAnimatedNumberTearoffTable.AddTearoff(this, domAnimatedNumber); + } else { + sSVGSecondAnimatedNumberTearoffTable.AddTearoff(this, domAnimatedNumber); + } + } + + return domAnimatedNumber.forget(); +} + +nsSVGNumberPair::DOMAnimatedNumber::~DOMAnimatedNumber() +{ + if (mIndex == eFirst) { + sSVGFirstAnimatedNumberTearoffTable.RemoveTearoff(mVal); + } else { + sSVGSecondAnimatedNumberTearoffTable.RemoveTearoff(mVal); + } +} + +nsISMILAttr* +nsSVGNumberPair::ToSMILAttr(nsSVGElement *aSVGElement) +{ + return new SMILNumberPair(this, aSVGElement); +} + +nsresult +nsSVGNumberPair::SMILNumberPair::ValueFromString(const nsAString& aStr, + const dom::SVGAnimationElement* /*aSrcElement*/, + nsSMILValue& aValue, + bool& aPreventCachingOfSandwich) const +{ + float values[2]; + + nsresult rv = ParseNumberOptionalNumber(aStr, values); + if (NS_FAILED(rv)) { + return rv; + } + + nsSMILValue val(&SVGNumberPairSMILType::sSingleton); + val.mU.mNumberPair[0] = values[0]; + val.mU.mNumberPair[1] = values[1]; + aValue = val; + aPreventCachingOfSandwich = false; + + return NS_OK; +} + +nsSMILValue +nsSVGNumberPair::SMILNumberPair::GetBaseValue() const +{ + nsSMILValue val(&SVGNumberPairSMILType::sSingleton); + val.mU.mNumberPair[0] = mVal->mBaseVal[0]; + val.mU.mNumberPair[1] = mVal->mBaseVal[1]; + return val; +} + +void +nsSVGNumberPair::SMILNumberPair::ClearAnimValue() +{ + if (mVal->mIsAnimated) { + mVal->mIsAnimated = false; + mVal->mAnimVal[0] = mVal->mBaseVal[0]; + mVal->mAnimVal[1] = mVal->mBaseVal[1]; + mSVGElement->DidAnimateNumberPair(mVal->mAttrEnum); + } +} + +nsresult +nsSVGNumberPair::SMILNumberPair::SetAnimValue(const nsSMILValue& aValue) +{ + NS_ASSERTION(aValue.mType == &SVGNumberPairSMILType::sSingleton, + "Unexpected type to assign animated value"); + if (aValue.mType == &SVGNumberPairSMILType::sSingleton) { + mVal->SetAnimValue(aValue.mU.mNumberPair, mSVGElement); + } + return NS_OK; +} |