Bug 374111 - DeCOMtaminate SVG viewBox; r+sr=roc
authorCraig Topper <craig.topper@gmail.com>
Tue, 03 Feb 2009 15:42:24 +0100
changeset 24554 13b5a7af35bbf3f026ef44577db05615a6133cde
parent 24553 39219f4ec8101f1ff11c5d7175b5337a21ef4503
child 24555 6d123d6a104ac0a5eaffdc98e91c0148ee7d9f0f
push id5113
push usersgautherie.bz@free.fr
push dateTue, 03 Feb 2009 14:44:19 +0000
treeherdermozilla-central@c23d77b0d600 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs374111
milestone1.9.2a1pre
Bug 374111 - DeCOMtaminate SVG viewBox; r+sr=roc
content/svg/content/src/Makefile.in
content/svg/content/src/nsSVGAnimatedRect.cpp
content/svg/content/src/nsSVGAnimatedRect.h
content/svg/content/src/nsSVGElement.cpp
content/svg/content/src/nsSVGElement.h
content/svg/content/src/nsSVGLength.cpp
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/nsSVGRect.cpp
content/svg/content/src/nsSVGRect.h
content/svg/content/src/nsSVGSVGElement.cpp
content/svg/content/src/nsSVGSVGElement.h
content/svg/content/src/nsSVGSymbolElement.cpp
content/svg/content/src/nsSVGViewBox.cpp
content/svg/content/src/nsSVGViewBox.h
content/svg/content/test/test_dataTypes.html
layout/svg/base/src/nsSVGOuterSVGFrame.cpp
layout/svg/base/src/nsSVGPatternFrame.cpp
layout/svg/base/src/nsSVGPatternFrame.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 \
 		nsSVGAnimatedTransformList.cpp \
 		nsSVGBoolean.cpp \
 		nsSVGCircleElement.cpp \
 		nsSVGClipPathElement.cpp \
 		nsSVGDataParser.cpp \
 		nsSVGDefsElement.cpp \
 		nsSVGDescElement.cpp \
 		nsSVGElement.cpp \
@@ -131,16 +130,17 @@ CPPSRCS		= \
 		nsSVGTextElement.cpp \
 		nsSVGTextPathElement.cpp \
 		nsSVGTitleElement.cpp \
 		nsSVGTransform.cpp \
 		nsSVGTransformList.cpp \
 		nsSVGTransformListParser.cpp \
 		nsSVGUseElement.cpp \
 		nsSVGValue.cpp \
+		nsSVGViewBox.cpp \
 		$(NULL)
 
 ifdef MOZ_SMIL
 CPPSRCS += nsSVGAnimateElement.cpp \
            nsSVGAnimateTransformElement.cpp \
            nsSVGAnimationElement.cpp \
            nsSVGSetElement.cpp \
            nsSVGTransformSMILType.cpp \
deleted file mode 100644
--- a/content/svg/content/src/nsSVGAnimatedRect.cpp
+++ /dev/null
@@ -1,202 +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 the Mozilla SVG project.
- *
- * The Initial Developer of the Original Code is
- * Crocodile Clips Ltd..
- * Portions created by the Initial Developer are Copyright (C) 2001
- * 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 ***** */
-
-#include "nsSVGAnimatedRect.h"
-#include "nsSVGRect.h"
-#include "nsSVGValue.h"
-#include "nsWeakReference.h"
-#include "nsContentUtils.h"
-
-////////////////////////////////////////////////////////////////////////
-// nsSVGAnimatedRect
-
-class nsSVGAnimatedRect : public nsIDOMSVGAnimatedRect,
-                          public nsSVGValue,
-                          public nsISVGValueObserver
-{  
-protected:
-  friend nsresult NS_NewSVGAnimatedRect(nsIDOMSVGAnimatedRect** result,
-                                        nsIDOMSVGRect* baseVal);
-
-  nsSVGAnimatedRect();
-  ~nsSVGAnimatedRect();
-  void Init(nsIDOMSVGRect* baseVal);
-  
-public:
-  // nsISupports interface:
-  NS_DECL_ISUPPORTS
-
-  // nsIDOMSVGAnimatedRect interface:
-  NS_DECL_NSIDOMSVGANIMATEDRECT
-
-  // 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<nsIDOMSVGRect> mBaseVal;
-};
-
-
-//----------------------------------------------------------------------
-// Implementation
-
-nsSVGAnimatedRect::nsSVGAnimatedRect()
-{
-}
-
-nsSVGAnimatedRect::~nsSVGAnimatedRect()
-{
-  if (!mBaseVal) return;
-    nsCOMPtr<nsISVGValue> val = do_QueryInterface(mBaseVal);
-  if (!val) return;
-  val->RemoveObserver(this);
-}
-
-void
-nsSVGAnimatedRect::Init(nsIDOMSVGRect* baseVal)
-{
-  mBaseVal = baseVal;
-  if (!mBaseVal) return;
-  nsCOMPtr<nsISVGValue> val = do_QueryInterface(mBaseVal);
-  if (!val) return;
-  val->AddObserver(this);
-}
-
-//----------------------------------------------------------------------
-// nsISupports methods:
-
-NS_IMPL_ADDREF(nsSVGAnimatedRect)
-NS_IMPL_RELEASE(nsSVGAnimatedRect)
-
-NS_INTERFACE_MAP_BEGIN(nsSVGAnimatedRect)
-  NS_INTERFACE_MAP_ENTRY(nsISVGValue)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedRect)
-  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
-  NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
-  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGAnimatedRect)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
-NS_INTERFACE_MAP_END
-
-//----------------------------------------------------------------------
-// nsISVGValue methods:
-
-NS_IMETHODIMP
-nsSVGAnimatedRect::SetValueString(const nsAString& aValue)
-{
-  nsCOMPtr<nsISVGValue> value = do_QueryInterface(mBaseVal);
-  return value->SetValueString(aValue);
-}
-
-NS_IMETHODIMP
-nsSVGAnimatedRect::GetValueString(nsAString& aValue)
-{
-  nsCOMPtr<nsISVGValue> value = do_QueryInterface(mBaseVal);
-  return value->GetValueString(aValue);
-}
-
-//----------------------------------------------------------------------
-// nsIDOMSVGAnimatedRect methods:
-
-/* readonly attribute nsIDOMSVGRect baseVal; */
-NS_IMETHODIMP
-nsSVGAnimatedRect::GetBaseVal(nsIDOMSVGRect * *aBaseVal)
-{
-  *aBaseVal = mBaseVal;
-  NS_ADDREF(*aBaseVal);
-  return NS_OK;
-}
-
-/* readonly attribute nsIDOMSVGRect animVal; */
-NS_IMETHODIMP
-nsSVGAnimatedRect::GetAnimVal(nsIDOMSVGRect * *aAnimVal)
-{
-  *aAnimVal = mBaseVal;
-  NS_ADDREF(*aAnimVal);
-  return NS_OK;
-}
-
-//----------------------------------------------------------------------
-// nsISVGValueObserver methods
-
-NS_IMETHODIMP
-nsSVGAnimatedRect::WillModifySVGObservable(nsISVGValue* observable,
-                                           modificationType aModType)
-{
-  WillModify(aModType);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSVGAnimatedRect::DidModifySVGObservable (nsISVGValue* observable,
-                                           modificationType aModType)
-{
-  DidModify(aModType);
-  return NS_OK;
-}
-
-
-////////////////////////////////////////////////////////////////////////
-// Exported creation functions:
-
-nsresult
-NS_NewSVGAnimatedRect(nsIDOMSVGAnimatedRect** result,
-                      nsIDOMSVGRect* baseVal)
-{
-  *result = nsnull;
-  
-  nsSVGAnimatedRect* animatedRect = new nsSVGAnimatedRect();
-  if(!animatedRect) return NS_ERROR_OUT_OF_MEMORY;
-  NS_ADDREF(animatedRect);
-
-  animatedRect->Init(baseVal);
-  
-  *result = (nsIDOMSVGAnimatedRect*) animatedRect;
-  
-  return NS_OK;
-}
-
deleted file mode 100644
--- a/content/svg/content/src/nsSVGAnimatedRect.h
+++ /dev/null
@@ -1,49 +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 the Mozilla SVG project.
- *
- * The Initial Developer of the Original Code is
- * Crocodile Clips Ltd..
- * Portions created by the Initial Developer are Copyright (C) 2001
- * 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_SVGANIMATEDRECT_H__
-#define __NS_SVGANIMATEDRECT_H__
-
-#include "nsIDOMSVGAnimatedRect.h"
-#include "nsIDOMSVGRect.h"
-
-nsresult
-NS_NewSVGAnimatedRect(nsIDOMSVGAnimatedRect** result,
-                      nsIDOMSVGRect* baseVal);
-
-#endif //__NS_SVGANIMATEDRECT_H__
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -68,16 +68,17 @@
 #include "nsIEventListenerManager.h"
 #include "nsSVGUtils.h"
 #include "nsSVGLength2.h"
 #include "nsSVGNumber2.h"
 #include "nsSVGInteger.h"
 #include "nsSVGAngle.h"
 #include "nsSVGBoolean.h"
 #include "nsSVGEnum.h"
+#include "nsSVGViewBox.h"
 #include "nsSVGString.h"
 #include "nsIDOMSVGUnitTypes.h"
 #include "nsIDOMSVGLengthList.h"
 #include "nsIDOMSVGAnimatedLengthList.h"
 #include "nsIDOMSVGNumberList.h"
 #include "nsIDOMSVGAnimatedNumberList.h"
 #include "nsIDOMSVGPointList.h"
 #include "nsIDOMSVGAnimatedPoints.h"
@@ -145,16 +146,22 @@ nsSVGElement::Init()
   }
 
   EnumAttributesInfo enumInfo = GetEnumInfo();
 
   for (i = 0; i < enumInfo.mEnumCount; i++) {
     enumInfo.Reset(i);
   }
 
+  nsSVGViewBox *viewBox = GetViewBox();
+
+  if (viewBox) {
+    viewBox->Init();
+  }
+
   nsSVGPreserveAspectRatio *preserveAspectRatio =
     GetPreserveAspectRatio();
 
   if (preserveAspectRatio) {
     preserveAspectRatio->Init();
   }
 
   StringAttributesInfo stringInfo = GetStringInfo();
@@ -438,26 +445,38 @@ nsSVGElement::ParseAttribute(PRInt32 aNa
             enumInfo.Reset(i);
           }
           foundMatch = PR_TRUE;
           break;
         }
       }
     }
 
-    if (!foundMatch && aAttribute == nsGkAtoms::preserveAspectRatio) {
+    if (!foundMatch) {
+      // Check for nsSVGViewBox attribute
+      if (aAttribute == nsGkAtoms::viewBox) {
+        nsSVGViewBox* viewBox = GetViewBox();
+        if (viewBox) {
+          rv = viewBox->SetBaseValueString(aValue, this, PR_FALSE);
+          if (NS_FAILED(rv)) {
+            viewBox->Init();
+          }
+          foundMatch = PR_TRUE;
+        }
       // Check for nsSVGPreserveAspectRatio attribute
-      nsSVGPreserveAspectRatio *preserveAspectRatio =
-        GetPreserveAspectRatio();
-      if (preserveAspectRatio) {
-        rv = preserveAspectRatio->SetBaseValueString(aValue, this, PR_FALSE);
-        if (NS_FAILED(rv)) {
-          preserveAspectRatio->Init();
+      } else if (aAttribute == nsGkAtoms::preserveAspectRatio) {
+        nsSVGPreserveAspectRatio *preserveAspectRatio =
+          GetPreserveAspectRatio();
+        if (preserveAspectRatio) {
+          rv = preserveAspectRatio->SetBaseValueString(aValue, this, PR_FALSE);
+          if (NS_FAILED(rv)) {
+            preserveAspectRatio->Init();
+          }
+          foundMatch = PR_TRUE;
         }
-        foundMatch = PR_TRUE;
       }
     }
   }
 
   if (!foundMatch) {
     // Check for nsSVGString attribute
     StringAttributesInfo stringInfo = GetStringInfo();
     for (PRUint32 i = 0; i < stringInfo.mStringCount; i++) {
@@ -594,25 +613,35 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespa
           enumInfo.Reset(i);
           DidChangeEnum(i, PR_FALSE);
           foundMatch = PR_TRUE;
           break;
         }
       }
     }
 
-    if (!foundMatch && aName == nsGkAtoms::preserveAspectRatio) {
+    if (!foundMatch) {
+      // Check if this is a nsViewBox attribute going away
+      if (aName == nsGkAtoms::viewBox) {
+        nsSVGViewBox* viewBox = GetViewBox();
+        if (viewBox) {
+          viewBox->Init();
+          DidChangeViewBox(PR_FALSE);
+          foundMatch = PR_TRUE;
+        }
       // Check if this is a preserveAspectRatio attribute going away
-      nsSVGPreserveAspectRatio *preserveAspectRatio =
-        GetPreserveAspectRatio();
+      } else if (aName == nsGkAtoms::preserveAspectRatio) {
+        nsSVGPreserveAspectRatio *preserveAspectRatio =
+          GetPreserveAspectRatio();
 
-      if (preserveAspectRatio) {
-        preserveAspectRatio->Init();
-        DidChangePreserveAspectRatio(PR_FALSE);
-        foundMatch = PR_TRUE;
+        if (preserveAspectRatio) {
+          preserveAspectRatio->Init();
+          DidChangePreserveAspectRatio(PR_FALSE);
+          foundMatch = PR_TRUE;
+        }
       }
     }
   }
 
   if (!foundMatch) {
     // Check if this is a string attribute going away
     StringAttributesInfo stringInfo = GetStringInfo();
 
@@ -639,22 +668,16 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespa
   }
 
   return nsSVGElementBase::UnsetAttr(aNamespaceID, aName, aNotify);
 }
 
 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<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) {
@@ -1466,16 +1489,38 @@ nsSVGElement::DidChangeEnum(PRUint8 aAtt
 
   nsAutoString newStr;
   info.mEnums[aAttrEnum].GetBaseValueString(newStr, this);
 
   SetAttr(kNameSpaceID_None, *info.mEnumInfo[aAttrEnum].mName,
           newStr, PR_TRUE);
 }
 
+nsSVGViewBox *
+nsSVGElement::GetViewBox()
+{
+  return nsnull;
+}
+
+void
+nsSVGElement::DidChangeViewBox(PRBool aDoSetAttr)
+{
+  if (!aDoSetAttr)
+    return;
+
+  nsSVGViewBox *viewBox = GetViewBox();
+
+  NS_ASSERTION(viewBox, "DidChangeViewBox on element with no viewBox attrib");
+
+  nsAutoString newStr;
+  viewBox->GetBaseValueString(newStr);
+
+  SetAttr(kNameSpaceID_None, nsGkAtoms::viewBox, newStr, PR_TRUE);
+}
+
 nsSVGPreserveAspectRatio *
 nsSVGElement::GetPreserveAspectRatio()
 {
   return nsnull;
 }
 
 void
 nsSVGElement::DidChangePreserveAspectRatio(PRBool aDoSetAttr)
--- a/content/svg/content/src/nsSVGElement.h
+++ b/content/svg/content/src/nsSVGElement.h
@@ -62,16 +62,17 @@
 class nsSVGSVGElement;
 class nsSVGLength2;
 class nsSVGNumber2;
 class nsSVGInteger;
 class nsSVGAngle;
 class nsSVGBoolean;
 class nsSVGEnum;
 struct nsSVGEnumMapping;
+class nsSVGViewBox;
 class nsSVGPreserveAspectRatio;
 class nsSVGString;
 
 typedef nsStyledElement nsSVGElementBase;
 
 class nsSVGElement : public nsSVGElementBase,    // nsIContent
                      public nsISVGValueObserver  // :nsISupportsWeakReference
 {
@@ -139,16 +140,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 DidChangeViewBox(PRBool aDoSetAttr);
   virtual void DidChangePreserveAspectRatio(PRBool aDoSetAttr);
   virtual void DidChangeString(PRUint8 aAttrEnum) {}
 
   void DidAnimateLength(PRUint8 aAttrEnum);
 
   void GetAnimatedLengthValues(float *aFirst, ...);
   void GetAnimatedNumberValues(float *aFirst, ...);
   void GetAnimatedIntegerValues(PRInt32 *aFirst, ...);
@@ -325,18 +327,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
+  // We assume all viewboxes and preserveAspectRatios are alike
+  // so we don't need to wrap the class
+  virtual nsSVGViewBox *GetViewBox();
   virtual nsSVGPreserveAspectRatio *GetPreserveAspectRatio();
   virtual StringAttributesInfo GetStringInfo();
 
   static nsSVGEnumMapping sSVGUnitTypesMap[];
 
 private:
   /* read <number-optional-number> */
   nsresult
--- a/content/svg/content/src/nsSVGLength.cpp
+++ b/content/svg/content/src/nsSVGLength.cpp
@@ -45,72 +45,58 @@
 #include "nsTextFormatter.h"
 #include "prdtoa.h"
 #include "nsCRT.h"
 #include "nsSVGSVGElement.h"
 #include "nsIDOMSVGNumber.h"
 #include "nsISVGValueUtils.h"
 #include "nsWeakReference.h"
 #include "nsContentUtils.h"
-#include "nsIDOMSVGAnimatedRect.h"
 
 ////////////////////////////////////////////////////////////////////////
 // nsSVGLength class
 
 class nsSVGLength : public nsISVGLength,
-                    public nsSVGValue,
-                    public nsISVGValueObserver
+                    public nsSVGValue
 {
 protected:
   friend nsresult NS_NewSVGLength(nsISVGLength** result,
                                   float value,
                                   PRUint16 unit);
 
   friend nsresult NS_NewSVGLength(nsISVGLength** result,
                                   const nsAString &value);
   
   nsSVGLength(float value, PRUint16 unit);
   nsSVGLength();
-  virtual ~nsSVGLength();
 
 public:
   // nsISupports interface:
   NS_DECL_ISUPPORTS
 
   // nsIDOMSVGLength interface:
   NS_DECL_NSIDOMSVGLENGTH
 
   // nsISVGLength interface:
   NS_IMETHOD SetContext(nsIWeakReference *aContext, PRUint8 aCtxType);
 
   // nsISVGValue interface:
   NS_IMETHOD SetValueString(const nsAString& aValue);
   NS_IMETHOD GetValueString(nsAString& aValue);
   
-  // nsISVGValueObserver interface:
-  NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
-                                     modificationType aModType);
-  NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
-                                     modificationType aModType);
-
   // nsISupportsWeakReference
   // implementation inherited from nsSupportsWeakReference
   
 protected:
   // implementation helpers:
   float mmPerPixel();
   float AxisLength();
   float EmLength();
   float ExLength();
   PRBool IsValidUnitType(PRUint16 unit);
-  void MaybeAddAsObserver();
-  void MaybeRemoveAsObserver();
-
-  // helper - returns a rect if we need to observe it (percentage length)
-  already_AddRefed<nsIDOMSVGRect> MaybeGetCtxRect();
 
   nsWeakPtr mElement;  // owning element - weakptr to avoid reference loop
   float mValueInSpecifiedUnits;
   PRUint16 mSpecifiedUnitType;
   PRUint8 mCtxType;
 };
 
 
@@ -149,40 +135,32 @@ NS_NewSVGLength(nsISVGLength** result,
 
 
 nsSVGLength::nsSVGLength(float value,
                          PRUint16 unit)
     : mValueInSpecifiedUnits(value),
       mSpecifiedUnitType(unit),
       mCtxType(0)
 {
-  // we don't have a context yet, so we don't call MaybeAddAsObserver()
 }
 
 nsSVGLength::nsSVGLength()
 {
 }
 
-nsSVGLength::~nsSVGLength()
-{
-  MaybeRemoveAsObserver();
-}
-
 //----------------------------------------------------------------------
 // nsISupports methods:
 
 NS_IMPL_ADDREF(nsSVGLength)
 NS_IMPL_RELEASE(nsSVGLength)
 
 NS_INTERFACE_MAP_BEGIN(nsSVGLength)
   NS_INTERFACE_MAP_ENTRY(nsISVGValue)
-  NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
   NS_INTERFACE_MAP_ENTRY(nsISVGLength)
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGLength)
-  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGLength)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
 NS_INTERFACE_MAP_END
 
 //----------------------------------------------------------------------
 // nsISVGValue methods:
 
 NS_IMETHODIMP
@@ -193,35 +171,16 @@ nsSVGLength::SetValueString(const nsAStr
 
 NS_IMETHODIMP
 nsSVGLength::GetValueString(nsAString& aValue)
 {
   return GetValueAsString(aValue);
 }
 
 //----------------------------------------------------------------------
-// nsISVGValueObserver methods
-
-NS_IMETHODIMP
-nsSVGLength::WillModifySVGObservable(nsISVGValue* observable,
-                                     modificationType aModType)
-{
-  WillModify(aModType);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsSVGLength::DidModifySVGObservable(nsISVGValue* observable,
-                                    modificationType aModType)
-{
-  DidModify(aModType);
-  return NS_OK;
-}
-
-//----------------------------------------------------------------------
 // nsIDOMSVGLength methods:
 
 /* readonly attribute unsigned short unitType; */
 NS_IMETHODIMP
 nsSVGLength::GetUnitType(PRUint16 *aUnitType)
 {
   *aUnitType = mSpecifiedUnitType;
   return NS_OK;
@@ -459,76 +418,49 @@ nsSVGLength::SetValueAsString(const nsAS
 NS_IMETHODIMP
 nsSVGLength::NewValueSpecifiedUnits(PRUint16 unitType, float valueInSpecifiedUnits)
 {
   NS_ENSURE_FINITE(valueInSpecifiedUnits, NS_ERROR_ILLEGAL_VALUE);
 
   if (!IsValidUnitType(unitType))
     return NS_ERROR_FAILURE;
 
-  PRBool observer_change = (unitType != mSpecifiedUnitType);
-
   WillModify();
-  if (observer_change)
-    MaybeRemoveAsObserver();
   mValueInSpecifiedUnits = valueInSpecifiedUnits;
   mSpecifiedUnitType     = unitType;
-  if (observer_change)
-    MaybeAddAsObserver();
   DidModify();
   
   return NS_OK;
 }
 
 /* void convertToSpecifiedUnits (in unsigned short unitType); */
 NS_IMETHODIMP
 nsSVGLength::ConvertToSpecifiedUnits(PRUint16 unitType)
 {
   if (!IsValidUnitType(unitType))
     return NS_ERROR_FAILURE;
 
-  PRBool observer_change = (unitType != mSpecifiedUnitType);
-
   WillModify();
-  if (observer_change)
-    MaybeRemoveAsObserver();
   float valueInUserUnits;
   GetValue(&valueInUserUnits);
   mSpecifiedUnitType = unitType;
   SetValue(valueInUserUnits);
-  if (observer_change)
-    MaybeAddAsObserver();
   DidModify();
   
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
 // nsISVGLength methods:
 NS_IMETHODIMP
 nsSVGLength::SetContext(nsIWeakReference *aContext, PRUint8 aCtxType)
 {
-  /* Unless our unit type is SVG_LENGTHTYPE_NUMBER or SVG_LENGTHTYPE_PX, our
-     user unit value is determined by our context and we must notify our
-     observers that we have changed. */
-
-  if (mSpecifiedUnitType != SVG_LENGTHTYPE_NUMBER &&
-      mSpecifiedUnitType != SVG_LENGTHTYPE_PX) {
-    WillModify(mod_context);
-    MaybeRemoveAsObserver();
-  }
-
   mElement = aContext;
   mCtxType = aCtxType;
 
-  if (mSpecifiedUnitType != SVG_LENGTHTYPE_NUMBER &&
-      mSpecifiedUnitType != SVG_LENGTHTYPE_PX) {
-    MaybeAddAsObserver();
-    DidModify(mod_context);
-  }
   return NS_OK;
 }
 
 
 //----------------------------------------------------------------------
 // Implementation helpers:
 
 float nsSVGLength::mmPerPixel()
@@ -592,37 +524,8 @@ float nsSVGLength::ExLength()
 PRBool nsSVGLength::IsValidUnitType(PRUint16 unit)
 {
   if (unit > SVG_LENGTHTYPE_UNKNOWN && unit <= SVG_LENGTHTYPE_PC)
     return PR_TRUE;
 
   return PR_FALSE;
 }
 
-already_AddRefed<nsIDOMSVGRect> nsSVGLength::MaybeGetCtxRect()
-{
-  if ((mSpecifiedUnitType == SVG_LENGTHTYPE_PERCENTAGE) && mElement) {
-    nsCOMPtr<nsIContent> element = do_QueryReferent(mElement);
-    if (element) {
-      nsSVGSVGElement *ctx =
-        static_cast<nsSVGElement*>(element.get())->GetCtx();
-      if (ctx)
-        return ctx->GetCtxRect();
-    }
-  }
-
-  return nsnull;
-}
-
-void nsSVGLength::MaybeAddAsObserver()
-{
-  nsCOMPtr<nsIDOMSVGRect> rect = MaybeGetCtxRect();
-  if (rect)
-    NS_ADD_SVGVALUE_OBSERVER(rect);
-}
-
-void nsSVGLength::MaybeRemoveAsObserver()
-{
-  nsCOMPtr<nsIDOMSVGRect> rect = MaybeGetCtxRect();
-  if (rect)
-    NS_REMOVE_SVGVALUE_OBSERVER(rect);
-}
-
--- a/content/svg/content/src/nsSVGMarkerElement.cpp
+++ b/content/svg/content/src/nsSVGMarkerElement.cpp
@@ -30,18 +30,16 @@
  * 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 "nsSVGAnimatedRect.h"
-#include "nsSVGRect.h"
 #include "nsCOMPtr.h"
 #include "nsISVGValueUtils.h"
 #include "nsSVGPreserveAspectRatio.h"
 #include "nsSVGMatrix.h"
 #include "nsDOMError.h"
 #include "nsSVGUtils.h"
 #include "nsSVGMarkerElement.h"
 
@@ -130,52 +128,28 @@ nsSVGOrientType::ToDOMAnimatedEnum(nsIDO
   return NS_OK;
 }
 
 nsSVGMarkerElement::nsSVGMarkerElement(nsINodeInfo *aNodeInfo)
   : nsSVGMarkerElementBase(aNodeInfo), mCoordCtx(nsnull)
 {
 }
 
-nsresult
-nsSVGMarkerElement::Init()
-{
-  nsresult rv = nsSVGMarkerElementBase::Init();
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  // Create mapped properties:
-
-  // DOM property: viewBox
-  {
-    nsCOMPtr<nsIDOMSVGRect> viewbox;
-    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);
-  }
-
-  return NS_OK;
-}
-
 //----------------------------------------------------------------------
 // nsIDOMNode methods
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGMarkerElement)
 
 //----------------------------------------------------------------------
 // nsIDOMSVGFitToViewBox methods
 
 /* readonly attribute nsIDOMSVGAnimatedRect viewBox; */
   NS_IMETHODIMP nsSVGMarkerElement::GetViewBox(nsIDOMSVGAnimatedRect * *aViewBox)
 {
-  *aViewBox = mViewBox;
-  NS_ADDREF(*aViewBox);
-  return NS_OK;
+  return mViewBox.ToDOMAnimatedRect(aViewBox, this);
 }
 
 /* readonly attribute nsIDOMSVGAnimatedPreserveAspectRatio preserveAspectRatio; */
 NS_IMETHODIMP
 nsSVGMarkerElement::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
                                            **aPreserveAspectRatio)
 {
   return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(aPreserveAspectRatio, this);
@@ -243,27 +217,16 @@ NS_IMETHODIMP nsSVGMarkerElement::SetOri
   float f;
   angle->GetValue(&f);
   mAngleAttributes[ORIENT].SetBaseValue(f, this);
 
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
-// nsISVGValueObserver methods:
-
-NS_IMETHODIMP
-nsSVGMarkerElement::DidModifySVGObservable(nsISVGValue* observable,
-                                           nsISVGValue::modificationType aModType)
-{
-  mViewBoxToViewportTransform = nsnull;
-  return NS_OK;
-}
-
-//----------------------------------------------------------------------
 // nsIContent methods
 
 NS_IMETHODIMP_(PRBool)
 nsSVGMarkerElement::IsAttributeMapped(const nsIAtom* name) const
 {
   static const MappedAttributeEntry* const map[] = {
     sFEFloodMap,
     sFiltersMap,
@@ -313,22 +276,19 @@ nsSVGMarkerElement::ParseAttribute(PRInt
 }
 
 nsresult
 nsSVGMarkerElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
                               PRBool aNotify)
 {
   if (aNamespaceID == kNameSpaceID_None) {
     if (aName == nsGkAtoms::viewBox && mCoordCtx) {
-      nsCOMPtr<nsIDOMSVGRect> vb;
-      mViewBox->GetAnimVal(getter_AddRefs(vb));
-      vb->SetX(0);
-      vb->SetY(0);
-      vb->SetWidth(mLengthAttributes[MARKERWIDTH].GetAnimValue(mCoordCtx));
-      vb->SetHeight(mLengthAttributes[MARKERHEIGHT].GetAnimValue(mCoordCtx));
+      mViewBox.SetBaseValue(0, 0, mLengthAttributes[MARKERWIDTH].GetAnimValue(mCoordCtx),
+                            mLengthAttributes[MARKERHEIGHT].GetAnimValue(mCoordCtx),
+                            this, PR_FALSE);
       return nsGenericElement::UnsetAttr(aNamespaceID, aName, aNotify);
     } else if (aName == nsGkAtoms::orient) {
       mOrientType.SetBaseValue(SVG_MARKER_ORIENT_ANGLE);
     }
   }
 
   return nsSVGMarkerElementBase::UnsetAttr(aNamespaceID, aName, aNotify);
 }
@@ -340,42 +300,48 @@ void
 nsSVGMarkerElement::DidChangeLength(PRUint8 aAttrEnum, PRBool aDoSetAttr)
 {
   nsSVGMarkerElementBase::DidChangeLength(aAttrEnum, aDoSetAttr);
 
   mViewBoxToViewportTransform = nsnull;
 
   if (mCoordCtx && !HasAttr(kNameSpaceID_None, nsGkAtoms::viewBox) &&
       (aAttrEnum == MARKERWIDTH || aAttrEnum == MARKERHEIGHT)) {
-    nsCOMPtr<nsIDOMSVGRect> vb;
-    mViewBox->GetAnimVal(getter_AddRefs(vb));
-    vb->SetWidth(mLengthAttributes[MARKERWIDTH].GetAnimValue(mCoordCtx));
-    vb->SetHeight(mLengthAttributes[MARKERHEIGHT].GetAnimValue(mCoordCtx));
+    mViewBox.SetBaseValue(0, 0, mLengthAttributes[MARKERWIDTH].GetAnimValue(mCoordCtx),
+                          mLengthAttributes[MARKERHEIGHT].GetAnimValue(mCoordCtx),
+                          this, PR_FALSE);
   }
 }
 
 void
+nsSVGMarkerElement::DidChangeViewBox(PRBool aDoSetAttr)
+{
+  nsSVGMarkerElementBase::DidChangeViewBox(aDoSetAttr);
+
+  mViewBoxToViewportTransform = nsnull;
+}
+
+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;
-    mViewBox->GetAnimVal(getter_AddRefs(vb));
-    vb->SetWidth(mLengthAttributes[MARKERWIDTH].GetAnimValue(mCoordCtx));
-    vb->SetHeight(mLengthAttributes[MARKERHEIGHT].GetAnimValue(mCoordCtx));
+    mViewBox.SetBaseValue(0, 0, mLengthAttributes[MARKERWIDTH].GetAnimValue(mCoordCtx),
+                          mLengthAttributes[MARKERHEIGHT].GetAnimValue(mCoordCtx),
+                          this, PR_FALSE);
   }
 }
 
 nsSVGElement::LengthAttributesInfo
 nsSVGMarkerElement::GetLengthInfo()
 {
   return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
                               NS_ARRAY_LENGTH(sLengthInfo));
@@ -390,16 +356,22 @@ nsSVGMarkerElement::GetAngleInfo()
 
 nsSVGElement::EnumAttributesInfo
 nsSVGMarkerElement::GetEnumInfo()
 {
   return EnumAttributesInfo(mEnumAttributes, sEnumInfo,
                             NS_ARRAY_LENGTH(sEnumInfo));
 }
 
+nsSVGViewBox *
+nsSVGMarkerElement::GetViewBox()
+{
+  return &mViewBox;
+}
+
 nsSVGPreserveAspectRatio *
 nsSVGMarkerElement::GetPreserveAspectRatio()
 {
   return &mPreserveAspectRatio;
 }
 
 //----------------------------------------------------------------------
 // public helpers
@@ -434,40 +406,30 @@ nsSVGMarkerElement::GetViewboxToViewport
 {
   *_retval = nsnull;
 
   if (!mViewBoxToViewportTransform) {
     float viewportWidth =
       mLengthAttributes[MARKERWIDTH].GetAnimValue(mCoordCtx);
     float viewportHeight = 
       mLengthAttributes[MARKERHEIGHT].GetAnimValue(mCoordCtx);
-    
-    float viewboxX, viewboxY, viewboxWidth, viewboxHeight;
-    {
-      nsCOMPtr<nsIDOMSVGRect> vb;
-      mViewBox->GetAnimVal(getter_AddRefs(vb));
-      NS_ASSERTION(vb, "could not get viewbox");
-      vb->GetX(&viewboxX);
-      vb->GetY(&viewboxY);
-      vb->GetWidth(&viewboxWidth);
-      vb->GetHeight(&viewboxHeight);
-    }
-    if (viewboxWidth <= 0.0f || viewboxHeight <= 0.0f) {
+   
+    const nsSVGViewBoxRect& viewbox = mViewBox.GetAnimValue(); 
+
+    if (viewbox.width <= 0.0f || viewbox.height <= 0.0f) {
       return NS_ERROR_FAILURE; // invalid - don't paint element
     }
 
-    float refX =
-      mLengthAttributes[REFX].GetAnimValue(mCoordCtx);
-    float refY = 
-      mLengthAttributes[REFY].GetAnimValue(mCoordCtx);
+    float refX = mLengthAttributes[REFX].GetAnimValue(mCoordCtx);
+    float refY = mLengthAttributes[REFY].GetAnimValue(mCoordCtx);
 
     nsCOMPtr<nsIDOMSVGMatrix> vb2vp =
       nsSVGUtils::GetViewBoxTransform(viewportWidth, viewportHeight,
-                                      viewboxX, viewboxY,
-                                      viewboxWidth, viewboxHeight,
+                                      viewbox.x, viewbox.y,
+                                      viewbox.width, viewbox.height,
                                       mPreserveAspectRatio,
                                       PR_TRUE);
     NS_ENSURE_TRUE(vb2vp, NS_ERROR_OUT_OF_MEMORY);
     nsSVGUtils::TransformPoint(vb2vp, &refX, &refY);
 
     nsCOMPtr<nsIDOMSVGMatrix> translate;
     NS_NewSVGMatrix(getter_AddRefs(translate),
                     1.0f, 0.0f, 0.0f, 1.0f, -refX, -refY);
--- 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 "nsSVGViewBox.h"
 #include "nsSVGPreserveAspectRatio.h"
 
 class nsSVGOrientType
 {
 public:
   nsSVGOrientType()
    : mAnimVal(nsIDOMSVGMarkerElement::SVG_MARKER_ORIENT_ANGLE),
      mBaseVal(nsIDOMSVGMarkerElement::SVG_MARKER_ORIENT_ANGLE) {}
@@ -98,44 +99,40 @@ class nsSVGMarkerElement : public nsSVGM
                            public nsIDOMSVGFitToViewBox
 {
   friend class nsSVGMarkerFrame;
 
 protected:
   friend nsresult NS_NewSVGMarkerElement(nsIContent **aResult,
                                          nsINodeInfo *aNodeInfo);
   nsSVGMarkerElement(nsINodeInfo* aNodeInfo);
-  nsresult Init();
 
 public:
   // interfaces:
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMSVGMARKERELEMENT
   NS_DECL_NSIDOMSVGFITTOVIEWBOX
 
   // xxx I wish we could use virtual inheritance
   NS_FORWARD_NSIDOMNODE(nsSVGElement::)
   NS_FORWARD_NSIDOMELEMENT(nsSVGElement::)
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGElement::)
 
-  // nsISVGValueObserver
-  NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
-                                     nsISVGValue::modificationType aModType);
-
   // nsIContent interface
   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* name) const;
 
   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 DidChangeViewBox(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);
 
@@ -147,34 +144,35 @@ protected:
                                 const nsAString& aValue,
                                 nsAttrValue& aResult);
 
   void SetParentCoordCtxProvider(nsSVGSVGElement *aContext);
 
   virtual LengthAttributesInfo GetLengthInfo();
   virtual AngleAttributesInfo GetAngleInfo();
   virtual EnumAttributesInfo GetEnumInfo();
+  virtual nsSVGViewBox *GetViewBox();
   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];
 
+  nsSVGViewBox             mViewBox;
   nsSVGPreserveAspectRatio mPreserveAspectRatio;
 
   // derived properties (from 'orient') handled separately
   nsSVGOrientType                        mOrientType;
 
   nsSVGSVGElement                       *mCoordCtx;
-  nsCOMPtr<nsIDOMSVGAnimatedRect>        mViewBox;
   nsCOMPtr<nsIDOMSVGMatrix>         mViewBoxToViewportTransform;
 };
 
 #endif
--- a/content/svg/content/src/nsSVGPatternElement.cpp
+++ b/content/svg/content/src/nsSVGPatternElement.cpp
@@ -35,18 +35,16 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsSVGTransformList.h"
 #include "nsSVGAnimatedTransformList.h"
 #include "nsCOMPtr.h"
 #include "nsGkAtoms.h"
-#include "nsSVGAnimatedRect.h"
-#include "nsSVGRect.h"
 #include "nsSVGMatrix.h"
 #include "nsSVGPatternElement.h"
 #include "nsIFrame.h"
 
 //--------------------- Patterns ------------------------
 
 nsSVGElement::LengthInfo nsSVGPatternElement::sLengthInfo[4] =
 {
@@ -112,46 +110,31 @@ nsSVGPatternElement::Init()
     NS_ENSURE_SUCCESS(rv,rv);
     rv = NS_NewSVGAnimatedTransformList(getter_AddRefs(mPatternTransform),
                                         transformList);
     NS_ENSURE_SUCCESS(rv,rv);
     rv = AddMappedSVGValue(nsGkAtoms::patternTransform, mPatternTransform);
     NS_ENSURE_SUCCESS(rv,rv);
   }
 
-  // nsIDOMSVGFitToViewBox properties
-
-  // DOM property: viewBox
-  {
-    nsCOMPtr<nsIDOMSVGRect> viewbox;
-    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);
-  }
-
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
 // nsIDOMNode method
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGPatternElement)
 
 //----------------------------------------------------------------------
 // nsIDOMSVGFitToViewBox methods
 
 /* readonly attribute nsIDOMSVGAnimatedRect viewBox; */
 NS_IMETHODIMP nsSVGPatternElement::GetViewBox(nsIDOMSVGAnimatedRect * *aViewBox)
 {
-  *aViewBox = mViewBox;
-  NS_ADDREF(*aViewBox);
-  return NS_OK;
+  return mViewBox.ToDOMAnimatedRect(aViewBox, this);
 }
 
 /* readonly attribute nsIDOMSVGAnimatedPreserveAspectRatio preserveAspectRatio; */
 NS_IMETHODIMP
 nsSVGPatternElement::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
                                             **aPreserveAspectRatio)
 {
   return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(aPreserveAspectRatio, this);
@@ -248,16 +231,22 @@ nsSVGPatternElement::GetLengthInfo()
 
 nsSVGElement::EnumAttributesInfo
 nsSVGPatternElement::GetEnumInfo()
 {
   return EnumAttributesInfo(mEnumAttributes, sEnumInfo,
                             NS_ARRAY_LENGTH(sEnumInfo));
 }
 
+nsSVGViewBox *
+nsSVGPatternElement::GetViewBox()
+{
+  return &mViewBox;
+}
+
 nsSVGPreserveAspectRatio *
 nsSVGPatternElement::GetPreserveAspectRatio()
 {
   return &mPreserveAspectRatio;
 }
 
 nsSVGElement::StringAttributesInfo
 nsSVGPatternElement::GetStringInfo()
--- a/content/svg/content/src/nsSVGPatternElement.h
+++ b/content/svg/content/src/nsSVGPatternElement.h
@@ -42,16 +42,17 @@
 #include "nsSVGStylableElement.h"
 #include "nsIDOMSVGURIReference.h"
 #include "nsIDOMSVGFitToViewBox.h"
 #include "nsIDOMSVGPatternElement.h"
 #include "nsIDOMSVGUnitTypes.h"
 #include "nsSVGLength2.h"
 #include "nsSVGEnum.h"
 #include "nsSVGString.h"
+#include "nsSVGViewBox.h"
 #include "nsSVGPreserveAspectRatio.h"
 
 //--------------------- Patterns ------------------------
 
 typedef nsSVGStylableElement nsSVGPatternElementBase;
 
 class nsSVGPatternElement : public nsSVGPatternElementBase,
                             public nsIDOMSVGURIReference,
@@ -88,16 +89,17 @@ public:
   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* name) const;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
 protected:
 
   virtual LengthAttributesInfo GetLengthInfo();
   virtual EnumAttributesInfo GetEnumInfo();
+  virtual nsSVGViewBox *GetViewBox();
   virtual nsSVGPreserveAspectRatio *GetPreserveAspectRatio();
   virtual StringAttributesInfo GetStringInfo();
 
   // nsIDOMSVGPatternElement values
   enum { X, Y, WIDTH, HEIGHT };
   nsSVGLength2 mLengthAttributes[4];
   static LengthInfo sLengthInfo[4];
 
@@ -108,13 +110,13 @@ protected:
   nsCOMPtr<nsIDOMSVGAnimatedTransformList> mPatternTransform;
 
   // nsIDOMSVGURIReference properties
   enum { HREF };
   nsSVGString mStringAttributes[1];
   static StringInfo sStringInfo[1];
 
   // nsIDOMSVGFitToViewbox properties
-  nsCOMPtr<nsIDOMSVGAnimatedRect> mViewBox;
+  nsSVGViewBox mViewBox;
   nsSVGPreserveAspectRatio mPreserveAspectRatio;
 };
 
 #endif
--- a/content/svg/content/src/nsSVGRect.cpp
+++ b/content/svg/content/src/nsSVGRect.cpp
@@ -51,177 +51,86 @@
 //----------------------------------------------------------------------
 // implementation:
 
 nsSVGRect::nsSVGRect(float x, float y, float w, float h)
     : mX(x), mY(y), mWidth(w), mHeight(h)
 {
 }
 
-void
-nsSVGRect::Clear()
-{
-  mX = mY = mWidth = mHeight = 0.0f;
-}
-
 //----------------------------------------------------------------------
 // nsISupports methods:
 
 NS_IMPL_ADDREF(nsSVGRect)
 NS_IMPL_RELEASE(nsSVGRect)
 
 NS_INTERFACE_MAP_BEGIN(nsSVGRect)
-  NS_INTERFACE_MAP_ENTRY(nsISVGValue)
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGRect)
   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGRect)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 //----------------------------------------------------------------------
-// nsISVGValue methods:
-
-NS_IMETHODIMP
-nsSVGRect::SetValueString(const nsAString& aValue)
-{
-  nsresult rv = NS_OK;
-
-  char* str = ToNewCString(aValue);
-
-  char* rest = str;
-  char* token;
-  const char* delimiters = ",\x20\x9\xD\xA";
-
-  double vals[4];
-  int i;
-  for (i=0;i<4;++i) {
-    if (!(token = nsCRT::strtok(rest, delimiters, &rest))) break; // parse error
-
-    char *end;
-    vals[i] = PR_strtod(token, &end);
-    if (*end != '\0') break; // parse error
-  }
-  if (i!=4 || (nsCRT::strtok(rest, delimiters, &rest)!=0)) {
-    // there was a parse error.
-    rv = NS_ERROR_FAILURE;
-  }
-  else {
-    WillModify();
-    mX      = float(vals[0]);
-    mY      = float(vals[1]);
-    mWidth  = float(vals[2]);
-    mHeight = float(vals[3]);
-    DidModify();
-  }
-
-  nsMemory::Free(str);
-
-  return rv;
-}
-
-NS_IMETHODIMP
-nsSVGRect::GetValueString(nsAString& aValue)
-{
-  PRUnichar buf[200];
-  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
-                            NS_LITERAL_STRING("%g %g %g %g").get(),
-                            (double)mX, (double)mY,
-                            (double)mWidth, (double)mHeight);
-  aValue.Assign(buf);
-
-  return NS_OK;
-}
-
-//----------------------------------------------------------------------
 // nsIDOMSVGRect methods:
 
 /* attribute float x; */
 NS_IMETHODIMP nsSVGRect::GetX(float *aX)
 {
   *aX = mX;
   return NS_OK;
 }
 NS_IMETHODIMP nsSVGRect::SetX(float aX)
 {
   NS_ENSURE_FINITE(aX, NS_ERROR_ILLEGAL_VALUE);
-  WillModify();
   mX = aX;
-  DidModify();
   return NS_OK;
 }
 
 /* attribute float y; */
 NS_IMETHODIMP nsSVGRect::GetY(float *aY)
 {
   *aY = mY;
   return NS_OK;
 }
 NS_IMETHODIMP nsSVGRect::SetY(float aY)
 {
   NS_ENSURE_FINITE(aY, NS_ERROR_ILLEGAL_VALUE);
-  WillModify();
   mY = aY;
-  DidModify();
   return NS_OK;
 }
 
 /* attribute float width; */
 NS_IMETHODIMP nsSVGRect::GetWidth(float *aWidth)
 {
   *aWidth = mWidth;
   return NS_OK;
 }
 NS_IMETHODIMP nsSVGRect::SetWidth(float aWidth)
 {
   NS_ENSURE_FINITE(aWidth, NS_ERROR_ILLEGAL_VALUE);
-  WillModify();
   mWidth = aWidth;
-  DidModify();
   return NS_OK;
 }
 
 /* attribute float height; */
 NS_IMETHODIMP nsSVGRect::GetHeight(float *aHeight)
 {
   *aHeight = mHeight;
   return NS_OK;
 }
 NS_IMETHODIMP nsSVGRect::SetHeight(float aHeight)
 {
   NS_ENSURE_FINITE(aHeight, NS_ERROR_ILLEGAL_VALUE);
-  WillModify();
   mHeight = aHeight;
-  DidModify();
   return NS_OK;
 }
 
 
 
 ////////////////////////////////////////////////////////////////////////
-// Implement a readonly version of SVGRect
-//
-// We need this because attributes of some SVG interfaces *and* the objects the
-// attributes refer to (including SVGRects) are supposed to be readonly
-
-class nsSVGReadonlyRect : public nsSVGRect
-{
-public:
-  nsSVGReadonlyRect(float x, float y, float width, float height)
-    : nsSVGRect(x, y, width, height)
-  {
-  }
-
-  // override setters to make the whole object readonly
-  NS_IMETHODIMP SetX(float) { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
-  NS_IMETHODIMP SetY(float) { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
-  NS_IMETHODIMP SetWidth(float) { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
-  NS_IMETHODIMP SetHeight(float) { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
-  NS_IMETHODIMP SetValueString(const nsAString&) { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
-};
-
-////////////////////////////////////////////////////////////////////////
 // Exported creation functions:
 
 nsresult
 NS_NewSVGRect(nsIDOMSVGRect** result, float x, float y,
               float width, float height)
 {
   *result = new nsSVGRect(x, y, width, height);
   if (!*result) return NS_ERROR_OUT_OF_MEMORY;
@@ -232,18 +141,8 @@ NS_NewSVGRect(nsIDOMSVGRect** result, fl
 nsresult
 NS_NewSVGRect(nsIDOMSVGRect** result, const gfxRect& rect)
 {
   return NS_NewSVGRect(result,
                        rect.X(), rect.Y(),
                        rect.Width(), rect.Height());
 }
 
-nsresult
-NS_NewSVGReadonlyRect(nsIDOMSVGRect** result, float x, float y,
-                      float width, float height)
-{
-  *result = new nsSVGReadonlyRect(x, y, width, height);
-  if (!*result) return NS_ERROR_OUT_OF_MEMORY;
-  NS_ADDREF(*result);
-  return NS_OK;
-}
-
--- a/content/svg/content/src/nsSVGRect.h
+++ b/content/svg/content/src/nsSVGRect.h
@@ -47,39 +47,27 @@
 nsresult
 NS_NewSVGRect(nsIDOMSVGRect** result,
               float x=0.0f, float y=0.0f,
               float width=0.0f, float height=0.0f);
 
 nsresult
 NS_NewSVGRect(nsIDOMSVGRect** result, const gfxRect& rect);
 
-nsresult
-NS_NewSVGReadonlyRect(nsIDOMSVGRect** result,
-                      float x=0.0f, float y=0.0f,
-                      float width=0.0f, float height=0.0f);
-
 ////////////////////////////////////////////////////////////////////////
 // nsSVGRect class
 
-class nsSVGRect : public nsIDOMSVGRect,
-                  public nsSVGValue
+class nsSVGRect : public nsIDOMSVGRect
 {
 public:
   nsSVGRect(float x=0.0f, float y=0.0f, float w=0.0f, float h=0.0f);
 
   // nsISupports interface:
   NS_DECL_ISUPPORTS
 
   // nsIDOMSVGRect interface:
   NS_DECL_NSIDOMSVGRECT
 
-  // nsISVGValue interface:
-  NS_IMETHOD SetValueString(const nsAString& aValue);
-  NS_IMETHOD GetValueString(nsAString& aValue);
-
-  void Clear();
-
 protected:
   float mX, mY, mWidth, mHeight;
 };
 
 #endif //__NS_SVGRECT_H__
--- a/content/svg/content/src/nsSVGSVGElement.cpp
+++ b/content/svg/content/src/nsSVGSVGElement.cpp
@@ -41,27 +41,25 @@
 #include "nsGkAtoms.h"
 #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 "nsSVGMatrix.h"
 #include "nsSVGPoint.h"
 #include "nsSVGTransform.h"
 #include "nsIDOMEventTarget.h"
 #include "nsBindingManager.h"
 #include "nsIFrame.h"
 #include "nsISVGSVGFrame.h" //XXX
 #include "nsSVGNumber.h"
 #include "nsSVGRect.h"
-#include "nsSVGPreserveAspectRatio.h"
 #include "nsISVGValueUtils.h"
 #include "nsDOMError.h"
 #include "nsISVGChildFrame.h"
 #include "nsGUIEvent.h"
 #include "nsSVGUtils.h"
 #include "nsSVGSVGElement.h"
 
 #ifdef MOZ_SMIL
@@ -149,43 +147,22 @@ nsSVGSVGElement::nsSVGSVGElement(nsINode
     mRedrawSuspendCount(0),
     mDispatchEvent(PR_FALSE)
 #ifdef MOZ_SMIL
     ,mStartAnimationOnBindToTree(!aFromParser)
 #endif // MOZ_SMIL
 {
 }
 
-nsSVGSVGElement::~nsSVGSVGElement()
-{
-  if (mViewBox) {
-    NS_REMOVE_SVGVALUE_OBSERVER(mViewBox);
-  }
-}
-
-  
 nsresult
 nsSVGSVGElement::Init()
 {
   nsresult rv = nsSVGSVGElementBase::Init();
   NS_ENSURE_SUCCESS(rv,rv);
   
-  // nsIDOMSVGFitToViewBox attributes ------:
-  
-  // DOM property: viewBox , #IMPLIED attrib: viewBox
-  {
-    nsCOMPtr<nsIDOMSVGRect> viewbox;
-    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: currentScale
   {
     rv = NS_NewSVGNumber(getter_AddRefs(mCurrentScale), 1.0f);
     NS_ENSURE_SUCCESS(rv,rv);
     NS_ADD_SVGVALUE_OBSERVER(mCurrentScale);
   }
 
   // DOM property: currentTranslate
@@ -723,19 +700,17 @@ nsSVGSVGElement::GetElementById(const ns
 
 //----------------------------------------------------------------------
 // nsIDOMSVGFitToViewBox methods
 
 /* readonly attribute nsIDOMSVGAnimatedRect viewBox; */
 NS_IMETHODIMP
 nsSVGSVGElement::GetViewBox(nsIDOMSVGAnimatedRect * *aViewBox)
 {
-  *aViewBox = mViewBox;
-  NS_ADDREF(*aViewBox);
-  return NS_OK;
+  return mViewBox.ToDOMAnimatedRect(aViewBox, this);
 }
 
 /* readonly attribute nsIDOMSVGAnimatedPreserveAspectRatio preserveAspectRatio; */
 NS_IMETHODIMP
 nsSVGSVGElement::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
                                         **aPreserveAspectRatio)
 {
   return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(aPreserveAspectRatio, this);
@@ -1191,46 +1166,16 @@ nsSVGSVGElement::IsAttributeMapped(const
     sTextContentElementsMap,
     sViewportsMap
   };
 
   return FindAttributeDependence(name, map, NS_ARRAY_LENGTH(map)) ||
     nsSVGSVGElementBase::IsAttributeMapped(name);
 }
 
-nsresult
-nsSVGSVGElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                              const nsAString* aValue, PRBool aNotify)
-{
-  nsSVGSVGElementBase::AfterSetAttr(aNameSpaceID, aName, aValue, aNotify);
-
-  // We need to do this here because the calling
-  // InvalidateTransformNotifyFrame in DidModifySVGObservable would
-  // happen too early, before HasAttr(viewBox) returns true (important
-  // in the case of adding a viewBox)
-  if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::viewBox) {
-    InvalidateTransformNotifyFrame();
-  }
-
-  return NS_OK;
-}
-
-nsresult
-nsSVGSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
-                           PRBool aNotify)
-{
-  nsSVGSVGElementBase::UnsetAttr(aNamespaceID, aName, aNotify);
-
-  if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::viewBox) {
-    InvalidateTransformNotifyFrame();
-  }
-
-  return NS_OK;
-}
-
 //----------------------------------------------------------------------
 // nsIContent methods:
 
 #ifdef MOZ_SMIL
 nsresult
 nsSVGSVGElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   if (aVisitor.mEvent->message == NS_SVG_LOAD) {
@@ -1286,37 +1231,32 @@ nsSVGSVGElement::DidModifySVGObservable 
       nsEventStatus status = nsEventStatus_eIgnore;
       nsGUIEvent event(PR_TRUE, NS_SVG_ZOOM, 0);
       event.eventStructType = NS_SVGZOOM_EVENT;
       presShell->HandleDOMEventWithTarget(this, &event, &status);
     }
     else {
       return NS_OK;  // we don't care about currentScale changes on non-root
     }
-  }
-  else {
+  } else {
     nsCOMPtr<nsIDOMSVGPoint> p = do_QueryInterface(observable);
     if (p && p==mCurrentTranslate) {
       if (mDispatchEvent && IsRoot()) {
         nsEventStatus status = nsEventStatus_eIgnore;
         nsEvent event(PR_TRUE, NS_SVG_SCROLL);
         event.eventStructType = NS_SVG_EVENT;
         presShell->HandleDOMEventWithTarget(this, &event, &status);
       }
       else {
         return NS_OK;  // we don't care about currentScale changes on non-root
       }
     }
   }
 
-  // Deal with viewBox in AfterSetAttr (see comment there for reason)
-  nsCOMPtr<nsIDOMSVGAnimatedRect> r = do_QueryInterface(observable);
-  if (r != mViewBox) {
-    InvalidateTransformNotifyFrame();
-  }
+  InvalidateTransformNotifyFrame();
 
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement overrides
 
 PRBool
@@ -1346,39 +1286,33 @@ nsSVGSVGElement::GetViewboxToViewportTra
     // outer svg
     viewportWidth = mViewportWidth;
     viewportHeight = mViewportHeight;
   } else {
     viewportWidth = mLengthAttributes[WIDTH].GetAnimValue(ctx);
     viewportHeight = mLengthAttributes[HEIGHT].GetAnimValue(ctx);
   }
 
-  float viewboxX, viewboxY, viewboxWidth, viewboxHeight;
+  nsSVGViewBoxRect viewbox;
   if (HasAttr(kNameSpaceID_None, nsGkAtoms::viewBox)) {
-    nsCOMPtr<nsIDOMSVGRect> vb;
-    mViewBox->GetAnimVal(getter_AddRefs(vb));
-    NS_ASSERTION(vb, "could not get viewbox");
-    vb->GetX(&viewboxX);
-    vb->GetY(&viewboxY);
-    vb->GetWidth(&viewboxWidth);
-    vb->GetHeight(&viewboxHeight);
+    viewbox = mViewBox.GetAnimValue();
   } else {
-    viewboxX = viewboxY = 0.0f;
-    viewboxWidth = viewportWidth;
-    viewboxHeight = viewportHeight;
+    viewbox.x = viewbox.y = 0.0f;
+    viewbox.width  = viewportWidth;
+    viewbox.height = viewportHeight;
   }
 
-  if (viewboxWidth <= 0.0f || viewboxHeight <= 0.0f) {
+  if (viewbox.width <= 0.0f || viewbox.height <= 0.0f) {
     return NS_ERROR_FAILURE; // invalid - don't paint element
   }
 
   nsCOMPtr<nsIDOMSVGMatrix> xform =
     nsSVGUtils::GetViewBoxTransform(viewportWidth, viewportHeight,
-                                    viewboxX, viewboxY,
-                                    viewboxWidth, viewboxHeight,
+                                    viewbox.x, viewbox.y,
+                                    viewbox.width, viewbox.height,
                                     mPreserveAspectRatio);
   xform.swap(*_retval);
 
   return NS_OK;
 }
 
 #ifdef MOZ_SMIL
 nsresult
@@ -1517,72 +1451,38 @@ nsSVGSVGElement::InvalidateTransformNoti
     }
 #endif
   }
 }
 
 //----------------------------------------------------------------------
 // nsSVGSVGElement
 
-already_AddRefed<nsIDOMSVGRect>
-nsSVGSVGElement::GetCtxRect()
+float
+nsSVGSVGElement::GetLength(PRUint8 aCtxType)
 {
-  float w, h;
-  nsCOMPtr<nsIDOMSVGRect> vb;
+  float h, w;
+
   if (HasAttr(kNameSpaceID_None, nsGkAtoms::viewBox)) {
-    mViewBox->GetAnimVal(getter_AddRefs(vb));
-    vb->GetWidth(&w);
-    vb->GetHeight(&h);
+    const nsSVGViewBoxRect& viewbox = mViewBox.GetAnimValue();
+    w = viewbox.width;
+    h = viewbox.height;
   } else {
     nsSVGSVGElement *ctx = GetCtx();
     if (ctx) {
       w = mLengthAttributes[WIDTH].GetAnimValue(ctx);
       h = mLengthAttributes[HEIGHT].GetAnimValue(ctx);
     } else {
       w = mViewportWidth;
       h = mViewportHeight;
     }
   }
 
-  if (!vb || w < 0.0f || h < 0.0f) {
-    NS_NewSVGRect(getter_AddRefs(vb), 0, 0, PR_MAX(w, 0.0f), PR_MAX(h, 0.0f));
-  }
-
-  nsIDOMSVGRect *retval = nsnull;
-  vb.swap(retval);
-  return retval;
-}
-
-float
-nsSVGSVGElement::GetLength(PRUint8 aCtxType)
-{
-  float h, w;
-
-  if (HasAttr(kNameSpaceID_None, nsGkAtoms::viewBox)) {
-    nsCOMPtr<nsIDOMSVGRect> vb;
-    mViewBox->GetAnimVal(getter_AddRefs(vb));
-    vb->GetHeight(&h);
-    vb->GetWidth(&w);
-  } else {
-    nsSVGSVGElement *ctx = GetCtx();
-    if (ctx) {
-      w = mLengthAttributes[WIDTH].GetAnimValue(ctx);
-      h = mLengthAttributes[HEIGHT].GetAnimValue(ctx);
-    } else {
-      w = mViewportWidth;
-      h = mViewportHeight;
-    }
-  }
-
-  if (w < 0.0f) {
-    w = 0.0f;
-  }
-  if (h < 0.0f) {
-    h = 0.0f;
-  }
+  w = PR_MAX(w, 0.0f);
+  h = PR_MAX(h, 0.0f);
 
   switch (aCtxType) {
   case nsSVGUtils::X:
     return w;
   case nsSVGUtils::Y:
     return h;
   case nsSVGUtils::XY:
     return float(nsSVGUtils::ComputeNormalizedHypotenuse(w, h));
@@ -1628,16 +1528,30 @@ nsSVGSVGElement::DidChangeEnum(PRUint8 a
 nsSVGElement::EnumAttributesInfo
 nsSVGSVGElement::GetEnumInfo()
 {
   return EnumAttributesInfo(mEnumAttributes, sEnumInfo,
                             NS_ARRAY_LENGTH(sEnumInfo));
 }
 
 void
+nsSVGSVGElement::DidChangeViewBox(PRBool aDoSetAttr)
+{
+  nsSVGSVGElementBase::DidChangeViewBox(aDoSetAttr);
+
+  InvalidateTransformNotifyFrame();
+}
+
+nsSVGViewBox *
+nsSVGSVGElement::GetViewBox()
+{
+  return &mViewBox;
+}
+
+void
 nsSVGSVGElement::DidChangePreserveAspectRatio(PRBool aDoSetAttr)
 {
   nsSVGSVGElementBase::DidChangePreserveAspectRatio(aDoSetAttr);
 
   InvalidateTransformNotifyFrame();
 }
 
 nsSVGPreserveAspectRatio *
--- 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 "nsSVGViewBox.h"
 #include "nsSVGPreserveAspectRatio.h"
 
 #ifdef MOZ_SMIL
 class nsSMILTimeContainer;
 #endif // MOZ_SMIL
 
 #define QI_AND_CAST_TO_NSSVGSVGELEMENT(base)                                  \
   (nsCOMPtr<nsIDOMSVGSVGElement>(do_QueryInterface(base)) ?                   \
@@ -82,17 +83,16 @@ class nsSVGSVGElement : public nsSVGSVGE
   friend class nsSVGOuterSVGFrame;
   friend class nsSVGInnerSVGFrame;
 
 protected:
   friend nsresult NS_NewSVGSVGElement(nsIContent **aResult,
                                       nsINodeInfo *aNodeInfo,
                                       PRBool aFromParser);
   nsSVGSVGElement(nsINodeInfo* aNodeInfo, PRBool aFromParser);
-  virtual ~nsSVGSVGElement();
   nsresult Init();
   
 public:
 
   // interfaces:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMSVGSVGELEMENT
   NS_DECL_NSIDOMSVGFITTOVIEWBOX
@@ -140,47 +140,42 @@ public:
 #endif // MOZ_SMIL
 
   // nsIContent interface
   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
 #ifdef MOZ_SMIL
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
 #endif // MOZ_SMIL
 
-  virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
-                                const nsAString* aValue, PRBool aNotify);
-  virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
-                             PRBool aNotify);
-
   // nsISVGValueObserver
   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 DidChangeViewBox(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);
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
-  svgFloatSize GetViewportSize() {
+  svgFloatSize GetViewportSize() const {
     return svgFloatSize(mViewportWidth, mViewportHeight);
   }
 
-  void SetViewportSize(svgFloatSize& aSize) {
+  void SetViewportSize(const svgFloatSize& aSize) {
     mViewportWidth  = aSize.width;
     mViewportHeight = aSize.height;
   }
 
 protected:
   // nsSVGElement overrides
   PRBool IsEventName(nsIAtom* aName);
 
@@ -226,22 +221,23 @@ protected:
 
   virtual EnumAttributesInfo GetEnumInfo();
 
   enum { ZOOMANDPAN };
   nsSVGEnum mEnumAttributes[1];
   static nsSVGEnumMapping sZoomAndPanMap[];
   static EnumInfo sEnumInfo[1];
 
+  virtual nsSVGViewBox *GetViewBox();
   virtual nsSVGPreserveAspectRatio *GetPreserveAspectRatio();
 
+  nsSVGViewBox             mViewBox;
   nsSVGPreserveAspectRatio mPreserveAspectRatio;
 
   nsSVGSVGElement                  *mCoordCtx;
-  nsCOMPtr<nsIDOMSVGAnimatedRect>   mViewBox;
 
   // 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,35 +31,31 @@
  * 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 "nsSVGViewBox.h"
 #include "nsSVGPreserveAspectRatio.h"
-#include "nsIDOMSVGRect.h"
-#include "nsIDOMSVGLength.h"
 #include "nsIDOMSVGFitToViewBox.h"
-#include "nsSVGRect.h"
-#include "nsSVGAnimatedRect.h"
 #include "nsGkAtoms.h"
 
 typedef nsSVGStylableElement nsSVGSymbolElementBase;
 
 class nsSVGSymbolElement : public nsSVGSymbolElementBase,
                            public nsIDOMSVGFitToViewBox,
                            public nsIDOMSVGSymbolElement
 {
 protected:
   friend nsresult NS_NewSVGSymbolElement(nsIContent **aResult,
                                          nsINodeInfo *aNodeInfo);
   nsSVGSymbolElement(nsINodeInfo* aNodeInfo);
-  nsresult Init();
 
 public:
   // interfaces:
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMSVGSYMBOLELEMENT
   NS_DECL_NSIDOMSVGFITTOVIEWBOX
 
@@ -69,19 +65,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 nsSVGViewBox *GetViewBox();
   virtual nsSVGPreserveAspectRatio *GetPreserveAspectRatio();
 
-  nsCOMPtr<nsIDOMSVGAnimatedRect> mViewBox;
+  nsSVGViewBox mViewBox;
   nsSVGPreserveAspectRatio mPreserveAspectRatio;
 };
 
 NS_IMPL_NS_NEW_SVG_ELEMENT(Symbol)
 
 //----------------------------------------------------------------------
 // nsISupports methods
 
@@ -99,51 +96,28 @@ NS_INTERFACE_MAP_END_INHERITING(nsSVGSym
 // Implementation
 
 nsSVGSymbolElement::nsSVGSymbolElement(nsINodeInfo *aNodeInfo)
   : nsSVGSymbolElementBase(aNodeInfo)
 {
 }
 
 
-nsresult
-nsSVGSymbolElement::Init()
-{
-  nsresult rv = nsSVGSymbolElementBase::Init();
-  NS_ENSURE_SUCCESS(rv,rv);
-
-
-  // DOM property: viewBox
-  {
-    nsCOMPtr<nsIDOMSVGRect> viewbox;
-    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);
-  }
-
-  return NS_OK;
-}
-
 //----------------------------------------------------------------------
 // nsIDOMNode methods
 
 NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGSymbolElement)
 
 //----------------------------------------------------------------------
 // nsIDOMSVGFitToViewBox methods
 
 /* readonly attribute nsIDOMSVGAnimatedRect viewBox; */
 NS_IMETHODIMP nsSVGSymbolElement::GetViewBox(nsIDOMSVGAnimatedRect * *aViewBox)
 {
-  *aViewBox = mViewBox;
-  NS_ADDREF(*aViewBox);
-  return NS_OK;
+  return mViewBox.ToDOMAnimatedRect(aViewBox, this);
 }
 
 /* readonly attribute nsIDOMSVGAnimatedPreserveAspectRatio preserveAspectRatio; */
 NS_IMETHODIMP
 nsSVGSymbolElement::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
                                            **aPreserveAspectRatio)
 {
   return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(aPreserveAspectRatio, this);
@@ -171,13 +145,19 @@ nsSVGSymbolElement::IsAttributeMapped(co
 
   return FindAttributeDependence(name, map, NS_ARRAY_LENGTH(map)) ||
     nsSVGSymbolElementBase::IsAttributeMapped(name);
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
+nsSVGViewBox *
+nsSVGSymbolElement::GetViewBox()
+{
+  return &mViewBox;
+}
+
 nsSVGPreserveAspectRatio *
 nsSVGSymbolElement::GetPreserveAspectRatio()
 {
   return &mPreserveAspectRatio;
 }
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/nsSVGViewBox.cpp
@@ -0,0 +1,223 @@
+/* -*- 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 "nsSVGViewBox.h"
+#include "prdtoa.h"
+#include "nsTextFormatter.h"
+
+NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGViewBox::DOMBaseVal, mSVGElement)
+NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGViewBox::DOMAnimVal, mSVGElement)
+NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGViewBox::DOMAnimatedRect, mSVGElement)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGViewBox::DOMBaseVal)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGViewBox::DOMBaseVal)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGViewBox::DOMAnimVal)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGViewBox::DOMAnimVal)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGViewBox::DOMAnimatedRect)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGViewBox::DOMAnimatedRect)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGViewBox::DOMBaseVal)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGRect)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGRect)
+NS_INTERFACE_MAP_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGViewBox::DOMAnimVal)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGRect)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGRect)
+NS_INTERFACE_MAP_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGViewBox::DOMAnimatedRect)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedRect)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGAnimatedRect)
+NS_INTERFACE_MAP_END
+
+/* Implementation */
+
+void
+nsSVGViewBox::Init()
+{
+  mBaseVal = nsSVGViewBoxRect();
+  mAnimVal = nsnull;
+}
+
+const nsSVGViewBoxRect&
+nsSVGViewBox::GetAnimValue() const
+{
+  if (mAnimVal)
+    return *mAnimVal;
+
+  return mBaseVal;
+}
+
+void
+nsSVGViewBox::SetBaseValue(float aX, float aY, float aWidth, float aHeight,
+                           nsSVGElement *aSVGElement, PRBool aDoSetAttr)
+{
+  mAnimVal = nsnull;
+  mBaseVal.x = aX;
+  mBaseVal.y = aY;
+  mBaseVal.width  = aWidth;
+  mBaseVal.height = aHeight;
+
+  aSVGElement->DidChangeViewBox(aDoSetAttr);
+}
+
+nsresult
+nsSVGViewBox::SetBaseValueString(const nsAString& aValue,
+                                 nsSVGElement *aSVGElement,
+                                 PRBool aDoSetAttr)
+{
+  nsresult rv = NS_OK;
+
+  char *str = ToNewUTF8String(aValue);
+
+  char *rest = str;
+  char *token;
+  const char *delimiters = ",\x20\x9\xD\xA";
+
+  float vals[4];
+  int i;
+  for (i=0;i<4;++i) {
+    if (!(token = nsCRT::strtok(rest, delimiters, &rest))) break; // parse error
+
+    char *end;
+    vals[i] = (float)PR_strtod(token, &end);
+    if (*end != '\0') break; // parse error
+  }
+  if (i!=4 || (nsCRT::strtok(rest, delimiters, &rest)!=0)) {
+    // there was a parse error.
+    rv = NS_ERROR_FAILURE;
+  } else {
+    mAnimVal = nsnull;
+    mBaseVal.x = vals[0];
+    mBaseVal.y = vals[1];
+    mBaseVal.width = vals[2];
+    mBaseVal.height = vals[3];
+  }
+
+  nsMemory::Free(str);
+
+  return rv;
+}
+
+void
+nsSVGViewBox::GetBaseValueString(nsAString& aValue) const
+{
+  PRUnichar buf[200];
+  nsTextFormatter::snprintf(buf, sizeof(buf)/sizeof(PRUnichar),
+                            NS_LITERAL_STRING("%g %g %g %g").get(),
+                            (double)mBaseVal.x, (double)mBaseVal.y,
+                            (double)mBaseVal.width, (double)mBaseVal.height);
+  aValue.Assign(buf);
+}
+
+nsresult
+nsSVGViewBox::ToDOMAnimatedRect(nsIDOMSVGAnimatedRect **aResult,
+                                nsSVGElement* aSVGElement)
+{
+  *aResult = new DOMAnimatedRect(this, aSVGElement);
+  NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
+
+  NS_ADDREF(*aResult);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSVGViewBox::DOMAnimatedRect::GetBaseVal(nsIDOMSVGRect **aResult)
+{
+  *aResult = new nsSVGViewBox::DOMBaseVal(mVal, mSVGElement);
+  NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
+
+  NS_ADDREF(*aResult);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSVGViewBox::DOMAnimatedRect::GetAnimVal(nsIDOMSVGRect **aResult)
+{
+  *aResult = new nsSVGViewBox::DOMAnimVal(mVal, mSVGElement);
+  NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
+
+  NS_ADDREF(*aResult);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSVGViewBox::DOMBaseVal::SetX(float aX)
+{
+  nsSVGViewBoxRect rect = mVal->GetBaseValue();
+  rect.x = aX;
+  mVal->SetBaseValue(rect.x, rect.y, rect.width, rect.height,
+                     mSVGElement, PR_TRUE);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSVGViewBox::DOMBaseVal::SetY(float aY)
+{
+  nsSVGViewBoxRect rect = mVal->GetBaseValue();
+  rect.y = aY;
+  mVal->SetBaseValue(rect.x, rect.y, rect.width, rect.height,
+                     mSVGElement, PR_TRUE);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSVGViewBox::DOMBaseVal::SetWidth(float aWidth)
+{
+  nsSVGViewBoxRect rect = mVal->GetBaseValue();
+  rect.width = aWidth;
+  mVal->SetBaseValue(rect.x, rect.y, rect.width, rect.height,
+                     mSVGElement, PR_TRUE);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSVGViewBox::DOMBaseVal::SetHeight(float aHeight)
+{
+  nsSVGViewBoxRect rect = mVal->GetBaseValue();
+  rect.height = aHeight;
+  mVal->SetBaseValue(rect.x, rect.y, rect.width, rect.height,
+                     mSVGElement, PR_TRUE);
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/content/svg/content/src/nsSVGViewBox.h
@@ -0,0 +1,156 @@
+/* -*- 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_SVGVIEWBOX_H__
+#define __NS_SVGVIEWBOX_H__
+
+#include "nsIDOMSVGRect.h"
+#include "nsIDOMSVGAnimatedRect.h"
+#include "nsSVGElement.h"
+#include "nsDOMError.h"
+
+struct nsSVGViewBoxRect
+{
+  float x, y;
+  float width, height;
+
+  nsSVGViewBoxRect() : x(0), y(0), width(0), height(0) {}
+  nsSVGViewBoxRect(float aX, float aY, float aWidth, float aHeight) :
+    x(aX), y(aY), width(aWidth), height(aHeight) {}
+};
+
+class nsSVGViewBox
+{
+
+public:
+
+  void Init();
+
+  const nsSVGViewBoxRect& GetBaseValue() const
+    { return mBaseVal; }
+  void SetBaseValue(float aX, float aY, float aWidth, float aHeight,
+                    nsSVGElement *aSVGElement, PRBool aDoSetAttr);
+
+  const nsSVGViewBoxRect& GetAnimValue() const;
+
+  nsresult SetBaseValueString(const nsAString& aValue,
+                              nsSVGElement *aSVGElement,
+                              PRBool aDoSetAttr);
+  void GetBaseValueString(nsAString& aValue) const;
+
+  nsresult ToDOMAnimatedRect(nsIDOMSVGAnimatedRect **aResult,
+                             nsSVGElement *aSVGElement);
+
+private:
+
+  nsSVGViewBoxRect mBaseVal;
+  nsAutoPtr<nsSVGViewBoxRect> mAnimVal;
+
+  struct DOMBaseVal : public nsIDOMSVGRect
+  {
+    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+    NS_DECL_CYCLE_COLLECTION_CLASS(DOMBaseVal)
+
+    DOMBaseVal(nsSVGViewBox *aVal, nsSVGElement *aSVGElement)
+      : mVal(aVal), mSVGElement(aSVGElement) {}
+
+    nsSVGViewBox* mVal; // kept alive because it belongs to content
+    nsRefPtr<nsSVGElement> mSVGElement;
+
+    NS_IMETHOD GetX(float *aX)
+      { *aX = mVal->GetBaseValue().x; return NS_OK; }
+    NS_IMETHOD GetY(float *aY)
+      { *aY = mVal->GetBaseValue().y; return NS_OK; }
+    NS_IMETHOD GetWidth(float *aWidth)
+      { *aWidth = mVal->GetBaseValue().width; return NS_OK; }
+    NS_IMETHOD GetHeight(float *aHeight)
+      { *aHeight = mVal->GetBaseValue().height; return NS_OK; }
+
+    NS_IMETHOD SetX(float aX);
+    NS_IMETHOD SetY(float aY);
+    NS_IMETHOD SetWidth(float aWidth);
+    NS_IMETHOD SetHeight(float aHeight);
+  };
+
+  struct DOMAnimVal : public nsIDOMSVGRect
+  {
+    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+    NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimVal)
+
+    DOMAnimVal(nsSVGViewBox *aVal, nsSVGElement *aSVGElement)
+      : mVal(aVal), mSVGElement(aSVGElement) {}
+
+    nsSVGViewBox* mVal; // kept alive because it belongs to content
+    nsRefPtr<nsSVGElement> mSVGElement;
+
+    NS_IMETHOD GetX(float *aX)
+      { *aX = mVal->GetAnimValue().x; return NS_OK; }
+    NS_IMETHOD GetY(float *aY)
+      { *aY = mVal->GetAnimValue().y; return NS_OK; }
+    NS_IMETHOD GetWidth(float *aWidth)
+      { *aWidth = mVal->GetAnimValue().width; return NS_OK; }
+    NS_IMETHOD GetHeight(float *aHeight)
+      { *aHeight = mVal->GetAnimValue().height; return NS_OK; }
+
+    NS_IMETHOD SetX(float aX)
+      { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
+    NS_IMETHOD SetY(float aY)
+      { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
+    NS_IMETHOD SetWidth(float aWidth)
+      { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
+    NS_IMETHOD SetHeight(float aHeight)
+      { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
+  };
+
+  struct DOMAnimatedRect : public nsIDOMSVGAnimatedRect
+  {
+    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+    NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimatedRect)
+
+    DOMAnimatedRect(nsSVGViewBox *aVal, nsSVGElement *aSVGElement)
+      : mVal(aVal), mSVGElement(aSVGElement) {}
+
+    nsSVGViewBox* mVal; // kept alive because it belongs to content
+    nsRefPtr<nsSVGElement> mSVGElement;
+
+    NS_IMETHOD GetBaseVal(nsIDOMSVGRect **aResult);
+    NS_IMETHOD GetAnimVal(nsIDOMSVGRect **aResult);
+  };
+};
+
+#endif // __NS_SVGVIEWBOX_H__
--- a/content/svg/content/test/test_dataTypes.html
+++ b/content/svg/content/test/test_dataTypes.html
@@ -137,16 +137,54 @@ function runTests()
   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");
 
+  // viewBox attribute
+  var baseViewBox = marker.viewBox.baseVal;
+  var animViewBox = marker.viewBox.animVal;
+  is(baseViewBox.x, 0, "viewBox baseVal");
+  is(animViewBox.x, 0, "viewBox baseVal");
+  is(baseViewBox.y, 0, "viewBox baseVal");
+  is(animViewBox.y, 0, "viewBox baseVal");
+  is(baseViewBox.width, 0, "viewBox baseVal");
+  is(animViewBox.width, 0, "viewBox baseVal");
+  is(baseViewBox.height, 0, "viewBox baseVal");
+  is(animViewBox.height, 0, "viewBox baseVal");
+  baseViewBox.x = 10;
+  baseViewBox.y = 11;
+  baseViewBox.width = 12;
+  baseViewBox.height = 13;
+  is(marker.getAttribute("viewBox"), "10 11 12 13", "viewBox attribute");
+
+  marker.setAttribute("viewBox", "1 2 3 4");
+  is(marker.viewBox.baseVal.x, 1, "viewBox.x baseVal");
+  is(marker.viewBox.animVal.x, 1, "viewBox.x animVal");
+  is(marker.viewBox.baseVal.y, 2, "viewbox.y baseVal");
+  is(marker.viewBox.animVal.y, 2, "viewbox.y animVal");
+  is(marker.viewBox.baseVal.width, 3, "viewbox.width baseVal");
+  is(marker.viewBox.animVal.width, 3, "viewbox.width animVal");
+  is(marker.viewBox.baseVal.height, 4, "viewbox.heigth baseVal");
+  is(marker.viewBox.animVal.height, 4, "viewbox.heigth animVal");
+  marker.viewBox.baseVal.x = 5;
+  is(marker.viewBox.animVal.x, 5, "viewBox.x animVal");
+  marker.viewBox.baseVal.y = 6;
+  is(marker.viewBox.animVal.y, 6, "viewBox.y animVal");
+  marker.viewBox.baseVal.width = 7;
+  is(marker.viewBox.animVal.width, 7, "viewBox.width animVal");
+  marker.viewBox.baseVal.height = 8;
+  is(marker.viewBox.animVal.height, 8, "viewBox.height animVal");
+  is(marker.getAttribute("viewBox"), "5 6 7 8", "viewBox attribute");
+  marker.removeAttribute("viewBox");
+  is(marker.hasAttribute("viewBox"), false, "viewBox hasAttribute");
+
   SimpleTest.finish();
 }
 
 window.addEventListener("load", runTests, false);
 </script>
 </pre>
 </body>
 </html>
--- a/layout/svg/base/src/nsSVGOuterSVGFrame.cpp
+++ b/layout/svg/base/src/nsSVGOuterSVGFrame.cpp
@@ -36,22 +36,20 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsSVGOuterSVGFrame.h"
 #include "nsIDOMSVGSVGElement.h"
 #include "nsSVGSVGElement.h"
 #include "nsSVGTextFrame.h"
 #include "nsSVGForeignObjectFrame.h"
-#include "nsSVGRect.h"
 #include "nsDisplayList.h"
 #include "nsStubMutationObserver.h"
 #include "gfxContext.h"
 #include "nsPresShellIterator.h"
-#include "nsIDOMSVGAnimatedRect.h"
 #include "nsIContentViewer.h"
 #include "nsIDocShell.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMWindowInternal.h"
 #include "nsPIDOMWindow.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsSVGMatrix.h"
@@ -290,21 +288,20 @@ nsSVGOuterSVGFrame::GetIntrinsicRatio()
       ratio.height = 0;
     }
     return ratio;
   }
 
   if (content->HasAttr(kNameSpaceID_None, nsGkAtoms::viewBox)) {
     // XXXjwatt we need to fix our viewBox code so that we can tell whether the
     // viewBox attribute specifies a valid rect or not.
-    float viewBoxWidth, viewBoxHeight;
-    nsCOMPtr<nsIDOMSVGRect> viewBox;
-    content->mViewBox->GetAnimVal(getter_AddRefs(viewBox));
-    viewBox->GetWidth(&viewBoxWidth);
-    viewBox->GetHeight(&viewBoxHeight);
+    const nsSVGViewBoxRect viewbox = content->mViewBox.GetAnimValue();
+    float viewBoxWidth = viewbox.width;
+    float viewBoxHeight = viewbox.height;
+
     if (viewBoxWidth < 0.0f) {
       viewBoxWidth = 0.0f;
     }
     if (viewBoxHeight < 0.0f) {
       viewBoxHeight = 0.0f;
     }
     return nsSize(viewBoxWidth, viewBoxHeight);
   }
--- a/layout/svg/base/src/nsSVGPatternFrame.cpp
+++ b/layout/svg/base/src/nsSVGPatternFrame.cpp
@@ -378,58 +378,56 @@ nsSVGPatternFrame::GetPatternTransform()
   nsCOMPtr<nsIDOMSVGMatrix> patternTransform =
     nsSVGTransformList::GetConsolidationMatrix(lTrans);
   if (patternTransform) {
     matrix = nsSVGUtils::ConvertSVGMatrixToThebes(patternTransform);
   }
   return matrix;
 }
 
-NS_IMETHODIMP
-nsSVGPatternFrame::GetViewBox(nsIDOMSVGRect **aViewBox)
+const nsSVGViewBox &
+nsSVGPatternFrame::GetViewBox()
 {
   nsSVGPatternElement *patternElement =
     GetPatternWithAttr(nsGkAtoms::viewBox, mContent);
 
-  nsCOMPtr<nsIDOMSVGAnimatedRect> viewBox;
-  patternElement->GetViewBox(getter_AddRefs(viewBox));
-  return viewBox->GetAnimVal(aViewBox);
+  return patternElement->mViewBox;
 }
 
 const nsSVGPreserveAspectRatio &
 nsSVGPatternFrame::GetPreserveAspectRatio()
 {
   nsSVGPatternElement *patternElement =
     GetPatternWithAttr(nsGkAtoms::preserveAspectRatio, mContent);
 
   return patternElement->mPreserveAspectRatio;
 }
 
-nsSVGLength2 *
+const nsSVGLength2 *
 nsSVGPatternFrame::GetX()
 {
   nsSVGPatternElement *pattern = GetPatternWithAttr(nsGkAtoms::x, mContent);
   return &pattern->mLengthAttributes[nsSVGPatternElement::X];
 }
 
-nsSVGLength2 *
+const nsSVGLength2 *
 nsSVGPatternFrame::GetY()
 {
   nsSVGPatternElement *pattern = GetPatternWithAttr(nsGkAtoms::y, mContent);
   return &pattern->mLengthAttributes[nsSVGPatternElement::Y];
 }
 
-nsSVGLength2 *
+const nsSVGLength2 *
 nsSVGPatternFrame::GetWidth()
 {
   nsSVGPatternElement *pattern = GetPatternWithAttr(nsGkAtoms::width, mContent);
   return &pattern->mLengthAttributes[nsSVGPatternElement::WIDTH];
 }
 
-nsSVGLength2 *
+const nsSVGLength2 *
 nsSVGPatternFrame::GetHeight()
 {
   nsSVGPatternElement *pattern = GetPatternWithAttr(nsGkAtoms::height, mContent);
   return &pattern->mLengthAttributes[nsSVGPatternElement::HEIGHT];
 }
 
 // Private (helper) methods
 nsSVGPatternFrame *
@@ -509,17 +507,17 @@ nsSVGPatternFrame::GetPatternRect(nsIDOM
 {
   // Get our type
   PRUint16 type = GetPatternUnits();
 
   // We need to initialize our box
   float x,y,width,height;
 
   // Get the pattern x,y,width, and height
-  nsSVGLength2 *tmpX, *tmpY, *tmpHeight, *tmpWidth;
+  const nsSVGLength2 *tmpX, *tmpY, *tmpHeight, *tmpWidth;
   tmpX = GetX();
   tmpY = GetY();
   tmpHeight = GetHeight();
   tmpWidth = GetWidth();
 
   if (type == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
     x = nsSVGUtils::ObjectSpace(bbox, tmpX);
     y = nsSVGUtils::ObjectSpace(bbox, tmpY);
@@ -532,17 +530,17 @@ nsSVGPatternFrame::GetPatternRect(nsIDOM
     width = nsSVGUtils::UserSpace(content, tmpWidth) * scale;
     height = nsSVGUtils::UserSpace(content, tmpHeight) * scale;
   }
 
   return NS_NewSVGRect(patternRect, x, y, width, height);
 }
 
 static float
-GetLengthValue(nsSVGLength2 *aLength)
+GetLengthValue(const nsSVGLength2 *aLength)
 {
   return aLength->GetAnimValue(static_cast<nsSVGSVGElement*>(nsnull));
 }
 
 nsresult
 nsSVGPatternFrame::ConstructCTM(nsIDOMSVGMatrix **aCTM,
                                 nsIDOMSVGRect *callerBBox,
                                 nsIDOMSVGMatrix *callerCTM)
@@ -560,36 +558,28 @@ nsSVGPatternFrame::ConstructCTM(nsIDOMSV
     callerBBox->GetHeight(&height);
     NS_NewSVGMatrix(getter_AddRefs(tCTM), width, 0.0f, 0.0f,
                     height, 0.0f, 0.0f);
   } else {
     float scale = nsSVGUtils::MaxExpansion(callerCTM);
     NS_NewSVGMatrix(getter_AddRefs(tCTM), scale, 0, 0, scale, 0, 0);
   }
 
-  // Do we have a viewbox?
-  nsCOMPtr<nsIDOMSVGRect> viewRect;
-  GetViewBox(getter_AddRefs(viewRect));
+  const nsSVGViewBoxRect viewBox = GetViewBox().GetAnimValue();
 
-  // See if we really have something
-  float viewBoxX, viewBoxY, viewBoxHeight, viewBoxWidth;
-  viewRect->GetX(&viewBoxX);
-  viewRect->GetY(&viewBoxY);
-  viewRect->GetHeight(&viewBoxHeight);
-  viewRect->GetWidth(&viewBoxWidth);
-  if (viewBoxHeight > 0.0f && viewBoxWidth > 0.0f) {
+  if (viewBox.height > 0.0f && viewBox.width > 0.0f) {
 
     float viewportWidth = GetLengthValue(GetWidth());
     float viewportHeight = GetLengthValue(GetHeight());
     float refX = GetLengthValue(GetX());
     float refY = GetLengthValue(GetY());
 
     tempTM = nsSVGUtils::GetViewBoxTransform(viewportWidth, viewportHeight,
-                                             viewBoxX + refX, viewBoxY + refY,
-                                             viewBoxWidth, viewBoxHeight,
+                                             viewBox.x + refX, viewBox.y + refY,
+                                             viewBox.width, viewBox.height,
                                              GetPreserveAspectRatio(),
                                              PR_TRUE);
 
   } else {
     // No viewBox, construct from the (modified) parent matrix
     NS_NewSVGMatrix(getter_AddRefs(tempTM));
   }
   tCTM->Multiply(tempTM, aCTM);
--- a/layout/svg/base/src/nsSVGPatternFrame.h
+++ b/layout/svg/base/src/nsSVGPatternFrame.h
@@ -110,29 +110,29 @@ protected:
   // Internal methods for handling referenced patterns
   nsSVGPatternFrame* GetReferencedPattern();
   // Helper to look at our pattern and then along its reference chain (if any)
   // to find the first pattern with the specified attribute. Returns
   // null if there isn't one.
   nsSVGPatternElement* GetPatternWithAttr(nsIAtom *aAttrName, nsIContent *aDefault);
 
   //
-  nsSVGLength2 *GetX();
-  nsSVGLength2 *GetY();
-  nsSVGLength2 *GetWidth();
-  nsSVGLength2 *GetHeight();
+  const nsSVGLength2 *GetX();
+  const nsSVGLength2 *GetY();
+  const nsSVGLength2 *GetWidth();
+  const nsSVGLength2 *GetHeight();
 
   PRUint16 GetPatternUnits();
   PRUint16 GetPatternContentUnits();
   gfxMatrix GetPatternTransform();
 
+  const nsSVGViewBox &GetViewBox();
   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,
                               nsIDOMSVGMatrix *callerCTM);
   nsresult   ConstructCTM(nsIDOMSVGMatrix **ctm,