Bug 1365092 - Moves side effects of HTMLAnchorElement's SetAttr, UnsetAttr, and ParseAttribute functions to the corresponding BeforeSetAttr and AfterSetAttr functions draft
authorKirk Steuber <ksteuber@mozilla.com>
Wed, 17 May 2017 10:39:09 -0700
changeset 583822 e0dcaef2c04e28c532e2204851b1f0ba1b7a3583
parent 583338 3a252b4c386721a2152780f63fa59af7d67097d6
child 584046 852f998025f52f0628d57c06e9526a35b7a0aa00
child 584104 a5eafba1a1cb895c7e192c9f9c5de76bac89b2e0
push id60568
push userksteuber@mozilla.com
push dateWed, 24 May 2017 17:52:07 +0000
bugs1365092
milestone55.0a1
Bug 1365092 - Moves side effects of HTMLAnchorElement's SetAttr, UnsetAttr, and ParseAttribute functions to the corresponding BeforeSetAttr and AfterSetAttr functions This is necessary to facilitate the transition to cloning attributes instead of reparsing them. MozReview-Commit-ID: 2SZcYqWGJF6
dom/html/HTMLAnchorElement.cpp
dom/html/HTMLAnchorElement.h
--- a/dom/html/HTMLAnchorElement.cpp
+++ b/dom/html/HTMLAnchorElement.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/dom/HTMLAnchorElementBinding.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsGkAtoms.h"
 #include "nsHTMLDNSPrefetch.h"
+#include "nsAttrValueOrString.h"
 #include "nsIDocument.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsIURI.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Anchor)
 
 namespace mozilla {
@@ -360,94 +361,75 @@ HTMLAnchorElement::GetHrefURI() const
   if (uri) {
     return uri.forget();
   }
 
   return GetHrefURIForAnchors();
 }
 
 nsresult
-HTMLAnchorElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
-                           nsIAtom* aPrefix, const nsAString& aValue,
-                           bool aNotify)
+HTMLAnchorElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+                                 const nsAttrValueOrString* aValue,
+                                 bool aNotify)
 {
-  bool reset = false;
-  if (aName == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) {
-    // If we do not have a cached URI, we have some value here so we must reset
-    // our link state after calling the parent.
-    if (!Link::HasCachedURI()) {
-      reset = true;
-    }
-    // However, if we have a cached URI, we'll want to see if the value changed.
-    else {
-      nsAutoString val;
-      GetHref(val);
-      if (!val.Equals(aValue)) {
+  if (aNamespaceID == kNameSpaceID_None) {
+    if (aName == nsGkAtoms::href) {
+      bool reset = false;
+      if (!aValue) {
         reset = true;
+      } else {
+        // If we do not have a cached URI, we have some value here so we must
+        // reset our link state after calling the parent.
+        if (!Link::HasCachedURI()) {
+          reset = true;
+        }
+        // However, if we have a cached URI, we'll want to see if the value
+        // changed.
+        else {
+          const nsAttrValue* oldValue =
+            mAttrsAndChildren.GetAttr(nsGkAtoms::href);
+          if (!aValue->EqualsAsStrings(*oldValue)) {
+            reset = true;
+          }
+        }
       }
-    }
-    if (reset) {
-      CancelDNSPrefetch(HTML_ANCHOR_DNS_PREFETCH_DEFERRED,
-                        HTML_ANCHOR_DNS_PREFETCH_REQUESTED);
+      if (reset) {
+        CancelDNSPrefetch(HTML_ANCHOR_DNS_PREFETCH_DEFERRED,
+                          HTML_ANCHOR_DNS_PREFETCH_REQUESTED);
+      }
     }
   }
 
-  nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
-                                              aValue, aNotify);
-
-  // The ordering of the parent class's SetAttr call and Link::ResetLinkState
-  // is important here!  The attribute is not set until SetAttr returns, and
-  // we will need the updated attribute value because notifying the document
-  // that content states have changed will call IntrinsicState, which will try
-  // to get updated information about the visitedness from Link.
-  if (reset) {
-    Link::ResetLinkState(!!aNotify, true);
-    if (IsInComposedDoc()) {
-      TryDNSPrefetch();
-    }
-  }
-
-  return rv;
+  return nsGenericHTMLElement::BeforeSetAttr(aNamespaceID, aName, aValue,
+                                             aNotify);
 }
 
 nsresult
-HTMLAnchorElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
-                             bool aNotify)
+HTMLAnchorElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+                                const nsAttrValue* aValue,
+                                const nsAttrValue* aOldValue, bool aNotify)
 {
-  bool href =
-    (aAttribute == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID);
-
-  if (href) {
-    CancelDNSPrefetch(HTML_ANCHOR_DNS_PREFETCH_DEFERRED,
-                      HTML_ANCHOR_DNS_PREFETCH_REQUESTED);
+  if (aNamespaceID == kNameSpaceID_None) {
+    if (aName == nsGkAtoms::href) {
+      if (aValue) {
+        if (!Link::HasCachedURI() || !aOldValue ||
+            !aValue->Equals(*aOldValue)) {
+          Link::ResetLinkState(!!aNotify, true);
+          if (IsInComposedDoc()) {
+            TryDNSPrefetch();
+          }
+        }
+      } else {
+        Link::ResetLinkState(!!aNotify, false);
+      }
+    }
   }
 
-  nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttribute,
-                                                aNotify);
-
-  // The ordering of the parent class's UnsetAttr call and Link::ResetLinkState
-  // is important here!  The attribute is not unset until UnsetAttr returns, and
-  // we will need the updated attribute value because notifying the document
-  // that content states have changed will call IntrinsicState, which will try
-  // to get updated information about the visitedness from Link.
-  if (href) {
-    Link::ResetLinkState(!!aNotify, false);
-  }
-
-  return rv;
-}
-
-bool
-HTMLAnchorElement::ParseAttribute(int32_t aNamespaceID,
-                                  nsIAtom* aAttribute,
-                                  const nsAString& aValue,
-                                  nsAttrValue& aResult)
-{
-  return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
-                                              aResult);
+  return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName,
+                                            aValue, aOldValue, aNotify);
 }
 
 EventStates
 HTMLAnchorElement::IntrinsicState() const
 {
   return Link::LinkState() | nsGenericHTMLElement::IntrinsicState();
 }
 
--- a/dom/html/HTMLAnchorElement.h
+++ b/dom/html/HTMLAnchorElement.h
@@ -61,30 +61,23 @@ public:
   virtual nsresult GetEventTargetParent(
                      EventChainPreVisitor& aVisitor) override;
   virtual nsresult PostHandleEvent(
                      EventChainPostVisitor& aVisitor) override;
   virtual bool IsLink(nsIURI** aURI) const override;
   virtual void GetLinkTarget(nsAString& aTarget) override;
   virtual already_AddRefed<nsIURI> GetHrefURI() const override;
 
-  nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
-                   const nsAString& aValue, bool aNotify)
-  {
-    return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
-  }
-  virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
-                           nsIAtom* aPrefix, const nsAString& aValue,
-                           bool aNotify) override;
-  virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
-                             bool aNotify) override;
-  virtual bool ParseAttribute(int32_t aNamespaceID,
-                                nsIAtom* aAttribute,
-                                const nsAString& aValue,
-                                nsAttrValue& aResult) override;
+  virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+                                 const nsAttrValueOrString* aValue,
+                                 bool aNotify) override;
+  virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
+                                const nsAttrValue* aValue,
+                                const nsAttrValue* aOldValue,
+                                bool aNotify) override;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
                          bool aPreallocateChildren) const override;
 
   virtual EventStates IntrinsicState() const override;
 
   virtual void OnDNSPrefetchDeferred() override;
   virtual void OnDNSPrefetchRequested() override;