Merge backout.
authorMs2ger <ms2ger@gmail.com>
Sun, 05 May 2013 10:10:18 +0200
changeset 141833 46e41b0f0674b5321eae4fa9c09d475273aa62d2
parent 141832 397ed6df2ad65af9e5d30b318cb3d12fd5ca9998 (current diff)
parent 141831 745a6846cf43d157f368a3621724b062e521ddff (diff)
child 141834 dc4345aeb64cf3b3aa2c3f14aac3697d2ece71c3
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone23.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge backout.
--- a/content/svg/content/src/SVGFragmentIdentifier.cpp
+++ b/content/svg/content/src/SVGFragmentIdentifier.cpp
@@ -6,109 +6,127 @@
 #include "SVGFragmentIdentifier.h"
 #include "mozilla/dom/SVGSVGElement.h"
 #include "mozilla/dom/SVGViewElement.h"
 #include "nsSVGAnimatedTransformList.h"
 
 using namespace mozilla;
 
 static bool
-IsMatchingParameter(const nsAString &aString, const nsAString &aParameterName)
+IsMatchingParameter(const nsAString& aString, const nsAString& aParameterName)
 {
   // The first two tests ensure aString.Length() > aParameterName.Length()
   // so it's then safe to do the third test
   return StringBeginsWith(aString, aParameterName) &&
          aString.Last() == ')' &&
          aString.CharAt(aParameterName.Length()) == '(';
 }
 
 inline bool
 IgnoreWhitespace(PRUnichar aChar)
 {
   return false;
 }
 
 static dom::SVGViewElement*
-GetViewElement(nsIDocument *aDocument, const nsAString &aId)
+GetViewElement(nsIDocument* aDocument, const nsAString& aId)
 {
   dom::Element* element = aDocument->GetElementById(aId);
   return (element && element->IsSVG(nsGkAtoms::view)) ?
             static_cast<dom::SVGViewElement*>(element) : nullptr;
 }
 
 void
-SVGFragmentIdentifier::SaveOldPreserveAspectRatio(dom::SVGSVGElement *root)
+SVGFragmentIdentifier::SaveOldPreserveAspectRatio(dom::SVGSVGElement* root)
 {
   if (root->mPreserveAspectRatio.IsExplicitlySet()) {
     root->SetPreserveAspectRatioProperty(root->mPreserveAspectRatio.GetBaseValue());
   }
 }
 
 void 
-SVGFragmentIdentifier::RestoreOldPreserveAspectRatio(dom::SVGSVGElement *root)
+SVGFragmentIdentifier::RestoreOldPreserveAspectRatio(dom::SVGSVGElement* root)
 {
-  const SVGPreserveAspectRatio *oldPARPtr = root->GetPreserveAspectRatioProperty();
+  const SVGPreserveAspectRatio* oldPARPtr = root->GetPreserveAspectRatioProperty();
   if (oldPARPtr) {
     root->mPreserveAspectRatio.SetBaseValue(*oldPARPtr, root);
   } else if (root->mPreserveAspectRatio.IsExplicitlySet()) {
     mozilla::ErrorResult error;
     root->RemoveAttribute(NS_LITERAL_STRING("preserveAspectRatio"), error);
   }
 }
 
 void 
-SVGFragmentIdentifier::SaveOldViewBox(dom::SVGSVGElement *root)
+SVGFragmentIdentifier::SaveOldViewBox(dom::SVGSVGElement* root)
 {
   if (root->mViewBox.IsExplicitlySet()) {
     root->SetViewBoxProperty(root->mViewBox.GetBaseValue());
   }
 }
 
 void 
-SVGFragmentIdentifier::RestoreOldViewBox(dom::SVGSVGElement *root)
+SVGFragmentIdentifier::RestoreOldViewBox(dom::SVGSVGElement* root)
 {
-  const nsSVGViewBoxRect *oldViewBoxPtr = root->GetViewBoxProperty();
+  const nsSVGViewBoxRect* oldViewBoxPtr = root->GetViewBoxProperty();
   if (oldViewBoxPtr) {
     root->mViewBox.SetBaseValue(*oldViewBoxPtr, root);
   } else if (root->mViewBox.IsExplicitlySet()) {
     mozilla::ErrorResult error;
     root->RemoveAttribute(NS_LITERAL_STRING("viewBox"), error);
   }
 }
 
 void 
-SVGFragmentIdentifier::SaveOldZoomAndPan(dom::SVGSVGElement *root)
+SVGFragmentIdentifier::SaveOldZoomAndPan(dom::SVGSVGElement* root)
 {
   if (root->mEnumAttributes[dom::SVGSVGElement::ZOOMANDPAN].IsExplicitlySet()) {
     root->SetZoomAndPanProperty(root->mEnumAttributes[dom::SVGSVGElement::ZOOMANDPAN].GetBaseValue());
   }
 }
 
 void
-SVGFragmentIdentifier::RestoreOldZoomAndPan(dom::SVGSVGElement *root)
+SVGFragmentIdentifier::RestoreOldZoomAndPan(dom::SVGSVGElement* root)
 {
   uint16_t oldZoomAndPan = root->GetZoomAndPanProperty();
   if (oldZoomAndPan != SVG_ZOOMANDPAN_UNKNOWN) {
     root->mEnumAttributes[dom::SVGSVGElement::ZOOMANDPAN].SetBaseValue(oldZoomAndPan, root);
   } else if (root->mEnumAttributes[dom::SVGSVGElement::ZOOMANDPAN].IsExplicitlySet()) {
     mozilla::ErrorResult error;
     root->RemoveAttribute(NS_LITERAL_STRING("zoomAndPan"), error);
   }
 }
 
 void 
-SVGFragmentIdentifier::ClearTransform(dom::SVGSVGElement *root)
+SVGFragmentIdentifier::SaveOldTransform(dom::SVGSVGElement* root)
 {
-  root->mFragmentIdentifierTransform = nullptr;
-  root->InvalidateTransformNotifyFrame();
+  nsSVGAnimatedTransformList* transformList = root->GetAnimatedTransformList();
+
+  if (transformList && transformList->IsExplicitlySet()) {
+    root->SetTransformProperty(transformList->GetBaseValue());
+  }
+}
+
+void 
+SVGFragmentIdentifier::RestoreOldTransform(dom::SVGSVGElement* root)
+{
+  const SVGTransformList* oldTransformPtr = root->GetTransformProperty();
+  if (oldTransformPtr) {
+    root->GetAnimatedTransformList(nsSVGElement::DO_ALLOCATE)->SetBaseValue(*oldTransformPtr);
+  } else {
+    nsSVGAnimatedTransformList* transformList = root->GetAnimatedTransformList();
+    if (transformList && transformList->IsExplicitlySet()) {
+      mozilla::ErrorResult error;
+      root->RemoveAttribute(NS_LITERAL_STRING("transform"), error);
+    }
+  }
 }
 
 bool
-SVGFragmentIdentifier::ProcessSVGViewSpec(const nsAString &aViewSpec,
-                                          dom::SVGSVGElement *root)
+SVGFragmentIdentifier::ProcessSVGViewSpec(const nsAString& aViewSpec,
+                                          dom::SVGSVGElement* root)
 {
   if (!IsMatchingParameter(aViewSpec, NS_LITERAL_STRING("svgView"))) {
     return false;
   }
 
   // SVGViewAttributes may occur in any order, but each type may only occur
   // at most one time in a correctly formed SVGViewSpec.
   // If we encounter any attribute more than once or get any syntax errors
@@ -151,37 +169,31 @@ SVGFragmentIdentifier::ProcessSVGViewSpe
     } else if (IsMatchingParameter(token, NS_LITERAL_STRING("preserveAspectRatio"))) {
       if (preserveAspectRatioFound ||
           NS_FAILED(root->mPreserveAspectRatio.SetBaseValueString(
                       params, root, true))) {
         return false;
       }
       preserveAspectRatioFound = true;
     } else if (IsMatchingParameter(token, NS_LITERAL_STRING("transform"))) {
-      nsSVGAnimatedTransformList transforms;
       if (transformFound ||
-          NS_FAILED(transforms.SetBaseValueString(params))) {
+          NS_FAILED(root->GetAnimatedTransformList(nsSVGElement::DO_ALLOCATE)->
+                      SetBaseValueString(params))) {
         return false;
       }
-      if (!root->mFragmentIdentifierTransform) {
-        root->mFragmentIdentifierTransform = new gfxMatrix();
-      }
-      *root->mFragmentIdentifierTransform =
-        transforms.GetBaseValue().GetConsolidationMatrix();
-      root->InvalidateTransformNotifyFrame();
       transformFound = true;
     } else if (IsMatchingParameter(token, NS_LITERAL_STRING("zoomAndPan"))) {
       if (zoomAndPanFound) {
         return false;
       }
-      nsIAtom *valAtom = NS_GetStaticAtom(params);
+      nsIAtom* valAtom = NS_GetStaticAtom(params);
       if (!valAtom) {
         return false;
       }
-      const nsSVGEnumMapping *mapping = dom::SVGSVGElement::sZoomAndPanMap;
+      const nsSVGEnumMapping* mapping = dom::SVGSVGElement::sZoomAndPanMap;
       while (mapping->mKey) {
         if (valAtom == *(mapping->mKey)) {
           // If we've got a valid zoomAndPan value, then set it on our root element.
           if (NS_FAILED(root->mEnumAttributes[dom::SVGSVGElement::ZOOMANDPAN].SetBaseValue(
                           mapping->mVal, root))) {
             return false;
           }
           break;
@@ -198,49 +210,49 @@ SVGFragmentIdentifier::ProcessSVGViewSpe
       return false;
     }
   } while (tokenizer.hasMoreTokens());
 
   if (root->mUseCurrentView) {
     // A previous SVGViewSpec may have overridden some attributes.
     // If they are no longer overridden we need to restore the old values.
     if (!transformFound) {
-      ClearTransform(root);
+      RestoreOldTransform(root);
     }
     if (!viewBoxFound) {
       RestoreOldViewBox(root);
     }
     if (!preserveAspectRatioFound) {
       RestoreOldPreserveAspectRatio(root);
     }
     if (!zoomAndPanFound) {
       RestoreOldZoomAndPan(root);
     }
   }
 
   return true;
 }
 
 bool
-SVGFragmentIdentifier::ProcessFragmentIdentifier(nsIDocument *aDocument,
-                                                 const nsAString &aAnchorName)
+SVGFragmentIdentifier::ProcessFragmentIdentifier(nsIDocument* aDocument,
+                                                 const nsAString& aAnchorName)
 {
   NS_ABORT_IF_FALSE(aDocument->GetRootElement()->IsSVG(nsGkAtoms::svg),
                     "expecting an SVG root element");
 
-  dom::SVGSVGElement *rootElement =
+  dom::SVGSVGElement* rootElement =
     static_cast<dom::SVGSVGElement*>(aDocument->GetRootElement());
 
   if (!rootElement->mUseCurrentView) {
     SaveOldViewBox(rootElement);
     SaveOldPreserveAspectRatio(rootElement);
     SaveOldZoomAndPan(rootElement);
   }
 
-  const dom::SVGViewElement *viewElement = GetViewElement(aDocument, aAnchorName);
+  const dom::SVGViewElement* viewElement = GetViewElement(aDocument, aAnchorName);
 
   if (viewElement) {
     if (!rootElement->mCurrentViewID) {
       rootElement->mCurrentViewID = new nsString();
     }
     *rootElement->mCurrentViewID = aAnchorName;
     rootElement->mUseCurrentView = true;
     rootElement->InvalidateTransformNotifyFrame();
@@ -255,14 +267,15 @@ SVGFragmentIdentifier::ProcessFragmentId
     return true;
   }
   RestoreOldViewBox(rootElement);
   rootElement->ClearViewBoxProperty();
   RestoreOldPreserveAspectRatio(rootElement);
   rootElement->ClearPreserveAspectRatioProperty();
   RestoreOldZoomAndPan(rootElement);
   rootElement->ClearZoomAndPanProperty();
-  ClearTransform(rootElement);
+  RestoreOldTransform(rootElement);
+  rootElement->ClearTransformProperty();
   if (wasOverridden) {
     rootElement->InvalidateTransformNotifyFrame();
   }
   return false;
 }
--- a/content/svg/content/src/SVGFragmentIdentifier.h
+++ b/content/svg/content/src/SVGFragmentIdentifier.h
@@ -44,14 +44,15 @@ private:
   // Save and restore things we override in case we want to go back e.g. the
   // user presses the back button
   static void SaveOldPreserveAspectRatio(dom::SVGSVGElement *root);
   static void RestoreOldPreserveAspectRatio(dom::SVGSVGElement *root);
   static void SaveOldViewBox(dom::SVGSVGElement *root);
   static void RestoreOldViewBox(dom::SVGSVGElement *root);
   static void SaveOldZoomAndPan(dom::SVGSVGElement *root);
   static void RestoreOldZoomAndPan(dom::SVGSVGElement *root);
-  static void ClearTransform(dom::SVGSVGElement *root);
+  static void SaveOldTransform(dom::SVGSVGElement *root);
+  static void RestoreOldTransform(dom::SVGSVGElement *root);
 };
 
 } // namespace mozilla
 
 #endif // MOZILLA_SVGFRAGMENTIDENTIFIER_H__
--- a/content/svg/content/src/SVGSVGElement.cpp
+++ b/content/svg/content/src/SVGSVGElement.cpp
@@ -957,46 +957,43 @@ SVGSVGElement::GetLength(uint8_t aCtxTyp
 
 /* virtual */ gfxMatrix
 SVGSVGElement::PrependLocalTransformsTo(const gfxMatrix &aMatrix,
                                         TransformTypes aWhich) const
 {
   NS_ABORT_IF_FALSE(aWhich != eChildToUserSpace || aMatrix.IsIdentity(),
                     "Skipping eUserSpaceToParent transforms makes no sense");
 
+  // 'transform' attribute:
+  gfxMatrix fromUserSpace =
+    SVGSVGElementBase::PrependLocalTransformsTo(aMatrix, aWhich);
+  if (aWhich == eUserSpaceToParent) {
+    return fromUserSpace;
+  }
+
   if (IsInner()) {
     float x, y;
     const_cast<SVGSVGElement*>(this)->GetAnimatedLengthValues(&x, &y, nullptr);
     if (aWhich == eAllTransforms) {
       // the common case
-      return GetViewBoxTransform() * gfxMatrix().Translate(gfxPoint(x, y)) * aMatrix;
-    }
-    if (aWhich == eUserSpaceToParent) {
-      return gfxMatrix().Translate(gfxPoint(x, y)) * aMatrix;
+      return GetViewBoxTransform() * gfxMatrix().Translate(gfxPoint(x, y)) * fromUserSpace;
     }
     NS_ABORT_IF_FALSE(aWhich == eChildToUserSpace, "Unknown TransformTypes");
-    return GetViewBoxTransform(); // no need to multiply identity aMatrix
-  }
-
-  if (aWhich == eUserSpaceToParent) {
-    // only inner-<svg> has eUserSpaceToParent transforms
-    return aMatrix;
+    return GetViewBoxTransform() * fromUserSpace;
   }
 
   if (IsRoot()) {
     gfxMatrix zoomPanTM;
     zoomPanTM.Translate(gfxPoint(mCurrentTranslate.GetX(), mCurrentTranslate.GetY()));
     zoomPanTM.Scale(mCurrentScale, mCurrentScale);
-    gfxMatrix matrix = mFragmentIdentifierTransform ? 
-                         *mFragmentIdentifierTransform * aMatrix : aMatrix;
-    return GetViewBoxTransform() * zoomPanTM * matrix;
+    return GetViewBoxTransform() * zoomPanTM * fromUserSpace;
   }
 
   // outer-<svg>, but inline in some other content:
-  return GetViewBoxTransform() * aMatrix;
+  return GetViewBoxTransform() * fromUserSpace;
 }
 
 /* virtual */ bool
 SVGSVGElement::HasValidDimensions() const
 {
   return !IsInner() ||
     ((!mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() ||
        mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0) &&
@@ -1049,17 +1046,17 @@ SVGSVGElement::ShouldSynthesizeViewBox()
   nsIDocument* doc = GetCurrentDoc();
   return doc &&
     doc->IsBeingUsedAsImage() &&
     !mIsPaintingSVGImageElement &&
     !GetParent();
 }
 
 
-// Callback function, for freeing uint64_t values stored in property table
+// Callback function, for freeing SVGPreserveAspectRatio values stored in property table
 static void
 ReleasePreserveAspectRatioPropertyValue(void*    aObject,       /* unused */
                                         nsIAtom* aPropertyName, /* unused */
                                         void*    aPropertyValue,
                                         void*    aData          /* unused */)
 {
   SVGPreserveAspectRatio* valPtr =
     static_cast<SVGPreserveAspectRatio*>(aPropertyValue);
@@ -1163,17 +1160,17 @@ SVGSVGElement::FlushImageTransformInvali
                     "Should only be called on image documents");
 
   if (mImageNeedsTransformInvalidation) {
     InvalidateTransformNotifyFrame();
     mImageNeedsTransformInvalidation = false;
   }
 }
 
-// Callback function, for freeing uint64_t values stored in property table
+// Callback function, for freeing nsSVGViewBoxRect values stored in property table
 static void
 ReleaseViewBoxPropertyValue(void*    aObject,       /* unused */
                             nsIAtom* aPropertyName, /* unused */
                             void*    aPropertyValue,
                             void*    aData          /* unused */)
 {
   nsSVGViewBoxRect* valPtr =
     static_cast<nsSVGViewBoxRect*>(aPropertyValue);
@@ -1240,10 +1237,57 @@ SVGSVGElement::GetZoomAndPanProperty() c
 }
 
 bool
 SVGSVGElement::ClearZoomAndPanProperty()
 {
   return UnsetProperty(nsGkAtoms::zoomAndPan);
 }
 
+// Callback function, for freeing SVGTransformList values stored in property table
+static void
+ReleaseTransformPropertyValue(void*    aObject,       /* unused */
+                              nsIAtom* aPropertyName, /* unused */
+                              void*    aPropertyValue,
+                              void*    aData          /* unused */)
+{
+  SVGTransformList* valPtr =
+    static_cast<SVGTransformList*>(aPropertyValue);
+  delete valPtr;
+}
+
+bool
+SVGSVGElement::SetTransformProperty(const SVGTransformList& aTransform)
+{
+  SVGTransformList* pTransformOverridePtr = new SVGTransformList(aTransform);
+  nsresult rv = SetProperty(nsGkAtoms::transform,
+                            pTransformOverridePtr,
+                            ReleaseTransformPropertyValue,
+                            true);
+  NS_ABORT_IF_FALSE(rv != NS_PROPTABLE_PROP_OVERWRITTEN,
+                    "Setting override value when it's already set...?"); 
+
+  if (MOZ_UNLIKELY(NS_FAILED(rv))) {
+    // property-insertion failed (e.g. OOM in property-table code)
+    delete pTransformOverridePtr;
+    return false;
+  }
+  return true;
+}
+
+const SVGTransformList*
+SVGSVGElement::GetTransformProperty() const
+{
+  void* valPtr = GetProperty(nsGkAtoms::transform);
+  if (valPtr) {
+    return static_cast<SVGTransformList*>(valPtr);
+  }
+  return nullptr;
+}
+
+bool
+SVGSVGElement::ClearTransformProperty()
+{
+  return UnsetProperty(nsGkAtoms::transform);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/content/svg/content/src/SVGSVGElement.h
+++ b/content/svg/content/src/SVGSVGElement.h
@@ -273,16 +273,19 @@ private:
   const SVGPreserveAspectRatio* GetPreserveAspectRatioProperty() const;
   bool ClearPreserveAspectRatioProperty();
   bool SetViewBoxProperty(const nsSVGViewBoxRect& aViewBox);
   const nsSVGViewBoxRect* GetViewBoxProperty() const;
   bool ClearViewBoxProperty();
   bool SetZoomAndPanProperty(uint16_t aValue);
   uint16_t GetZoomAndPanProperty() const;
   bool ClearZoomAndPanProperty();
+  bool SetTransformProperty(const SVGTransformList& aValue);
+  const SVGTransformList* GetTransformProperty() const;
+  bool ClearTransformProperty();
 
   bool IsRoot() const {
     NS_ASSERTION((IsInDoc() && !GetParent()) ==
                  (OwnerDoc() && (OwnerDoc()->GetRootElement() == this)),
                  "Can't determine if we're root");
     return IsInDoc() && !GetParent();
   }
 
@@ -343,17 +346,16 @@ private:
   static EnumInfo sEnumInfo[1];
 
   virtual nsSVGViewBox *GetViewBox();
   virtual SVGAnimatedPreserveAspectRatio *GetPreserveAspectRatio();
 
   nsSVGViewBox                   mViewBox;
   SVGAnimatedPreserveAspectRatio mPreserveAspectRatio;
 
-  nsAutoPtr<gfxMatrix>           mFragmentIdentifierTransform;
   nsAutoPtr<nsString>            mCurrentViewID;
 
   // 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
--- a/content/svg/content/src/nsSVGAnimatedTransformList.cpp
+++ b/content/svg/content/src/nsSVGAnimatedTransformList.cpp
@@ -20,32 +20,38 @@ nsresult
 nsSVGAnimatedTransformList::SetBaseValueString(const nsAString& aValue)
 {
   SVGTransformList newBaseValue;
   nsresult rv = newBaseValue.SetValueFromString(aValue);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
+  return SetBaseValue(newBaseValue);
+}
+
+nsresult
+nsSVGAnimatedTransformList::SetBaseValue(const SVGTransformList& aValue)
+{
   SVGAnimatedTransformList *domWrapper =
     SVGAnimatedTransformList::GetDOMWrapperIfExists(this);
   if (domWrapper) {
     // We must send this notification *before* changing mBaseVal! If the length
     // of our baseVal is being reduced, our baseVal's DOM wrapper list may have
     // to remove DOM items from itself, and any removed DOM items need to copy
     // their internal counterpart values *before* we change them.
     //
-    domWrapper->InternalBaseValListWillChangeLengthTo(newBaseValue.Length());
+    domWrapper->InternalBaseValListWillChangeLengthTo(aValue.Length());
   }
 
   // We don't need to call DidChange* here - we're only called by
   // nsSVGElement::ParseAttribute under Element::SetAttr,
   // which takes care of notifying.
 
-  rv = mBaseVal.CopyFrom(newBaseValue);
+  nsresult rv = mBaseVal.CopyFrom(aValue);
   if (NS_FAILED(rv) && domWrapper) {
     // Attempting to increase mBaseVal's length failed - reduce domWrapper
     // back to the same length:
     domWrapper->InternalBaseValListWillChangeLengthTo(mBaseVal.Length());
   } else {
     mIsAttrSet = true;
   }
   return rv;
--- a/content/svg/content/src/nsSVGAnimatedTransformList.h
+++ b/content/svg/content/src/nsSVGAnimatedTransformList.h
@@ -51,16 +51,18 @@ public:
    * SVGAnimatedTransformList::InternalBaseValListWillChangeTo), this method
    * returns a const reference. Only our friend classes may get mutable
    * references to mBaseVal.
    */
   const SVGTransformList& GetBaseValue() const {
     return mBaseVal;
   }
 
+  nsresult SetBaseValue(const SVGTransformList& aValue);
+
   nsresult SetBaseValueString(const nsAString& aValue);
 
   void ClearBaseValue();
 
   const SVGTransformList& GetAnimValue() const {
     return mAnimVal ? *mAnimVal : mBaseVal;
   }
 
--- a/content/svg/content/test/test_getCTM.html
+++ b/content/svg/content/test/test_getCTM.html
@@ -40,18 +40,18 @@ function runTest()
   var sym = doc.getElementById("sym");
   var symbolRect = doc.getElementById("symbolRect");
   var fO = doc.getElementById("fO");
   /* Tests the consistency with nearestViewportElement
      (code is from test_viewport.html) */
   // root.nearestViewportElement == null
   is((function(){try{return root.getCTM()}catch(e){return e}})(), null, "root.getCTM()");
   // inner.nearestViewportElement == root
-  is((function(){try{return inner.getCTM().e}catch(e){return e}})(), 31, "inner.getCTM().e");
-  is((function(){try{return inner.getCTM().f}catch(e){return e}})(), 42, "inner.getCTM().f");
+  is((function(){try{return inner.getCTM().e}catch(e){return e}})(), 1, "inner.getCTM().e");
+  is((function(){try{return inner.getCTM().f}catch(e){return e}})(), 2, "inner.getCTM().f");
   // g1.nearestViewportElement == inner
   is((function(){try{return g1.getCTM().e}catch(e){return e}})(), 30, "g1.getCTM().e");
   is((function(){try{return g1.getCTM().f}catch(e){return e}})(), 40, "g1.getCTM().f");
   // outer.nearestViewportElement == null
   is((function(){try{return outer.getCTM()}catch(e){return e}})(), null, "outer.getCTM()");
   // g2.nearestViewportElement == outer
   is((function(){try{return g2.getCTM().e}catch(e){return e}})(), 600, "g2.getCTM().e");
   is((function(){try{return g2.getCTM().f}catch(e){return e}})(), 700, "g2.getCTM().f");
@@ -70,18 +70,18 @@ function runTest()
   is((function(){try{return g5.getCTM()}catch(e){return e}})(), null, "g5.getCTM()");
 
   /* Tests the consistency with farthestViewportElement
      (code is from test_viewport.html) */
   // root.farthestViewportElement == null (but actually == root)
   is((function(){try{return root.getScreenCTM().e}catch(e){return e}})(), 11, "root.getScreenCTM().e");
   is((function(){try{return root.getScreenCTM().f}catch(e){return e}})(), 22, "root.getScreenCTM().f");
   // inner.farthestViewportElement == root
-  is((function(){try{return inner.getScreenCTM().e}catch(e){return e}})(), 45, "inner.getScreenCTM().e");
-  is((function(){try{return inner.getScreenCTM().f}catch(e){return e}})(), 68, "inner.getScreenCTM().f");
+  is((function(){try{return inner.getScreenCTM().e}catch(e){return e}})(), 15, "inner.getScreenCTM().e");
+  is((function(){try{return inner.getScreenCTM().f}catch(e){return e}})(), 28, "inner.getScreenCTM().f");
   // g1.farthestViewportElement == root
   is((function(){try{return g1.getScreenCTM().e}catch(e){return e}})(), 45, "g1.getScreenCTM().e");
   is((function(){try{return g1.getScreenCTM().f}catch(e){return e}})(), 68, "g1.getScreenCTM().f");
   // outer.farthestViewportElement == null (but actually == root)
   is((function(){try{return outer.getScreenCTM().e}catch(e){return e}})(), 46, "outer.getScreenCTM().e");
   is((function(){try{return outer.getScreenCTM().f}catch(e){return e}})(), 69, "outer.getScreenCTM().f");
   // outer.farthestViewportElement == null (but actually == root)
   is((function(){try{return outer2.getScreenCTM().e}catch(e){return e}})(), -19, "outer2.getScreenCTM().e");
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -267,16 +267,17 @@ pref(svg.paint-order.enabled,true) == pa
 == suspend-02.svg pass.svg
 == suspend-03.svg pass.svg
 == suspend-04.svg pass.svg
 == suspend-05.svg pass.svg
 == suspend-06.svg pass.svg
 == suspend-07.svg pass.svg
 == suspend-08.svg pass.svg
 == svg-transform-01.svg pass.svg
+== svg-transform-02.svg pass.svg
 == symbol-01.svg symbol-01-ref.svg
 == text-font-size-01.svg pass.svg
 random-if(gtk2Widget) == text-font-weight-01.svg text-font-weight-01-ref.svg # bug 386713
 == text-gradient-01.svg text-gradient-01-ref.svg
 random-if(winWidget) == text-gradient-02.svg text-gradient-02-ref.svg # see bug 590101
 == text-gradient-03.svg pass.svg
 HTTP(..) == text-gradient-04.svg text-gradient-04-ref.svg
 == text-in-link-01.svg text-in-link-01-ref.svg
--- a/layout/reftests/svg/smil/motion/animateMotion-by-1.svg
+++ b/layout/reftests/svg/smil/motion/animateMotion-by-1.svg
@@ -6,28 +6,25 @@
     function doTest() {
       setTimeAndSnapshot(101, true);
     }
     window.addEventListener("MozReftestInvalidate", doTest, false);
   </script>
 
   <!-- Big green background to match lime.svg -->
   <rect width="100%" height="100%" fill="lime"/>
-  <!-- Red "workspace" (should be covered up, if tests pass) -->
+  <!-- Red "workspaces" (should be covered up, if tests pass) -->
   <rect x="100" y="100" width="100" height="100" fill="red"/>
+  <rect x="100" y="300" width="100" height="100" fill="red"/>
 
   <!-- FIRST ROW -->
   <!-- Check that 'by' works at all -->
-  <rect fill="lime" x="0" y="0" width="50" height="25">
+  <rect fill="lime" x="0" y="0" width="50" height="50">
     <animateMotion by="100, 100" begin="100" dur="1" fill="freeze"/>
   </rect>
-  <foreignObject id="fo" x="0" y="25" width="50" height="25">
-    <div xmlns="http://www.w3.org/1999/xhtml" style="width:100%;height:100%;background-color:lime"/>
-  </foreignObject>
-  <animateMotion xlink:href="#fo" by="100, 100" begin="100" dur="1" fill="freeze"/>
 
   <!-- Check that 'by' is additive w/ 'by' -->
   <rect fill="lime" x="50" y="50" width="50" height="50">
     <animateMotion by="60, 75" begin="100" dur="1" fill="freeze"/>
     <animateMotion by="40, -25" begin="100" dur="1" fill="freeze"/>
   </rect>
 
   <!-- SECOND ROW -->
@@ -37,9 +34,20 @@
     <animateMotion by="50, 50" begin="100" dur="1" fill="freeze"/>
   </rect>
 
   <!-- Check that 'from-to' replaces 'by' -->
   <rect fill="lime" width="50" height="50">
     <animateMotion by="500, 500" begin="100" dur="1" fill="freeze"/>
     <animateMotion from="300,300" to="150,150" begin="100" dur="1" fill="freeze"/>
   </rect>
+
+  <!-- Other tags -->
+  <foreignObject id="fo" x="0" y="0" width="100" height="50">
+    <div xmlns="http://www.w3.org/1999/xhtml" style="width:100%;height:100%;background-color:lime"/>
+  </foreignObject>
+  <animateMotion xlink:href="#fo" by="100, 300" begin="100" dur="1" fill="freeze"/>
+
+  <svg x="0" y="50" width="100" height="50">
+    <rect width="100" height="50" fill="lime"/>
+    <animateMotion by="100, 300" begin="100" dur="1" fill="freeze"/>
+  </svg>
 </svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/smil/motion/animateMotion-by-2.svg
@@ -0,0 +1,16 @@
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink"
+     class="reftest-wait" transform="translate(100,0)">
+  <script xlink:href="../smil-util.js" type="text/javascript"/>
+  <script type="text/javascript">
+    function doTest() {
+      setTimeAndSnapshot(101, true);
+    }
+    window.addEventListener("MozReftestInvalidate", doTest, false);
+  </script>
+
+  <animateMotion by="-100, 0" begin="100" dur="1" fill="freeze"/>
+
+  <!-- Big green background to match lime.svg -->
+  <rect width="100%" height="100%" fill="lime"/>
+</svg>
--- a/layout/reftests/svg/smil/motion/reftest.list
+++ b/layout/reftests/svg/smil/motion/reftest.list
@@ -1,12 +1,13 @@
 # Tests related to SVG Animation (using SMIL), focusing on the animateMotion
 # element.
 
 skip-if(B2G) == animateMotion-by-1.svg      lime.svg # bug 773482
+skip-if(B2G) == animateMotion-by-2.svg      lime.svg # bug 773482
 skip-if(B2G) == animateMotion-from-to-1.svg lime.svg # bug 773482
 == animateMotion-indefinite-to-1.svg lime.svg
 == animateMotion-indefinite-to-2.svg lime.svg
 skip-if(B2G) == animateMotion-rotate-1a.svg lime.svg # bug 773482
 skip-if(B2G) == animateMotion-rotate-1b.svg lime.svg # bug 773482
 == animateMotion-rotate-2.svg  lime.svg
 == animateMotion-to-overridden-1.svg lime.svg
 == animateMotion-values-linear-1.svg animateMotion-values-linear-1-ref.svg
copy from layout/reftests/svg/svg-transform-01.svg
copy to layout/reftests/svg/svg-transform-02.svg
--- a/layout/reftests/svg/svg-transform-01.svg
+++ b/layout/reftests/svg/svg-transform-02.svg
@@ -1,16 +1,16 @@
 <!--
      Any copyright is dedicated to the Public Domain.
      http://creativecommons.org/publicdomain/zero/1.0/
 -->
 <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
-  <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=861188 -->
+  <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=863994 -->
 
   <rect width="100%" height="100%" fill="lime"/>
 
   <svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" x="100" y="100" viewBox="0 0 640 480">
     <rect width="100%" height="100%" fill="red"/>
   </svg>
-  <svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" x="100" y="100" viewBox="0 0 640 480" transform="">
+  <svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" x="100" y="100" viewBox="0 0 640 480" transform="translate(0, 0)">
     <rect width="100%" height="100%" fill="lime"/>
   </svg>
 </svg>
--- a/layout/svg/nsSVGOuterSVGFrame.h
+++ b/layout/svg/nsSVGOuterSVGFrame.h
@@ -91,19 +91,20 @@ public:
                       GetFirstPrincipalChild()->GetType() ==
                         nsGkAtoms::svgOuterSVGAnonChildFrame,
                       "Where is our anonymous child?");
     return GetFirstPrincipalChild()->GetContentInsertionFrame();
   }
 
   virtual bool IsSVGTransformed(gfxMatrix *aOwnTransform,
                                 gfxMatrix *aFromParentTransform) const {
-    // Outer-<svg> can transform its children with viewBox, currentScale and
-    // currentTranslate, but it itself is not transformed by SVG transforms.
-    return false;
+    // Our anonymous wrapper performs the transforms. We simply
+    // return whether we are transformed here but don't apply the transforms
+    // themselves.
+    return GetFirstPrincipalChild()->IsTransformed();
   }
 
   // nsISVGSVGFrame interface:
   virtual void NotifyViewportOrTransformChanged(uint32_t aFlags);
 
   // nsISVGChildFrame methods:
   NS_IMETHOD PaintSVG(nsRenderingContext* aContext,
                       const nsIntRect *aDirtyRect);
@@ -250,23 +251,16 @@ public:
 
   /**
    * Get the "type" of the frame
    *
    * @see nsGkAtoms::svgOuterSVGAnonChildFrame
    */
   virtual nsIAtom* GetType() const;
 
-  virtual bool IsSVGTransformed(gfxMatrix *aOwnTransform,
-                                gfxMatrix *aFromParentTransform) const {
-    // Outer-<svg> can transform its children with viewBox, currentScale and
-    // currentTranslate, but it itself is not transformed by _SVG_ transforms.
-    return false;
-  }
-
   // nsSVGContainerFrame methods:
   virtual gfxMatrix GetCanvasTM(uint32_t aFor) {
     // GetCanvasTM returns the transform from an SVG frame to the frame's
     // nsSVGOuterSVGFrame's content box, so we do not include any x/y offset
     // set on us for any CSS border or padding on our nsSVGOuterSVGFrame.
     return static_cast<nsSVGOuterSVGFrame*>(mParent)->GetCanvasTM(aFor);
   }