Bug 584293. Make .style faster. r=peterv
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 05 Aug 2010 17:59:36 -0400
changeset 48944 e7b3d37b2bbd759749efb88a71fd97464bcd587c
parent 48943 6e97f59bcb1c98149673afa14796f1736adfeaab
child 48945 52a83d6aea2054002339499aa32077cb59fe1c35
push idunknown
push userunknown
push dateunknown
reviewerspeterv
bugs584293
milestone2.0b4pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 584293. Make .style faster. r=peterv
content/base/src/nsStyledElement.cpp
content/base/src/nsStyledElement.h
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsGenericHTMLElement.h
content/svg/content/src/nsSVGStylableElement.cpp
content/svg/content/src/nsSVGStylableElement.h
content/xul/content/src/nsXULElement.cpp
content/xul/content/src/nsXULElement.h
dom/base/nsDOMClassInfoID.h
js/src/xpconnect/src/Makefile.in
js/src/xpconnect/src/dom_quickstubs.qsconf
--- a/content/base/src/nsStyledElement.cpp
+++ b/content/base/src/nsStyledElement.cpp
@@ -46,16 +46,17 @@
 #include "nsDOMCSSDeclaration.h"
 #include "nsDOMCSSAttrDeclaration.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIDocument.h"
 #include "nsICSSStyleRule.h"
 #include "nsCSSParser.h"
 #include "mozilla/css/Loader.h"
 #include "nsIDOMMutationEvent.h"
+#include "nsXULElement.h"
 
 #ifdef MOZ_SVG
 #include "nsIDOMSVGStylable.h"
 #endif
 
 //----------------------------------------------------------------------
 // nsIContent methods
 
@@ -230,38 +231,44 @@ nsStyledElement::UnbindFromTree(PRBool a
 
   nsStyledElementBase::UnbindFromTree(aDeep, aNullParent);
 }
 
 
 // ---------------------------------------------------------------
 // Others and helpers
 
-nsresult
-nsStyledElement::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
+nsIDOMCSSStyleDeclaration*
+nsStyledElement::GetStyle(nsresult* retval)
 {
+  nsXULElement* xulElement = nsXULElement::FromContent(this);
+  if (xulElement) {
+    nsresult rv = xulElement->EnsureLocalStyle();
+    if (NS_FAILED(rv)) {
+      *retval = rv;
+      return nsnull;
+    }
+  }
+    
   nsGenericElement::nsDOMSlots *slots = GetDOMSlots();
-  NS_ENSURE_TRUE(slots, NS_ERROR_OUT_OF_MEMORY);
 
   if (!slots->mStyle) {
     // Just in case...
     ReparseStyleAttribute(PR_TRUE);
 
     slots->mStyle = new nsDOMCSSAttributeDeclaration(this
 #ifdef MOZ_SMIL
                                                      , PR_FALSE
 #endif // MOZ_SMIL
                                                      );
-    NS_ENSURE_TRUE(slots->mStyle, NS_ERROR_OUT_OF_MEMORY);
     SetFlags(NODE_MAY_HAVE_STYLE);
   }
 
-  // Why bother with QI?
-  NS_ADDREF(*aStyle = slots->mStyle);
-  return NS_OK;
+  *retval = NS_OK;
+  return slots->mStyle;
 }
 
 nsresult
 nsStyledElement::ReparseStyleAttribute(PRBool aForceInDataDoc)
 {
   if (!HasFlag(NODE_MAY_HAVE_STYLE)) {
     return NS_OK;
   }
--- a/content/base/src/nsStyledElement.h
+++ b/content/base/src/nsStyledElement.h
@@ -76,34 +76,34 @@ public:
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               PRBool aCompileEventHandlers);
   virtual void UnbindFromTree(PRBool aDeep, PRBool aNullParent);
 
   virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
                              PRBool aNotify);
 
+  nsIDOMCSSStyleDeclaration* GetStyle(nsresult* retval);
+
 protected:
 
   /**
    * Parse a style attr value into a CSS rulestruct (or, if there is no
    * document, leave it as a string) and return as nsAttrValue.
    *
    * @param aValue the value to parse
    * @param aResult the resulting HTMLValue [OUT]
    */
   void ParseStyleAttribute(const nsAString& aValue,
                            nsAttrValue& aResult,
                            PRBool aForceInDataDoc);
 
   virtual PRBool ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aAttribute,
                                 const nsAString& aValue, nsAttrValue& aResult);
 
-  nsresult GetStyle(nsIDOMCSSStyleDeclaration** aStyle);
-
   /**
    * Create the style struct from the style attr.  Used when an element is
    * first put into a document.  Only has an effect if the old value is a
    * string.  If aForceInDataDoc is true, will reparse even if we're in a data
    * document.
    */
   nsresult  ReparseStyleAttribute(PRBool aForceInDataDoc);
 };
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -227,17 +227,24 @@ class nsGenericHTMLElementTearoff : publ
   {
   }
 
   virtual ~nsGenericHTMLElementTearoff()
   {
   }
 
   NS_FORWARD_NSIDOMNSHTMLELEMENT(mElement->)
-  NS_FORWARD_NSIDOMELEMENTCSSINLINESTYLE(mElement->)
+  NS_IMETHOD GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
+  {
+    nsresult rv;
+    *aStyle = mElement->GetStyle(&rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+    NS_ADDREF(*aStyle);
+    return NS_OK;
+  }
 
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsGenericHTMLElementTearoff,
                                            nsIDOMNSHTMLElement)
 
 private:
   nsRefPtr<nsGenericHTMLElement> mElement;
 };
 
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -123,21 +123,16 @@ public:
   nsresult GetDir(nsAString& aDir);
   nsresult SetDir(const nsAString& aDir);
   nsresult GetClassName(nsAString& aClassName);
   nsresult SetClassName(const nsAString& aClassName);
 
   // nsIDOMNSHTMLElement methods. Note that these are non-virtual
   // methods, implementations are expected to forward calls to these
   // methods.
-  // Forward to GetStyle which is protected in the super-class
-  inline nsresult GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
-  {
-    return nsGenericHTMLElementBase::GetStyle(aStyle);
-  }
   nsresult GetOffsetTop(PRInt32* aOffsetTop);
   nsresult GetOffsetLeft(PRInt32* aOffsetLeft);
   nsresult GetOffsetWidth(PRInt32* aOffsetWidth);
   nsresult GetOffsetHeight(PRInt32* aOffsetHeight);
   nsresult GetOffsetParent(nsIDOMElement** aOffsetParent);
   virtual nsresult GetInnerHTML(nsAString& aInnerHTML);
   virtual nsresult SetInnerHTML(const nsAString& aInnerHTML);
   nsresult ScrollIntoView(PRBool aTop, PRUint8 optional_argc);
--- a/content/svg/content/src/nsSVGStylableElement.cpp
+++ b/content/svg/content/src/nsSVGStylableElement.cpp
@@ -92,17 +92,23 @@ nsSVGStylableElement::GetClassName(nsIDO
   NS_ADDREF(*aClassName);
   return NS_OK;
 }
 
 /* readonly attribute nsIDOMCSSStyleDeclaration style; */
 NS_IMETHODIMP
 nsSVGStylableElement::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
 {
-  return nsSVGStylableElementBase::GetStyle(aStyle);
+  nsresult rv;
+  *aStyle = GetStyle(&rv);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  NS_ADDREF(*aStyle);
+  return NS_OK;
 }
 
 /* nsIDOMCSSValue getPresentationAttribute (in DOMString name); */
 NS_IMETHODIMP
 nsSVGStylableElement::GetPresentationAttribute(const nsAString& aName,
                                                nsIDOMCSSValue** aReturn)
 {
   // Let's not implement this just yet. The CSSValue interface has been
--- a/content/svg/content/src/nsSVGStylableElement.h
+++ b/content/svg/content/src/nsSVGStylableElement.h
@@ -59,16 +59,21 @@ public:
 
   // nsIContent
   virtual const nsAttrValue* DoGetClasses() const;
 
   // nsSVGElement
   virtual nsresult UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aAttribute,
                              PRBool aNotify);
 
+  nsIDOMCSSStyleDeclaration* GetStyle(nsresult* retval)
+  {
+    return nsSVGStylableElementBase::GetStyle(retval);
+  }
+
 protected:
 
   // nsSVGElement
   virtual PRBool ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aName,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult);
 
 private:
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -207,17 +207,24 @@ public:
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXULElementTearoff,
                                            nsIDOMElementCSSInlineStyle)
 
   nsXULElementTearoff(nsXULElement *aElement)
     : mElement(aElement)
   {
   }
 
-  NS_FORWARD_NSIDOMELEMENTCSSINLINESTYLE(static_cast<nsXULElement*>(mElement.get())->)
+  NS_IMETHOD GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
+  {
+    nsresult rv;
+    *aStyle = static_cast<nsXULElement*>(mElement.get())->GetStyle(&rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+    NS_ADDREF(*aStyle);
+    return NS_OK;
+  }
   NS_FORWARD_NSIFRAMELOADEROWNER(static_cast<nsXULElement*>(mElement.get())->);
 private:
   nsCOMPtr<nsIDOMXULElement> mElement;
 };
 
 NS_IMPL_CYCLE_COLLECTION_1(nsXULElementTearoff, mElement)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULElementTearoff)
@@ -1918,41 +1925,40 @@ NS_IMPL_XUL_STRING_ATTR(Persist, persist
 NS_IMPL_XUL_STRING_ATTR(Left, left)
 NS_IMPL_XUL_STRING_ATTR(Top, top)
 NS_IMPL_XUL_STRING_ATTR(Datasources, datasources)
 NS_IMPL_XUL_STRING_ATTR(Ref, ref)
 NS_IMPL_XUL_STRING_ATTR(TooltipText, tooltiptext)
 NS_IMPL_XUL_STRING_ATTR(StatusText, statustext)
 
 nsresult
-nsXULElement::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
+nsXULElement::EnsureLocalStyle()
 {
-    nsresult rv;
-
     // Clone the prototype rule, if we don't have a local one.
     if (mPrototype &&
         !mAttrsAndChildren.GetAttr(nsGkAtoms::style, kNameSpaceID_None)) {
 
         nsXULPrototypeAttribute *protoattr =
                   FindPrototypeAttribute(kNameSpaceID_None, nsGkAtoms::style);
         if (protoattr && protoattr->mValue.Type() == nsAttrValue::eCSSStyleRule) {
             nsCOMPtr<nsICSSRule> ruleClone;
-            rv = protoattr->mValue.GetCSSStyleRuleValue()->Clone(*getter_AddRefs(ruleClone));
+            nsresult rv = protoattr->mValue.GetCSSStyleRuleValue()->
+                Clone(*getter_AddRefs(ruleClone));
             NS_ENSURE_SUCCESS(rv, rv);
 
             nsAttrValue value;
             nsCOMPtr<nsICSSStyleRule> styleRule = do_QueryInterface(ruleClone);
             value.SetTo(styleRule);
 
             rv = mAttrsAndChildren.SetAndTakeAttr(nsGkAtoms::style, value);
             NS_ENSURE_SUCCESS(rv, rv);
         }
     }
 
-    return nsStyledElement::GetStyle(aStyle);
+    return NS_OK;
 }
 
 nsresult
 nsXULElement::LoadSrc()
 {
     // Allow frame loader only on objects for which a container box object
     // can be obtained.
     nsIAtom* tag = Tag();
--- a/content/xul/content/src/nsXULElement.h
+++ b/content/xul/content/src/nsXULElement.h
@@ -561,17 +561,17 @@ public:
     NS_FORWARD_NSIDOMELEMENT(nsGenericElement::)
 
     // nsIDOMXULElement
     NS_DECL_NSIDOMXULELEMENT
 
     virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
     virtual PRInt32 IntrinsicState() const;
 
-    nsresult GetStyle(nsIDOMCSSStyleDeclaration** aStyle);
+    nsresult EnsureLocalStyle();
 
     nsresult GetFrameLoader(nsIFrameLoader** aFrameLoader);
     already_AddRefed<nsFrameLoader> GetFrameLoader();
     nsresult SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner);
 
     virtual void RecompileScriptEventListeners();
 
     // This function should ONLY be used by BindToTree implementations.
--- a/dom/base/nsDOMClassInfoID.h
+++ b/dom/base/nsDOMClassInfoID.h
@@ -78,17 +78,19 @@ DOMCI_CASTABLE_INTERFACE(nsINode, nsINod
 DOMCI_CASTABLE_INTERFACE(nsIContent, nsIContent, 1, _extra)                   \
 DOMCI_CASTABLE_INTERFACE(nsIDocument, nsIDocument, 2, _extra)                 \
 DOMCI_CASTABLE_INTERFACE(nsINodeList, nsINodeList, 3, _extra)                 \
 DOMCI_CASTABLE_INTERFACE(nsICSSDeclaration, nsICSSDeclaration, 4, _extra)     \
 DOMCI_CASTABLE_INTERFACE(nsGenericTextNode, nsGenericTextNode, 5, _extra)     \
 DOMCI_CASTABLE_INTERFACE(nsDocument, nsIDocument, 6, _extra)                  \
 DOMCI_CASTABLE_INTERFACE(nsGenericHTMLElement, nsGenericHTMLElement, 7,       \
                          _extra)                                              \
-DOMCI_CASTABLE_INTERFACE(nsHTMLDocument, nsIDocument, 8, _extra)
+DOMCI_CASTABLE_INTERFACE(nsHTMLDocument, nsIDocument, 8, _extra)              \
+DOMCI_CASTABLE_INTERFACE(nsStyledElement, nsStyledElement, 9, _extra)         \
+DOMCI_CASTABLE_INTERFACE(nsSVGStylableElement, nsIContent, 10, _extra)
 
 // Make sure all classes mentioned in DOMCI_CASTABLE_INTERFACES
 // have been declared.
 #define DOMCI_CASTABLE_INTERFACE(_interface, _u1, _u2, _u3) class _interface;
 DOMCI_CASTABLE_INTERFACES(unused)
 #undef DOMCI_CASTABLE_INTERFACE
 
 #ifdef _IMPL_NS_LAYOUT
--- a/js/src/xpconnect/src/Makefile.in
+++ b/js/src/xpconnect/src/Makefile.in
@@ -119,16 +119,17 @@ LOCAL_INCLUDES = \
 		-I$(srcdir)/../wrappers \
 		-I$(srcdir)/../loader \
 		-I$(topsrcdir)/js/src \
 		-I$(topsrcdir)/js/src/nanojit \
 		-I$(topsrcdir)/caps/include \
 		-I$(topsrcdir)/content/base/src \
 		-I$(topsrcdir)/content/html/content/src \
 		-I$(topsrcdir)/content/html/document/src \
+		-I$(topsrcdir)/content/svg/content/src \
 		-I$(topsrcdir)/layout/style \
 		-I$(topsrcdir)/layout/base \
 		$(NULL)
 
 EXTRA_DSO_LDOPTS += \
 		$(MOZ_COMPONENT_LIBS) \
 		$(MOZ_JS_LIBS) \
 		$(NULL)
--- a/js/src/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/src/xpconnect/src/dom_quickstubs.qsconf
@@ -378,16 +378,17 @@ members = [
     'nsIDOMStorage.removeItem',
     'nsIDOMStorage.clear',
     'nsIDOMStorageItem.value',
     'nsIDOMStorageWindow.*',
 
     # dom/interfaces/stylesheets - None.
 
     # dom/interfaces/svg - None.
+    'nsIDOMSVGStylable.*',
 
     # dom/interfaces/threads - None.
 
     # dom/interfaces/traversal
     'nsIDOMDocumentTraversal.createNodeIterator',
     'nsIDOMNodeIterator.nextNode',
 
     # dom/interfaces/views
@@ -501,16 +502,17 @@ customIncludes = [
     'nsIContent.h',
     'nsIDocument.h',
     'nsINodeList.h',
     'nsCSSPropertiesQS.h',
     'nsDocument.h',
     'nsGenericDOMDataNode.h',
     'nsGenericElement.h',
     'nsGenericHTMLElement.h',
+    'nsSVGStylableElement.h',
     'nsHTMLDocument.h',
     'nsDOMQS.h',
     ]
 
 customQuickStubs = [
     'CustomQS_WebGL.h',
     'CustomQS_Canvas2D.h'
     ]
@@ -841,16 +843,29 @@ customMethodCalls = {
         'canFail': False
         },
     'nsIDOMNSHTMLElement_': {
         'thisType': 'nsGenericHTMLElement'
         },
     'nsIDOMHTMLElement_': {
         'thisType': 'nsGenericHTMLElement'
         },
+    'nsIDOMElementCSSInlineStyle_': {
+        'thisType': 'nsStyledElement'
+        },
+    'nsIDOMElementCSSInlineStyle_GetStyle': {
+        'thisType': 'nsStyledElement',
+        'code': '    nsIDOMCSSStyleDeclaration* result = '
+                'self->GetStyle(&rv);'
+        },
+    'nsIDOMSVGStylable_GetStyle': {
+        'thisType': 'nsSVGStylableElement',
+        'code': '    nsIDOMCSSStyleDeclaration* result = '
+                'self->GetStyle(&rv);'
+        },
     'nsIDOMDocument_': {
         'thisType': 'nsDocument'
         },
     'nsIDOMDocument_GetElementById': {
         'thisType': 'nsDocument',
         'code': '    mozilla::dom::Element *result = self->GetElementById(arg0);',
         'canFail': False
         },