void
SVGLengthListSMILType::Init(nsSMILValue &aValue) const
{
  NS_ABORT_IF_FALSE(aValue.IsNull(), "Unexpected value type");

  SVGLengthListAndInfo* lengthList = new SVGLengthListAndInfo();

  // See the comment documenting Init() in our header file:
  lengthList->SetCanZeroPadList(true);

  aValue.mU.mPtr = lengthList;
  aValue.mType = this;
}
nsresult
SVGLengthListSMILType::Assign(nsSMILValue& aDest,
                              const nsSMILValue& aSrc) const
{
  NS_PRECONDITION(aDest.mType == aSrc.mType, "Incompatible SMIL types");
  NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL value");

  const SVGLengthListAndInfo* src =
    static_cast<const SVGLengthListAndInfo*>(aSrc.mU.mPtr);
  SVGLengthListAndInfo* dest =
    static_cast<SVGLengthListAndInfo*>(aDest.mU.mPtr);

  return dest->CopyFrom(*src);
}
nsSMILValue
SVGAnimatedLengthList::SMILAnimatedLengthList::GetBaseValue() const
{
  // To benefit from Return Value Optimization and avoid copy constructor calls
  // due to our use of return-by-value, we must return the exact same object
  // from ALL return points. This function must only return THIS variable:
  nsSMILValue val;

  nsSMILValue tmp(&SVGLengthListSMILType::sSingleton);
  SVGLengthListAndInfo *llai = static_cast<SVGLengthListAndInfo*>(tmp.mU.mPtr);
  nsresult rv = llai->CopyFrom(mVal->mBaseVal);
  if (NS_SUCCEEDED(rv)) {
    llai->SetInfo(mElement, mAxis, mCanZeroPadList);
    val.Swap(tmp);
  }
  return val;
}
nsresult
SVGAnimatedLengthList::
  SMILAnimatedLengthList::ValueFromString(const nsAString& aStr,
                               const nsISMILAnimationElement* /*aSrcElement*/,
                               nsSMILValue& aValue,
                               bool& aPreventCachingOfSandwich) const
{
  nsSMILValue val(&SVGLengthListSMILType::sSingleton);
  SVGLengthListAndInfo *llai = static_cast<SVGLengthListAndInfo*>(val.mU.mPtr);
  nsresult rv = llai->SetValueFromString(aStr);
  if (NS_SUCCEEDED(rv)) {
    llai->SetInfo(mElement, mAxis, mCanZeroPadList);
    aValue.Swap(val);

    // If any of the lengths in the list depend on their context, then we must
    // prevent caching of the entire animation sandwich. This is because the
    // units of a length at a given index can change from sandwich layer to
    // layer, and indeed even be different within a single sandwich layer. If
    // any length in the result of an animation sandwich is the result of the
    // addition of lengths where one or more of those lengths is context
    // dependent, then naturally the resultant length is also context
    // dependent, regardless of whether its actual unit is context dependent or
    // not. Unfortunately normal invalidation mechanisms won't cause us to
    // recalculate the result of the sandwich if the context changes, so we
    // take the (substantial) performance hit of preventing caching of the
    // sandwich layer, causing the animation sandwich to be recalculated every
    // single sample.

    aPreventCachingOfSandwich = PR_FALSE;
    for (PRUint32 i = 0; i < llai->Length(); ++i) {
      PRUint8 unit = (*llai)[i].GetUnit();
      if (unit == nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE ||
          unit == nsIDOMSVGLength::SVG_LENGTHTYPE_EMS ||
          unit == nsIDOMSVGLength::SVG_LENGTHTYPE_EXS) {
        aPreventCachingOfSandwich = PR_TRUE;
        break;
      }
    }
  }
  return rv;
}