dom/smil/nsSMILMappedAttribute.cpp
author Ryan VanderMeulen <ryanvm@gmail.com>
Thu, 10 Jul 2014 21:43:04 -0400
changeset 215438 70f3b01cb736ea9f21d692e537058ad3859a9c69
parent 191987 32f48d6d3389ea5db45cfc6e452ec52595c11a43
child 273536 bd079aadd3feeee3f9b9f73c5e0bc4bd6a870722
permissions -rw-r--r--
Backed out 5 changesets (bug 1020760, bug 1035653, bug 1020090) for leaks on a CLOSED TREE. Backed out changeset f0b20e3db93c (bug 1020760) Backed out changeset 412b654e5cd2 (bug 1035653) Backed out changeset 01ba0892af29 (bug 1020760) Backed out changeset c7de1f4b078f (bug 1020760) Backed out changeset 96aa9d33a1f5 (bug 1020090)

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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;
  nsRefPtr<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;
  }

  nsRefPtr<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()
{
  nsRefPtr<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->GetCurrentDoc();

  // Request animation restyle
  if (doc) {
    nsIPresShell* shell = doc->GetShell();
    if (shell) {
      shell->RestyleForAnimation(mElement, eRestyle_Self);
    }
  }
}

already_AddRefed<nsIAtom>
nsSMILMappedAttribute::GetAttrNameAtom() const
{
  return do_GetAtom(nsCSSProps::GetStringValue(mPropID));
}