Fix for bug 499781 (Move some methods from nsILink to nsIContent). r=bz, sr=dbaron.
authorPeter Van der Beken <peterv@propagandism.org>
Mon, 13 Jul 2009 13:48:06 +0200
changeset 30307 002c13585ad5bdf2523391213ffa650519c149a1
parent 30306 790e9b3af32b8f2a903dd0f99f02897248bfdf72
child 30308 2d7d5c5f2a2ed5804a814e67af33ae069c72ad3a
push idunknown
push userunknown
push dateunknown
reviewersbz, dbaron
bugs499781
milestone1.9.2a1pre
Fix for bug 499781 (Move some methods from nsILink to nsIContent). r=bz, sr=dbaron.
accessible/src/html/nsHTMLImageAccessible.cpp
accessible/src/html/nsHTMLLinkAccessible.cpp
content/base/public/nsIContent.h
content/base/src/nsDocument.cpp
content/html/content/public/nsILink.h
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsGenericHTMLElement.h
content/html/content/src/nsHTMLAnchorElement.cpp
content/html/content/src/nsHTMLAreaElement.cpp
content/html/content/src/nsHTMLDNSPrefetch.cpp
content/html/content/src/nsHTMLLinkElement.cpp
content/html/content/src/nsHTMLStyleElement.cpp
content/svg/content/src/nsSVGAElement.cpp
content/svg/content/src/nsSVGAElement.h
layout/generic/nsImageFrame.cpp
layout/style/nsCSSRuleProcessor.cpp
layout/style/nsIStyleRuleProcessor.h
layout/style/nsStyleUtil.cpp
layout/style/nsStyleUtil.h
webshell/public/nsILinkHandler.h
--- a/accessible/src/html/nsHTMLImageAccessible.cpp
+++ b/accessible/src/html/nsHTMLImageAccessible.cpp
@@ -279,19 +279,19 @@ nsHTMLImageAccessible::GetURI(PRInt32 aI
   if (!mapAreas)
     return NS_OK;
   
   nsCOMPtr<nsIDOMNode> domNode;
   mapAreas->Item(aIndex, getter_AddRefs(domNode));
   if (!domNode)
     return NS_ERROR_INVALID_ARG;
 
-  nsCOMPtr<nsILink> link(do_QueryInterface(domNode));
+  nsCOMPtr<nsIContent> link(do_QueryInterface(domNode));
   if (link)
-    link->GetHrefURI(aURI);
+    *aURI = link->GetHrefURI();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLImageAccessible::GetAnchor(PRInt32 aIndex, nsIAccessible **aAccessible)
 {
   NS_ENSURE_ARG_POINTER(aAccessible);
--- a/accessible/src/html/nsHTMLLinkAccessible.cpp
+++ b/accessible/src/html/nsHTMLLinkAccessible.cpp
@@ -77,21 +77,17 @@ nsHTMLLinkAccessible::GetStateInternal(P
   if (content && content->HasAttr(kNameSpaceID_None,
                                   nsAccessibilityAtoms::name)) {
     // This is how we indicate it is a named anchor
     // In other words, this anchor can be selected as a location :)
     // There is no other better state to use to indicate this.
     *aState |= nsIAccessibleStates::STATE_SELECTABLE;
   }
 
-  nsCOMPtr<nsILink> link = do_QueryInterface(mDOMNode);
-  NS_ENSURE_STATE(link);
-
-  nsLinkState linkState;
-  link->GetLinkState(linkState);
+  nsLinkState linkState = content->GetLinkState();
   if (linkState == eLinkState_NotLink || linkState == eLinkState_Unknown) {
     // This is a either named anchor (a link with also a name attribute) or
     // it doesn't have any attributes. Check if 'click' event handler is
     // registered, otherwise bail out.
     PRBool isOnclick = nsCoreUtils::HasListener(content,
                                                 NS_LITERAL_STRING("click"));
     if (!isOnclick)
       return NS_OK;
@@ -175,30 +171,29 @@ NS_IMETHODIMP
 nsHTMLLinkAccessible::GetURI(PRInt32 aIndex, nsIURI **aURI)
 {
   NS_ENSURE_ARG_POINTER(aURI);
   *aURI = nsnull;
 
   if (aIndex != 0)
     return NS_ERROR_INVALID_ARG;
 
-  nsCOMPtr<nsILink> link(do_QueryInterface(mDOMNode));
+  nsCOMPtr<nsIContent> link(do_QueryInterface(mDOMNode));
   NS_ENSURE_STATE(link);
 
-  return link->GetHrefURI(aURI);
+  *aURI = link->GetHrefURI();
+  return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Protected members
 
 PRBool
 nsHTMLLinkAccessible::IsLinked()
 {
-  nsCOMPtr<nsILink> link(do_QueryInterface(mDOMNode));
+  nsCOMPtr<nsIContent> link(do_QueryInterface(mDOMNode));
   if (!link)
     return PR_FALSE;
 
-  nsLinkState linkState;
-  nsresult rv = link->GetLinkState(linkState);
+  nsLinkState linkState = link->GetLinkState();
 
-  return NS_SUCCEEDED(rv) && linkState != eLinkState_NotLink &&
-         linkState != eLinkState_Unknown;
+  return linkState != eLinkState_NotLink && linkState != eLinkState_Unknown;
 }
--- a/content/base/public/nsIContent.h
+++ b/content/base/public/nsIContent.h
@@ -56,20 +56,27 @@ class nsRuleWalker;
 class nsAttrValue;
 class nsAttrName;
 class nsTextFragment;
 class nsIDocShell;
 #ifdef MOZ_SMIL
 class nsISMILAttr;
 #endif // MOZ_SMIL
 
+enum nsLinkState {
+  eLinkState_Unknown    = 0,
+  eLinkState_Unvisited  = 1,
+  eLinkState_Visited    = 2, 
+  eLinkState_NotLink    = 3
+};
+
 // IID for the nsIContent interface
 #define NS_ICONTENT_IID       \
-{ 0x08dadcc4, 0x057a, 0x4b8d, \
-  { 0x89, 0x43, 0x30, 0x0e, 0x61, 0xc6, 0x9d, 0x36 } }
+{ 0x4aaa38b8, 0x6bc1, 0x4d01, \
+  { 0xb6, 0x3d, 0xcd, 0x11, 0xc0, 0x84, 0x56, 0x9e } }
 
 /**
  * A node of content in a document's content model. This interface
  * is supported by all content objects.
  */
 class nsIContent : public nsINode {
 public:
 #ifdef MOZILLA_INTERNAL_API
@@ -594,16 +601,50 @@ public:
    * @note The out param, aURI, is guaranteed to be set to a non-null pointer
    *   when the return value is PR_TRUE.
    *
    * XXXjwatt: IMO IsInteractiveLink would be a better name.
    */
   virtual PRBool IsLink(nsIURI** aURI) const = 0;
 
   /**
+   * Get the cached state of the link.  If the state is unknown, 
+   * return eLinkState_Unknown.
+   *
+   * @return The cached link state of the link.
+   */
+  virtual nsLinkState GetLinkState() const
+  {
+    return eLinkState_NotLink;
+  }
+
+  /**
+   * Set the cached state of the link.
+   *
+   * @param aState The cached link state of the link.
+   */
+  virtual void SetLinkState(nsLinkState aState)
+  {
+    NS_ASSERTION(aState == eLinkState_NotLink,
+                 "Need to override SetLinkState?");
+  }
+
+  /**
+    * Get a pointer to the full href URI (fully resolved and canonicalized,
+    * since it's an nsIURI object) for link elements.
+    *
+    * @return A pointer to the URI or null if the element is not a link or it
+    *         has no HREF attribute.
+    */
+  virtual already_AddRefed<nsIURI> GetHrefURI() const
+  {
+    return nsnull;
+  }
+
+  /**
    * Give this element a chance to fire links that should be fired
    * automatically when loaded. If the element was an autoloading link
    * and it was successfully handled, we will throw special nsresult values.
    *
    * @param aShell the current doc shell (to possibly load the link on)
    * @throws NS_OK if nothing happened
    * @throws NS_XML_AUTOLINK_EMBED if the caller is loading the link embedded
    * @throws NS_XML_AUTOLINK_NEW if the caller is loading the link in a new
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -7300,20 +7300,17 @@ public:
     uri->GetSpec(spec);
     // We use nsCString::Equals here instead of nsIURI::Equals because
     // history matching is all based on spec equality
     if (!spec.Equals(matchURISpec))
       return;
 
     // Throw away the cached link state so it gets refetched by the style
     // system      
-    nsCOMPtr<nsILink> link = do_QueryInterface(aContent);
-    if (link) {
-      link->SetLinkState(eLinkState_Unknown);
-    }
+    aContent->SetLinkState(eLinkState_Unknown);
     contentVisited.AppendObject(aContent);
   }
 };
 
 void
 nsDocument::NotifyURIVisitednessChanged(nsIURI* aURI)
 {
   if (!mVisible) {
--- a/content/html/content/public/nsILink.h
+++ b/content/html/content/public/nsILink.h
@@ -40,56 +40,34 @@
 
 #include "nsISupports.h"
 #include "nsILinkHandler.h" // definition of nsLinkState
 
 class nsIURI;
 
 // IID for the nsILink interface
 #define NS_ILINK_IID    \
-{ 0x0c212bc4, 0xfcd7, 0x479d,  \
-  { 0x8c, 0x3f, 0x3b, 0xe8, 0xe6, 0x78, 0x74, 0x50 } }
+{ 0x6f374a11, 0x212d, 0x47d6, \
+  { 0x94, 0xd1, 0xe6, 0x7c, 0x23, 0x4d, 0x34, 0x99 } }
 
 /**
  * This interface allows SelectorMatches to get the canonical
  * URL pointed to by an element representing a link and allows
  * it to store the visited state of a link element in the link.
  * It is needed for performance reasons (to prevent copying of
  * strings and excessive calls to history).
  */
 class nsILink : public nsISupports {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ILINK_IID)
 
   /**
-   * Get the cached state of the link.  If the state is unknown, 
-   * return eLinkState_Unknown.
-   *
-   * @param aState [out] The cached link state of the link.
-   * @return NS_OK
+   * GetLinkState/SetLinkState/GetHrefURI were moved to nsIContent.
+   * @see nsIContent
    */
-  NS_IMETHOD GetLinkState(nsLinkState &aState) = 0;
-
-  /**
-   * Set the cached state of the link.
-   *
-   * @param aState The cached link state of the link.
-   * @return NS_OK
-   */
-  NS_IMETHOD SetLinkState(nsLinkState aState) = 0;
-
-  /**
-    * Get a pointer to the fully href URI (fully resolved and canonicalized,
-    * since it's an nsIURI object).
-    *
-    * @param aURI [out] A pointer to be filled in with a pointer to the URI
-    *             If the element has no HREF attribute, it is set to nsnull.
-    * @return NS_OK if the out pointer is filled in (possibly with nsnull)
-    */
-  NS_IMETHOD GetHrefURI(nsIURI** aURI) = 0;
 
   /**
    * Dispatch a LinkAdded event to the chrome event handler for this document.
    * This is used to notify the chrome listeners when restoring a page
    * presentation.  Currently, this only applies to HTML <link> elements.
    */
   NS_IMETHOD LinkAdded() = 0;
 
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -1008,33 +1008,34 @@ nsGenericHTMLElement::PostHandleEventFor
   return PostHandleEventForLinks(aVisitor);
 }
 
 PRBool
 nsGenericHTMLElement::IsHTMLLink(nsIURI** aURI) const
 {
   NS_PRECONDITION(aURI, "Must provide aURI out param");
 
-  GetHrefURIForAnchors(aURI);
+  *aURI = GetHrefURIForAnchors().get();
   // We promise out param is non-null if we return true, so base rv on it
   return *aURI != nsnull;
 }
 
-nsresult
-nsGenericHTMLElement::GetHrefURIForAnchors(nsIURI** aURI) const
+already_AddRefed<nsIURI>
+nsGenericHTMLElement::GetHrefURIForAnchors() const
 {
   // This is used by the three nsILink implementations and
   // nsHTMLStyleElement.
 
   // Get href= attribute (relative URI).
 
   // We use the nsAttrValue's copy of the URI string to avoid copying.
-  GetURIAttr(nsGkAtoms::href, nsnull, PR_FALSE, aURI);
-
-  return NS_OK;
+  nsCOMPtr<nsIURI> uri;
+  GetURIAttr(nsGkAtoms::href, nsnull, PR_FALSE, getter_AddRefs(uri));
+
+  return uri.forget();
 }
 
 void
 nsGenericHTMLElement::GetHrefURIToMutate(nsIURI** aURI)
 {
   GetURIAttr(nsGkAtoms::href, nsnull, PR_TRUE, aURI);
 }
 
@@ -3189,18 +3190,17 @@ nsGenericHTMLElement::SetPortInHrefURI(c
   SetHrefToURI(uri);
 
   return NS_OK;
 }
 
 nsresult
 nsGenericHTMLElement::GetProtocolFromHrefURI(nsAString& aProtocol)
 {
-  nsCOMPtr<nsIURI> uri;
-  GetHrefURIForAnchors(getter_AddRefs(uri));
+  nsCOMPtr<nsIURI> uri = GetHrefURIForAnchors();
 
   if (!uri) {
     aProtocol.AssignLiteral("http");
   } else {
     nsCAutoString scheme;
     uri->GetScheme(scheme);
     CopyASCIItoUTF16(scheme, aProtocol);
   }
@@ -3208,18 +3208,17 @@ nsGenericHTMLElement::GetProtocolFromHre
   return NS_OK;
 }
 
 nsresult
 nsGenericHTMLElement::GetHostFromHrefURI(nsAString& aHost)
 {
   aHost.Truncate();
 
-  nsCOMPtr<nsIURI> uri;
-  GetHrefURIForAnchors(getter_AddRefs(uri));
+  nsCOMPtr<nsIURI> uri = GetHrefURIForAnchors();
   if (!uri) {
     // Don't throw from these methods!  Not a valid URI means return
     // empty string.
     return NS_OK;
   }
 
   nsCAutoString hostport;
   nsresult rv = uri->GetHostPort(hostport);
@@ -3233,18 +3232,17 @@ nsGenericHTMLElement::GetHostFromHrefURI
 
   return NS_OK;
 }
 
 nsresult
 nsGenericHTMLElement::GetHostnameFromHrefURI(nsAString& aHostname)
 {
   aHostname.Truncate();
-  nsCOMPtr<nsIURI> uri;
-  GetHrefURIForAnchors(getter_AddRefs(uri));
+  nsCOMPtr<nsIURI> uri = GetHrefURIForAnchors();
   if (!uri) {
     // Don't throw from these methods!  Not a valid URI means return
     // empty string.
     return NS_OK;
   }
 
   nsCAutoString host;
   nsresult rv = uri->GetHost(host);
@@ -3259,18 +3257,17 @@ nsGenericHTMLElement::GetHostnameFromHre
   return NS_OK;
 }
 
 nsresult
 nsGenericHTMLElement::GetPathnameFromHrefURI(nsAString& aPathname)
 {
   aPathname.Truncate();
 
-  nsCOMPtr<nsIURI> uri;
-  GetHrefURIForAnchors(getter_AddRefs(uri));
+  nsCOMPtr<nsIURI> uri = GetHrefURIForAnchors();
   if (!uri) {
     // Don't throw from these methods!  Not a valid URI means return
     // empty string.
     return NS_OK;
   }
 
   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
 
@@ -3289,18 +3286,17 @@ nsGenericHTMLElement::GetPathnameFromHre
 
   return NS_OK;
 }
 
 nsresult
 nsGenericHTMLElement::GetSearchFromHrefURI(nsAString& aSearch)
 {
   aSearch.Truncate();
-  nsCOMPtr<nsIURI> uri;
-  GetHrefURIForAnchors(getter_AddRefs(uri));
+  nsCOMPtr<nsIURI> uri = GetHrefURIForAnchors();
   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   if (!url) {
     // Don't throw from these methods!  Not a valid URI means return
     // empty string.
     return NS_OK;
   }
 
   nsCAutoString search;
@@ -3314,18 +3310,17 @@ nsGenericHTMLElement::GetSearchFromHrefU
 
   return NS_OK;
 }
 
 nsresult
 nsGenericHTMLElement::GetPortFromHrefURI(nsAString& aPort)
 {
   aPort.Truncate();
-  nsCOMPtr<nsIURI> uri;
-  GetHrefURIForAnchors(getter_AddRefs(uri));
+  nsCOMPtr<nsIURI> uri = GetHrefURIForAnchors();
   if (!uri) {
     // Don't throw from these methods!  Not a valid URI means return
     // empty string.
     return NS_OK;
   }
 
   PRInt32 port;
   nsresult rv = uri->GetPort(&port);
@@ -3345,18 +3340,17 @@ nsGenericHTMLElement::GetPortFromHrefURI
 
   return NS_OK;
 }
 
 nsresult
 nsGenericHTMLElement::GetHashFromHrefURI(nsAString& aHash)
 {
   aHash.Truncate();
-  nsCOMPtr<nsIURI> uri;
-  GetHrefURIForAnchors(getter_AddRefs(uri));
+  nsCOMPtr<nsIURI> uri = GetHrefURIForAnchors();
   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   if (!url) {
     // Don't throw from these methods!  Not a valid URI means return
     // empty string.
     return NS_OK;
   }
 
   nsCAutoString ref;
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -191,17 +191,17 @@ public:
    * @return PR_TRUE if the event can be handled, PR_FALSE otherwise
    */
   PRBool CheckHandleEventForAnchorsPreconditions(nsEventChainVisitor& aVisitor);
   nsresult PreHandleEventForAnchors(nsEventChainPreVisitor& aVisitor);
   nsresult PostHandleEventForAnchors(nsEventChainPostVisitor& aVisitor);
   PRBool IsHTMLLink(nsIURI** aURI) const;
 
   // Used by A, AREA, LINK, and STYLE.
-  nsresult GetHrefURIForAnchors(nsIURI** aURI) const;
+  already_AddRefed<nsIURI> GetHrefURIForAnchors() const;
 
   // As above, but makes sure to return a URI object that we can mutate with
   // impunity without changing our current URI.  That is, if the URI is cached
   // it clones it and returns the clone.
   void GetHrefURIToMutate(nsIURI** aURI);
 
   // HTML element methods
   void Compact() { mAttrsAndChildren.Compact(); }
--- a/content/html/content/src/nsHTMLAnchorElement.cpp
+++ b/content/html/content/src/nsHTMLAnchorElement.cpp
@@ -94,19 +94,16 @@ public:
 
   // nsIDOMNSHTMLAnchorElement
   NS_DECL_NSIDOMNSHTMLANCHORELEMENT
 
   // nsIDOMNSHTMLAnchorElement2
   NS_DECL_NSIDOMNSHTMLANCHORELEMENT2
 
   // nsILink
-  NS_IMETHOD GetLinkState(nsLinkState &aState);
-  NS_IMETHOD SetLinkState(nsLinkState aState);
-  NS_IMETHOD GetHrefURI(nsIURI** aURI);
   NS_IMETHOD LinkAdded() { return NS_OK; }
   NS_IMETHOD LinkRemoved() { return NS_OK; }
 
   // override from nsGenericHTMLElement
   NS_IMETHOD GetDraggable(PRBool* aDraggable);
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
@@ -114,16 +111,19 @@ public:
   virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
                               PRBool aNullParent = PR_TRUE);
   virtual PRBool IsHTMLFocusable(PRBool *aIsFocusable, PRInt32 *aTabIndex);
 
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
   virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
   virtual PRBool IsLink(nsIURI** aURI) const;
   virtual void GetLinkTarget(nsAString& aTarget);
+  virtual nsLinkState GetLinkState() const;
+  virtual void SetLinkState(nsLinkState aState);
+  virtual already_AddRefed<nsIURI> GetHrefURI() const;
 
   nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                    const nsAString& aValue, PRBool aNotify)
   {
     return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
   }
   virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                            nsIAtom* aPrefix, const nsAString& aValue,
@@ -417,34 +417,32 @@ nsHTMLAnchorElement::GetPing(nsAString& 
 }
 
 NS_IMETHODIMP
 nsHTMLAnchorElement::SetPing(const nsAString& aValue)
 {
   return SetAttr(kNameSpaceID_None, nsGkAtoms::ping, aValue, PR_TRUE);
 }
 
-NS_IMETHODIMP
-nsHTMLAnchorElement::GetLinkState(nsLinkState &aState)
+nsLinkState
+nsHTMLAnchorElement::GetLinkState() const
 {
-  aState = mLinkState;
-  return NS_OK;
+  return mLinkState;
 }
 
-NS_IMETHODIMP
+void
 nsHTMLAnchorElement::SetLinkState(nsLinkState aState)
 {
   mLinkState = aState;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsHTMLAnchorElement::GetHrefURI(nsIURI** aURI)
+already_AddRefed<nsIURI>
+nsHTMLAnchorElement::GetHrefURI() const
 {
-  return GetHrefURIForAnchors(aURI);
+  return GetHrefURIForAnchors();
 }
 
 nsresult
 nsHTMLAnchorElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                              nsIAtom* aPrefix, const nsAString& aValue,
                              PRBool aNotify)
 {
   if (aName == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) {
--- a/content/html/content/src/nsHTMLAreaElement.cpp
+++ b/content/html/content/src/nsHTMLAreaElement.cpp
@@ -76,26 +76,26 @@ public:
 
   // nsIDOMNSHTMLAreaElement
   NS_DECL_NSIDOMNSHTMLAREAELEMENT
 
   // nsIDOMNSHTMLAreaElement2
   NS_DECL_NSIDOMNSHTMLAREAELEMENT2
 
   // nsILink
-  NS_IMETHOD GetLinkState(nsLinkState &aState);
-  NS_IMETHOD SetLinkState(nsLinkState aState);
-  NS_IMETHOD GetHrefURI(nsIURI** aURI);
   NS_IMETHOD LinkAdded() { return NS_OK; }
   NS_IMETHOD LinkRemoved() { return NS_OK; }
 
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
   virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
   virtual PRBool IsLink(nsIURI** aURI) const;
   virtual void GetLinkTarget(nsAString& aTarget);
+  virtual nsLinkState GetLinkState() const;
+  virtual void SetLinkState(nsLinkState aState);
+  virtual already_AddRefed<nsIURI> GetHrefURI() const;
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               PRBool aCompileEventHandlers);
   virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
                               PRBool aNullParent = PR_TRUE);
   nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                    const nsAString& aValue, PRBool aNotify)
@@ -315,27 +315,25 @@ nsHTMLAreaElement::GetPing(nsAString& aV
 }
 
 NS_IMETHODIMP
 nsHTMLAreaElement::SetPing(const nsAString& aValue)
 {
   return SetAttr(kNameSpaceID_None, nsGkAtoms::ping, aValue, PR_TRUE);
 }
 
-NS_IMETHODIMP
-nsHTMLAreaElement::GetLinkState(nsLinkState &aState)
+nsLinkState
+nsHTMLAreaElement::GetLinkState() const
 {
-  aState = mLinkState;
-  return NS_OK;
+  return mLinkState;
 }
 
-NS_IMETHODIMP
+void
 nsHTMLAreaElement::SetLinkState(nsLinkState aState)
 {
   mLinkState = aState;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsHTMLAreaElement::GetHrefURI(nsIURI** aURI)
+already_AddRefed<nsIURI>
+nsHTMLAreaElement::GetHrefURI() const
 {
-  return GetHrefURIForAnchors(aURI);
+  return GetHrefURIForAnchors();
 }
--- a/content/html/content/src/nsHTMLDNSPrefetch.cpp
+++ b/content/html/content/src/nsHTMLDNSPrefetch.cpp
@@ -255,17 +255,17 @@ nsHTMLDNSPrefetch::nsDeferrals::SubmitQu
   NS_ASSERTION(NS_IsMainThread(), "nsDeferrals::SubmitQueue must be on main thread");
   nsCString hostName;
   if (!sDNSService) return;
 
   while (mHead != mTail) {
 
     if (mEntries[mTail].mElement->GetOwnerDoc()) {
       nsCOMPtr<nsIURI> hrefURI;
-      mEntries[mTail].mElement->GetHrefURIForAnchors(getter_AddRefs(hrefURI));
+      hrefURI = mEntries[mTail].mElement->GetHrefURIForAnchors();
       if (hrefURI)
         hrefURI->GetAsciiHost(hostName);
       
       if (!hostName.IsEmpty()) {
         nsCOMPtr<nsICancelable> tmpOutstanding;
 
         sDNSService->AsyncResolve(hostName, 
                                   mEntries[mTail].mFlags | nsIDNSService::RESOLVE_SPECULATE,
--- a/content/html/content/src/nsHTMLLinkElement.cpp
+++ b/content/html/content/src/nsHTMLLinkElement.cpp
@@ -80,19 +80,16 @@ public:
 
   // nsIDOMHTMLElement
   NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::)
 
   // nsIDOMHTMLLinkElement
   NS_DECL_NSIDOMHTMLLINKELEMENT
 
   // nsILink
-  NS_IMETHOD    GetLinkState(nsLinkState &aState);
-  NS_IMETHOD    SetLinkState(nsLinkState aState);
-  NS_IMETHOD    GetHrefURI(nsIURI** aURI);
   NS_IMETHOD    LinkAdded();
   NS_IMETHOD    LinkRemoved();
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               PRBool aCompileEventHandlers);
   virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
                               PRBool aNullParent = PR_TRUE);
@@ -107,16 +104,19 @@ public:
                            PRBool aNotify);
   virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
                              PRBool aNotify);
 
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
   virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
   virtual PRBool IsLink(nsIURI** aURI) const;
   virtual void GetLinkTarget(nsAString& aTarget);
+  virtual nsLinkState GetLinkState() const;
+  virtual void SetLinkState(nsLinkState aState);
+  virtual already_AddRefed<nsIURI> GetHrefURI() const;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
 protected:
   virtual void GetStyleSheetURL(PRBool* aIsInline,
                                 nsIURI** aURI);
   virtual void GetStyleSheetInfo(nsAString& aTitle,
                                  nsAString& aType,
@@ -372,42 +372,40 @@ void
 nsHTMLLinkElement::GetLinkTarget(nsAString& aTarget)
 {
   GetAttr(kNameSpaceID_None, nsGkAtoms::target, aTarget);
   if (aTarget.IsEmpty()) {
     GetBaseTarget(aTarget);
   }
 }
 
-NS_IMETHODIMP
-nsHTMLLinkElement::GetLinkState(nsLinkState &aState)
+nsLinkState
+nsHTMLLinkElement::GetLinkState() const
 {
-  aState = mLinkState;
-  return NS_OK;
+  return mLinkState;
 }
 
-NS_IMETHODIMP
+void
 nsHTMLLinkElement::SetLinkState(nsLinkState aState)
 {
   mLinkState = aState;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsHTMLLinkElement::GetHrefURI(nsIURI** aURI)
+already_AddRefed<nsIURI>
+nsHTMLLinkElement::GetHrefURI() const
 {
-  return GetHrefURIForAnchors(aURI);
+  return GetHrefURIForAnchors();
 }
 
 void
 nsHTMLLinkElement::GetStyleSheetURL(PRBool* aIsInline,
                                     nsIURI** aURI)
 {
   *aIsInline = PR_FALSE;
-  GetHrefURIForAnchors(aURI);
+  *aURI = GetHrefURIForAnchors().get();
   return;
 }
 
 void
 nsHTMLLinkElement::GetStyleSheetInfo(nsAString& aTitle,
                                      nsAString& aType,
                                      nsAString& aMedia,
                                      PRBool* aIsAlternate)
--- a/content/html/content/src/nsHTMLStyleElement.cpp
+++ b/content/html/content/src/nsHTMLStyleElement.cpp
@@ -323,17 +323,17 @@ nsHTMLStyleElement::GetStyleSheetURL(PRB
   }
   if (!IsInHTMLDocument()) {
     // We stopped supporting <style src="..."> for XHTML as it is
     // non-standard.
     *aIsInline = PR_TRUE;
     return;
   }
 
-  GetHrefURIForAnchors(aURI);
+  *aURI = GetHrefURIForAnchors().get();
   return;
 }
 
 void
 nsHTMLStyleElement::GetStyleSheetInfo(nsAString& aTitle,
                                       nsAString& aType,
                                       nsAString& aMedia,
                                       PRBool* aIsAlternate)
--- a/content/svg/content/src/nsSVGAElement.cpp
+++ b/content/svg/content/src/nsSVGAElement.cpp
@@ -115,43 +115,37 @@ NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGAEl
 NS_IMETHODIMP
 nsSVGAElement::GetTarget(nsIDOMSVGAnimatedString * *aTarget)
 {
   return mStringAttributes[TARGET].ToDOMAnimatedString(aTarget, this);
 }
 
 
 //----------------------------------------------------------------------
-// nsILink methods
+// nsIContent methods
 
-NS_IMETHODIMP
-nsSVGAElement::GetLinkState(nsLinkState &aState)
+nsLinkState
+nsSVGAElement::GetLinkState() const
 {
-  aState = mLinkState;
-  return NS_OK;
+  return mLinkState;
 }
 
-NS_IMETHODIMP
+void
 nsSVGAElement::SetLinkState(nsLinkState aState)
 {
   mLinkState = aState;
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsSVGAElement::GetHrefURI(nsIURI** aURI)
+already_AddRefed<nsIURI>
+nsSVGAElement::GetHrefURI() const
 {
-  *aURI = nsnull;
-  return NS_OK; // XXX GetHrefURIForAnchors(aURI);
+  return nsnull; // XXX GetHrefURIForAnchors();
 }
 
 
-//----------------------------------------------------------------------
-// nsIContent methods
-
 PRBool
 nsSVGAElement::IsFocusable(PRInt32 *aTabIndex)
 {
   nsCOMPtr<nsIURI> uri;
   if (IsLink(getter_AddRefs(uri))) {
     if (aTabIndex) {
       *aTabIndex = ((sTabFocusModel & eTabFocus_linksMask) == 0 ? -1 : 0);
     }
--- a/content/svg/content/src/nsSVGAElement.h
+++ b/content/svg/content/src/nsSVGAElement.h
@@ -66,26 +66,26 @@ public:
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGAElementBase::)
 
   // nsINode interface methods
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
   virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor);
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   // nsILink
-  NS_IMETHOD GetLinkState(nsLinkState &aState);
-  NS_IMETHOD SetLinkState(nsLinkState aState);
-  NS_IMETHOD GetHrefURI(nsIURI** aURI);
   NS_IMETHOD LinkAdded() { return NS_OK; }
   NS_IMETHOD LinkRemoved() { return NS_OK; }
 
   // nsIContent
   virtual PRBool IsFocusable(PRInt32 *aTabIndex = nsnull);
   virtual PRBool IsLink(nsIURI** aURI) const;
   virtual void GetLinkTarget(nsAString& aTarget);
+  virtual nsLinkState GetLinkState() const;
+  virtual void SetLinkState(nsLinkState aState);
+  virtual already_AddRefed<nsIURI> GetHrefURI() const;
 
 protected:
 
   virtual StringAttributesInfo GetStringInfo();
 
   enum { HREF, TARGET };
   nsSVGString mStringAttributes[2];
   static StringInfo sStringInfo[2];
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1375,17 +1375,17 @@ nsImageFrame::GetAnchorHREFTargetAndNode
   *aHref = nsnull;
   *aNode = nsnull;
 
   // Walk up the content tree, looking for an nsIDOMAnchorElement
   for (nsIContent* content = mContent->GetParent();
        content; content = content->GetParent()) {
     nsCOMPtr<nsILink> link(do_QueryInterface(content));
     if (link) {
-      link->GetHrefURI(aHref);
+      *aHref = content->GetHrefURI().get();
       status = (*aHref != nsnull);
 
       nsCOMPtr<nsIDOMHTMLAnchorElement> anchor(do_QueryInterface(content));
       if (anchor) {
         anchor->GetTarget(aTarget);
       }
       NS_ADDREF(*aNode = content);
       break;
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -904,18 +904,17 @@ RuleProcessorData::RuleProcessorData(nsP
     mIsHTMLContent = (mNameSpaceID == kNameSpaceID_XHTML);
 
     // if HTML content and it has some attributes, check for an HTML link
     // NOTE: optimization: cannot be a link if no attributes (since it needs an href)
     nsILinkHandler* linkHandler =
       mPresContext ? mPresContext->GetLinkHandler() : nsnull;
     if (mIsHTMLContent && mHasAttributes) {
       // check if it is an HTML Link
-      if(nsStyleUtil::IsHTMLLink(aContent, mContentTag, linkHandler,
-                                 &mLinkState)) {
+      if(nsStyleUtil::IsHTMLLink(aContent, linkHandler, &mLinkState)) {
         mIsLink = PR_TRUE;
       }
     } 
 
     // if not an HTML link, check for a simple xlink (cannot be both HTML link and xlink)
     // NOTE: optimization: cannot be an XLink if no attributes (since it needs an 
     if(!mIsLink &&
        mHasAttributes && 
--- a/layout/style/nsIStyleRuleProcessor.h
+++ b/layout/style/nsIStyleRuleProcessor.h
@@ -44,23 +44,22 @@
 
 #ifndef nsIStyleRuleProcessor_h___
 #define nsIStyleRuleProcessor_h___
 
 #include <stdio.h>
 
 #include "nsISupports.h"
 #include "nsPresContext.h" // for nsCompatability
-#include "nsILinkHandler.h"
 #include "nsString.h"
 #include "nsChangeHint.h"
+#include "nsIContent.h"
 
 class nsIStyleSheet;
 class nsPresContext;
-class nsIContent;
 class nsIAtom;
 class nsICSSPseudoComparator;
 class nsRuleWalker;
 class nsAttrValue;
 
 // The implementation of the constructor and destructor are currently in
 // nsCSSRuleProcessor.cpp.
 
--- a/layout/style/nsStyleUtil.cpp
+++ b/layout/style/nsStyleUtil.cpp
@@ -37,17 +37,16 @@
 
 #include <math.h>
 #include "nsStyleUtil.h"
 #include "nsCRT.h"
 #include "nsStyleConsts.h"
 
 #include "nsGkAtoms.h"
 #include "nsILinkHandler.h"
-#include "nsILink.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsINameSpaceManager.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "nsReadableUtils.h"
 #include "nsContentUtils.h"
 #include "nsTextFormatter.h"
@@ -424,65 +423,50 @@ GetLinkStateFromURI(nsIURI* aURI, nsICon
       state = eLinkState_Unvisited;
     }
   }
 
   return state;  
 }
 
 /*static*/
-PRBool nsStyleUtil::IsHTMLLink(nsIContent *aContent, nsIAtom *aTag,
+PRBool nsStyleUtil::IsHTMLLink(nsIContent *aContent,
                                nsILinkHandler *aLinkHandler,
                                nsLinkState *aState)
 {
-  NS_ASSERTION(aContent && aState, "null arg in IsHTMLLink");
+  NS_ASSERTION(aContent->IsNodeOfType(nsINode::eHTML),
+               "Only use this function with HTML elements");
+  NS_ASSERTION(aState, "null arg in IsHTMLLink");
 
-  // check for:
-  //  - HTML ANCHOR with valid HREF
-  //  - HTML LINK with valid HREF
-  //  - HTML AREA with valid HREF
+  nsLinkState linkState = aContent->GetLinkState();
+  if (linkState == eLinkState_Unknown) {
+    // if it is an anchor, area or link then check the href attribute
+    // make sure this anchor has a link even if we are not testing state
+    // if there is no link, then this anchor is not really a linkpseudo.
+    // bug=23209
 
-  PRBool result = PR_FALSE;
-
-  if ((aTag == nsGkAtoms::a) ||
-      (aTag == nsGkAtoms::link) ||
-      (aTag == nsGkAtoms::area)) {
+    nsCOMPtr<nsIURI> hrefURI = aContent->GetHrefURI();
 
-    nsCOMPtr<nsILink> link( do_QueryInterface(aContent) );
-    // In XML documents, this can be null.
-    if (link) {
-      nsLinkState linkState;
-      link->GetLinkState(linkState);
-      if (linkState == eLinkState_Unknown) {
-        // if it is an anchor, area or link then check the href attribute
-        // make sure this anchor has a link even if we are not testing state
-        // if there is no link, then this anchor is not really a linkpseudo.
-        // bug=23209
-
-        nsCOMPtr<nsIURI> hrefURI;
-        link->GetHrefURI(getter_AddRefs(hrefURI));
-
-        if (hrefURI) {
-          linkState = GetLinkStateFromURI(hrefURI, aContent, aLinkHandler);
-        } else {
-          linkState = eLinkState_NotLink;
-        }
-        if (linkState != eLinkState_NotLink && aContent->IsInDoc()) {
-          aContent->GetCurrentDoc()->AddStyleRelevantLink(aContent, hrefURI);
-        }
-        link->SetLinkState(linkState);
-      }
-      if (linkState != eLinkState_NotLink) {
-        *aState = linkState;
-        result = PR_TRUE;
-      }
+    if (hrefURI) {
+      linkState = GetLinkStateFromURI(hrefURI, aContent, aLinkHandler);
+    } else {
+      linkState = eLinkState_NotLink;
     }
+    if (linkState != eLinkState_NotLink && aContent->IsInDoc()) {
+      aContent->GetCurrentDoc()->AddStyleRelevantLink(aContent, hrefURI);
+    }
+    aContent->SetLinkState(linkState);
+  }
+  if (linkState == eLinkState_NotLink) {
+    return PR_FALSE;
   }
 
-  return result;
+  *aState = linkState;
+
+  return PR_TRUE;
 }
 
 /*static*/
 PRBool nsStyleUtil::IsLink(nsIContent     *aContent,
                            nsILinkHandler *aLinkHandler,
                            nsLinkState    *aState)
 {
   // XXX PERF This function will cause serious performance problems on
--- a/layout/style/nsStyleUtil.h
+++ b/layout/style/nsStyleUtil.h
@@ -64,18 +64,17 @@ public:
                                          nsFontSizeType aFontSizeType = eFontSize_HTML);
 
   static nscoord FindNextLargerFontSize(nscoord aFontSize, PRInt32 aBasePointSize, 
                                         float aScalingFactor, nsPresContext* aPresContext,
                                         nsFontSizeType aFontSizeType = eFontSize_HTML);
 
   static PRInt32 ConstrainFontWeight(PRInt32 aWeight);
 
-  static PRBool IsHTMLLink(nsIContent *aContent, nsIAtom *aTag,
-                           nsILinkHandler *aLinkHandler,
+  static PRBool IsHTMLLink(nsIContent *aContent, nsILinkHandler *aLinkHandler,
                            nsLinkState *aState);
   static PRBool IsLink(nsIContent *aContent, nsILinkHandler *aLinkHandler,
                        nsLinkState *aState);
 
  static PRBool DashMatchCompare(const nsAString& aAttributeValue,
                                 const nsAString& aSelectorValue,
                                 const nsStringComparator& aComparator);
                                 
--- a/webshell/public/nsILinkHandler.h
+++ b/webshell/public/nsILinkHandler.h
@@ -33,35 +33,28 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 #ifndef nsILinkHandler_h___
 #define nsILinkHandler_h___
 
 #include "nsISupports.h"
+#include "nsIContent.h"
 
 class nsIInputStream;
 class nsIDocShell;
 class nsIRequest;
-class nsIContent;
 class nsString;
 class nsGUIEvent;
 
 // Interface ID for nsILinkHandler
 #define NS_ILINKHANDLER_IID \
  { 0x514bc565, 0x8d38, 0x4dde,{0xb4, 0xeb, 0xe7, 0xb5, 0x01, 0x2b, 0xf4, 0x64}}
 
-enum nsLinkState {
-  eLinkState_Unknown    = 0,
-  eLinkState_Unvisited  = 1,
-  eLinkState_Visited    = 2, 
-  eLinkState_NotLink    = 3
-};
-
 /**
  * Interface used for handling clicks on links
  */
 class nsILinkHandler : public nsISupports {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ILINKHANDLER_IID)
 
   /**