diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /dom/smil/nsSMILCSSValueType.cpp | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'dom/smil/nsSMILCSSValueType.cpp')
-rw-r--r-- | dom/smil/nsSMILCSSValueType.cpp | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/dom/smil/nsSMILCSSValueType.cpp b/dom/smil/nsSMILCSSValueType.cpp new file mode 100644 index 000000000..ed89e7710 --- /dev/null +++ b/dom/smil/nsSMILCSSValueType.cpp @@ -0,0 +1,447 @@ +/* -*- 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/. */ + +/* representation of a value for a SMIL-animated CSS property */ + +#include "nsSMILCSSValueType.h" +#include "nsString.h" +#include "nsSMILParserUtils.h" +#include "nsSMILValue.h" +#include "nsCSSValue.h" +#include "nsColor.h" +#include "nsPresContext.h" +#include "mozilla/StyleAnimationValue.h" +#include "mozilla/dom/Element.h" +#include "nsDebug.h" +#include "nsStyleUtil.h" +#include "nsIDocument.h" + +using namespace mozilla::dom; +using mozilla::StyleAnimationValue; + +/*static*/ nsSMILCSSValueType nsSMILCSSValueType::sSingleton; + +struct ValueWrapper { + ValueWrapper(nsCSSPropertyID aPropID, const StyleAnimationValue& aValue) : + mPropID(aPropID), mCSSValue(aValue) {} + + nsCSSPropertyID mPropID; + StyleAnimationValue mCSSValue; +}; + +// Helper Methods +// -------------- +static const StyleAnimationValue* +GetZeroValueForUnit(StyleAnimationValue::Unit aUnit) +{ + static const StyleAnimationValue + sZeroCoord(0, StyleAnimationValue::CoordConstructor); + static const StyleAnimationValue + sZeroPercent(0.0f, StyleAnimationValue::PercentConstructor); + static const StyleAnimationValue + sZeroFloat(0.0f, StyleAnimationValue::FloatConstructor); + static const StyleAnimationValue + sZeroColor(NS_RGB(0,0,0), StyleAnimationValue::ColorConstructor); + + MOZ_ASSERT(aUnit != StyleAnimationValue::eUnit_Null, + "Need non-null unit for a zero value"); + switch (aUnit) { + case StyleAnimationValue::eUnit_Coord: + return &sZeroCoord; + case StyleAnimationValue::eUnit_Percent: + return &sZeroPercent; + case StyleAnimationValue::eUnit_Float: + return &sZeroFloat; + case StyleAnimationValue::eUnit_Color: + return &sZeroColor; + default: + return nullptr; + } +} + +// This method requires at least one of its arguments to be non-null. +// +// If one argument is null, this method updates it to point to "zero" +// for the other argument's Unit (if applicable; otherwise, we return false). +// +// If neither argument is null, this method generally does nothing, though it +// may apply a workaround for the special case where a 0 length-value is mixed +// with a eUnit_Float value. (See comment below.) +// +// Returns true on success, or false. +static bool +FinalizeStyleAnimationValues(const StyleAnimationValue*& aValue1, + const StyleAnimationValue*& aValue2) +{ + MOZ_ASSERT(aValue1 || aValue2, + "expecting at least one non-null value"); + + // Are we missing either val? (If so, it's an implied 0 in other val's units) + if (!aValue1) { + aValue1 = GetZeroValueForUnit(aValue2->GetUnit()); + return !!aValue1; // Fail if we have no zero value for this unit. + } + if (!aValue2) { + aValue2 = GetZeroValueForUnit(aValue1->GetUnit()); + return !!aValue2; // Fail if we have no zero value for this unit. + } + + // Ok, both values were specified. + // Need to handle a special-case, though: unitless nonzero length (parsed as + // eUnit_Float) mixed with unitless 0 length (parsed as eUnit_Coord). These + // won't interoperate in StyleAnimationValue, since their Units don't match. + // In this case, we replace the eUnit_Coord 0 value with eUnit_Float 0 value. + const StyleAnimationValue& zeroCoord = + *GetZeroValueForUnit(StyleAnimationValue::eUnit_Coord); + if (*aValue1 == zeroCoord && + aValue2->GetUnit() == StyleAnimationValue::eUnit_Float) { + aValue1 = GetZeroValueForUnit(StyleAnimationValue::eUnit_Float); + } else if (*aValue2 == zeroCoord && + aValue1->GetUnit() == StyleAnimationValue::eUnit_Float) { + aValue2 = GetZeroValueForUnit(StyleAnimationValue::eUnit_Float); + } + + return true; +} + +static void +InvertSign(StyleAnimationValue& aValue) +{ + switch (aValue.GetUnit()) { + case StyleAnimationValue::eUnit_Coord: + aValue.SetCoordValue(-aValue.GetCoordValue()); + break; + case StyleAnimationValue::eUnit_Percent: + aValue.SetPercentValue(-aValue.GetPercentValue()); + break; + case StyleAnimationValue::eUnit_Float: + aValue.SetFloatValue(-aValue.GetFloatValue()); + break; + default: + NS_NOTREACHED("Calling InvertSign with an unsupported unit"); + break; + } +} + +static ValueWrapper* +ExtractValueWrapper(nsSMILValue& aValue) +{ + return static_cast<ValueWrapper*>(aValue.mU.mPtr); +} + +static const ValueWrapper* +ExtractValueWrapper(const nsSMILValue& aValue) +{ + return static_cast<const ValueWrapper*>(aValue.mU.mPtr); +} + +// Class methods +// ------------- +void +nsSMILCSSValueType::Init(nsSMILValue& aValue) const +{ + MOZ_ASSERT(aValue.IsNull(), "Unexpected SMIL value type"); + + aValue.mU.mPtr = nullptr; + aValue.mType = this; +} + +void +nsSMILCSSValueType::Destroy(nsSMILValue& aValue) const +{ + MOZ_ASSERT(aValue.mType == this, "Unexpected SMIL value type"); + delete static_cast<ValueWrapper*>(aValue.mU.mPtr); + aValue.mType = nsSMILNullType::Singleton(); +} + +nsresult +nsSMILCSSValueType::Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const +{ + MOZ_ASSERT(aDest.mType == aSrc.mType, "Incompatible SMIL types"); + MOZ_ASSERT(aDest.mType == this, "Unexpected SMIL value type"); + const ValueWrapper* srcWrapper = ExtractValueWrapper(aSrc); + ValueWrapper* destWrapper = ExtractValueWrapper(aDest); + + if (srcWrapper) { + if (!destWrapper) { + // barely-initialized dest -- need to alloc & copy + aDest.mU.mPtr = new ValueWrapper(*srcWrapper); + } else { + // both already fully-initialized -- just copy straight across + *destWrapper = *srcWrapper; + } + } else if (destWrapper) { + // fully-initialized dest, barely-initialized src -- clear dest + delete destWrapper; + aDest.mU.mPtr = destWrapper = nullptr; + } // else, both are barely-initialized -- nothing to do. + + return NS_OK; +} + +bool +nsSMILCSSValueType::IsEqual(const nsSMILValue& aLeft, + const nsSMILValue& aRight) const +{ + MOZ_ASSERT(aLeft.mType == aRight.mType, "Incompatible SMIL types"); + MOZ_ASSERT(aLeft.mType == this, "Unexpected SMIL value"); + const ValueWrapper* leftWrapper = ExtractValueWrapper(aLeft); + const ValueWrapper* rightWrapper = ExtractValueWrapper(aRight); + + if (leftWrapper) { + if (rightWrapper) { + // Both non-null + NS_WARNING_ASSERTION(leftWrapper != rightWrapper, + "Two nsSMILValues with matching ValueWrapper ptr"); + return (leftWrapper->mPropID == rightWrapper->mPropID && + leftWrapper->mCSSValue == rightWrapper->mCSSValue); + } + // Left non-null, right null + return false; + } + if (rightWrapper) { + // Left null, right non-null + return false; + } + // Both null + return true; +} + +nsresult +nsSMILCSSValueType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd, + uint32_t aCount) const +{ + MOZ_ASSERT(aValueToAdd.mType == aDest.mType, + "Trying to add invalid types"); + MOZ_ASSERT(aValueToAdd.mType == this, "Unexpected source type"); + + ValueWrapper* destWrapper = ExtractValueWrapper(aDest); + const ValueWrapper* valueToAddWrapper = ExtractValueWrapper(aValueToAdd); + MOZ_ASSERT(destWrapper || valueToAddWrapper, + "need at least one fully-initialized value"); + + nsCSSPropertyID property = (valueToAddWrapper ? valueToAddWrapper->mPropID : + destWrapper->mPropID); + // Special case: font-size-adjust and stroke-dasharray are explicitly + // non-additive (even though StyleAnimationValue *could* support adding them) + if (property == eCSSProperty_font_size_adjust || + property == eCSSProperty_stroke_dasharray) { + return NS_ERROR_FAILURE; + } + + const StyleAnimationValue* valueToAdd = valueToAddWrapper ? + &valueToAddWrapper->mCSSValue : nullptr; + const StyleAnimationValue* destValue = destWrapper ? + &destWrapper->mCSSValue : nullptr; + if (!FinalizeStyleAnimationValues(valueToAdd, destValue)) { + return NS_ERROR_FAILURE; + } + // Did FinalizeStyleAnimationValues change destValue? + // If so, update outparam to use the new value. + if (destWrapper && &destWrapper->mCSSValue != destValue) { + destWrapper->mCSSValue = *destValue; + } + + // Handle barely-initialized "zero" destination. + if (!destWrapper) { + aDest.mU.mPtr = destWrapper = + new ValueWrapper(property, *destValue); + } + + return StyleAnimationValue::Add(property, + destWrapper->mCSSValue, *valueToAdd, aCount) ? + NS_OK : NS_ERROR_FAILURE; +} + +nsresult +nsSMILCSSValueType::ComputeDistance(const nsSMILValue& aFrom, + const nsSMILValue& aTo, + double& aDistance) const +{ + MOZ_ASSERT(aFrom.mType == aTo.mType, + "Trying to compare different types"); + MOZ_ASSERT(aFrom.mType == this, "Unexpected source type"); + + const ValueWrapper* fromWrapper = ExtractValueWrapper(aFrom); + const ValueWrapper* toWrapper = ExtractValueWrapper(aTo); + MOZ_ASSERT(toWrapper, "expecting non-null endpoint"); + + const StyleAnimationValue* fromCSSValue = fromWrapper ? + &fromWrapper->mCSSValue : nullptr; + const StyleAnimationValue* toCSSValue = &toWrapper->mCSSValue; + if (!FinalizeStyleAnimationValues(fromCSSValue, toCSSValue)) { + return NS_ERROR_FAILURE; + } + + return StyleAnimationValue::ComputeDistance(toWrapper->mPropID, + *fromCSSValue, *toCSSValue, + nullptr, + aDistance) ? + NS_OK : NS_ERROR_FAILURE; +} + +nsresult +nsSMILCSSValueType::Interpolate(const nsSMILValue& aStartVal, + const nsSMILValue& aEndVal, + double aUnitDistance, + nsSMILValue& aResult) const +{ + MOZ_ASSERT(aStartVal.mType == aEndVal.mType, + "Trying to interpolate different types"); + MOZ_ASSERT(aStartVal.mType == this, + "Unexpected types for interpolation"); + MOZ_ASSERT(aResult.mType == this, "Unexpected result type"); + MOZ_ASSERT(aUnitDistance >= 0.0 && aUnitDistance <= 1.0, + "unit distance value out of bounds"); + MOZ_ASSERT(!aResult.mU.mPtr, "expecting barely-initialized outparam"); + + const ValueWrapper* startWrapper = ExtractValueWrapper(aStartVal); + const ValueWrapper* endWrapper = ExtractValueWrapper(aEndVal); + MOZ_ASSERT(endWrapper, "expecting non-null endpoint"); + + const StyleAnimationValue* startCSSValue = startWrapper ? + &startWrapper->mCSSValue : nullptr; + const StyleAnimationValue* endCSSValue = &endWrapper->mCSSValue; + if (!FinalizeStyleAnimationValues(startCSSValue, endCSSValue)) { + return NS_ERROR_FAILURE; + } + + StyleAnimationValue resultValue; + if (StyleAnimationValue::Interpolate(endWrapper->mPropID, + *startCSSValue, *endCSSValue, + aUnitDistance, resultValue)) { + aResult.mU.mPtr = new ValueWrapper(endWrapper->mPropID, resultValue); + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +// Helper function to extract presContext +static nsPresContext* +GetPresContextForElement(Element* aElem) +{ + nsIDocument* doc = aElem->GetUncomposedDoc(); + if (!doc) { + // This can happen if we process certain types of restyles mid-sample + // and remove anonymous animated content from the document as a result. + // See bug 534975. + return nullptr; + } + nsIPresShell* shell = doc->GetShell(); + return shell ? shell->GetPresContext() : nullptr; +} + +// Helper function to parse a string into a StyleAnimationValue +static bool +ValueFromStringHelper(nsCSSPropertyID aPropID, + Element* aTargetElement, + nsPresContext* aPresContext, + const nsAString& aString, + StyleAnimationValue& aStyleAnimValue, + bool* aIsContextSensitive) +{ + // If value is negative, we'll strip off the "-" so the CSS parser won't + // barf, and then manually make the parsed value negative. + // (This is a partial solution to let us accept some otherwise out-of-bounds + // CSS values. Bug 501188 will provide a more complete fix.) + bool isNegative = false; + uint32_t subStringBegin = 0; + + // NOTE: We need to opt-out 'stroke-dasharray' from the negative-number + // check. Its values might look negative (e.g. by starting with "-1"), but + // they're more complicated than our simple negation logic here can handle. + if (aPropID != eCSSProperty_stroke_dasharray) { + int32_t absValuePos = nsSMILParserUtils::CheckForNegativeNumber(aString); + if (absValuePos > 0) { + isNegative = true; + subStringBegin = (uint32_t)absValuePos; // Start parsing after '-' sign + } + } + RefPtr<nsStyleContext> styleContext = + nsComputedDOMStyle::GetStyleContextForElement(aTargetElement, nullptr, + aPresContext->PresShell()); + if (!styleContext) { + return false; + } + nsDependentSubstring subString(aString, subStringBegin); + if (!StyleAnimationValue::ComputeValue(aPropID, aTargetElement, styleContext, + subString, true, aStyleAnimValue, + aIsContextSensitive)) { + return false; + } + if (isNegative) { + InvertSign(aStyleAnimValue); + } + + if (aPropID == eCSSProperty_font_size) { + // Divide out text-zoom, since SVG is supposed to ignore it + MOZ_ASSERT(aStyleAnimValue.GetUnit() == StyleAnimationValue::eUnit_Coord, + "'font-size' value with unexpected style unit"); + aStyleAnimValue.SetCoordValue(aStyleAnimValue.GetCoordValue() / + aPresContext->TextZoom()); + } + return true; +} + +// static +void +nsSMILCSSValueType::ValueFromString(nsCSSPropertyID aPropID, + Element* aTargetElement, + const nsAString& aString, + nsSMILValue& aValue, + bool* aIsContextSensitive) +{ + MOZ_ASSERT(aValue.IsNull(), "Outparam should be null-typed"); + nsPresContext* presContext = GetPresContextForElement(aTargetElement); + if (!presContext) { + NS_WARNING("Not parsing animation value; unable to get PresContext"); + return; + } + + nsIDocument* doc = aTargetElement->GetUncomposedDoc(); + if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr, + doc->NodePrincipal(), + doc->GetDocumentURI(), + 0, aString, nullptr)) { + return; + } + + StyleAnimationValue parsedValue; + if (ValueFromStringHelper(aPropID, aTargetElement, presContext, + aString, parsedValue, aIsContextSensitive)) { + sSingleton.Init(aValue); + aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue); + } +} + +// static +bool +nsSMILCSSValueType::ValueToString(const nsSMILValue& aValue, + nsAString& aString) +{ + MOZ_ASSERT(aValue.mType == &nsSMILCSSValueType::sSingleton, + "Unexpected SMIL value type"); + const ValueWrapper* wrapper = ExtractValueWrapper(aValue); + return !wrapper || + StyleAnimationValue::UncomputeValue(wrapper->mPropID, + wrapper->mCSSValue, aString); +} + +// static +nsCSSPropertyID +nsSMILCSSValueType::PropertyFromValue(const nsSMILValue& aValue) +{ + if (aValue.mType != &nsSMILCSSValueType::sSingleton) { + return eCSSProperty_UNKNOWN; + } + + const ValueWrapper* wrapper = ExtractValueWrapper(aValue); + if (!wrapper) { + return eCSSProperty_UNKNOWN; + } + + return wrapper->mPropID; +} |