diff options
Diffstat (limited to 'dom/smil/nsSMILMappedAttribute.cpp')
-rw-r--r-- | dom/smil/nsSMILMappedAttribute.cpp | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/dom/smil/nsSMILMappedAttribute.cpp b/dom/smil/nsSMILMappedAttribute.cpp new file mode 100644 index 000000000..b43469fac --- /dev/null +++ b/dom/smil/nsSMILMappedAttribute.cpp @@ -0,0 +1,150 @@ +/* -*- 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 SMIL-animatable mapped attribute on an element */ +#include "nsSMILMappedAttribute.h" +#include "nsContentUtils.h" +#include "nsError.h" // For NS_PROPTABLE_PROP_OVERWRITTEN +#include "nsSMILValue.h" +#include "nsSMILCSSValueType.h" +#include "nsIDocument.h" +#include "nsIPresShell.h" +#include "nsCSSProps.h" +#include "mozilla/dom/Element.h" + +// Callback function, for freeing string buffers stored in property table +static void +ReleaseStringBufferPropertyValue(void* aObject, /* unused */ + nsIAtom* aPropertyName, /* unused */ + void* aPropertyValue, + void* aData /* unused */) +{ + nsStringBuffer* buf = static_cast<nsStringBuffer*>(aPropertyValue); + buf->Release(); +} + + +nsresult +nsSMILMappedAttribute::ValueFromString(const nsAString& aStr, + const mozilla::dom::SVGAnimationElement* aSrcElement, + nsSMILValue& aValue, + bool& aPreventCachingOfSandwich) const +{ + NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE); + + nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue, + &aPreventCachingOfSandwich); + return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK; +} + +nsSMILValue +nsSMILMappedAttribute::GetBaseValue() const +{ + nsAutoString baseStringValue; + RefPtr<nsIAtom> attrName = GetAttrNameAtom(); + bool success = mElement->GetAttr(kNameSpaceID_None, attrName, + baseStringValue); + nsSMILValue baseValue; + if (success) { + // For base values, we don't need to worry whether the value returned is + // context-sensitive or not since the compositor will take care of comparing + // the returned (computed) base value and its cached value and determining + // if an update is required or not. + nsSMILCSSValueType::ValueFromString(mPropID, mElement, + baseStringValue, baseValue, nullptr); + } else { + // Attribute is unset -- use computed value. + // FIRST: Temporarily clear animated value, to make sure it doesn't pollute + // the computed value. (We want base value, _without_ animations applied.) + void* buf = mElement->UnsetProperty(SMIL_MAPPED_ATTR_ANIMVAL, + attrName, nullptr); + FlushChangesToTargetAttr(); + + // SECOND: we use nsSMILCSSProperty::GetBaseValue to look up the property's + // computed value. NOTE: This call will temporarily clear the SMIL + // override-style for the corresponding CSS property on our target element. + // This prevents any animations that target the CSS property from affecting + // animations that target the mapped attribute. + baseValue = nsSMILCSSProperty::GetBaseValue(); + + // FINALLY: If we originally had an animated value set, then set it again. + if (buf) { + mElement->SetProperty(SMIL_MAPPED_ATTR_ANIMVAL, attrName, buf, + ReleaseStringBufferPropertyValue); + FlushChangesToTargetAttr(); + } + } + return baseValue; +} + +nsresult +nsSMILMappedAttribute::SetAnimValue(const nsSMILValue& aValue) +{ + NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE); + + // Convert nsSMILValue to string + nsAutoString valStr; + if (!nsSMILCSSValueType::ValueToString(aValue, valStr)) { + NS_WARNING("Failed to convert nsSMILValue for mapped attr into a string"); + return NS_ERROR_FAILURE; + } + + RefPtr<nsIAtom> attrName = GetAttrNameAtom(); + nsStringBuffer* oldValStrBuf = static_cast<nsStringBuffer*> + (mElement->GetProperty(SMIL_MAPPED_ATTR_ANIMVAL, attrName)); + if (oldValStrBuf) { + nsString oldValStr; + nsContentUtils::PopulateStringFromStringBuffer(oldValStrBuf, oldValStr); + if (valStr.Equals(oldValStr)) { + // New animated value is the same as the old; nothing to do. + return NS_OK; + } + } + + // Set the string as this mapped attribute's animated value. + nsStringBuffer* valStrBuf = + nsCSSValue::BufferFromString(nsString(valStr)).take(); + nsresult rv = mElement->SetProperty(SMIL_MAPPED_ATTR_ANIMVAL, + attrName, valStrBuf, + ReleaseStringBufferPropertyValue); + if (rv == NS_PROPTABLE_PROP_OVERWRITTEN) { + rv = NS_OK; + } + FlushChangesToTargetAttr(); + + return rv; +} + +void +nsSMILMappedAttribute::ClearAnimValue() +{ + RefPtr<nsIAtom> attrName = GetAttrNameAtom(); + mElement->DeleteProperty(SMIL_MAPPED_ATTR_ANIMVAL, attrName); + FlushChangesToTargetAttr(); +} + +void +nsSMILMappedAttribute::FlushChangesToTargetAttr() const +{ + // Clear animated content-style-rule + mElement->DeleteProperty(SMIL_MAPPED_ATTR_ANIMVAL, + SMIL_MAPPED_ATTR_STYLERULE_ATOM); + nsIDocument* doc = mElement->GetUncomposedDoc(); + + // Request animation restyle + if (doc) { + nsIPresShell* shell = doc->GetShell(); + if (shell) { + shell->RestyleForAnimation(mElement, eRestyle_Self); + } + } +} + +already_AddRefed<nsIAtom> +nsSMILMappedAttribute::GetAttrNameAtom() const +{ + return NS_Atomize(nsCSSProps::GetStringValue(mPropID)); +} |