michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* representation of a SMIL-animatable mapped attribute on an element */ michael@0: #include "nsSMILMappedAttribute.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsError.h" // For NS_PROPTABLE_PROP_OVERWRITTEN michael@0: #include "nsSMILValue.h" michael@0: #include "nsSMILCSSValueType.h" michael@0: #include "nsIDocument.h" michael@0: #include "nsIPresShell.h" michael@0: #include "nsCSSProps.h" michael@0: #include "mozilla/dom/Element.h" michael@0: michael@0: // Callback function, for freeing string buffers stored in property table michael@0: static void michael@0: ReleaseStringBufferPropertyValue(void* aObject, /* unused */ michael@0: nsIAtom* aPropertyName, /* unused */ michael@0: void* aPropertyValue, michael@0: void* aData /* unused */) michael@0: { michael@0: nsStringBuffer* buf = static_cast(aPropertyValue); michael@0: buf->Release(); michael@0: } michael@0: michael@0: michael@0: nsresult michael@0: nsSMILMappedAttribute::ValueFromString(const nsAString& aStr, michael@0: const mozilla::dom::SVGAnimationElement* aSrcElement, michael@0: nsSMILValue& aValue, michael@0: bool& aPreventCachingOfSandwich) const michael@0: { michael@0: NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE); michael@0: michael@0: nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue, michael@0: &aPreventCachingOfSandwich); michael@0: return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK; michael@0: } michael@0: michael@0: nsSMILValue michael@0: nsSMILMappedAttribute::GetBaseValue() const michael@0: { michael@0: nsAutoString baseStringValue; michael@0: nsRefPtr attrName = GetAttrNameAtom(); michael@0: bool success = mElement->GetAttr(kNameSpaceID_None, attrName, michael@0: baseStringValue); michael@0: nsSMILValue baseValue; michael@0: if (success) { michael@0: // For base values, we don't need to worry whether the value returned is michael@0: // context-sensitive or not since the compositor will take care of comparing michael@0: // the returned (computed) base value and its cached value and determining michael@0: // if an update is required or not. michael@0: nsSMILCSSValueType::ValueFromString(mPropID, mElement, michael@0: baseStringValue, baseValue, nullptr); michael@0: } else { michael@0: // Attribute is unset -- use computed value. michael@0: // FIRST: Temporarily clear animated value, to make sure it doesn't pollute michael@0: // the computed value. (We want base value, _without_ animations applied.) michael@0: void* buf = mElement->UnsetProperty(SMIL_MAPPED_ATTR_ANIMVAL, michael@0: attrName, nullptr); michael@0: FlushChangesToTargetAttr(); michael@0: michael@0: // SECOND: we use nsSMILCSSProperty::GetBaseValue to look up the property's michael@0: // computed value. NOTE: This call will temporarily clear the SMIL michael@0: // override-style for the corresponding CSS property on our target element. michael@0: // This prevents any animations that target the CSS property from affecting michael@0: // animations that target the mapped attribute. michael@0: baseValue = nsSMILCSSProperty::GetBaseValue(); michael@0: michael@0: // FINALLY: If we originally had an animated value set, then set it again. michael@0: if (buf) { michael@0: mElement->SetProperty(SMIL_MAPPED_ATTR_ANIMVAL, attrName, buf, michael@0: ReleaseStringBufferPropertyValue); michael@0: FlushChangesToTargetAttr(); michael@0: } michael@0: } michael@0: return baseValue; michael@0: } michael@0: michael@0: nsresult michael@0: nsSMILMappedAttribute::SetAnimValue(const nsSMILValue& aValue) michael@0: { michael@0: NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE); michael@0: michael@0: // Convert nsSMILValue to string michael@0: nsAutoString valStr; michael@0: if (!nsSMILCSSValueType::ValueToString(aValue, valStr)) { michael@0: NS_WARNING("Failed to convert nsSMILValue for mapped attr into a string"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsRefPtr attrName = GetAttrNameAtom(); michael@0: nsStringBuffer* oldValStrBuf = static_cast michael@0: (mElement->GetProperty(SMIL_MAPPED_ATTR_ANIMVAL, attrName)); michael@0: if (oldValStrBuf) { michael@0: nsString oldValStr; michael@0: nsContentUtils::PopulateStringFromStringBuffer(oldValStrBuf, oldValStr); michael@0: if (valStr.Equals(oldValStr)) { michael@0: // New animated value is the same as the old; nothing to do. michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: // Set the string as this mapped attribute's animated value. michael@0: nsStringBuffer* valStrBuf = michael@0: nsCSSValue::BufferFromString(nsString(valStr)).take(); michael@0: nsresult rv = mElement->SetProperty(SMIL_MAPPED_ATTR_ANIMVAL, michael@0: attrName, valStrBuf, michael@0: ReleaseStringBufferPropertyValue); michael@0: if (rv == NS_PROPTABLE_PROP_OVERWRITTEN) { michael@0: rv = NS_OK; michael@0: } michael@0: FlushChangesToTargetAttr(); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: void michael@0: nsSMILMappedAttribute::ClearAnimValue() michael@0: { michael@0: nsRefPtr attrName = GetAttrNameAtom(); michael@0: mElement->DeleteProperty(SMIL_MAPPED_ATTR_ANIMVAL, attrName); michael@0: FlushChangesToTargetAttr(); michael@0: } michael@0: michael@0: void michael@0: nsSMILMappedAttribute::FlushChangesToTargetAttr() const michael@0: { michael@0: // Clear animated content-style-rule michael@0: mElement->DeleteProperty(SMIL_MAPPED_ATTR_ANIMVAL, michael@0: SMIL_MAPPED_ATTR_STYLERULE_ATOM); michael@0: nsIDocument* doc = mElement->GetCurrentDoc(); michael@0: michael@0: // Request animation restyle michael@0: if (doc) { michael@0: nsIPresShell* shell = doc->GetShell(); michael@0: if (shell) { michael@0: shell->RestyleForAnimation(mElement, eRestyle_Self); michael@0: } michael@0: } michael@0: } michael@0: michael@0: already_AddRefed michael@0: nsSMILMappedAttribute::GetAttrNameAtom() const michael@0: { michael@0: return do_GetAtom(nsCSSProps::GetStringValue(mPropID)); michael@0: }