Bug 470911. Make the preserveAspectRatio attribute storage much simpler and make the DOM accessors use tear-offs. With help from Craig Topper. r+sr=roc
authorRobert O'Callahan <robert@ocallahan.org>
Mon, 05 Jan 2009 14:19:38 +1300
changeset 23313 1fb9d185d8f1aa81c566b8c04a937bd458e7b2eb
parent 23312 e7e8b8ba64984cf329773a856ee305ecb7ab94a9
child 23314 6fe82507c1f3f2f8dbc6be45d05a8fd302b70b55
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs470911
milestone1.9.2a1pre
Bug 470911. Make the preserveAspectRatio attribute storage much simpler and make the DOM accessors use tear-offs. With help from Craig Topper. r+sr=roc
content/svg/content/src/Makefile.in
content/svg/content/src/nsSVGAnimatedPreserveAspectRatio.cpp
content/svg/content/src/nsSVGAnimatedPreserveAspectRatio.h
content/svg/content/src/nsSVGElement.cpp
content/svg/content/src/nsSVGElement.h
content/svg/content/src/nsSVGFilters.cpp
content/svg/content/src/nsSVGImageElement.cpp
content/svg/content/src/nsSVGImageElement.h
content/svg/content/src/nsSVGMarkerElement.cpp
content/svg/content/src/nsSVGMarkerElement.h
content/svg/content/src/nsSVGPatternElement.cpp
content/svg/content/src/nsSVGPatternElement.h
content/svg/content/src/nsSVGPreserveAspectRatio.cpp
content/svg/content/src/nsSVGPreserveAspectRatio.h
content/svg/content/src/nsSVGSVGElement.cpp
content/svg/content/src/nsSVGSVGElement.h
content/svg/content/src/nsSVGSymbolElement.cpp
content/svg/content/test/dataTypes-helper.svg
content/svg/content/test/test_dataTypes.html
layout/svg/base/src/nsSVGImageFrame.cpp
layout/svg/base/src/nsSVGPatternFrame.cpp
layout/svg/base/src/nsSVGPatternFrame.h
layout/svg/base/src/nsSVGUtils.cpp
layout/svg/base/src/nsSVGUtils.h
--- a/content/svg/content/src/Makefile.in
+++ b/content/svg/content/src/Makefile.in
@@ -67,17 +67,16 @@ REQUIRES	= xpcom \
 CPPSRCS		= \
 		nsDOMSVGZoomEvent.cpp \
 		nsDOMSVGEvent.cpp \
 		nsSVGAElement.cpp \
 		nsSVGAngle.cpp \
 		nsSVGAnimatedLengthList.cpp \
 		nsSVGAnimatedNumberList.cpp \
 		nsSVGAnimatedRect.cpp \
-		nsSVGAnimatedPreserveAspectRatio.cpp \
 		nsSVGAnimatedTransformList.cpp \
 		nsSVGBoolean.cpp \
 		nsSVGCircleElement.cpp \
 		nsSVGClipPathElement.cpp \
 		nsSVGDataParser.cpp \
 		nsSVGDefsElement.cpp \
 		nsSVGDescElement.cpp \
 		nsSVGElement.cpp \
deleted file mode 100644
--- a/content/svg/content/src/nsSVGAnimatedPreserveAspectRatio.cpp
+++ /dev/null
@@ -1,207 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla SVG Project code.
- *
- * The Initial Developer of the Original Code is
- * Jonathan Watt.
- * Portions created by the Initial Developer are Copyright (C) 2004
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Jonathan Watt <jonathan.watt@strath.ac.uk> (original author)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsSVGAnimatedPreserveAspectRatio.h"
-#include "nsSVGPreserveAspectRatio.h"
-#include "nsSVGValue.h"
-#include "nsWeakReference.h"
-#include "nsContentUtils.h"
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGAnimatedPreserveAspectRatio
-
-class nsSVGAnimatedPreserveAspectRatio : public nsIDOMSVGAnimatedPreserveAspectRatio,
-                                         public nsSVGValue,
-                                         public nsISVGValueObserver
-{
-protected:
-  friend nsresult NS_NewSVGAnimatedPreserveAspectRatio(
-                                 nsIDOMSVGAnimatedPreserveAspectRatio** result,
-                                 nsIDOMSVGPreserveAspectRatio* baseVal);
-
-  nsSVGAnimatedPreserveAspectRatio();
-  ~nsSVGAnimatedPreserveAspectRatio();
-  void Init(nsIDOMSVGPreserveAspectRatio* baseVal);
-
-public:
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGAnimatedPreserveAspectRatio interface:
-  NS_DECL_NSIDOMSVGANIMATEDPRESERVEASPECTRATIO
-
-  // remainder of nsISVGValue interface:
-  NS_IMETHOD SetValueString(const nsAString& aValue);
-  NS_IMETHOD GetValueString(nsAString& aValue);
-
-  // nsISVGValueObserver
-  NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
-                                     modificationType aModType);
-  NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
-                                     modificationType aModType);
-
-  // nsISupportsWeakReference
-  // implementation inherited from nsSupportsWeakReference
-
-protected:
-  nsCOMPtr<nsIDOMSVGPreserveAspectRatio> mBaseVal;
-};
-
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsSVGAnimatedPreserveAspectRatio::nsSVGAnimatedPreserveAspectRatio()
-{
-}
-
-nsSVGAnimatedPreserveAspectRatio::~nsSVGAnimatedPreserveAspectRatio()
-{
-  nsCOMPtr<nsISVGValue> val( do_QueryInterface(mBaseVal) );
-  if (!val) return;
-  val->RemoveObserver(this);
-}
-
-void
-nsSVGAnimatedPreserveAspectRatio::Init(nsIDOMSVGPreserveAspectRatio* aBaseVal)
-{
-  mBaseVal = aBaseVal;
-  nsCOMPtr<nsISVGValue> val( do_QueryInterface(mBaseVal) );
-  NS_ASSERTION(val, "baseval needs to implement nsISVGValue interface");
-  if (!val) return;
-  val->AddObserver(this);
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-
-NS_IMPL_ADDREF(nsSVGAnimatedPreserveAspectRatio)
-NS_IMPL_RELEASE(nsSVGAnimatedPreserveAspectRatio)
-
-NS_INTERFACE_MAP_BEGIN(nsSVGAnimatedPreserveAspectRatio)
-  NS_INTERFACE_MAP_ENTRY(nsISVGValue)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedPreserveAspectRatio)
-  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
-  NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
-  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGAnimatedPreserveAspectRatio)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
-NS_INTERFACE_MAP_END
-
-//----------------------------------------------------------------------
-// nsISVGValue methods:
-
-NS_IMETHODIMP
-nsSVGAnimatedPreserveAspectRatio::SetValueString(const nsAString& aValue)
-{
-  nsresult rv;
-  nsCOMPtr<nsISVGValue> val( do_QueryInterface(mBaseVal, &rv) );
-  return NS_FAILED(rv)? rv: val->SetValueString(aValue);
-}
-
-NS_IMETHODIMP
-nsSVGAnimatedPreserveAspectRatio::GetValueString(nsAString& aValue)
-{
-  nsresult rv;
-  nsCOMPtr<nsISVGValue> val( do_QueryInterface(mBaseVal, &rv) );
-  return NS_FAILED(rv)? rv: val->GetValueString(aValue);
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGAnimatedPreserveAspectRatio methods:
-
-/* readonly attribute nsIDOMSVGPreserveAspectRatio baseVal; */
-NS_IMETHODIMP
-nsSVGAnimatedPreserveAspectRatio::GetBaseVal(nsIDOMSVGPreserveAspectRatio** aBaseVal)
-{
-  *aBaseVal = mBaseVal;
-  NS_ADDREF(*aBaseVal);
-  return NS_OK;
-}
-
-/* readonly attribute nsIDOMSVGPreserveAspectRatio animVal; */
-NS_IMETHODIMP
-nsSVGAnimatedPreserveAspectRatio::GetAnimVal(nsIDOMSVGPreserveAspectRatio** aAnimVal)
-{
-  *aAnimVal = mBaseVal;
-  NS_ADDREF(*aAnimVal);
-  return NS_OK;
-}
-
-//----------------------------------------------------------------------
-// nsISVGValueObserver methods
-
-NS_IMETHODIMP
-nsSVGAnimatedPreserveAspectRatio::WillModifySVGObservable(nsISVGValue* observable,
-                                                          modificationType aModType)
-{
-  WillModify(aModType);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSVGAnimatedPreserveAspectRatio::DidModifySVGObservable (nsISVGValue* observable,
-                                                          modificationType aModType)
-{
-  DidModify(aModType);
-  return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////
-// Exported creation functions:
-
-nsresult
-NS_NewSVGAnimatedPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio** result,
-                                     nsIDOMSVGPreserveAspectRatio* baseVal)
-{
-  *result = nsnull;
-
-  if (!baseVal) {
-    NS_ERROR("need baseVal");
-    return NS_ERROR_FAILURE;
-  }
-
-  nsSVGAnimatedPreserveAspectRatio* animatedPreserveAspectRatio = new nsSVGAnimatedPreserveAspectRatio();
-  if (!animatedPreserveAspectRatio)
-    return NS_ERROR_OUT_OF_MEMORY;
-
-  NS_ADDREF(animatedPreserveAspectRatio);
-  animatedPreserveAspectRatio->Init(baseVal);
-  *result = (nsIDOMSVGAnimatedPreserveAspectRatio*) animatedPreserveAspectRatio;
-
-  return NS_OK;
-}
deleted file mode 100644
--- a/content/svg/content/src/nsSVGAnimatedPreserveAspectRatio.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla SVG Project code.
- *
- * The Initial Developer of the Original Code is
- * Jonathan Watt.
- * Portions created by the Initial Developer are Copyright (C) 2004
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Jonathan Watt <jonathan.watt@strath.ac.uk> (original author)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef __NS_SVGANIMATEDPRESERVEASPECTRATIO_H__
-#define __NS_SVGANIMATEDPRESERVEASPECTRATIO_H__
-
-#include "nsIDOMSVGAnimPresAspRatio.h"
-#include "nsIDOMSVGPresAspectRatio.h"
-
-nsresult
-NS_NewSVGAnimatedPreserveAspectRatio(
-                                 nsIDOMSVGAnimatedPreserveAspectRatio** result,
-                                 nsIDOMSVGPreserveAspectRatio* baseVal);
-
-#endif //__NS_SVGANIMATEDPRESERVEASPECTRATIO_H__
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -139,16 +139,23 @@ nsSVGElement::Init()
   }
 
   EnumAttributesInfo enumInfo = GetEnumInfo();
 
   for (i = 0; i < enumInfo.mEnumCount; i++) {
     enumInfo.Reset(i);
   }
 
+  nsSVGPreserveAspectRatio *preserveAspectRatio =
+    GetPreserveAspectRatio();
+
+  if (preserveAspectRatio) {
+    preserveAspectRatio->Init();
+  }
+
   StringAttributesInfo stringInfo = GetStringInfo();
 
   for (i = 0; i < stringInfo.mStringCount; i++) {
     stringInfo.Reset(i);
   }
 
   return NS_OK;
 }
@@ -424,16 +431,29 @@ nsSVGElement::ParseAttribute(PRInt32 aNa
           if (NS_FAILED(rv)) {
             enumInfo.Reset(i);
           }
           foundMatch = PR_TRUE;
           break;
         }
       }
     }
+
+    if (!foundMatch && aAttribute == nsGkAtoms::preserveAspectRatio) {
+      // Check for nsSVGPreserveAspectRatio attribute
+      nsSVGPreserveAspectRatio *preserveAspectRatio =
+        GetPreserveAspectRatio();
+      if (preserveAspectRatio) {
+        rv = preserveAspectRatio->SetBaseValueString(aValue, this, PR_FALSE);
+        if (NS_FAILED(rv)) {
+          preserveAspectRatio->Init();
+        }
+        foundMatch = PR_TRUE;
+      }
+    }
   }
 
   if (!foundMatch) {
     // Check for nsSVGString attribute
     StringAttributesInfo stringInfo = GetStringInfo();
     for (PRUint32 i = 0; i < stringInfo.mStringCount; i++) {
       if (aNamespaceID == stringInfo.mStringInfo[i].mNamespaceID &&
           aAttribute == *stringInfo.mStringInfo[i].mName) {
@@ -567,16 +587,28 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespa
         if (aName == *enumInfo.mEnumInfo[i].mName) {
           enumInfo.Reset(i);
           DidChangeEnum(i, PR_FALSE);
           foundMatch = PR_TRUE;
           break;
         }
       }
     }
+
+    if (!foundMatch && aName == nsGkAtoms::preserveAspectRatio) {
+      // Check if this is a preserveAspectRatio attribute going away
+      nsSVGPreserveAspectRatio *preserveAspectRatio =
+        GetPreserveAspectRatio();
+
+      if (preserveAspectRatio) {
+        preserveAspectRatio->Init();
+        DidChangePreserveAspectRatio(PR_FALSE);
+        foundMatch = PR_TRUE;
+      }
+    }
   }
 
   if (!foundMatch) {
     // Check if this is a string attribute going away
     StringAttributesInfo stringInfo = GetStringInfo();
 
     for (PRUint32 i = 0; i < stringInfo.mStringCount; i++) {
       if (aNamespaceID == stringInfo.mStringInfo[i].mNamespaceID &&
@@ -607,27 +639,16 @@ void
 nsSVGElement::ResetOldStyleBaseType(nsISVGValue *svg_value)
 {
   nsCOMPtr<nsIDOMSVGAnimatedRect> r = do_QueryInterface(svg_value);
   if (r) {
     nsCOMPtr<nsIDOMSVGRect> rect;
     r->GetBaseVal(getter_AddRefs(rect));
     static_cast<nsSVGRect*>(rect.get())->Clear();
   }
-  nsCOMPtr<nsIDOMSVGAnimatedPreserveAspectRatio> ar = do_QueryInterface(svg_value);
-  if (ar) {
-    nsCOMPtr<nsIDOMSVGPreserveAspectRatio> par;
-    ar->GetBaseVal(getter_AddRefs(par));
-    par->SetAlign(nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID);
-    par->SetMeetOrSlice(nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET);
-  }
-  nsCOMPtr<nsIDOMSVGPointList> pl = do_QueryInterface(svg_value);
-  if (pl) {
-    pl->Clear();
-  }
   nsCOMPtr<nsIDOMSVGAnimatedLengthList> ll = do_QueryInterface(svg_value);
   if (ll) {
     nsCOMPtr<nsIDOMSVGLengthList> lengthlist;
     ll->GetBaseVal(getter_AddRefs(lengthlist));
     lengthlist->Clear();
   }
   nsCOMPtr<nsIDOMSVGAnimatedNumberList> nl = do_QueryInterface(svg_value);
   if (nl) {
@@ -1422,16 +1443,40 @@ nsSVGElement::DidChangeEnum(PRUint8 aAtt
 
   nsAutoString newStr;
   info.mEnums[aAttrEnum].GetBaseValueString(newStr, this);
 
   SetAttr(kNameSpaceID_None, *info.mEnumInfo[aAttrEnum].mName,
           newStr, PR_TRUE);
 }
 
+nsSVGPreserveAspectRatio *
+nsSVGElement::GetPreserveAspectRatio()
+{
+  return nsnull;
+}
+
+void
+nsSVGElement::DidChangePreserveAspectRatio(PRBool aDoSetAttr)
+{
+  if (!aDoSetAttr)
+    return;
+
+  nsSVGPreserveAspectRatio *preserveAspectRatio = GetPreserveAspectRatio();
+
+  NS_ASSERTION(preserveAspectRatio,
+               "DidChangePreserveAspectRatio on element with no preserveAspectRatio attrib");
+
+  nsAutoString newStr;
+  preserveAspectRatio->GetBaseValueString(newStr);
+
+  SetAttr(kNameSpaceID_None, nsGkAtoms::preserveAspectRatio,
+          newStr, PR_TRUE);
+}
+
 nsSVGElement::StringAttributesInfo
 nsSVGElement::GetStringInfo()
 {
   return StringAttributesInfo(nsnull, nsnull, 0);
 }
 
 void nsSVGElement::StringAttributesInfo::Reset(PRUint8 aAttrEnum)
 {
--- a/content/svg/content/src/nsSVGElement.h
+++ b/content/svg/content/src/nsSVGElement.h
@@ -57,16 +57,17 @@
 class nsSVGSVGElement;
 class nsSVGLength2;
 class nsSVGNumber2;
 class nsSVGInteger;
 class nsSVGAngle;
 class nsSVGBoolean;
 class nsSVGEnum;
 struct nsSVGEnumMapping;
+class nsSVGPreserveAspectRatio;
 class nsSVGString;
 
 typedef nsStyledElement nsSVGElementBase;
 
 class nsSVGElement : public nsSVGElementBase,    // nsIContent
                      public nsISVGValueObserver  // :nsISupportsWeakReference
 {
 protected:
@@ -133,16 +134,17 @@ public:
   nsSVGSVGElement* GetCtx();
 
   virtual void DidChangeLength(PRUint8 aAttrEnum, PRBool aDoSetAttr);
   virtual void DidChangeNumber(PRUint8 aAttrEnum, PRBool aDoSetAttr);
   virtual void DidChangeInteger(PRUint8 aAttrEnum, PRBool aDoSetAttr);
   virtual void DidChangeAngle(PRUint8 aAttrEnum, PRBool aDoSetAttr);
   virtual void DidChangeBoolean(PRUint8 aAttrEnum, PRBool aDoSetAttr);
   virtual void DidChangeEnum(PRUint8 aAttrEnum, PRBool aDoSetAttr);
+  virtual void DidChangePreserveAspectRatio(PRBool aDoSetAttr);
   virtual void DidChangeString(PRUint8 aAttrEnum, PRBool aDoSetAttr);
 
   void GetAnimatedLengthValues(float *aFirst, ...);
   void GetAnimatedNumberValues(float *aFirst, ...);
   void GetAnimatedIntegerValues(PRInt32 *aFirst, ...);
 
   virtual void RecompileScriptEventListeners();
 
@@ -304,16 +306,19 @@ protected:
   };
 
   virtual LengthAttributesInfo GetLengthInfo();
   virtual NumberAttributesInfo GetNumberInfo();
   virtual IntegerAttributesInfo GetIntegerInfo();
   virtual AngleAttributesInfo GetAngleInfo();
   virtual BooleanAttributesInfo GetBooleanInfo();
   virtual EnumAttributesInfo GetEnumInfo();
+  // We assume all preserveAspectRatios are alike so we don't
+  // need to wrap the class
+  virtual nsSVGPreserveAspectRatio *GetPreserveAspectRatio();
   virtual StringAttributesInfo GetStringInfo();
 
   static nsSVGEnumMapping sSVGUnitTypesMap[];
 
 private:
   /* read <number-optional-number> */
   nsresult
   ParseNumberOptionalNumber(const nsAString& aValue,
--- a/content/svg/content/src/nsSVGFilters.cpp
+++ b/content/svg/content/src/nsSVGFilters.cpp
@@ -59,17 +59,16 @@
 #include "gfxContext.h"
 #include "nsSVGLengthList.h"
 #include "nsIDOMSVGURIReference.h"
 #include "nsImageLoadingContent.h"
 #include "imgIContainer.h"
 #include "gfxIImageFrame.h"
 #include "nsIImage.h"
 #include "nsNetUtil.h"
-#include "nsSVGAnimatedPreserveAspectRatio.h"
 #include "nsSVGPreserveAspectRatio.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsSVGMatrix.h"
 #include "nsSVGFilterElement.h"
 #include "nsSVGString.h"
 
 #if defined(XP_WIN) 
 // Prevent Windows redefining LoadImage
@@ -5142,17 +5141,16 @@ class nsSVGFEImageElement : public nsSVG
                             public nsIDOMSVGURIReference,
                             public nsImageLoadingContent
 {
 protected:
   friend nsresult NS_NewSVGFEImageElement(nsIContent **aResult,
                                           nsINodeInfo *aNodeInfo);
   nsSVGFEImageElement(nsINodeInfo* aNodeInfo);
   virtual ~nsSVGFEImageElement();
-  nsresult Init();
 
 public:
   virtual PRBool SubregionIsUnionOfRegions() { return PR_FALSE; }
 
   // interfaces:
   NS_DECL_ISUPPORTS_INHERITED
 
   // FE Base
@@ -5199,23 +5197,24 @@ private:
   void Invalidate();
 
   nsresult LoadSVGImage(PRBool aForce, PRBool aNotify);
 
 protected:
   virtual PRBool OperatesOnSRGB(nsSVGFilterInstance*,
                                 PRUint32, Image*) { return PR_TRUE; }
 
+  virtual nsSVGPreserveAspectRatio *GetPreserveAspectRatio();
   virtual StringAttributesInfo GetStringInfo();
 
   enum { RESULT, HREF };
   nsSVGString mStringAttributes[2];
   static StringInfo sStringInfo[2];
 
-  nsCOMPtr<nsIDOMSVGAnimatedPreserveAspectRatio> mPreserveAspectRatio;
+  nsSVGPreserveAspectRatio mPreserveAspectRatio;
 };
 
 nsSVGElement::StringInfo nsSVGFEImageElement::sStringInfo[2] =
 {
   { &nsGkAtoms::result, kNameSpaceID_None },
   { &nsGkAtoms::href, kNameSpaceID_XLink }
 };
 
@@ -5244,38 +5243,16 @@ nsSVGFEImageElement::nsSVGFEImageElement
 {
 }
 
 nsSVGFEImageElement::~nsSVGFEImageElement()
 {
   DestroyImageLoadingContent();
 }
 
-nsresult
-nsSVGFEImageElement::Init()
-{
-  nsresult rv = nsSVGFEImageElementBase::Init();
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  {
-    nsCOMPtr<nsIDOMSVGPreserveAspectRatio> preserveAspectRatio;
-    rv = NS_NewSVGPreserveAspectRatio(getter_AddRefs(preserveAspectRatio));
-    NS_ENSURE_SUCCESS(rv,rv);
-    rv = NS_NewSVGAnimatedPreserveAspectRatio(
-                                          getter_AddRefs(mPreserveAspectRatio),
-                                          preserveAspectRatio);
-    NS_ENSURE_SUCCESS(rv,rv);
-    rv = AddMappedSVGValue(nsGkAtoms::preserveAspectRatio,
-                           mPreserveAspectRatio);
-    NS_ENSURE_SUCCESS(rv,rv);
-  }
-
-  return rv;
-}
-
 //----------------------------------------------------------------------
 
 nsresult
 nsSVGFEImageElement::LoadSVGImage(PRBool aForce, PRBool aNotify)
 {
   // resolve href attribute
   nsCOMPtr<nsIURI> baseURI = GetBaseURI();
 
@@ -5415,16 +5392,22 @@ nsSVGFEImageElement::ComputeTargetBBox(c
   // image bounds and compute an accurate bounding box for the filter
   // primitive result.
   return GetMaxRect();
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
+nsSVGPreserveAspectRatio *
+nsSVGFEImageElement::GetPreserveAspectRatio()
+{
+  return &mPreserveAspectRatio;
+}
+
 nsSVGElement::StringAttributesInfo
 nsSVGFEImageElement::GetStringInfo()
 {
   return StringAttributesInfo(mStringAttributes, sStringInfo,
                               NS_ARRAY_LENGTH(sStringInfo));
 }
 
 //----------------------------------------------------------------------
--- a/content/svg/content/src/nsSVGImageElement.cpp
+++ b/content/svg/content/src/nsSVGImageElement.cpp
@@ -31,94 +31,24 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include "nsGkAtoms.h"
-#include "nsSVGLength.h"
-#include "nsSVGString.h"
+#include "nsSVGImageElement.h"
 #include "nsCOMPtr.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
-#include "nsSVGAnimatedPreserveAspectRatio.h"
-#include "nsSVGPreserveAspectRatio.h"
 #include "imgIContainer.h"
 #include "imgIDecoderObserver.h"
-#include "nsSVGPathGeometryElement.h"
-#include "nsIDOMSVGImageElement.h"
-#include "nsIDOMSVGURIReference.h"
-#include "nsImageLoadingContent.h"
-#include "nsSVGLength2.h"
 #include "gfxContext.h"
 
-class nsIDOMSVGAnimatedPreserveAspectRatio;
-
-typedef nsSVGPathGeometryElement nsSVGImageElementBase;
-
-class nsSVGImageElement : public nsSVGImageElementBase,
-                          public nsIDOMSVGImageElement,
-                          public nsIDOMSVGURIReference,
-                          public nsImageLoadingContent
-{
-protected:
-  friend nsresult NS_NewSVGImageElement(nsIContent **aResult,
-                                        nsINodeInfo *aNodeInfo);
-  nsSVGImageElement(nsINodeInfo *aNodeInfo);
-  virtual ~nsSVGImageElement();
-  nsresult Init();
-
-public:
-  // interfaces:
-  
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIDOMSVGIMAGEELEMENT
-  NS_DECL_NSIDOMSVGURIREFERENCE
-
-  // xxx I wish we could use virtual inheritance
-  NS_FORWARD_NSIDOMNODE(nsSVGImageElementBase::)
-  NS_FORWARD_NSIDOMELEMENT(nsSVGImageElementBase::)
-  NS_FORWARD_NSIDOMSVGELEMENT(nsSVGImageElementBase::)
-
-  // nsIContent interface
-  virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                                const nsAString* aValue, PRBool aNotify);
-  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
-                              nsIContent* aBindingParent,
-                              PRBool aCompileEventHandlers);
-
-  virtual PRInt32 IntrinsicState() const;
-
-  NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* name) const;
-
-  // nsSVGPathGeometryElement methods:
-  virtual void ConstructPath(gfxContext *aCtx);
-
-  virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
-
-protected:
-  nsresult LoadSVGImage(PRBool aForce, PRBool aNotify);
-
-  virtual LengthAttributesInfo GetLengthInfo();
-  virtual StringAttributesInfo GetStringInfo();
-
-  enum { X, Y, WIDTH, HEIGHT };
-  nsSVGLength2 mLengthAttributes[4];
-  static LengthInfo sLengthInfo[4];
-
-  enum { HREF };
-  nsSVGString mStringAttributes[1];
-  static StringInfo sStringInfo[1];
-
-  nsCOMPtr<nsIDOMSVGAnimatedPreserveAspectRatio> mPreserveAspectRatio;
-};
-
 nsSVGElement::LengthInfo nsSVGImageElement::sLengthInfo[4] =
 {
   { &nsGkAtoms::x, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::X },
   { &nsGkAtoms::y, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::Y },
   { &nsGkAtoms::width, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::X },
   { &nsGkAtoms::height, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER, nsSVGUtils::Y },
 };
 
@@ -151,41 +81,16 @@ nsSVGImageElement::nsSVGImageElement(nsI
 {
 }
 
 nsSVGImageElement::~nsSVGImageElement()
 {
   DestroyImageLoadingContent();
 }
 
-nsresult
-nsSVGImageElement::Init()
-{
-  nsresult rv = nsSVGImageElementBase::Init();
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  // Create mapped properties:
-
-  // DOM property: preserveAspectRatio , #IMPLIED attrib: preserveAspectRatio
-  {
-    nsCOMPtr<nsIDOMSVGPreserveAspectRatio> preserveAspectRatio;
-    rv = NS_NewSVGPreserveAspectRatio(getter_AddRefs(preserveAspectRatio));
-    NS_ENSURE_SUCCESS(rv,rv);
-    rv = NS_NewSVGAnimatedPreserveAspectRatio(
-                                          getter_AddRefs(mPreserveAspectRatio),
-                                          preserveAspectRatio);
-    NS_ENSURE_SUCCESS(rv,rv);
-    rv = AddMappedSVGValue(nsGkAtoms::preserveAspectRatio,
-                           mPreserveAspectRatio);
-    NS_ENSURE_SUCCESS(rv,rv);
-  }
-
-  return rv;
-}
-
 //----------------------------------------------------------------------
 // nsIDOMNode methods
 
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGImageElement)
 
 
 //----------------------------------------------------------------------
@@ -215,42 +120,30 @@ NS_IMETHODIMP nsSVGImageElement::GetHeig
   return mLengthAttributes[HEIGHT].ToDOMAnimatedLength(aHeight, this);
 }
 
 /* readonly attribute nsIDOMSVGAnimatedPreserveAspectRatio preserveAspectRatio; */
 NS_IMETHODIMP
 nsSVGImageElement::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
                                           **aPreserveAspectRatio)
 {
-  *aPreserveAspectRatio = mPreserveAspectRatio;
-  NS_IF_ADDREF(*aPreserveAspectRatio);
-  return NS_OK;
+  return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(aPreserveAspectRatio, this);
 }
 
 //----------------------------------------------------------------------
 // nsIDOMSVGURIReference methods:
 
 /* readonly attribute nsIDOMSVGAnimatedString href; */
 NS_IMETHODIMP
 nsSVGImageElement::GetHref(nsIDOMSVGAnimatedString * *aHref)
 {
   return mStringAttributes[HREF].ToDOMAnimatedString(aHref, this);
 }
 
 //----------------------------------------------------------------------
-// nsSVGElement methods
-
-nsSVGElement::LengthAttributesInfo
-nsSVGImageElement::GetLengthInfo()
-{
-  return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
-                              NS_ARRAY_LENGTH(sLengthInfo));
-}
-
-//----------------------------------------------------------------------
 
 nsresult
 nsSVGImageElement::LoadSVGImage(PRBool aForce, PRBool aNotify)
 {
   // resolve href attribute
   nsCOMPtr<nsIURI> baseURI = GetBaseURI();
 
   nsAutoString href(mStringAttributes[HREF].GetAnimValue());
@@ -342,14 +235,27 @@ nsSVGImageElement::ConstructPath(gfxCont
     return;
 
   aCtx->Rectangle(gfxRect(x, y, width, height));
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
+nsSVGElement::LengthAttributesInfo
+nsSVGImageElement::GetLengthInfo()
+{
+  return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
+                              NS_ARRAY_LENGTH(sLengthInfo));
+}
+
+nsSVGPreserveAspectRatio *
+nsSVGImageElement::GetPreserveAspectRatio()
+{
+  return &mPreserveAspectRatio;
+}
+
 nsSVGElement::StringAttributesInfo
 nsSVGImageElement::GetStringInfo()
 {
   return StringAttributesInfo(mStringAttributes, sStringInfo,
                               NS_ARRAY_LENGTH(sStringInfo));
 }
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/nsSVGImageElement.h
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Mozilla SVG project.
+ *
+ * The Initial Developer of the Original Code is
+ * Crocodile Clips Ltd..
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __NS_SVGIMAGEELEMENT_H__
+#define __NS_SVGIMAGEELEMENT_H__
+
+#include "nsSVGPathGeometryElement.h"
+#include "nsIDOMSVGImageElement.h"
+#include "nsIDOMSVGURIReference.h"
+#include "nsImageLoadingContent.h"
+#include "nsSVGString.h"
+#include "nsSVGLength2.h"
+#include "nsSVGPreserveAspectRatio.h"
+
+typedef nsSVGPathGeometryElement nsSVGImageElementBase;
+
+class nsSVGImageElement : public nsSVGImageElementBase,
+                          public nsIDOMSVGImageElement,
+                          public nsIDOMSVGURIReference,
+                          public nsImageLoadingContent
+{
+  friend class nsSVGImageFrame;
+
+protected:
+  friend nsresult NS_NewSVGImageElement(nsIContent **aResult,
+                                        nsINodeInfo *aNodeInfo);
+  nsSVGImageElement(nsINodeInfo *aNodeInfo);
+  virtual ~nsSVGImageElement();
+
+public:
+  // interfaces:
+  
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIDOMSVGIMAGEELEMENT
+  NS_DECL_NSIDOMSVGURIREFERENCE
+
+  // xxx I wish we could use virtual inheritance
+  NS_FORWARD_NSIDOMNODE(nsSVGImageElementBase::)
+  NS_FORWARD_NSIDOMELEMENT(nsSVGImageElementBase::)
+  NS_FORWARD_NSIDOMSVGELEMENT(nsSVGImageElementBase::)
+
+  // nsIContent interface
+  virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
+                                const nsAString* aValue, PRBool aNotify);
+  virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                              nsIContent* aBindingParent,
+                              PRBool aCompileEventHandlers);
+
+  virtual PRInt32 IntrinsicState() const;
+
+  NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* name) const;
+
+  // nsSVGPathGeometryElement methods:
+  virtual void ConstructPath(gfxContext *aCtx);
+
+  virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
+
+protected:
+  nsresult LoadSVGImage(PRBool aForce, PRBool aNotify);
+
+  virtual LengthAttributesInfo GetLengthInfo();
+  virtual nsSVGPreserveAspectRatio *GetPreserveAspectRatio();
+  virtual StringAttributesInfo GetStringInfo();
+
+  enum { X, Y, WIDTH, HEIGHT };
+  nsSVGLength2 mLengthAttributes[4];
+  static LengthInfo sLengthInfo[4];
+
+  nsSVGPreserveAspectRatio mPreserveAspectRatio;
+
+  enum { HREF };
+  nsSVGString mStringAttributes[1];
+  static StringInfo sStringInfo[1];
+};
+
+#endif
--- a/content/svg/content/src/nsSVGMarkerElement.cpp
+++ b/content/svg/content/src/nsSVGMarkerElement.cpp
@@ -34,17 +34,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsGkAtoms.h"
 #include "nsSVGAnimatedRect.h"
 #include "nsSVGRect.h"
 #include "nsCOMPtr.h"
 #include "nsISVGValueUtils.h"
-#include "nsSVGAnimatedPreserveAspectRatio.h"
 #include "nsSVGPreserveAspectRatio.h"
 #include "nsSVGMatrix.h"
 #include "nsDOMError.h"
 #include "nsSVGUtils.h"
 #include "nsSVGMarkerElement.h"
 
 nsSVGElement::LengthInfo nsSVGMarkerElement::sLengthInfo[4] =
 {
@@ -150,30 +149,16 @@ nsSVGMarkerElement::Init()
     rv = NS_NewSVGRect(getter_AddRefs(viewbox));
     NS_ENSURE_SUCCESS(rv,rv);
     rv = NS_NewSVGAnimatedRect(getter_AddRefs(mViewBox), viewbox);
     NS_ENSURE_SUCCESS(rv,rv);
     rv = AddMappedSVGValue(nsGkAtoms::viewBox, mViewBox);
     NS_ENSURE_SUCCESS(rv,rv);
   }
 
-  // DOM property: preserveAspectRatio
-  {
-    nsCOMPtr<nsIDOMSVGPreserveAspectRatio> preserveAspectRatio;
-    rv = NS_NewSVGPreserveAspectRatio(getter_AddRefs(preserveAspectRatio));
-    NS_ENSURE_SUCCESS(rv,rv);
-    rv = NS_NewSVGAnimatedPreserveAspectRatio(
-      getter_AddRefs(mPreserveAspectRatio),
-      preserveAspectRatio);
-    NS_ENSURE_SUCCESS(rv,rv);
-    rv = AddMappedSVGValue(nsGkAtoms::preserveAspectRatio,
-                           mPreserveAspectRatio);
-    NS_ENSURE_SUCCESS(rv,rv);
-  }
-  
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
 // nsIDOMNode methods
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGMarkerElement)
 
@@ -185,21 +170,20 @@ NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGMar
 {
   *aViewBox = mViewBox;
   NS_ADDREF(*aViewBox);
   return NS_OK;
 }
 
 /* readonly attribute nsIDOMSVGAnimatedPreserveAspectRatio preserveAspectRatio; */
 NS_IMETHODIMP
-nsSVGMarkerElement::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio * *aPreserveAspectRatio)
+nsSVGMarkerElement::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
+                                           **aPreserveAspectRatio)
 {
-  *aPreserveAspectRatio = mPreserveAspectRatio;
-  NS_ADDREF(*aPreserveAspectRatio);
-  return NS_OK;
+  return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(aPreserveAspectRatio, this);
 }
 
 //----------------------------------------------------------------------
 // nsIDOMSVGMarkerElement methods
 
 /* readonly attribute nsIDOMSVGAnimatedLength refX; */
 NS_IMETHODIMP nsSVGMarkerElement::GetRefX(nsIDOMSVGAnimatedLength * *aRefX)
 {
@@ -363,16 +347,24 @@ nsSVGMarkerElement::DidChangeLength(PRUi
       (aAttrEnum == MARKERWIDTH || aAttrEnum == MARKERHEIGHT)) {
     nsCOMPtr<nsIDOMSVGRect> vb;
     mViewBox->GetAnimVal(getter_AddRefs(vb));
     vb->SetWidth(mLengthAttributes[MARKERWIDTH].GetAnimValue(mCoordCtx));
     vb->SetHeight(mLengthAttributes[MARKERHEIGHT].GetAnimValue(mCoordCtx));
   }
 }
 
+void
+nsSVGMarkerElement::DidChangePreserveAspectRatio(PRBool aDoSetAttr)
+{
+  nsSVGMarkerElementBase::DidChangePreserveAspectRatio(aDoSetAttr);
+
+  mViewBoxToViewportTransform = nsnull;
+}
+
 void 
 nsSVGMarkerElement::SetParentCoordCtxProvider(nsSVGSVGElement *aContext)
 {
   mCoordCtx = aContext;
   mViewBoxToViewportTransform = nsnull;
 
   if (mCoordCtx && !HasAttr(kNameSpaceID_None, nsGkAtoms::viewBox)) {
     nsCOMPtr<nsIDOMSVGRect> vb;
@@ -398,16 +390,22 @@ nsSVGMarkerElement::GetAngleInfo()
 
 nsSVGElement::EnumAttributesInfo
 nsSVGMarkerElement::GetEnumInfo()
 {
   return EnumAttributesInfo(mEnumAttributes, sEnumInfo,
                             NS_ARRAY_LENGTH(sEnumInfo));
 }
 
+nsSVGPreserveAspectRatio *
+nsSVGMarkerElement::GetPreserveAspectRatio()
+{
+  return &mPreserveAspectRatio;
+}
+
 //----------------------------------------------------------------------
 // public helpers
 
 nsresult
 nsSVGMarkerElement::GetMarkerTransform(float aStrokeWidth,
                                        float aX, float aY, float aAngle,
                                        nsIDOMSVGMatrix **_retval)
 {
--- a/content/svg/content/src/nsSVGMarkerElement.h
+++ b/content/svg/content/src/nsSVGMarkerElement.h
@@ -38,16 +38,17 @@
 #define __NS_SVGMARKERELEMENT_H__
 
 #include "nsSVGGraphicElement.h"
 #include "nsIDOMSVGMarkerElement.h"
 #include "nsIDOMSVGFitToViewBox.h"
 #include "nsSVGLength2.h"
 #include "nsSVGEnum.h"
 #include "nsSVGAngle.h"
+#include "nsSVGPreserveAspectRatio.h"
 
 class nsSVGOrientType
 {
 public:
   nsSVGOrientType()
    : mAnimVal(nsIDOMSVGMarkerElement::SVG_MARKER_ORIENT_ANGLE),
      mBaseVal(nsIDOMSVGMarkerElement::SVG_MARKER_ORIENT_ANGLE) {}
 
@@ -125,16 +126,17 @@ public:
 
   virtual PRBool GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                          nsAString& aResult) const;
   virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
                              PRBool aNotify);
 
   // nsSVGElement specializations:
   virtual void DidChangeLength(PRUint8 aAttrEnum, PRBool aDoSetAttr);
+  virtual void DidChangePreserveAspectRatio(PRBool aDoSetAttr);
 
   // public helpers
   nsresult GetMarkerTransform(float aStrokeWidth,
                               float aX, float aY, float aAngle,
                               nsIDOMSVGMatrix **_retval);
   nsresult GetViewboxToViewportTransform(nsIDOMSVGMatrix **_retval);
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
@@ -145,32 +147,34 @@ protected:
                                 const nsAString& aValue,
                                 nsAttrValue& aResult);
 
   void SetParentCoordCtxProvider(nsSVGSVGElement *aContext);
 
   virtual LengthAttributesInfo GetLengthInfo();
   virtual AngleAttributesInfo GetAngleInfo();
   virtual EnumAttributesInfo GetEnumInfo();
+  virtual nsSVGPreserveAspectRatio *GetPreserveAspectRatio();
 
   enum { REFX, REFY, MARKERWIDTH, MARKERHEIGHT };
   nsSVGLength2 mLengthAttributes[4];
   static LengthInfo sLengthInfo[4];
 
   enum { MARKERUNITS };
   nsSVGEnum mEnumAttributes[1];
   static nsSVGEnumMapping sUnitsMap[];
   static EnumInfo sEnumInfo[1];
 
   enum { ORIENT };
   nsSVGAngle mAngleAttributes[1];
   static AngleInfo sAngleInfo[1];
 
+  nsSVGPreserveAspectRatio mPreserveAspectRatio;
+
   // derived properties (from 'orient') handled separately
   nsSVGOrientType                        mOrientType;
 
   nsSVGSVGElement                       *mCoordCtx;
   nsCOMPtr<nsIDOMSVGAnimatedRect>        mViewBox;
-  nsCOMPtr<nsIDOMSVGAnimatedPreserveAspectRatio> mPreserveAspectRatio;
   nsCOMPtr<nsIDOMSVGMatrix>         mViewBoxToViewportTransform;
 };
 
 #endif
--- a/content/svg/content/src/nsSVGPatternElement.cpp
+++ b/content/svg/content/src/nsSVGPatternElement.cpp
@@ -38,18 +38,16 @@
 
 #include "nsSVGTransformList.h"
 #include "nsSVGAnimatedTransformList.h"
 #include "nsCOMPtr.h"
 #include "nsGkAtoms.h"
 #include "nsSVGAnimatedRect.h"
 #include "nsSVGRect.h"
 #include "nsSVGMatrix.h"
-#include "nsSVGAnimatedPreserveAspectRatio.h"
-#include "nsSVGPreserveAspectRatio.h"
 #include "nsSVGPatternElement.h"
 #include "nsIFrame.h"
 
 //--------------------- Patterns ------------------------
 
 nsSVGElement::LengthInfo nsSVGPatternElement::sLengthInfo[4] =
 {
   { &nsGkAtoms::x, 0, nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE, nsSVGUtils::X },
@@ -128,31 +126,16 @@ nsSVGPatternElement::Init()
     rv = NS_NewSVGRect(getter_AddRefs(viewbox));
     NS_ENSURE_SUCCESS(rv,rv);
     rv = NS_NewSVGAnimatedRect(getter_AddRefs(mViewBox), viewbox);
     NS_ENSURE_SUCCESS(rv,rv);
     rv = AddMappedSVGValue(nsGkAtoms::viewBox, mViewBox);
     NS_ENSURE_SUCCESS(rv,rv);
   }
 
-  // DOM property: preserveAspectRatio
-  {
-    nsCOMPtr<nsIDOMSVGPreserveAspectRatio> preserveAspectRatio;
-    rv = NS_NewSVGPreserveAspectRatio(getter_AddRefs(preserveAspectRatio));
-    NS_ENSURE_SUCCESS(rv,rv);
-    rv = NS_NewSVGAnimatedPreserveAspectRatio(
-                                          getter_AddRefs(mPreserveAspectRatio),
-                                          preserveAspectRatio);
-    NS_ENSURE_SUCCESS(rv,rv);
-    rv = AddMappedSVGValue(nsGkAtoms::preserveAspectRatio,
-                           mPreserveAspectRatio);
-    NS_ENSURE_SUCCESS(rv,rv);
-  }
-
-
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
 // nsIDOMNode method
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGPatternElement)
 
@@ -164,21 +147,20 @@ NS_IMETHODIMP nsSVGPatternElement::GetVi
 {
   *aViewBox = mViewBox;
   NS_ADDREF(*aViewBox);
   return NS_OK;
 }
 
 /* readonly attribute nsIDOMSVGAnimatedPreserveAspectRatio preserveAspectRatio; */
 NS_IMETHODIMP
-nsSVGPatternElement::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio * *aPreserveAspectRatio)
+nsSVGPatternElement::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
+                                            **aPreserveAspectRatio)
 {
-  *aPreserveAspectRatio = mPreserveAspectRatio;
-  NS_ADDREF(*aPreserveAspectRatio);
-  return NS_OK;
+  return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(aPreserveAspectRatio, this);
 }
 
 //----------------------------------------------------------------------
 // nsIDOMSVGPatternElement methods
 
 /* readonly attribute nsIDOMSVGAnimatedEnumeration patternUnits; */
 NS_IMETHODIMP nsSVGPatternElement::GetPatternUnits(nsIDOMSVGAnimatedEnumeration * *aPatternUnits)
 {
@@ -267,16 +249,22 @@ nsSVGPatternElement::GetLengthInfo()
 
 nsSVGElement::EnumAttributesInfo
 nsSVGPatternElement::GetEnumInfo()
 {
   return EnumAttributesInfo(mEnumAttributes, sEnumInfo,
                             NS_ARRAY_LENGTH(sEnumInfo));
 }
 
+nsSVGPreserveAspectRatio *
+nsSVGPatternElement::GetPreserveAspectRatio()
+{
+  return &mPreserveAspectRatio;
+}
+
 nsSVGElement::StringAttributesInfo
 nsSVGPatternElement::GetStringInfo()
 {
   return StringAttributesInfo(mStringAttributes, sStringInfo,
                               NS_ARRAY_LENGTH(sStringInfo));
 }
 
 //----------------------------------------------------------------------
--- a/content/svg/content/src/nsSVGPatternElement.h
+++ b/content/svg/content/src/nsSVGPatternElement.h
@@ -43,16 +43,17 @@
 #include "nsIDOMSVGURIReference.h"
 #include "nsIDOMSVGFitToViewBox.h"
 #include "nsIDOMSVGPatternElement.h"
 #include "nsIDOMSVGUnitTypes.h"
 #include "nsSVGLength2.h"
 #include "nsStubMutationObserver.h"
 #include "nsSVGEnum.h"
 #include "nsSVGString.h"
+#include "nsSVGPreserveAspectRatio.h"
 
 //--------------------- Patterns ------------------------
 
 typedef nsSVGStylableElement nsSVGPatternElementBase;
 
 class nsSVGPatternElement : public nsSVGPatternElementBase,
                             public nsIDOMSVGURIReference,
                             public nsIDOMSVGFitToViewBox,
@@ -98,16 +99,17 @@ public:
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
 protected:
 
   void PushUpdate();
 
   virtual LengthAttributesInfo GetLengthInfo();
   virtual EnumAttributesInfo GetEnumInfo();
+  virtual nsSVGPreserveAspectRatio *GetPreserveAspectRatio();
   virtual StringAttributesInfo GetStringInfo();
 
   // nsIDOMSVGPatternElement values
   enum { X, Y, WIDTH, HEIGHT };
   nsSVGLength2 mLengthAttributes[4];
   static LengthInfo sLengthInfo[4];
 
   enum { PATTERNUNITS, PATTERNCONTENTUNITS };
@@ -118,12 +120,12 @@ protected:
 
   // nsIDOMSVGURIReference properties
   enum { HREF };
   nsSVGString mStringAttributes[1];
   static StringInfo sStringInfo[1];
 
   // nsIDOMSVGFitToViewbox properties
   nsCOMPtr<nsIDOMSVGAnimatedRect> mViewBox;
-  nsCOMPtr<nsIDOMSVGAnimatedPreserveAspectRatio> mPreserveAspectRatio;
+  nsSVGPreserveAspectRatio mPreserveAspectRatio;
 };
 
 #endif
--- a/content/svg/content/src/nsSVGPreserveAspectRatio.cpp
+++ b/content/svg/content/src/nsSVGPreserveAspectRatio.cpp
@@ -32,260 +32,237 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsSVGPreserveAspectRatio.h"
-#include "nsSVGValue.h"
-#include "nsCRT.h"
-#include "nsContentUtils.h"
+#include "nsWhitespaceTokenizer.h"
 
 ////////////////////////////////////////////////////////////////////////
 // nsSVGPreserveAspectRatio class
 
-class nsSVGPreserveAspectRatio : public nsIDOMSVGPreserveAspectRatio,
-                                 public nsSVGValue
-{
-protected:
-  friend nsresult NS_NewSVGPreserveAspectRatio(
-                                        nsIDOMSVGPreserveAspectRatio** result,
-                                        PRUint16 aAlign,
-                                        PRUint16 aMeetOrSlice);
+NS_SVG_VAL_IMPL_CYCLE_COLLECTION(
+  nsSVGPreserveAspectRatio::DOMBaseVal, mSVGElement)
+NS_SVG_VAL_IMPL_CYCLE_COLLECTION(
+  nsSVGPreserveAspectRatio::DOMAnimVal, mSVGElement)
+NS_SVG_VAL_IMPL_CYCLE_COLLECTION(
+  nsSVGPreserveAspectRatio::DOMAnimPAspectRatio, mSVGElement)
 
-  nsSVGPreserveAspectRatio(PRUint16 aAlign, PRUint16 aMeetOrSlice);
-  ~nsSVGPreserveAspectRatio();
-
-public:
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGPreserveAspectRatio::DOMBaseVal)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGPreserveAspectRatio::DOMBaseVal)
 
-  // nsIDOMSVGPreserveAspectRatio interface:
-  NS_DECL_NSIDOMSVGPRESERVEASPECTRATIO
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGPreserveAspectRatio::DOMAnimVal)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGPreserveAspectRatio::DOMAnimVal)
 
-  // nsISVGValue interface:
-  NS_IMETHOD SetValueString(const nsAString& aValue);
-  NS_IMETHOD GetValueString(nsAString& aValue);
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGPreserveAspectRatio::DOMAnimPAspectRatio)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGPreserveAspectRatio::DOMAnimPAspectRatio)
 
-protected:
-  PRUint16 mAlign, mMeetOrSlice;
-};
-
-//----------------------------------------------------------------------
-// implementation:
-
-
-nsSVGPreserveAspectRatio::nsSVGPreserveAspectRatio(PRUint16 aAlign,
-                                                   PRUint16 aMeetOrSlice)
-    : mAlign(aAlign), mMeetOrSlice(aMeetOrSlice)
-{
-}
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGPreserveAspectRatio::DOMBaseVal)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGPreserveAspectRatio)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGPreserveAspectRatio)
+NS_INTERFACE_MAP_END
 
-nsSVGPreserveAspectRatio::~nsSVGPreserveAspectRatio()
-{
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGPreserveAspectRatio::DOMAnimVal)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGPreserveAspectRatio)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGPreserveAspectRatio)
+NS_INTERFACE_MAP_END
 
-NS_IMPL_ADDREF(nsSVGPreserveAspectRatio)
-NS_IMPL_RELEASE(nsSVGPreserveAspectRatio)
-
-NS_INTERFACE_MAP_BEGIN(nsSVGPreserveAspectRatio)
-  NS_INTERFACE_MAP_ENTRY(nsISVGValue)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGPreserveAspectRatio)
-  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGPreserveAspectRatio)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGPreserveAspectRatio::DOMAnimPAspectRatio)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedPreserveAspectRatio)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGAnimatedPreserveAspectRatio)
 NS_INTERFACE_MAP_END
 
-//----------------------------------------------------------------------
-// nsISVGValue methods:
+/* Implementation */
 
-NS_IMETHODIMP
-nsSVGPreserveAspectRatio::SetValueString(const nsAString& aValue)
-{
-  char* str = ToNewCString(aValue);
-  if (!str) return NS_ERROR_OUT_OF_MEMORY;
+static const char *sAlignStrings[] =
+  { "none", "xMinYMin", "xMidYMin", "xMaxYMin", "xMinYMid", "xMidYMid",
+    "xMaxYMid", "xMinYMax", "xMidYMax", "xMaxYMax" };
 
-  nsresult rv = NS_OK;
+static const char *sMeetOrSliceStrings[] = { "meet", "slice" };
 
-  char* rest = str;
-  char* token;
-  const char* delimiters = "\x20\x9\xD\xA";
-  PRUint16 align, meetOrSlice;
+static PRUint16
+GetAlignForString(const nsAString &aAlignString)
+{
+  for (PRUint32 i = 0 ; i < NS_ARRAY_LENGTH(sAlignStrings) ; i++) {
+    if (aAlignString.EqualsASCII(sAlignStrings[i])) {
+      return (i + nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE);
+    }
+  }
 
-  token = nsCRT::strtok(rest, delimiters, &rest);
-
-  if (token && !strcmp(token, "defer"))
-    // Ignore: only applicable for preserveAspectRatio on 'image' elements
-    token = nsCRT::strtok(rest, delimiters, &rest);
+  return nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_UNKNOWN;
+}
 
-  if (token) {
-    if (!strcmp(token, "none"))
-      align = SVG_PRESERVEASPECTRATIO_NONE;
-    else if (!strcmp(token, "xMinYMin"))
-      align = SVG_PRESERVEASPECTRATIO_XMINYMIN;
-    else if (!strcmp(token, "xMidYMin"))
-      align = SVG_PRESERVEASPECTRATIO_XMIDYMIN;
-    else if (!strcmp(token, "xMaxYMin"))
-      align = SVG_PRESERVEASPECTRATIO_XMAXYMIN;
-    else if (!strcmp(token, "xMinYMid"))
-      align = SVG_PRESERVEASPECTRATIO_XMINYMID;
-    else if (!strcmp(token, "xMidYMid"))
-      align = SVG_PRESERVEASPECTRATIO_XMIDYMID;
-    else if (!strcmp(token, "xMaxYMid"))
-      align = SVG_PRESERVEASPECTRATIO_XMAXYMID;
-    else if (!strcmp(token, "xMinYMax"))
-      align = SVG_PRESERVEASPECTRATIO_XMINYMAX;
-    else if (!strcmp(token, "xMidYMax"))
-      align = SVG_PRESERVEASPECTRATIO_XMIDYMAX;
-    else if (!strcmp(token, "xMaxYMax"))
-      align = SVG_PRESERVEASPECTRATIO_XMAXYMAX;
-    else
-      rv = NS_ERROR_FAILURE;
+static void
+GetAlignString(nsAString& aAlignString, PRUint16 aAlign)
+{
+  NS_ASSERTION(
+    aAlign >= nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE &&
+    aAlign <= nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX,
+    "Unknown align");
 
-    if (NS_SUCCEEDED(rv)) {
-      token = nsCRT::strtok(rest, delimiters, &rest);
-      if (token) {
-        if (!strcmp(token, "meet"))
-          meetOrSlice = SVG_MEETORSLICE_MEET;
-        else if (!strcmp(token, "slice"))
-          meetOrSlice = SVG_MEETORSLICE_SLICE;
-        else
-          rv = NS_ERROR_FAILURE;
-      }
-      else
-        meetOrSlice = SVG_MEETORSLICE_MEET;
+  aAlignString.AssignASCII(
+    sAlignStrings[aAlign -
+                  nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE]);
+}
+
+static PRUint16
+GetMeetOrSliceForString(const nsAString &aMeetOrSlice)
+{
+  for (PRUint32 i = 0 ; i < NS_ARRAY_LENGTH(sMeetOrSliceStrings) ; i++) {
+    if (aMeetOrSlice.EqualsASCII(sMeetOrSliceStrings[i])) {
+      return (i + nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET);
     }
   }
-  else  // align not specified
-    rv = NS_ERROR_FAILURE;
+
+  return nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_UNKNOWN;
+}
 
-  if (nsCRT::strtok(rest, delimiters, &rest))  // there's more
-    rv = NS_ERROR_FAILURE;
+static void
+GetMeetOrSliceString(nsAString& aMeetOrSliceString, PRUint16 aMeetOrSlice)
+{
+  NS_ASSERTION(
+    aMeetOrSlice >= nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET &&
+    aMeetOrSlice <= nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE,
+    "Unknown meetOrSlice");
+
+  aMeetOrSliceString.AssignASCII(
+    sMeetOrSliceStrings[aMeetOrSlice -
+                        nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET]);
+}
 
-  if (NS_SUCCEEDED(rv)) {
-    WillModify();
-    mAlign = align;
-    mMeetOrSlice = meetOrSlice;
-    DidModify();
-  }
+nsresult
+nsSVGPreserveAspectRatio::ToDOMBaseVal(nsIDOMSVGPreserveAspectRatio **aResult,
+                                       nsSVGElement *aSVGElement)
+{
+  *aResult = new DOMBaseVal(this, aSVGElement);
+  if (!*aResult)
+    return NS_ERROR_OUT_OF_MEMORY;
 
-  nsMemory::Free(str);
+  NS_ADDREF(*aResult);
+  return NS_OK;
+}
 
-  return rv;
+nsresult
+nsSVGPreserveAspectRatio::ToDOMAnimVal(nsIDOMSVGPreserveAspectRatio **aResult,
+                                       nsSVGElement *aSVGElement)
+{
+  *aResult = new DOMAnimVal(this, aSVGElement);
+  if (!*aResult)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  NS_ADDREF(*aResult);
+  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsSVGPreserveAspectRatio::GetValueString(nsAString& aValue)
+nsresult
+nsSVGPreserveAspectRatio::SetBaseValueString(const nsAString &aValueAsString,
+                                             nsSVGElement *aSVGElement,
+                                             PRBool aDoSetAttr)
 {
-  // XXX: defer isn't stored
+  if (aValueAsString.IsEmpty() ||
+      NS_IsAsciiWhitespace(aValueAsString[0])) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsWhitespaceTokenizer tokenizer(aValueAsString);
+  if (!tokenizer.hasMoreTokens()) {
+    return NS_ERROR_FAILURE;
+  }
+  const nsAString &token = tokenizer.nextToken();
+
+  nsresult rv;
+  PreserveAspectRatio val;
 
-  switch (mAlign) {
-    case SVG_PRESERVEASPECTRATIO_NONE:
-      aValue.AssignLiteral("none");
-      break;
-    case SVG_PRESERVEASPECTRATIO_XMINYMIN:
-      aValue.AssignLiteral("xMinYMin");
-      break;
-    case SVG_PRESERVEASPECTRATIO_XMIDYMIN:
-      aValue.AssignLiteral("xMidYMin");
-      break;
-    case SVG_PRESERVEASPECTRATIO_XMAXYMIN:
-      aValue.AssignLiteral("xMaxYMin");
-      break;
-    case SVG_PRESERVEASPECTRATIO_XMINYMID:
-      aValue.AssignLiteral("xMinYMid");
-      break;
-    case SVG_PRESERVEASPECTRATIO_XMIDYMID:
-      aValue.AssignLiteral("xMidYMid");
-      break;
-    case SVG_PRESERVEASPECTRATIO_XMAXYMID:
-      aValue.AssignLiteral("xMaxYMid");
-      break;
-    case SVG_PRESERVEASPECTRATIO_XMINYMAX:
-      aValue.AssignLiteral("xMinYMax");
-      break;
-    case SVG_PRESERVEASPECTRATIO_XMIDYMAX:
-      aValue.AssignLiteral("xMidYMax");
-      break;
-    case SVG_PRESERVEASPECTRATIO_XMAXYMAX:
-      aValue.AssignLiteral("xMaxYMax");
-      break;
-    default:
-      NS_NOTREACHED("Unknown value for mAlign");
+  val.mDefer = token.EqualsLiteral("defer");
+
+  if (val.mDefer) {
+    if (!tokenizer.hasMoreTokens()) {
+      return NS_ERROR_FAILURE;
+    }
+    rv = val.SetAlign(GetAlignForString(tokenizer.nextToken()));
+  } else {
+    rv = val.SetAlign(GetAlignForString(token));
+  }
+
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+
+  if (tokenizer.hasMoreTokens()) {
+    rv = val.SetMeetOrSlice(GetMeetOrSliceForString(tokenizer.nextToken()));
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+  } else {
+    val.mMeetOrSlice = nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET;
   }
 
-  // XXX: meetOrSlice may not have been specified in the attribute
+  if (tokenizer.hasMoreTokens()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  mAnimVal = mBaseVal = val;
+  return NS_OK;
+}
+
+void
+nsSVGPreserveAspectRatio::GetBaseValueString(nsAString & aValueAsString)
+{
+  nsAutoString tmpString;
+
+  aValueAsString.Truncate();
+
+  if (mBaseVal.mDefer) {
+    aValueAsString.AppendLiteral("defer ");
+  }
 
-  if (mAlign != SVG_PRESERVEASPECTRATIO_NONE) {
-    switch (mMeetOrSlice) {
-      case SVG_MEETORSLICE_MEET:
-        aValue.AppendLiteral(" meet");
-        break;
-      case SVG_MEETORSLICE_SLICE:
-        aValue.AppendLiteral(" slice");
-        break;
-      default:
-        NS_NOTREACHED("Unknown value for mMeetOrSlice");
-    }
+  GetAlignString(tmpString, mBaseVal.mAlign);
+  aValueAsString.Append(tmpString);
+
+  if (mBaseVal.mAlign !=
+      nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) {
+
+    aValueAsString.AppendLiteral(" ");
+    GetMeetOrSliceString(tmpString, mBaseVal.mMeetOrSlice);
+    aValueAsString.Append(tmpString);
   }
+}
+
+nsresult
+nsSVGPreserveAspectRatio::SetBaseAlign(PRUint16 aAlign,
+                                       nsSVGElement *aSVGElement)
+{
+  nsresult rv = mBaseVal.SetAlign(aAlign);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  mAnimVal.mAlign = mBaseVal.mAlign;
+  aSVGElement->DidChangePreserveAspectRatio(PR_TRUE);
 
   return NS_OK;
 }
 
-//----------------------------------------------------------------------
-// nsIDOMSVGPreserveAspectRatio methods:
-
-/* attribute unsigned short align; */
-NS_IMETHODIMP nsSVGPreserveAspectRatio::GetAlign(PRUint16 *aAlign)
+nsresult
+nsSVGPreserveAspectRatio::SetBaseMeetOrSlice(PRUint16 aMeetOrSlice,
+                                             nsSVGElement *aSVGElement)
 {
-  *aAlign = mAlign;
-  return NS_OK;
-}
-NS_IMETHODIMP nsSVGPreserveAspectRatio::SetAlign(PRUint16 aAlign)
-{
-  if (aAlign < SVG_PRESERVEASPECTRATIO_NONE ||
-      aAlign > SVG_PRESERVEASPECTRATIO_XMAXYMAX)
-    return NS_ERROR_FAILURE;
+  nsresult rv = mBaseVal.SetMeetOrSlice(aMeetOrSlice);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  WillModify();
-  mAlign = aAlign;
-  DidModify();
+  mAnimVal.mMeetOrSlice = mBaseVal.mMeetOrSlice;
+  aSVGElement->DidChangePreserveAspectRatio(PR_TRUE);
 
   return NS_OK;
 }
 
-/* attribute unsigned short meetOrSlice; */
-NS_IMETHODIMP nsSVGPreserveAspectRatio::GetMeetOrSlice(PRUint16 *aMeetOrSlice)
+nsresult
+nsSVGPreserveAspectRatio::ToDOMAnimatedPreserveAspectRatio(
+  nsIDOMSVGAnimatedPreserveAspectRatio **aResult,
+  nsSVGElement *aSVGElement)
 {
-  *aMeetOrSlice = mMeetOrSlice;
+  *aResult = new DOMAnimPAspectRatio(this, aSVGElement);
+  if (!*aResult)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  NS_ADDREF(*aResult);
   return NS_OK;
 }
-NS_IMETHODIMP nsSVGPreserveAspectRatio::SetMeetOrSlice(PRUint16 aMeetOrSlice)
-{
-  if (aMeetOrSlice < SVG_MEETORSLICE_MEET ||
-      aMeetOrSlice > SVG_MEETORSLICE_SLICE)
-    return NS_ERROR_FAILURE;
-
-  WillModify();
-  mMeetOrSlice = aMeetOrSlice;
-  DidModify();
-
-  return NS_OK;
-}
-
-
-////////////////////////////////////////////////////////////////////////
-// Exported creation functions:
-
-nsresult
-NS_NewSVGPreserveAspectRatio(nsIDOMSVGPreserveAspectRatio** result,
-                             PRUint16 aAlign, PRUint16 aMeetOrSlice)
-{
-  *result = (nsIDOMSVGPreserveAspectRatio*) new nsSVGPreserveAspectRatio(aAlign, aMeetOrSlice);
-  if (!*result) return NS_ERROR_OUT_OF_MEMORY;
-
-  NS_ADDREF(*result);
-  return NS_OK;
-}
--- a/content/svg/content/src/nsSVGPreserveAspectRatio.h
+++ b/content/svg/content/src/nsSVGPreserveAspectRatio.h
@@ -35,15 +35,156 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef __NS_SVGPRESERVEASPECTRATIO_H__
 #define __NS_SVGPRESERVEASPECTRATIO_H__
 
 #include "nsIDOMSVGPresAspectRatio.h"
+#include "nsIDOMSVGAnimPresAspRatio.h"
+#include "nsSVGElement.h"
+#include "nsDOMError.h"
 
-nsresult
-NS_NewSVGPreserveAspectRatio(nsIDOMSVGPreserveAspectRatio** result,
- PRUint16 aAlign=nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID,
- PRUint16 aMeetOrSlice=nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET);
+class nsSVGPreserveAspectRatio
+{
+public:
+  class PreserveAspectRatio
+  {
+  friend class nsSVGPreserveAspectRatio;
+
+  public:
+    nsresult SetAlign(PRUint16 aAlign) {
+      if (aAlign < nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE ||
+          aAlign > nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX)
+        return NS_ERROR_FAILURE;
+      mAlign = static_cast<PRUint8>(aAlign);
+      return NS_OK;
+    };
+
+    PRUint16 GetAlign() const {
+      return mAlign;
+    };
+
+    nsresult SetMeetOrSlice(PRUint16 aMeetOrSlice) {
+      if (aMeetOrSlice < nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET ||
+          aMeetOrSlice > nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE)
+        return NS_ERROR_FAILURE;
+      mMeetOrSlice = static_cast<PRUint8>(aMeetOrSlice);
+      return NS_OK;
+    };
+
+    PRUint16 GetMeetOrSlice() const {
+      return mMeetOrSlice;
+    };
+
+    void SetDefer(PRBool aDefer) {
+      mDefer = aDefer;
+    };
+
+    PRBool GetDefer() const {
+      return mDefer;
+    };
+
+  private:
+    PRUint8 mAlign;
+    PRUint8 mMeetOrSlice;
+    PRPackedBool mDefer;
+  };
+
+  void Init() {
+    mBaseVal.mAlign = nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID;
+    mBaseVal.mMeetOrSlice = nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET;
+    mBaseVal.mDefer = PR_FALSE;
+    mAnimVal = mBaseVal;
+  }
+
+  nsresult SetBaseValueString(const nsAString& aValue,
+                              nsSVGElement *aSVGElement,
+                              PRBool aDoSetAttr);
+  void GetBaseValueString(nsAString& aValue);
+
+  nsresult SetBaseAlign(PRUint16 aAlign, nsSVGElement *aSVGElement);
+  nsresult SetBaseMeetOrSlice(PRUint16 aMeetOrSlice, nsSVGElement *aSVGElement);
+  const PreserveAspectRatio &GetBaseValue() const
+    { return mBaseVal; }
+  const PreserveAspectRatio &GetAnimValue() const
+    { return mAnimVal; }
+
+  nsresult ToDOMAnimatedPreserveAspectRatio(
+    nsIDOMSVGAnimatedPreserveAspectRatio **aResult,
+    nsSVGElement* aSVGElement);
+
+private:
+
+  PreserveAspectRatio mAnimVal;
+  PreserveAspectRatio mBaseVal;
+
+  nsresult ToDOMBaseVal(nsIDOMSVGPreserveAspectRatio **aResult,
+                        nsSVGElement* aSVGElement);
+  nsresult ToDOMAnimVal(nsIDOMSVGPreserveAspectRatio **aResult,
+                        nsSVGElement* aSVGElement);
+
+  struct DOMBaseVal : public nsIDOMSVGPreserveAspectRatio
+  {
+    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+    NS_DECL_CYCLE_COLLECTION_CLASS(DOMBaseVal)
+
+    DOMBaseVal(nsSVGPreserveAspectRatio* aVal, nsSVGElement *aSVGElement)
+      : mVal(aVal), mSVGElement(aSVGElement) {}
+    
+    nsSVGPreserveAspectRatio* mVal; // kept alive because it belongs to mSVGElement
+    nsRefPtr<nsSVGElement> mSVGElement;
+    
+    NS_IMETHOD GetAlign(PRUint16* aAlign)
+      { *aAlign = mVal->GetBaseValue().mAlign; return NS_OK; }
+    NS_IMETHOD SetAlign(PRUint16 aAlign)
+      { return mVal->SetBaseAlign(aAlign, mSVGElement); }
+
+    NS_IMETHOD GetMeetOrSlice(PRUint16* aMeetOrSlice)
+      { *aMeetOrSlice = mVal->GetBaseValue().mMeetOrSlice; return NS_OK; }
+    NS_IMETHOD SetMeetOrSlice(PRUint16 aMeetOrSlice)
+      { return mVal->SetBaseMeetOrSlice(aMeetOrSlice, mSVGElement); }
+  };
+
+  struct DOMAnimVal : public nsIDOMSVGPreserveAspectRatio
+  {
+    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+    NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimVal)
+
+    DOMAnimVal(nsSVGPreserveAspectRatio* aVal, nsSVGElement *aSVGElement)
+      : mVal(aVal), mSVGElement(aSVGElement) {}
+    
+    nsSVGPreserveAspectRatio* mVal; // kept alive because it belongs to mSVGElement
+    nsRefPtr<nsSVGElement> mSVGElement;
+    
+    NS_IMETHOD GetAlign(PRUint16* aAlign)
+      { *aAlign = mVal->GetBaseValue().mAlign; return NS_OK; }
+    NS_IMETHOD SetAlign(PRUint16 aAlign)
+      { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
+
+    NS_IMETHOD GetMeetOrSlice(PRUint16* aMeetOrSlice)
+      { *aMeetOrSlice = mVal->GetBaseValue().mMeetOrSlice; return NS_OK; }
+    NS_IMETHOD SetMeetOrSlice(PRUint16 aValue)
+      { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
+  };
+
+  struct DOMAnimPAspectRatio : public nsIDOMSVGAnimatedPreserveAspectRatio
+  {
+    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+    NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimPAspectRatio)
+
+    DOMAnimPAspectRatio(nsSVGPreserveAspectRatio* aVal, nsSVGElement *aSVGElement)
+      : mVal(aVal), mSVGElement(aSVGElement) {}
+    
+    nsSVGPreserveAspectRatio* mVal; // kept alive because it belongs to content
+    nsRefPtr<nsSVGElement> mSVGElement;
+
+    NS_IMETHOD GetBaseVal(nsIDOMSVGPreserveAspectRatio **aBaseVal)
+      { return mVal->ToDOMBaseVal(aBaseVal, mSVGElement); }
+
+    NS_IMETHOD GetAnimVal(nsIDOMSVGPreserveAspectRatio **aAnimVal)
+      { return mVal->ToDOMAnimVal(aAnimVal, mSVGElement); }
+  };
+
+};
 
 #endif //__NS_SVGPRESERVEASPECTRATIO_H__
--- a/content/svg/content/src/nsSVGSVGElement.cpp
+++ b/content/svg/content/src/nsSVGSVGElement.cpp
@@ -41,17 +41,16 @@
 #include "nsSVGLength.h"
 #include "nsSVGAngle.h"
 #include "nsCOMPtr.h"
 #include "nsIPresShell.h"
 #include "nsContentUtils.h"
 #include "nsIDocument.h"
 #include "nsPresContext.h"
 #include "nsSVGAnimatedRect.h"
-#include "nsSVGAnimatedPreserveAspectRatio.h"
 #include "nsSVGMatrix.h"
 #include "nsSVGPoint.h"
 #include "nsSVGTransform.h"
 #include "nsIDOMEventTarget.h"
 #include "nsBindingManager.h"
 #include "nsIFrame.h"
 #include "nsISVGSVGFrame.h" //XXX
 #include "nsSVGNumber.h"
@@ -116,19 +115,16 @@ nsSVGSVGElement::nsSVGSVGElement(nsINode
     mPreviousScale(0),
     mRedrawSuspendCount(0),
     mDispatchEvent(PR_FALSE)
 {
 }
 
 nsSVGSVGElement::~nsSVGSVGElement()
 {
-  if (mPreserveAspectRatio) {
-    NS_REMOVE_SVGVALUE_OBSERVER(mPreserveAspectRatio);
-  }
   if (mViewBox) {
     NS_REMOVE_SVGVALUE_OBSERVER(mViewBox);
   }
 }
 
   
 nsresult
 nsSVGSVGElement::Init()
@@ -144,30 +140,16 @@ nsSVGSVGElement::Init()
     rv = NS_NewSVGRect(getter_AddRefs(viewbox));
     NS_ENSURE_SUCCESS(rv,rv);
     rv = NS_NewSVGAnimatedRect(getter_AddRefs(mViewBox), viewbox);
     NS_ENSURE_SUCCESS(rv,rv);
     rv = AddMappedSVGValue(nsGkAtoms::viewBox, mViewBox);
     NS_ENSURE_SUCCESS(rv,rv);
   }
 
-  // DOM property: preserveAspectRatio , #IMPLIED attrib: preserveAspectRatio
-  {
-    nsCOMPtr<nsIDOMSVGPreserveAspectRatio> preserveAspectRatio;
-    rv = NS_NewSVGPreserveAspectRatio(getter_AddRefs(preserveAspectRatio));
-    NS_ENSURE_SUCCESS(rv,rv);
-    rv = NS_NewSVGAnimatedPreserveAspectRatio(
-                                          getter_AddRefs(mPreserveAspectRatio),
-                                          preserveAspectRatio);
-    NS_ENSURE_SUCCESS(rv,rv);
-    rv = AddMappedSVGValue(nsGkAtoms::preserveAspectRatio,
-                           mPreserveAspectRatio);
-    NS_ENSURE_SUCCESS(rv,rv);
-  }
-
   // DOM property: currentScale
   {
     rv = NS_NewSVGNumber(getter_AddRefs(mCurrentScale), 1.0f);
     NS_ENSURE_SUCCESS(rv,rv);
     NS_ADD_SVGVALUE_OBSERVER(mCurrentScale);
   }
 
   // DOM property: currentTranslate
@@ -637,21 +619,20 @@ nsSVGSVGElement::GetViewBox(nsIDOMSVGAni
 {
   *aViewBox = mViewBox;
   NS_ADDREF(*aViewBox);
   return NS_OK;
 }
 
 /* readonly attribute nsIDOMSVGAnimatedPreserveAspectRatio preserveAspectRatio; */
 NS_IMETHODIMP
-nsSVGSVGElement::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio * *aPreserveAspectRatio)
+nsSVGSVGElement::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
+                                        **aPreserveAspectRatio)
 {
-  *aPreserveAspectRatio = mPreserveAspectRatio;
-  NS_ADDREF(*aPreserveAspectRatio);
-  return NS_OK;
+  return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(aPreserveAspectRatio, this);
 }
 
 //----------------------------------------------------------------------
 // nsIDOMSVGLocatable methods
 
 /* readonly attribute nsIDOMSVGElement nearestViewportElement; */
 NS_IMETHODIMP
 nsSVGSVGElement::GetNearestViewportElement(nsIDOMSVGElement * *aNearestViewportElement)
@@ -1439,8 +1420,22 @@ nsSVGSVGElement::DidChangeEnum(PRUint8 a
 }
 
 nsSVGElement::EnumAttributesInfo
 nsSVGSVGElement::GetEnumInfo()
 {
   return EnumAttributesInfo(mEnumAttributes, sEnumInfo,
                             NS_ARRAY_LENGTH(sEnumInfo));
 }
+
+void
+nsSVGSVGElement::DidChangePreserveAspectRatio(PRBool aDoSetAttr)
+{
+  nsSVGSVGElementBase::DidChangePreserveAspectRatio(aDoSetAttr);
+
+  InvalidateTransformNotifyFrame();
+}
+
+nsSVGPreserveAspectRatio *
+nsSVGSVGElement::GetPreserveAspectRatio()
+{
+  return &mPreserveAspectRatio;
+}
--- a/content/svg/content/src/nsSVGSVGElement.h
+++ b/content/svg/content/src/nsSVGSVGElement.h
@@ -43,16 +43,17 @@
 #include "nsSVGStylableElement.h"
 #include "nsIDOMSVGSVGElement.h"
 #include "nsIDOMSVGFitToViewBox.h"
 #include "nsIDOMSVGLocatable.h"
 #include "nsIDOMSVGZoomAndPan.h"
 #include "nsIDOMSVGMatrix.h"
 #include "nsSVGLength2.h"
 #include "nsSVGEnum.h"
+#include "nsSVGPreserveAspectRatio.h"
 
 #define QI_AND_CAST_TO_NSSVGSVGELEMENT(base)                                  \
   (nsCOMPtr<nsIDOMSVGSVGElement>(do_QueryInterface(base)) ?                   \
    static_cast<nsSVGSVGElement*>(base.get()) : nsnull)
 
 typedef nsSVGStylableElement nsSVGSVGElementBase;
 
 class svgFloatSize {
@@ -141,16 +142,17 @@ public:
   NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
                                      nsISVGValue::modificationType aModType);
   NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
                                      nsISVGValue::modificationType aModType);
 
   // nsSVGElement specializations:
   virtual void DidChangeLength(PRUint8 aAttrEnum, PRBool aDoSetAttr);
   virtual void DidChangeEnum(PRUint8 aAttrEnum, PRBool aDoSetAttr);
+  virtual void DidChangePreserveAspectRatio(PRBool aDoSetAttr);
 
   // nsSVGSVGElement methods:
   float GetLength(PRUint8 mCtxType);
   float GetMMPerPx(PRUint8 mCtxType = 0);
   already_AddRefed<nsIDOMSVGRect> GetCtxRect();
 
   // public helpers:
   nsresult GetViewboxToViewportTransform(nsIDOMSVGMatrix **_retval);
@@ -190,19 +192,22 @@ protected:
 
   virtual EnumAttributesInfo GetEnumInfo();
 
   enum { ZOOMANDPAN };
   nsSVGEnum mEnumAttributes[1];
   static nsSVGEnumMapping sZoomAndPanMap[];
   static EnumInfo sEnumInfo[1];
 
+  virtual nsSVGPreserveAspectRatio *GetPreserveAspectRatio();
+
+  nsSVGPreserveAspectRatio mPreserveAspectRatio;
+
   nsSVGSVGElement                  *mCoordCtx;
   nsCOMPtr<nsIDOMSVGAnimatedRect>   mViewBox;
-  nsCOMPtr<nsIDOMSVGAnimatedPreserveAspectRatio> mPreserveAspectRatio;
 
   // The size of the rectangular SVG viewport into which we render. This is
   // not (necessarily) the same as the content area. See:
   //
   //   http://www.w3.org/TR/SVG11/coords.html#ViewportSpace
   //
   // XXXjwatt Currently only used for outer <svg>, but maybe we could use -1 to
   // flag this as an inner <svg> to save the overhead of GetCtx calls?
--- a/content/svg/content/src/nsSVGSymbolElement.cpp
+++ b/content/svg/content/src/nsSVGSymbolElement.cpp
@@ -31,17 +31,16 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsIDOMSVGSymbolElement.h"
 #include "nsSVGStylableElement.h"
-#include "nsSVGAnimatedPreserveAspectRatio.h"
 #include "nsSVGPreserveAspectRatio.h"
 #include "nsIDOMSVGRect.h"
 #include "nsIDOMSVGLength.h"
 #include "nsIDOMSVGFitToViewBox.h"
 #include "nsSVGRect.h"
 #include "nsSVGAnimatedRect.h"
 #include "nsGkAtoms.h"
 
@@ -70,19 +69,20 @@ public:
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGElement::)
 
   // nsIContent interface
   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* name) const;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
 protected:
+  virtual nsSVGPreserveAspectRatio *GetPreserveAspectRatio();
 
   nsCOMPtr<nsIDOMSVGAnimatedRect> mViewBox;
-  nsCOMPtr<nsIDOMSVGAnimatedPreserveAspectRatio> mPreserveAspectRatio;
+  nsSVGPreserveAspectRatio mPreserveAspectRatio;
 };
 
 NS_IMPL_NS_NEW_SVG_ELEMENT(Symbol)
 
 //----------------------------------------------------------------------
 // nsISupports methods
 
 NS_IMPL_ADDREF_INHERITED(nsSVGSymbolElement,nsSVGSymbolElementBase)
@@ -117,30 +117,16 @@ nsSVGSymbolElement::Init()
     rv = NS_NewSVGRect(getter_AddRefs(viewbox));
     NS_ENSURE_SUCCESS(rv,rv);
     rv = NS_NewSVGAnimatedRect(getter_AddRefs(mViewBox), viewbox);
     NS_ENSURE_SUCCESS(rv,rv);
     rv = AddMappedSVGValue(nsGkAtoms::viewBox, mViewBox);
     NS_ENSURE_SUCCESS(rv,rv);
   }
 
-  // DOM property: preserveAspectRatio
-  {
-    nsCOMPtr<nsIDOMSVGPreserveAspectRatio> preserveAspectRatio;
-    rv = NS_NewSVGPreserveAspectRatio(getter_AddRefs(preserveAspectRatio));
-    NS_ENSURE_SUCCESS(rv,rv);
-    rv = NS_NewSVGAnimatedPreserveAspectRatio(
-                                          getter_AddRefs(mPreserveAspectRatio),
-                                          preserveAspectRatio);
-    NS_ENSURE_SUCCESS(rv,rv);
-    rv = AddMappedSVGValue(nsGkAtoms::preserveAspectRatio,
-                           mPreserveAspectRatio);
-    NS_ENSURE_SUCCESS(rv,rv);
-  }
-
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
 // nsIDOMNode methods
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGSymbolElement)
 
@@ -152,21 +138,20 @@ NS_IMETHODIMP nsSVGSymbolElement::GetVie
 {
   *aViewBox = mViewBox;
   NS_ADDREF(*aViewBox);
   return NS_OK;
 }
 
 /* readonly attribute nsIDOMSVGAnimatedPreserveAspectRatio preserveAspectRatio; */
 NS_IMETHODIMP
-nsSVGSymbolElement::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio * *aPreserveAspectRatio)
+nsSVGSymbolElement::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
+                                           **aPreserveAspectRatio)
 {
-  *aPreserveAspectRatio = mPreserveAspectRatio;
-  NS_ADDREF(*aPreserveAspectRatio);
-  return NS_OK;
+  return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(aPreserveAspectRatio, this);
 }
 
 //----------------------------------------------------------------------
 // nsIContent methods
 
 NS_IMETHODIMP_(PRBool)
 nsSVGSymbolElement::IsAttributeMapped(const nsIAtom* name) const
 {
@@ -182,8 +167,17 @@ nsSVGSymbolElement::IsAttributeMapped(co
     sMarkersMap,
     sTextContentElementsMap,
     sViewportsMap
    };
 
   return FindAttributeDependence(name, map, NS_ARRAY_LENGTH(map)) ||
     nsSVGSymbolElementBase::IsAttributeMapped(name);
 }
+
+//----------------------------------------------------------------------
+// nsSVGElement methods
+
+nsSVGPreserveAspectRatio *
+nsSVGSymbolElement::GetPreserveAspectRatio()
+{
+  return &mPreserveAspectRatio;
+}
--- a/content/svg/content/test/dataTypes-helper.svg
+++ b/content/svg/content/test/dataTypes-helper.svg
@@ -6,11 +6,12 @@
 			<!-- <enum> (edgeMode) -->
 			<!-- <number> (divisor) -->
 			<!-- <integer> (targetX) -->
 			<!-- <string> (result) -->
 			<feConvolveMatrix id="convolve"/>
 		</filter>
 		<!-- <angle> (orient) -->
 		<!-- <length> (markerWidth) -->
+		<!-- <preserveAspectRatio> (preserveAspectRatio) -->
 		<marker id="marker"/>
 	</defs>
 </svg>
--- a/content/svg/content/test/test_dataTypes.html
+++ b/content/svg/content/test/test_dataTypes.html
@@ -100,16 +100,39 @@ function runTests()
 
   convolve.setAttribute("result", "foo");
   is(convolve.result.baseVal, "foo", "string baseVal");
   is(convolve.result.animVal, "foo", "string animVal");
   convolve.result.baseVal = "bar";
   is(convolve.result.animVal, "bar", "string animVal");
   is(convolve.getAttribute("result"), "bar", "string attribute");
 
+  // preserveAspectRatio attribute
+
+  marker.setAttribute("preserveAspectRatio", "xMinYMid slice");
+  is(marker.preserveAspectRatio.baseVal.align, 5, "preserveAspectRatio.align baseVal");
+  is(marker.preserveAspectRatio.animVal.align, 5, "preserveAspectRatio.align animVal");
+  is(marker.preserveAspectRatio.baseVal.meetOrSlice, 2, "preserveAspectRatio.meetOrSlice baseVal");
+  is(marker.preserveAspectRatio.animVal.meetOrSlice, 2, "preserveAspectRatio.meetOrSlice animVal");
+  marker.preserveAspectRatio.baseVal.align = 3;
+  is(marker.preserveAspectRatio.animVal.align, 3, "preserveAspectRatio animVal");
+  is(marker.preserveAspectRatio.animVal.meetOrSlice, 2, "preserveAspectRatio.meetOrSlice animVal");
+  marker.preserveAspectRatio.baseVal.meetOrSlice = 1;
+  is(marker.preserveAspectRatio.animVal.align, 3, "preserveAspectRatio animVal");
+  is(marker.preserveAspectRatio.animVal.meetOrSlice, 1, "preserveAspectRatio.meetOrSlice animVal");
+  is(marker.getAttribute("preserveAspectRatio"), "xMidYMin meet", "preserveAspectRatio attribute");
+  
+  var basePreserveAspectRatio = marker.preserveAspectRatio.baseVal;
+  var animPreserveAspectRatio = marker.preserveAspectRatio.animVal;
+  marker.setAttribute("preserveAspectRatio", "xMaxYMid slice");
+  is(basePreserveAspectRatio.align, 7, "preserveAspectRatio.align baseVal");
+  is(animPreserveAspectRatio.align, 7, "preserveAspectRatio.align animVal");
+  is(basePreserveAspectRatio.meetOrSlice, 2, "preserveAspectRatio.meetOrSlice baseVal");
+  is(animPreserveAspectRatio.meetOrSlice, 2, "preserveAspectRatio.meetOrSlice animVal");
+
   SimpleTest.finish();
 }
 
 window.addEventListener("load", runTests, false);
 </script>
 </pre>
 </body>
 </html>
--- a/layout/svg/base/src/nsSVGImageFrame.cpp
+++ b/layout/svg/base/src/nsSVGImageFrame.cpp
@@ -31,23 +31,22 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsSVGPathGeometryFrame.h"
 #include "nsIDOMSVGMatrix.h"
-#include "nsIDOMSVGAnimPresAspRatio.h"
 #include "imgIContainer.h"
 #include "gfxIImageFrame.h"
 #include "nsStubImageDecoderObserver.h"
 #include "nsImageLoadingContent.h"
 #include "nsIDOMSVGImageElement.h"
-#include "nsSVGElement.h"
+#include "nsSVGImageElement.h"
 #include "nsSVGUtils.h"
 #include "nsSVGMatrix.h"
 #include "gfxContext.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIImage.h"
 
 class nsSVGImageFrame;
 
@@ -192,32 +191,28 @@ nsSVGImageFrame::AttributeChanged(PRInt3
 
 already_AddRefed<nsIDOMSVGMatrix>
 nsSVGImageFrame::GetImageTransform()
 {
   nsCOMPtr<nsIDOMSVGMatrix> ctm;
   GetCanvasTM(getter_AddRefs(ctm));
 
   float x, y, width, height;
-  nsSVGElement *element = static_cast<nsSVGElement*>(mContent);
+  nsSVGImageElement *element = static_cast<nsSVGImageElement*>(mContent);
   element->GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
 
   PRInt32 nativeWidth, nativeHeight;
   mImageContainer->GetWidth(&nativeWidth);
   mImageContainer->GetHeight(&nativeHeight);
 
-  nsCOMPtr<nsIDOMSVGImageElement> image = do_QueryInterface(mContent);
-  nsCOMPtr<nsIDOMSVGAnimatedPreserveAspectRatio> ratio;
-  image->GetPreserveAspectRatio(getter_AddRefs(ratio));
-
   nsCOMPtr<nsIDOMSVGMatrix> trans, ctmXY, fini;
   trans = nsSVGUtils::GetViewBoxTransform(width, height,
                                           0, 0,
                                           nativeWidth, nativeHeight,
-                                          ratio);
+                                          element->mPreserveAspectRatio);
   ctm->Translate(x, y, getter_AddRefs(ctmXY));
   ctmXY->Multiply(trans, getter_AddRefs(fini));
 
   nsIDOMSVGMatrix *retval = nsnull;
   fini.swap(retval);
   return retval;
 }
 
--- a/layout/svg/base/src/nsSVGPatternFrame.cpp
+++ b/layout/svg/base/src/nsSVGPatternFrame.cpp
@@ -35,17 +35,16 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsGkAtoms.h"
 #include "nsIDOMSVGAnimatedRect.h"
 #include "nsIDOMSVGAnimTransformList.h"
 #include "nsSVGTransformList.h"
-#include "nsSVGAnimatedPreserveAspectRatio.h"
 #include "nsStyleContext.h"
 #include "nsINameSpaceManager.h"
 #include "nsISVGChildFrame.h"
 #include "nsIDOMSVGRect.h"
 #include "nsSVGMatrix.h"
 #include "nsSVGRect.h"
 #include "nsSVGUtils.h"
 #include "nsSVGEffects.h"
@@ -377,24 +376,23 @@ nsSVGPatternFrame::GetViewBox(nsIDOMSVGR
   nsSVGPatternElement *patternElement =
     GetPatternWithAttr(nsGkAtoms::viewBox, mContent);
 
   nsCOMPtr<nsIDOMSVGAnimatedRect> viewBox;
   patternElement->GetViewBox(getter_AddRefs(viewBox));
   return viewBox->GetAnimVal(aViewBox);
 }
 
-NS_IMETHODIMP
-nsSVGPatternFrame::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
-                                          **aPreserveAspectRatio)
+const nsSVGPreserveAspectRatio &
+nsSVGPatternFrame::GetPreserveAspectRatio()
 {
   nsSVGPatternElement *patternElement =
     GetPatternWithAttr(nsGkAtoms::preserveAspectRatio, mContent);
 
-  return patternElement->GetPreserveAspectRatio(aPreserveAspectRatio);
+  return patternElement->mPreserveAspectRatio;
 }
 
 nsSVGLength2 *
 nsSVGPatternFrame::GetX()
 {
   nsSVGPatternElement *pattern = GetPatternWithAttr(nsGkAtoms::x, mContent);
   return &pattern->mLengthAttributes[nsSVGPatternElement::X];
 }
@@ -565,23 +563,20 @@ nsSVGPatternFrame::ConstructCTM(nsIDOMSV
   viewRect->GetWidth(&viewBoxWidth);
   if (viewBoxHeight > 0.0f && viewBoxWidth > 0.0f) {
 
     float viewportWidth = GetLengthValue(GetWidth());
     float viewportHeight = GetLengthValue(GetHeight());
     float refX = GetLengthValue(GetX());
     float refY = GetLengthValue(GetY());
 
-    nsCOMPtr<nsIDOMSVGAnimatedPreserveAspectRatio> par;
-    GetPreserveAspectRatio(getter_AddRefs(par));
-
     tempTM = nsSVGUtils::GetViewBoxTransform(viewportWidth, viewportHeight,
                                              viewBoxX + refX, viewBoxY + refY,
                                              viewBoxWidth, viewBoxHeight,
-                                             par,
+                                             GetPreserveAspectRatio(),
                                              PR_TRUE);
 
   } else {
     // No viewBox, construct from the (modified) parent matrix
     NS_NewSVGMatrix(getter_AddRefs(tempTM));
   }
   tCTM->Multiply(tempTM, aCTM);
   return NS_OK;
--- a/layout/svg/base/src/nsSVGPatternFrame.h
+++ b/layout/svg/base/src/nsSVGPatternFrame.h
@@ -38,17 +38,17 @@
 
 #ifndef __NS_SVGPATTERNFRAME_H__
 #define __NS_SVGPATTERNFRAME_H__
 
 #include "nsIDOMSVGMatrix.h"
 #include "nsSVGPaintServerFrame.h"
 #include "gfxMatrix.h"
 
-class nsIDOMSVGAnimatedPreserveAspectRatio;
+class nsSVGPreserveAspectRatio;
 class nsIFrame;
 class nsSVGLength2;
 class nsSVGElement;
 class gfxContext;
 class gfxASurface;
 
 typedef nsSVGPaintServerFrame  nsSVGPatternFrameBase;
 
@@ -114,18 +114,18 @@ protected:
   nsSVGLength2 *GetY();
   nsSVGLength2 *GetWidth();
   nsSVGLength2 *GetHeight();
 
   PRUint16 GetPatternUnits();
   PRUint16 GetPatternContentUnits();
   gfxMatrix GetPatternTransform();
 
-  NS_IMETHOD GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
-                                                     **aPreserveAspectRatio);
+  const nsSVGPreserveAspectRatio &GetPreserveAspectRatio();
+
   NS_IMETHOD GetPatternFirstChild(nsIFrame **kid);
   NS_IMETHOD GetViewBox(nsIDOMSVGRect * *aMatrix);
   nsresult   GetPatternRect(nsIDOMSVGRect **patternRect,
                             nsIDOMSVGRect *bbox,
                             nsIDOMSVGMatrix *callerCTM,
                             nsSVGElement *content);
   gfxMatrix  GetPatternMatrix(nsIDOMSVGRect *bbox,
                               nsIDOMSVGRect *callerBBox,
--- a/layout/svg/base/src/nsSVGUtils.cpp
+++ b/layout/svg/base/src/nsSVGUtils.cpp
@@ -57,18 +57,17 @@
 #include "nsContentDLF.h"
 #include "nsContentUtils.h"
 #include "nsSVGFilterFrame.h"
 #include "nsINameSpaceManager.h"
 #include "nsIDOMSVGPoint.h"
 #include "nsSVGPoint.h"
 #include "nsDOMError.h"
 #include "nsSVGOuterSVGFrame.h"
-#include "nsIDOMSVGAnimPresAspRatio.h"
-#include "nsIDOMSVGPresAspectRatio.h"
+#include "nsSVGPreserveAspectRatio.h"
 #include "nsSVGMatrix.h"
 #include "nsSVGClipPathFrame.h"
 #include "nsSVGMaskFrame.h"
 #include "nsSVGContainerFrame.h"
 #include "nsSVGLength2.h"
 #include "nsGenericElement.h"
 #include "nsAttrValue.h"
 #include "nsSVGGeometryFrame.h"
@@ -752,30 +751,24 @@ nsSVGUtils::GetOuterSVGFrameAndCoveredRe
   *aRect = svg->GetCoveredRegion();
   return GetOuterSVGFrame(aFrame);
 }
 
 already_AddRefed<nsIDOMSVGMatrix>
 nsSVGUtils::GetViewBoxTransform(float aViewportWidth, float aViewportHeight,
                                 float aViewboxX, float aViewboxY,
                                 float aViewboxWidth, float aViewboxHeight,
-                                nsIDOMSVGAnimatedPreserveAspectRatio *aPreserveAspectRatio,
+                                const nsSVGPreserveAspectRatio &aPreserveAspectRatio,
                                 PRBool aIgnoreAlign)
 {
   NS_ASSERTION(aViewboxWidth > 0, "viewBox width must be greater than zero!");
   NS_ASSERTION(aViewboxHeight > 0, "viewBox height must be greater than zero!");
 
-  PRUint16 align, meetOrSlice;
-  {
-    nsCOMPtr<nsIDOMSVGPreserveAspectRatio> par;
-    aPreserveAspectRatio->GetAnimVal(getter_AddRefs(par));
-    NS_ASSERTION(par, "could not get preserveAspectRatio");
-    par->GetAlign(&align);
-    par->GetMeetOrSlice(&meetOrSlice);
-  }
+  PRUint16 align = aPreserveAspectRatio.GetAnimValue().GetAlign();
+  PRUint16 meetOrSlice = aPreserveAspectRatio.GetAnimValue().GetMeetOrSlice();
 
   // default to the defaults
   if (align == nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_UNKNOWN)
     align = nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID;
   if (meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_UNKNOWN)
     meetOrSlice = nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET;
 
   // alignment disabled for this matrix setup
--- a/layout/svg/base/src/nsSVGUtils.h
+++ b/layout/svg/base/src/nsSVGUtils.h
@@ -56,17 +56,17 @@ class nsFrameList;
 class nsIFrame;
 struct nsStyleSVGPaint;
 class nsIDOMSVGElement;
 class nsIDOMSVGLength;
 class nsIDOMSVGMatrix;
 class nsIURI;
 class nsSVGOuterSVGFrame;
 class nsIPresShell;
-class nsIDOMSVGAnimatedPreserveAspectRatio;
+class nsSVGPreserveAspectRatio;
 class nsIAtom;
 class nsSVGLength2;
 class nsSVGElement;
 class nsSVGSVGElement;
 class nsAttrValue;
 class gfxContext;
 class gfxASurface;
 class gfxPattern;
@@ -322,17 +322,17 @@ public:
   GetOuterSVGFrameAndCoveredRegion(nsIFrame* aFrame, nsRect* aRect);
 
   /* Generate a viewbox to viewport tranformation matrix */
   
   static already_AddRefed<nsIDOMSVGMatrix>
   GetViewBoxTransform(float aViewportWidth, float aViewportHeight,
                       float aViewboxX, float aViewboxY,
                       float aViewboxWidth, float aViewboxHeight,
-                      nsIDOMSVGAnimatedPreserveAspectRatio *aPreserveAspectRatio,
+                      const nsSVGPreserveAspectRatio &aPreserveAspectRatio,
                       PRBool aIgnoreAlign = PR_FALSE);
 
   /* Paint SVG frame with SVG effects - aDirtyRect is the area being
    * redrawn, in device pixel coordinates relative to the outer svg */
   static void
   PaintFrameWithEffects(nsSVGRenderState *aContext,
                         const nsIntRect *aDirtyRect,
                         nsIFrame *aFrame);