Bug 1245751 - Part 1: Allow href without xlink on SVG <a> elements. draft
authorBoris Chiou <boris.chiou@gmail.com>
Tue, 28 Jun 2016 17:22:30 +0800
changeset 407852 85f551a6c3ffed4ea5fddaea5fbb1dab33cb723b
parent 407818 506facea63169a29e04eb140663da1730052db64
child 407853 a2fab48360103db9641f1a0a7e2914884840791b
push id28064
push userbmo:boris.chiou@gmail.com
push dateWed, 31 Aug 2016 04:26:14 +0000
bugs1245751
milestone51.0a1
Bug 1245751 - Part 1: Allow href without xlink on SVG <a> elements. MozReview-Commit-ID: 6HwWv2Uxx5j
dom/base/Link.cpp
dom/svg/SVGAElement.cpp
dom/svg/SVGAElement.h
--- a/dom/base/Link.cpp
+++ b/dom/base/Link.cpp
@@ -40,20 +40,19 @@ Link::Link(Element *aElement)
 Link::~Link()
 {
   UnregisterFromHistory();
 }
 
 bool
 Link::ElementHasHref() const
 {
-  return ((!mElement->IsSVGElement() &&
-           mElement->HasAttr(kNameSpaceID_None, nsGkAtoms::href))
-        || (!mElement->IsHTMLElement() &&
-            mElement->HasAttr(kNameSpaceID_XLink, nsGkAtoms::href)));
+  return mElement->HasAttr(kNameSpaceID_None, nsGkAtoms::href) ||
+         (!mElement->IsHTMLElement() &&
+          mElement->HasAttr(kNameSpaceID_XLink, nsGkAtoms::href));
 }
 
 void
 Link::TryDNSPrefetch()
 {
   MOZ_ASSERT(mElement->IsInComposedDoc());
   if (ElementHasHref() && nsHTMLDNSPrefetch::IsAllowed(mElement->OwnerDoc())) {
     nsHTMLDNSPrefetch::PrefetchLow(this);
--- a/dom/svg/SVGAElement.cpp
+++ b/dom/svg/SVGAElement.cpp
@@ -22,18 +22,19 @@ namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGAElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return SVGAElementBinding::Wrap(aCx, this, aGivenProto);
 }
 
-nsSVGElement::StringInfo SVGAElement::sStringInfo[2] =
+nsSVGElement::StringInfo SVGAElement::sStringInfo[3] =
 {
+  { &nsGkAtoms::href, kNameSpaceID_None, true },
   { &nsGkAtoms::href, kNameSpaceID_XLink, true },
   { &nsGkAtoms::target, kNameSpaceID_None, true }
 };
 
 
 //----------------------------------------------------------------------
 // nsISupports methods
 
@@ -69,17 +70,19 @@ SVGAElement::SVGAElement(already_AddRefe
 
 SVGAElement::~SVGAElement()
 {
 }
 
 already_AddRefed<SVGAnimatedString>
 SVGAElement::Href()
 {
-  return mStringAttributes[HREF].ToDOMAnimatedString(this);
+  return mStringAttributes[HREF].IsExplicitlySet()
+         ? mStringAttributes[HREF].ToDOMAnimatedString(this)
+         : mStringAttributes[XLINK_HREF].ToDOMAnimatedString(this);
 }
 
 //----------------------------------------------------------------------
 // nsINode methods
 
 nsresult
 SVGAElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
 {
@@ -223,34 +226,38 @@ SVGAElement::IsLink(nsIURI** aURI) const
 
   static nsIContent::AttrValuesArray sShowVals[] =
     { &nsGkAtoms::_empty, &nsGkAtoms::_new, &nsGkAtoms::replace, nullptr };
 
   static nsIContent::AttrValuesArray sActuateVals[] =
     { &nsGkAtoms::_empty, &nsGkAtoms::onRequest, nullptr };
 
   // Optimization: check for href first for early return
-  const nsAttrValue* href = mAttrsAndChildren.GetAttr(nsGkAtoms::href,
-                                                      kNameSpaceID_XLink);
+  bool useXLink = !HasAttr(kNameSpaceID_None, nsGkAtoms::href);
+  const nsAttrValue* href =
+    useXLink
+    ? mAttrsAndChildren.GetAttr(nsGkAtoms::href, kNameSpaceID_XLink)
+    : mAttrsAndChildren.GetAttr(nsGkAtoms::href, kNameSpaceID_None);
+
   if (href &&
       FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::type,
                       sTypeVals, eCaseMatters) !=
                       nsIContent::ATTR_VALUE_NO_MATCH &&
       FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::show,
                       sShowVals, eCaseMatters) !=
                       nsIContent::ATTR_VALUE_NO_MATCH &&
       FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::actuate,
                       sActuateVals, eCaseMatters) !=
                       nsIContent::ATTR_VALUE_NO_MATCH) {
     nsCOMPtr<nsIURI> baseURI = GetBaseURI();
     // Get absolute URI
     nsAutoString str;
-    mStringAttributes[HREF].GetAnimValue(str, this);
-    nsContentUtils::NewURIWithDocumentCharset(aURI, str,
-                                              OwnerDoc(), baseURI);
+    const uint8_t idx = useXLink ? XLINK_HREF : HREF;
+    mStringAttributes[idx].GetAnimValue(str, this);
+    nsContentUtils::NewURIWithDocumentCharset(aURI, str, OwnerDoc(), baseURI);
     // must promise out param is non-null if we return true
     return !!*aURI;
   }
 
   *aURI = nullptr;
   return false;
 }
 
@@ -292,17 +299,19 @@ SVGAElement::SetAttr(int32_t aNameSpaceI
   nsresult rv = SVGAElementBase::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 (aName == nsGkAtoms::href && aNameSpaceID == kNameSpaceID_XLink) {
+  if (aName == nsGkAtoms::href &&
+      (aNameSpaceID == kNameSpaceID_XLink ||
+       aNameSpaceID == kNameSpaceID_None)) {
     Link::ResetLinkState(!!aNotify, true);
   }
 
   return rv;
 }
 
 nsresult
 SVGAElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttr,
@@ -310,18 +319,22 @@ SVGAElement::UnsetAttr(int32_t aNameSpac
 {
   nsresult rv = nsSVGElement::UnsetAttr(aNameSpaceID, aAttr, 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 (aAttr == nsGkAtoms::href && aNameSpaceID == kNameSpaceID_XLink) {
-    Link::ResetLinkState(!!aNotify, false);
+  if (aAttr == nsGkAtoms::href &&
+      (aNameSpaceID == kNameSpaceID_XLink ||
+       aNameSpaceID == kNameSpaceID_None)) {
+    bool hasHref = HasAttr(kNameSpaceID_None, nsGkAtoms::href) ||
+                   HasAttr(kNameSpaceID_XLink, nsGkAtoms::href);
+    Link::ResetLinkState(!!aNotify, hasHref);
   }
 
   return rv;
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
--- a/dom/svg/SVGAElement.h
+++ b/dom/svg/SVGAElement.h
@@ -71,17 +71,17 @@ public:
   void GetDownload(nsAString & aDownload);
   void SetDownload(const nsAString & aDownload, ErrorResult& rv);
 
 protected:
   virtual ~SVGAElement();
 
   virtual StringAttributesInfo GetStringInfo() override;
 
-  enum { HREF, TARGET };
-  nsSVGString mStringAttributes[2];
-  static StringInfo sStringInfo[2];
+  enum { HREF, XLINK_HREF, TARGET };
+  nsSVGString mStringAttributes[3];
+  static StringInfo sStringInfo[3];
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SVGAElement_h