Bug 757670 - make nsIPresShell::GetLinkLocation faster, r=bz, tbsaunde
authorAlexander Surkov <surkov.alexander@gmail.com>
Thu, 24 May 2012 15:57:16 +0900
changeset 94800 f0c9c6e916db8f0a1f8a2d071f0abf597d57c7f4
parent 94799 d9064a680e21f650c728b116ca554ed34cc0b60d
child 94801 8d1b746c137b6bca479a0a638574a602a71a3b21
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbz, tbsaunde
bugs757670
milestone15.0a1
Bug 757670 - make nsIPresShell::GetLinkLocation faster, r=bz, tbsaunde
accessible/src/base/nsAccessible.cpp
accessible/src/html/nsHTMLLinkAccessible.cpp
content/base/public/nsContentUtils.h
content/base/src/Link.h
content/base/src/nsContentUtils.cpp
content/html/content/src/nsHTMLAnchorElement.cpp
layout/base/nsDocumentViewer.cpp
layout/base/nsIPresShell.h
layout/base/nsPresShell.cpp
layout/base/nsPresShell.h
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -18,16 +18,17 @@
 #include "nsEventShell.h"
 #include "nsTextEquivUtils.h"
 #include "Relation.h"
 #include "Role.h"
 #include "RootAccessible.h"
 #include "States.h"
 #include "StyleInfo.h"
 
+#include "nsContentUtils.h"
 #include "nsIDOMCSSValue.h"
 #include "nsIDOMCSSPrimitiveValue.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentXBL.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLFormElement.h"
 #include "nsIDOMNodeFilter.h"
@@ -1674,23 +1675,18 @@ nsAccessible::Value(nsString& aValue)
                         aValue);
     }
   }
 
   if (!aValue.IsEmpty())
     return;
 
   // Check if it's a simple xlink.
-  if (nsCoreUtils::IsXLink(mContent)) {
-    nsIPresShell* presShell = mDoc->PresShell();
-    if (presShell) {
-      nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(mContent));
-      presShell->GetLinkLocation(DOMNode, aValue);
-    }
-  }
+  if (nsCoreUtils::IsXLink(mContent))
+    nsContentUtils::GetLinkLocation(mContent->AsElement(), aValue);
 }
 
 // nsIAccessibleValue
 NS_IMETHODIMP
 nsAccessible::GetMaximumValue(double *aMaximumValue)
 {
   return GetAttrValue(nsGkAtoms::aria_valuemax, aMaximumValue);
 }
--- a/accessible/src/html/nsHTMLLinkAccessible.cpp
+++ b/accessible/src/html/nsHTMLLinkAccessible.cpp
@@ -1,20 +1,21 @@
 /* -*- 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 "nsHTMLLinkAccessible.h"
 
 #include "nsCoreUtils.h"
+#include "nsDocAccessible.h"
 #include "Role.h"
 #include "States.h"
 
-#include "nsDocAccessible.h"
+#include "nsContentUtils.h"
 #include "nsEventStates.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLLinkAccessible
 ////////////////////////////////////////////////////////////////////////////////
@@ -72,22 +73,18 @@ nsHTMLLinkAccessible::NativeLinkState() 
 }
 
 void
 nsHTMLLinkAccessible::Value(nsString& aValue)
 {
   aValue.Truncate();
 
   nsHyperTextAccessible::Value(aValue);
-  if (!aValue.IsEmpty())
-    return;
-  
-  nsIPresShell* presShell(mDoc->PresShell());
-  nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(mContent));
-  presShell->GetLinkLocation(DOMNode, aValue);
+  if (aValue.IsEmpty())
+    nsContentUtils::GetLinkLocation(mContent->AsElement(), aValue);
 }
 
 PRUint8
 nsHTMLLinkAccessible::ActionCount()
 {
   return IsLinked() ? 1 : nsHyperTextAccessible::ActionCount();
 }
 
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1384,16 +1384,22 @@ public:
    *                   when the link is triggered.
    */
   static void TriggerLink(nsIContent *aContent, nsPresContext *aPresContext,
                           nsIURI *aLinkURI, const nsString& aTargetSpec,
                           bool aClick, bool aIsUserTriggered,
                           bool aIsTrusted);
 
   /**
+   * Get the link location.
+   */
+  static void GetLinkLocation(mozilla::dom::Element* aElement,
+                              nsString& aLocationString);
+
+  /**
    * Return top-level widget in the parent chain.
    */
   static nsIWidget* GetTopLevelWidget(nsIWidget* aWidget);
 
   /**
    * Return the localized ellipsis for UI.
    */
   static const nsDependentString GetLocalizedEllipsis();
--- a/content/base/src/Link.h
+++ b/content/base/src/Link.h
@@ -111,16 +111,17 @@ protected:
   {
     if (mCachedURI)
       return true;
 
     nsCOMPtr<nsIURI> uri(GetURI());
     return !!uri;
   }
 
+  nsIURI* GetCachedURI() const { return mCachedURI; }
   bool HasCachedURI() const { return !!mCachedURI; }
 
 private:
   /**
    * Unregisters from History so this node no longer gets notifications about
    * changes to visitedness.
    */
   void UnregisterFromHistory();
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -4485,16 +4485,29 @@ nsContentUtils::TriggerLink(nsIContent *
   // Only pass off the click event if the script security manager says it's ok.
   if (NS_SUCCEEDED(proceed)) {
     handler->OnLinkClick(aContent, aLinkURI, aTargetSpec.get(), nsnull, nsnull,
                          aIsTrusted);
   }
 }
 
 /* static */
+void
+nsContentUtils::GetLinkLocation(Element* aElement, nsString& aLocationString)
+{
+  nsCOMPtr<nsIURI> hrefURI = aElement->GetHrefURI();
+  if (hrefURI) {
+    nsCAutoString specUTF8;
+    nsresult rv = hrefURI->GetSpec(specUTF8);
+    if (NS_SUCCEEDED(rv))
+      CopyUTF8toUTF16(specUTF8, aLocationString);
+  }
+}
+
+/* static */
 nsIWidget*
 nsContentUtils::GetTopLevelWidget(nsIWidget* aWidget)
 {
   if (!aWidget)
     return nsnull;
 
   return aWidget->GetTopLevelWidget();
 }
--- a/content/html/content/src/nsHTMLAnchorElement.cpp
+++ b/content/html/content/src/nsHTMLAnchorElement.cpp
@@ -408,16 +408,22 @@ nsLinkState
 nsHTMLAnchorElement::GetLinkState() const
 {
   return Link::GetLinkState();
 }
 
 already_AddRefed<nsIURI>
 nsHTMLAnchorElement::GetHrefURI() const
 {
+  nsIURI* uri = Link::GetCachedURI();
+  if (uri) {
+    NS_ADDREF(uri);
+    return uri;
+  }
+
   return GetHrefURIForAnchors();
 }
 
 nsresult
 nsHTMLAnchorElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                              nsIAtom* aPrefix, const nsAString& aValue,
                              bool aNotify)
 {
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -2531,20 +2531,25 @@ NS_IMETHODIMP DocumentViewerImpl::CopySe
 NS_IMETHODIMP DocumentViewerImpl::CopyLinkLocation()
 {
   NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
   nsCOMPtr<nsIDOMNode> node;
   GetPopupLinkNode(getter_AddRefs(node));
   // make noise if we're not in a link
   NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
 
+  nsCOMPtr<dom::Element> elm(do_QueryInterface(node));
+  NS_ENSURE_TRUE(elm, NS_ERROR_FAILURE);
+
   nsAutoString locationText;
-  nsresult rv = mPresShell->GetLinkLocation(node, locationText);
-  NS_ENSURE_SUCCESS(rv, rv);
-
+  nsContentUtils::GetLinkLocation(elm, locationText);
+  if (locationText.IsEmpty())
+    return NS_ERROR_FAILURE;
+
+  nsresult rv = NS_OK;
   nsCOMPtr<nsIClipboardHelper> clipboard(do_GetService("@mozilla.org/widget/clipboardhelper;1", &rv));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // copy the href onto the clipboard
   return clipboard->CopyString(locationText);
 }
 
 NS_IMETHODIMP DocumentViewerImpl::CopyImage(PRInt32 aCopyFlags)
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -107,20 +107,20 @@ typedef struct CapturingContentInfo {
   // capture should only be allowed during a mousedown event
   bool mAllowed;
   bool mPointerLock;
   bool mRetargetToElement;
   bool mPreventDrag;
   nsIContent* mContent;
 } CapturingContentInfo;
 
-// d2236911-9b7c-490a-a08b-2580d5f7a6de
+// fcada634-fdea-45f5-b841-0a361d5f6a68
 #define NS_IPRESSHELL_IID \
-  { 0xd2236911, 0x9b7c, 0x490a, \
-    { 0xa0, 0x8b, 0x25, 0x80, 0xd5, 0xf7, 0xa6, 0xde } }
+  { 0xfcada634, 0xfdea, 0x45f5, \
+    { 0xb8, 0x41, 0x0a, 0x36, 0x1d, 0x5f, 0x6a, 0x68 } }
 
 // debug VerifyReflow flags
 #define VERIFY_REFLOW_ON                    0x01
 #define VERIFY_REFLOW_NOISY                 0x02
 #define VERIFY_REFLOW_ALL                   0x04
 #define VERIFY_REFLOW_DUMP_COMMANDS         0x08
 #define VERIFY_REFLOW_NOISY_RC              0x10
 #define VERIFY_REFLOW_REALLY_NOISY_RC       0x20
@@ -678,21 +678,16 @@ public:
   /**
    * Notification sent by a frame informing the pres shell that it is about to
    * be destroyed.
    * This allows any outstanding references to the frame to be cleaned up
    */
   virtual NS_HIDDEN_(void) NotifyDestroyingFrame(nsIFrame* aFrame) = 0;
 
   /**
-   * Get link location.
-   */
-  virtual NS_HIDDEN_(nsresult) GetLinkLocation(nsIDOMNode* aNode, nsAString& aLocation) const = 0;
-
-  /**
    * Get the caret, if it exists. AddRefs it.
    */
   virtual NS_HIDDEN_(already_AddRefed<nsCaret>) GetCaret() const = 0;
 
   /**
    * Invalidate the caret's current position if it's outside of its frame's
    * boundaries. This function is useful if you're batching selection
    * notifications and might remove the caret's frame out from under it.
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -3330,48 +3330,16 @@ PresShell::GetRectVisibility(nsIFrame* a
   if (r.XMost() <= insetRect.x)
     return nsRectVisibility_kLeftOfViewport;
   if (r.x >= insetRect.XMost())
     return nsRectVisibility_kRightOfViewport;
 
   return nsRectVisibility_kVisible;
 }
 
-// GetLinkLocation: copy link location to clipboard
-nsresult PresShell::GetLinkLocation(nsIDOMNode* aNode, nsAString& aLocationString) const
-{
-#ifdef DEBUG_dr
-  printf("dr :: PresShell::GetLinkLocation\n");
-#endif
-
-  NS_ENSURE_ARG_POINTER(aNode);
-
-  nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
-  if (content) {
-    nsCOMPtr<nsIURI> hrefURI = content->GetHrefURI();
-    if (hrefURI) {
-      nsCAutoString specUTF8;
-      nsresult rv = hrefURI->GetSpec(specUTF8);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      nsAutoString anchorText;
-      CopyUTF8toUTF16(specUTF8, anchorText);
-
-      // Remove all the '\t', '\r' and '\n' from 'anchorText'
-      static const char strippedChars[] = "\t\r\n";
-      anchorText.StripChars(strippedChars);
-      aLocationString = anchorText;
-      return NS_OK;
-    }
-  }
-
-  // if no link, fail.
-  return NS_ERROR_FAILURE;
-}
-
 void
 PresShell::ScheduleViewManagerFlush()
 {
   nsPresContext* presContext = GetPresContext();
   if (presContext) {
     presContext->RefreshDriver()->ScheduleViewManagerFlush();
   }
   if (mDocument) {
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -129,18 +129,16 @@ public:
                                        PRUint32      aFlags);
   virtual nsRectVisibility GetRectVisibility(nsIFrame *aFrame,
                                              const nsRect &aRect,
                                              nscoord aMinTwips) const;
 
   virtual NS_HIDDEN_(void) SetIgnoreFrameDestruction(bool aIgnore);
   virtual NS_HIDDEN_(void) NotifyDestroyingFrame(nsIFrame* aFrame);
 
-  virtual NS_HIDDEN_(nsresult) GetLinkLocation(nsIDOMNode* aNode, nsAString& aLocationString) const;
-
   virtual NS_HIDDEN_(nsresult) CaptureHistoryState(nsILayoutHistoryState** aLayoutHistoryState, bool aLeavingPage);
 
   virtual NS_HIDDEN_(void) UnsuppressPainting();
 
   virtual nsresult GetAgentStyleSheets(nsCOMArray<nsIStyleSheet>& aSheets);
   virtual nsresult SetAgentStyleSheets(const nsCOMArray<nsIStyleSheet>& aSheets);
 
   virtual nsresult AddOverrideStyleSheet(nsIStyleSheet *aSheet);