Bug 1393791 - Move SVG Use anonymous content to the frame. r=emilio
authorBobby Holley <bobbyholley@gmail.com>
Sun, 27 Aug 2017 11:15:03 -0700
changeset 377140 34d0b762abdbed8153eb80387461300c9e9e452d
parent 377139 69e1415e3ca00e2e2a679d304ab9102f9631e77e
child 377141 589f8ecf173bc96189395efc5dcd1529ebe82019
push id32402
push userarchaeopteryx@coole-files.de
push dateMon, 28 Aug 2017 14:47:04 +0000
treeherdermozilla-central@d5b6d113cf17 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
bugs1393791
milestone57.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
Bug 1393791 - Move SVG Use anonymous content to the frame. r=emilio This brings it into alignment with what everything else does. MozReview-Commit-ID: 2A9p8umHnKi
dom/svg/SVGUseElement.cpp
dom/svg/SVGUseElement.h
layout/svg/nsSVGUseFrame.cpp
layout/svg/nsSVGUseFrame.h
--- a/dom/svg/SVGUseElement.cpp
+++ b/dom/svg/SVGUseElement.cpp
@@ -12,16 +12,17 @@
 #include "mozilla/dom/SVGSVGElement.h"
 #include "nsIDocument.h"
 #include "nsIPresShell.h"
 #include "mozilla/dom/Element.h"
 #include "nsContentUtils.h"
 #include "nsIURI.h"
 #include "mozilla/URLExtraData.h"
 #include "nsSVGEffects.h"
+#include "nsSVGUseFrame.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Use)
 
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGUseElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
@@ -50,23 +51,21 @@ nsSVGElement::StringInfo SVGUseElement::
 // nsISupports methods
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(SVGUseElement)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SVGUseElement,
                                                 SVGUseElementBase)
   nsAutoScriptBlocker scriptBlocker;
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOriginal)
-  tmp->DestroyAnonymousContent();
   tmp->UnlinkSource();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SVGUseElement,
                                                   SVGUseElementBase)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginal)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClone)
   tmp->mSource.Traverse(&cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_ADDREF_INHERITED(SVGUseElement,SVGUseElementBase)
 NS_IMPL_RELEASE_INHERITED(SVGUseElement,SVGUseElementBase)
 
 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(SVGUseElement)
   NS_INTERFACE_TABLE_INHERITED(SVGUseElement, nsIMutationObserver)
@@ -208,21 +207,19 @@ void
 SVGUseElement::NodeWillBeDestroyed(const nsINode *aNode)
 {
   nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
   UnlinkSource();
 }
 
 //----------------------------------------------------------------------
 
-nsIContent*
+already_AddRefed<nsIContent>
 SVGUseElement::CreateAnonymousContent()
 {
-  mClone = nullptr;
-
   if (mSource.get()) {
     mSource.get()->RemoveMutationObserver(this);
   }
 
   LookupHref();
   nsIContent* targetContent = mSource.get();
   if (!targetContent)
     return nullptr;
@@ -288,71 +285,71 @@ SVGUseElement::CreateAnonymousContent()
   if (!baseURI) {
     return nullptr;
   }
   mContentURLData = new URLExtraData(baseURI.forget(),
                                      do_AddRef(OwnerDoc()->GetDocumentURI()),
                                      do_AddRef(NodePrincipal()));
 
   targetContent->AddMutationObserver(this);
-  mClone = newcontent;
 
 #ifdef DEBUG
   // Our anonymous clone can get restyled by various things
   // (e.g. SMIL).  Reconstructing its frame is OK, though, because
   // it's going to be our _only_ child in the frame tree, so can't get
   // mis-ordered with anything.
-  mClone->SetProperty(nsGkAtoms::restylableAnonymousNode,
-                      reinterpret_cast<void*>(true));
+  newcontent->SetProperty(nsGkAtoms::restylableAnonymousNode,
+                          reinterpret_cast<void*>(true));
 #endif // DEBUG
 
-  return mClone;
+  return newcontent.forget();
 }
 
 nsIURI*
 SVGUseElement::GetSourceDocURI()
 {
   nsIContent* targetContent = mSource.get();
   if (!targetContent)
     return nullptr;
 
   return targetContent->OwnerDoc()->GetDocumentURI();
 }
 
-void
-SVGUseElement::DestroyAnonymousContent()
-{
-  nsContentUtils::DestroyAnonymousContent(&mClone);
-}
-
 bool
 SVGUseElement::OurWidthAndHeightAreUsed() const
 {
-  return mClone && mClone->IsAnyOfSVGElements(nsGkAtoms::svg, nsGkAtoms::symbol);
+  auto* frame = GetFrame();
+  if (!frame || !frame->GetContentClone()) {
+    return false;
+  }
+  return frame->GetContentClone()->IsAnyOfSVGElements(nsGkAtoms::svg, nsGkAtoms::symbol);
 }
 
 //----------------------------------------------------------------------
 // implementation helpers
 
 void
 SVGUseElement::SyncWidthOrHeight(nsIAtom* aName)
 {
   NS_ASSERTION(aName == nsGkAtoms::width || aName == nsGkAtoms::height,
                "The clue is in the function name");
   NS_ASSERTION(OurWidthAndHeightAreUsed(), "Don't call this");
 
+  auto* frame = GetFrame();
+  nsIContent* clone = frame ? frame->GetContentClone() : nullptr;
+
   if (OurWidthAndHeightAreUsed()) {
-    nsSVGElement *target = static_cast<nsSVGElement*>(mClone.get());
+    auto* target = static_cast<nsSVGElement*>(clone);
     uint32_t index = *sLengthInfo[ATTR_WIDTH].mName == aName ? ATTR_WIDTH : ATTR_HEIGHT;
 
     if (mLengthAttributes[index].IsExplicitlySet()) {
       target->SetLength(aName, mLengthAttributes[index]);
       return;
     }
-    if (mClone->IsSVGElement(nsGkAtoms::svg)) {
+    if (clone->IsSVGElement(nsGkAtoms::svg)) {
       // Our width/height attribute is now no longer explicitly set, so we
       // need to revert the clone's width/height to the width/height of the
       // content that's being cloned.
       TriggerReclone();
       return;
     }
     // Our width/height attribute is now no longer explicitly set, so we
     // need to set the value to 100%
@@ -469,16 +466,24 @@ SVGUseElement::GetLengthInfo()
 
 nsSVGElement::StringAttributesInfo
 SVGUseElement::GetStringInfo()
 {
   return StringAttributesInfo(mStringAttributes, sStringInfo,
                               ArrayLength(sStringInfo));
 }
 
+nsSVGUseFrame*
+SVGUseElement::GetFrame() const
+{
+  nsIFrame* frame = GetPrimaryFrame();
+  MOZ_ASSERT_IF(frame, frame->IsSVGUseFrame());
+  return static_cast<nsSVGUseFrame*>(frame);
+}
+
 //----------------------------------------------------------------------
 // nsIContent methods
 
 NS_IMETHODIMP_(bool)
 SVGUseElement::IsAttributeMapped(const nsIAtom* name) const
 {
   static const MappedAttributeEntry* const map[] = {
     sFEFloodMap,
--- a/dom/svg/SVGUseElement.h
+++ b/dom/svg/SVGUseElement.h
@@ -52,19 +52,17 @@ public:
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
   NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
 
   // for nsSVGUseFrame's nsIAnonymousContentCreator implementation.
-  nsIContent* CreateAnonymousContent();
-  nsIContent* GetAnonymousContent() const { return mClone; }
-  void DestroyAnonymousContent();
+  already_AddRefed<nsIContent> CreateAnonymousContent();
 
   // nsSVGElement specializations:
   virtual gfxMatrix PrependLocalTransformsTo(
     const gfxMatrix &aMatrix,
     SVGTransformTypes aWhich = eAllTransforms) const override;
   virtual bool HasValidDimensions() const override;
 
   // nsIContent interface
@@ -93,16 +91,18 @@ protected:
         aFrom->RemoveMutationObserver(mContainer);
       }
       mContainer->TriggerReclone();
     }
   private:
     SVGUseElement* mContainer;
   };
 
+  nsSVGUseFrame* GetFrame() const;
+
   virtual LengthAttributesInfo GetLengthInfo() override;
   virtual StringAttributesInfo GetStringInfo() override;
 
   /**
    * Returns true if our width and height should be used, or false if they
    * should be ignored. As per the spec, this depends on the type of the
    * element that we're referencing.
    */
--- a/layout/svg/nsSVGUseFrame.cpp
+++ b/layout/svg/nsSVGUseFrame.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsSVGUseFrame.h"
+#include "nsContentUtils.h"
 
 #include "mozilla/dom/SVGUseElement.h"
 #include "nsContentList.h"
 #include "nsSVGEffects.h"
 
 using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
@@ -96,19 +97,18 @@ nsSVGUseFrame::AttributeChanged(int32_t 
   }
 
   return nsSVGGFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
 
 void
 nsSVGUseFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
-  RefPtr<SVGUseElement> use = static_cast<SVGUseElement*>(GetContent());
+  nsContentUtils::DestroyAnonymousContent(&mContentClone);
   nsSVGGFrame::DestroyFrom(aDestructRoot);
-  use->DestroyAnonymousContent();
 }
 
 
 //----------------------------------------------------------------------
 // nsSVGDisplayableFrame methods
 
 void
 nsSVGUseFrame::ReflowSVG()
@@ -163,28 +163,25 @@ nsSVGUseFrame::NotifySVGChanged(uint32_t
 //----------------------------------------------------------------------
 // nsIAnonymousContentCreator methods:
 
 nsresult
 nsSVGUseFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
 {
   SVGUseElement *use = static_cast<SVGUseElement*>(GetContent());
 
-  nsIContent* clone = use->CreateAnonymousContent();
+  mContentClone = use->CreateAnonymousContent();
   nsLayoutUtils::PostRestyleEvent(
     use, nsRestyleHint(0), nsChangeHint_InvalidateRenderingObservers);
-  if (!clone)
+  if (!mContentClone)
     return NS_ERROR_FAILURE;
-  if (!aElements.AppendElement(clone))
-    return NS_ERROR_OUT_OF_MEMORY;
+  aElements.AppendElement(mContentClone);
   return NS_OK;
 }
 
 void
 nsSVGUseFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
                                         uint32_t aFilter)
 {
-  SVGUseElement *use = static_cast<SVGUseElement*>(GetContent());
-  nsIContent* clone = use->GetAnonymousContent();
-  if (clone) {
-    aElements.AppendElement(clone);
+  if (mContentClone) {
+    aElements.AppendElement(mContentClone);
   }
 }
--- a/layout/svg/nsSVGUseFrame.h
+++ b/layout/svg/nsSVGUseFrame.h
@@ -50,13 +50,16 @@ public:
   void ReflowSVG() override;
   void NotifySVGChanged(uint32_t aFlags) override;
 
   // nsIAnonymousContentCreator
   nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
   void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
                                 uint32_t aFilter) override;
 
+  nsIContent* GetContentClone() { return mContentClone.get(); }
+
 private:
   bool mHasValidDimensions;
+  nsCOMPtr<nsIContent> mContentClone;
 };
 
 #endif // __NS_SVGUSEFRAME_H__