Bug 1355351: Add a node property to access the ::before and ::after pseudo-elements. r=heycam draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Sun, 16 Apr 2017 17:29:49 +0200
changeset 568269 8879dc3a6b637f1d0ba965f81658ca88c320dc40
parent 568126 7636849e6f5829175bc06af8b81051ac7b61a687
child 568270 ec399ec869742b141d3648e4a0ce84ba4bb05635
push id55809
push userbmo:emilio+bugs@crisal.io
push dateTue, 25 Apr 2017 22:14:00 +0000
reviewersheycam
bugs1355351
milestone55.0a1
Bug 1355351: Add a node property to access the ::before and ::after pseudo-elements. r=heycam MozReview-Commit-ID: FJxJp2U0Lxh
dom/base/nsGkAtomList.h
dom/xml/nsXMLElement.cpp
dom/xml/nsXMLElement.h
layout/base/nsCSSFrameConstructor.cpp
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -2137,22 +2137,24 @@ GK_ATOM(onphoto, "onphoto")
 GK_ATOM(onactivestatechanged, "onactivestatechanged")
 GK_ATOM(ongamepadbuttondown, "ongamepadbuttondown")
 GK_ATOM(ongamepadbuttonup, "ongamepadbuttonup")
 GK_ATOM(ongamepadaxismove, "ongamepadaxismove")
 GK_ATOM(ongamepadconnected, "ongamepadconnected")
 GK_ATOM(ongamepaddisconnected, "ongamepaddisconnected")
 
 // Content property names
+GK_ATOM(afterPseudoProperty, "afterPseudoProperty")  // nsXMLElement*
 GK_ATOM(animationsProperty, "AnimationsProperty")        // FrameAnimations*
 GK_ATOM(animationsOfBeforeProperty, "AnimationsOfBeforeProperty") // FrameAnimations*
 GK_ATOM(animationsOfAfterProperty, "AnimationsOfAfterProperty") // FrameAnimations*
 GK_ATOM(animationEffectsProperty, "AnimationEffectsProperty") // EffectSet*
 GK_ATOM(animationEffectsForBeforeProperty, "AnimationsEffectsForBeforeProperty") // EffectSet*
 GK_ATOM(animationEffectsForAfterProperty, "AnimationsEffectsForAfterProperty") // EffectSet*
+GK_ATOM(beforePseudoProperty, "beforePseudoProperty")  // nsXMLElement*
 GK_ATOM(cssPseudoElementBeforeProperty, "CSSPseudoElementBeforeProperty") // CSSPseudoElement*
 GK_ATOM(cssPseudoElementAfterProperty, "CSSPseudoElementAfterProperty") // CSSPseudoElement*
 GK_ATOM(transitionsProperty, "TransitionsProperty")        // FrameTransitions*
 GK_ATOM(transitionsOfBeforeProperty, "TransitionsOfBeforeProperty") // FrameTransitions*
 GK_ATOM(transitionsOfAfterProperty, "TransitionsOfAfterProperty") // FrameTransitions*
 GK_ATOM(genConInitializerProperty, "QuoteNodeProperty")
 GK_ATOM(labelMouseDownPtProperty, "LabelMouseDownPtProperty")
 GK_ATOM(lockedStyleStates, "lockedStyleStates")
--- a/dom/xml/nsXMLElement.cpp
+++ b/dom/xml/nsXMLElement.cpp
@@ -4,16 +4,17 @@
  * 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 "nsXMLElement.h"
 #include "mozilla/dom/ElementBinding.h"
 #include "mozilla/dom/ElementInlines.h"
 #include "nsContentUtils.h" // nsAutoScriptBlocker
 
+using namespace mozilla;
 using namespace mozilla::dom;
 
 nsresult
 NS_NewXMLElement(Element** aInstancePtrResult,
                  already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
 {
   nsXMLElement* it = new nsXMLElement(aNodeInfo);
   NS_ADDREF(*aInstancePtrResult = it);
@@ -24,9 +25,31 @@ NS_IMPL_ISUPPORTS_INHERITED(nsXMLElement
                             nsIDOMNode, nsIDOMElement)
 
 JSObject*
 nsXMLElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return ElementBinding::Wrap(aCx, this, aGivenProto);
 }
 
+void
+nsXMLElement::UnbindFromTree(bool aDeep, bool aNullParent)
+{
+  CSSPseudoElementType pseudoType = GetPseudoElementType();
+  bool isBefore = pseudoType == CSSPseudoElementType::before;
+  nsIAtom* property = isBefore
+    ? nsGkAtoms::beforePseudoProperty : nsGkAtoms::afterPseudoProperty;
+
+  switch (pseudoType) {
+    case CSSPseudoElementType::before:
+    case CSSPseudoElementType::after: {
+      MOZ_ASSERT(GetParent());
+      MOZ_ASSERT(GetParent()->IsElement());
+      GetParent()->DeleteProperty(property);
+      break;
+    }
+    default:
+      break;
+  }
+  Element::UnbindFromTree(aDeep, aNullParent);
+}
+
 NS_IMPL_ELEMENT_CLONE(nsXMLElement)
--- a/dom/xml/nsXMLElement.h
+++ b/dom/xml/nsXMLElement.h
@@ -30,15 +30,18 @@ public:
   // nsIDOMElement
   NS_FORWARD_NSIDOMELEMENT_TO_GENERIC
 
   // nsINode interface methods
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
 
+  virtual void UnbindFromTree(bool aDeep = true,
+                              bool aNullParent = true) override;
+
 protected:
   virtual ~nsXMLElement() {}
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 };
 
 #endif // nsXMLElement_h___
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -1832,21 +1832,17 @@ nsCSSFrameConstructor::CreateGeneratedCo
                                                   nsStyleContext*  aStyleContext,
                                                   CSSPseudoElementType aPseudoElement,
                                                   FrameConstructionItemList& aItems)
 {
   MOZ_ASSERT(aPseudoElement == CSSPseudoElementType::before ||
              aPseudoElement == CSSPseudoElementType::after,
              "unexpected aPseudoElement");
 
-  // XXXbz is this ever true?
-  if (!aParentContent->IsElement()) {
-    NS_ERROR("Bogus generated content parent");
-    return;
-  }
+  MOZ_ASSERT(aParentContent->IsElement());
 
   StyleSetHandle styleSet = mPresShell->StyleSet();
 
   // Probe for the existence of the pseudo-element
   RefPtr<nsStyleContext> pseudoStyleContext;
   pseudoStyleContext =
     styleSet->ProbePseudoElementStyle(aParentContent->AsElement(),
                                       aPseudoElement,
@@ -1864,16 +1860,23 @@ nsCSSFrameConstructor::CreateGeneratedCo
     nsGkAtoms::mozgeneratedcontentbefore : nsGkAtoms::mozgeneratedcontentafter;
   nodeInfo = mDocument->NodeInfoManager()->GetNodeInfo(elemName, nullptr,
                                                        kNameSpaceID_None,
                                                        nsIDOMNode::ELEMENT_NODE);
   nsCOMPtr<Element> container;
   nsresult rv = NS_NewXMLElement(getter_AddRefs(container), nodeInfo.forget());
   if (NS_FAILED(rv))
     return;
+
+  // Cleared when the pseudo is unbound from the tree, so no need to store a
+  // strong reference, nor a destructor.
+  nsIAtom* property = isBefore
+    ? nsGkAtoms::beforePseudoProperty : nsGkAtoms::afterPseudoProperty;
+  aParentContent->SetProperty(property, container.get());
+
   container->SetIsNativeAnonymousRoot();
   container->SetPseudoElementType(aPseudoElement);
 
   // If the parent is in a shadow tree, make sure we don't
   // bind with a document because shadow roots and its descendants
   // are not in document.
   nsIDocument* bindDocument =
     aParentContent->HasFlag(NODE_IS_IN_SHADOW_TREE) ? nullptr : mDocument;