Bug 537157: Explicitly prevent SMIL animations inside of XBL bindings from running. Also, make nsSMILCSSProperty directly create a computed style object, instead of using nsPIDOMWindow helper method. r=smaug sr=roc
authorDaniel Holbert <dholbert@cs.stanford.edu>
Wed, 06 Jan 2010 09:20:50 -0800
changeset 36884 15c10445598c58c309f5b85bf58a7fd5db668ef8
parent 36883 195c956764ce8b2967f7a30ec6951c634d9a822d
child 36885 85cd0f29742121fee9e836be53695745fe4051f0
push idunknown
push userunknown
push dateunknown
reviewerssmaug, roc
bugs537157
milestone1.9.3a1pre
Bug 537157: Explicitly prevent SMIL animations inside of XBL bindings from running. Also, make nsSMILCSSProperty directly create a computed style object, instead of using nsPIDOMWindow helper method. r=smaug sr=roc
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
content/smil/crashtests/537157-1.svg
content/smil/crashtests/crashtests.list
content/smil/nsSMILCSSProperty.cpp
content/xml/document/src/nsXMLDocument.h
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsPIDOMWindow.h
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -5349,17 +5349,17 @@ nsSMILAnimationController*
 nsDocument::GetAnimationController()
 {
   // We create the animation controller lazily because most documents won't want
   // one and only SVG documents and the like will call this
   if (mAnimationController)
     return mAnimationController;
   // Refuse to create an Animation Controller if SMIL is disabled, and also
   // for data documents.
-  if (!NS_SMILEnabled() || mLoadedAsData)
+  if (!NS_SMILEnabled() || mLoadedAsData || mLoadedAsInteractiveData)
     return nsnull;
 
   mAnimationController = NS_NewSMILAnimationController(this);
   
   // If there's a presContext then check the animation mode and pause if
   // necessary.
   nsIPresShell *shell = GetPrimaryShell();
   if (mAnimationController && shell) {
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -1190,16 +1190,21 @@ protected:
   PRPackedBool mSynchronousDOMContentLoaded:1;
 
   // If true, we have an input encoding.  If this is false, then the
   // document was created entirely in memory
   PRPackedBool mHaveInputEncoding:1;
 
   PRPackedBool mInXBLUpdate:1;
 
+  // This flag is only set in nsXMLDocument, for e.g. documents used in XBL. We
+  // don't want animations to play in such documents, so we need to store the
+  // flag here so that we can check it in nsDocument::GetAnimationController.
+  PRPackedBool mLoadedAsInteractiveData:1;
+
   PRUint8 mXMLDeclarationBits;
 
   PRUint8 mDefaultElementType;
 
   nsInterfaceHashtable<nsVoidPtrHashKey, nsPIBoxObject> *mBoxObjectTable;
 
   // The channel that got passed to StartDocumentLoad(), if any
   nsCOMPtr<nsIChannel> mChannel;
new file mode 100644
--- /dev/null
+++ b/content/smil/crashtests/537157-1.svg
@@ -0,0 +1,11 @@
+<svg xmlns="http://www.w3.org/2000/svg" style="-moz-binding:url(#xbl)">
+<bindings xmlns="http://www.mozilla.org/xbl">
+<binding id="xbl" inheritstyle="false">
+<content>
+<svg xmlns="http://www.w3.org/2000/svg">
+<animate attributeName="font-size"/>
+</svg>
+</content>
+</binding>
+</bindings>
+</svg>
--- a/content/smil/crashtests/crashtests.list
+++ b/content/smil/crashtests/crashtests.list
@@ -1,5 +1,6 @@
 load 523188-1.svg
 load 525099-1.svg
 load 526875-1.svg
 load 526875-2.svg
 load 529387-1.xhtml
+load 537157-1.svg
--- a/content/smil/nsSMILCSSProperty.cpp
+++ b/content/smil/nsSMILCSSProperty.cpp
@@ -39,17 +39,17 @@
 
 #include "nsSMILCSSProperty.h"
 #include "nsSMILCSSValueType.h"
 #include "nsSMILValue.h"
 #include "nsCSSDeclaration.h"
 #include "nsComputedDOMStyle.h"
 #include "nsStyleAnimation.h"
 #include "nsIContent.h"
-#include "nsPIDOMWindow.h"
+#include "nsIDOMElement.h"
 
 static PRBool
 GetCSSComputedValue(nsIContent* aElem,
                     nsCSSProperty aPropID,
                     nsAString& aResult)
 {
   NS_ENSURE_TRUE(nsSMILCSSProperty::IsPropertyAnimatable(aPropID),
                  PR_FALSE);
@@ -57,21 +57,28 @@ GetCSSComputedValue(nsIContent* aElem,
   nsIDocument* doc = aElem->GetCurrentDoc();
   if (!doc) {
     // This can happen if we process certain types of restyles mid-sample
     // and remove anonymous animated content from the document as a result.
     // See bug 534975.
     return PR_FALSE;
   }
 
-  nsPIDOMWindow* win = doc->GetWindow();
-  NS_ABORT_IF_FALSE(win, "actively animated document w/ no window");
-  nsRefPtr<nsComputedDOMStyle>
-    computedStyle(win->LookupComputedStyleFor(aElem));
-  if (computedStyle) {
+  nsIPresShell* shell = doc->GetPrimaryShell();
+  if (!shell) {
+    NS_WARNING("Unable to look up computed style -- no pres shell");
+    return PR_FALSE;
+  }
+
+  nsRefPtr<nsComputedDOMStyle> computedStyle;
+  nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(aElem));
+  nsresult rv = NS_NewComputedDOMStyle(domElement, EmptyString(), shell,
+                                       getter_AddRefs(computedStyle));
+
+  if (NS_SUCCEEDED(rv) && computedStyle) {
     // NOTE: This will produce an empty string for shorthand values
     computedStyle->GetPropertyValue(aPropID, aResult);
     return PR_TRUE;
   }
   return PR_FALSE;
 }
 
 // Class Methods
--- a/content/xml/document/src/nsXMLDocument.h
+++ b/content/xml/document/src/nsXMLDocument.h
@@ -78,15 +78,14 @@ public:
 protected:
   // mChannelIsPending indicates whether we're currently asynchronously loading
   // data from mChannel (via document.load() or normal load).  It's set to true
   // when we first find out about the channel (StartDocumentLoad) and set to
   // false in EndLoad or if ResetToURI() is called.  In the latter case our
   // mChannel is also cancelled.  Note that if this member is true, mChannel
   // cannot be null.
   PRPackedBool mChannelIsPending;
-  PRPackedBool mLoadedAsInteractiveData;
   PRPackedBool mAsync;
   PRPackedBool mLoopingForSyncLoad;
 };
 
 
 #endif // nsXMLDocument_h___
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -95,17 +95,16 @@
 #include "nsIDocShellTreeNode.h"
 #include "nsIEditorDocShell.h"
 #include "nsIDocCharset.h"
 #include "nsIDocument.h"
 #include "nsIHTMLDocument.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIDOMCrypto.h"
-#include "nsIDOMCSSStyleDeclaration.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMNSDocument.h"
 #include "nsIDOMDocumentView.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMDocumentEvent.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLElement.h"
@@ -1414,26 +1413,16 @@ nsGlobalWindow::WouldReuseInnerWindow(ns
     // If we're a chrome window, then we want to reuse the inner window.
     return itemType == nsIDocShellTreeItem::typeChrome;
   }
 
   // No treeItem: don't reuse the current inner window.
   return PR_FALSE;
 }
 
-already_AddRefed<nsComputedDOMStyle>
-nsGlobalWindow::LookupComputedStyleFor(nsIContent* aElem)
-{
-  nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(aElem));
-  nsRefPtr<nsComputedDOMStyle> computedDOMStyle;
-  GetComputedStyle(domElement, EmptyString(),
-                   getter_AddRefs(computedDOMStyle));
-  return computedDOMStyle.forget();
-}
-
 void
 nsGlobalWindow::SetOpenerScriptPrincipal(nsIPrincipal* aPrincipal)
 {
   FORWARD_TO_OUTER_VOID(SetOpenerScriptPrincipal, (aPrincipal));
 
   if (mDoc) {
     if (!mDoc->IsInitialDocument()) {
       // We have a document already, and it's not the original one.  Bail out.
@@ -7038,22 +7027,24 @@ nsGlobalWindow::UpdateCanvasFocus(PRBool
       }      
   }
 }
 
 //*****************************************************************************
 // nsGlobalWindow::nsIDOMViewCSS
 //*****************************************************************************
 
-// Helper method for below
-nsresult
+NS_IMETHODIMP
 nsGlobalWindow::GetComputedStyle(nsIDOMElement* aElt,
                                  const nsAString& aPseudoElt,
-                                 nsComputedDOMStyle** aReturn)
-{
+                                 nsIDOMCSSStyleDeclaration** aReturn)
+{
+  FORWARD_TO_OUTER(GetComputedStyle, (aElt, aPseudoElt, aReturn),
+                   NS_ERROR_NOT_INITIALIZED);
+
   NS_ENSURE_ARG_POINTER(aReturn);
   *aReturn = nsnull;
 
   if (!aElt) {
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
   }
 
   if (!mDocShell) {
@@ -7062,28 +7053,19 @@ nsGlobalWindow::GetComputedStyle(nsIDOME
 
   nsCOMPtr<nsIPresShell> presShell;
   mDocShell->GetPresShell(getter_AddRefs(presShell));
 
   if (!presShell) {
     return NS_OK;
   }
 
-  return NS_NewComputedDOMStyle(aElt, aPseudoElt, presShell,
-                                aReturn);
-}
-NS_IMETHODIMP
-nsGlobalWindow::GetComputedStyle(nsIDOMElement* aElt,
-                                 const nsAString& aPseudoElt,
-                                 nsIDOMCSSStyleDeclaration** aReturn)
-{
-  FORWARD_TO_OUTER(GetComputedStyle, (aElt, aPseudoElt, aReturn),
-                   NS_ERROR_NOT_INITIALIZED);
   nsRefPtr<nsComputedDOMStyle> compStyle;
-  nsresult rv = GetComputedStyle(aElt, aPseudoElt, getter_AddRefs(compStyle));
+  nsresult rv = NS_NewComputedDOMStyle(aElt, aPseudoElt, presShell,
+                                       getter_AddRefs(compStyle));
   NS_ENSURE_SUCCESS(rv, rv);
 
   *aReturn = compStyle.forget().get();
 
   return NS_OK;
 }
 
 //*****************************************************************************
@@ -8474,16 +8456,17 @@ nsGlobalWindow::TimerCallback(nsITimer *
 
   // Drop our reference to the timeout now that we're done with it.
   timeout->Release();
 }
 
 //*****************************************************************************
 // nsGlobalWindow: Helper Functions
 //*****************************************************************************
+
 nsresult
 nsGlobalWindow::GetTreeOwner(nsIDocShellTreeOwner **aTreeOwner)
 {
   FORWARD_TO_OUTER(GetTreeOwner, (aTreeOwner), NS_ERROR_NOT_INITIALIZED);
 
   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
 
   // If there's no docShellAsItem, this window must have been closed,
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -285,19 +285,16 @@ public:
   NS_DECL_NSIDOMNSEVENTTARGET
 
   // nsPIDOMWindow
   virtual NS_HIDDEN_(nsPIDOMWindow*) GetPrivateRoot();
   virtual NS_HIDDEN_(void) ActivateOrDeactivate(PRBool aActivate);
   virtual NS_HIDDEN_(void) SetChromeEventHandler(nsPIDOMEventTarget* aChromeEventHandler);
   virtual NS_HIDDEN_(nsIFocusController*) GetRootFocusController();
 
-  virtual NS_HIDDEN_(already_AddRefed<nsComputedDOMStyle>)
-    LookupComputedStyleFor(nsIContent* aElem);
-
   virtual NS_HIDDEN_(void) SetOpenerScriptPrincipal(nsIPrincipal* aPrincipal);
   virtual NS_HIDDEN_(nsIPrincipal*) GetOpenerScriptPrincipal();
 
   virtual NS_HIDDEN_(PopupControlState) PushPopupControlState(PopupControlState state, PRBool aForce) const;
   virtual NS_HIDDEN_(void) PopPopupControlState(PopupControlState state) const;
   virtual NS_HIDDEN_(PopupControlState) GetPopupControlState() const;
 
   virtual NS_HIDDEN_(nsresult) SaveWindowState(nsISupports **aState);
@@ -638,21 +635,16 @@ protected:
     // Note: might not actually return an nsTimeout.  Use IsTimeout to check.
     return static_cast<nsTimeout*>(PR_LIST_TAIL(&mTimeouts));
   }
 
   PRBool IsTimeout(PRCList* aList) {
     return aList != &mTimeouts;
   }
 
-  // Helper method for looking up computed style
-  nsresult GetComputedStyle(nsIDOMElement* aElt,
-                            const nsAString& aPseudoElt,
-                            nsComputedDOMStyle** aReturn);
-
   // Convenience functions for the many methods that need to scale
   // from device to CSS pixels or vice versa.  Note: if a presentation
   // context is not available, they will assume a 1:1 ratio.
   PRInt32 DevToCSSIntPixels(PRInt32 px);
   PRInt32 CSSToDevIntPixels(PRInt32 px);
   nsIntSize DevToCSSIntPixels(nsIntSize px);
   nsIntSize CSSToDevIntPixels(nsIntSize px);
 
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -48,18 +48,16 @@
 #include "nsPIDOMEventTarget.h"
 #include "nsIDOMDocument.h"
 #include "nsCOMPtr.h"
 #include "nsEvent.h"
 
 #define DOM_WINDOW_DESTROYED_TOPIC "dom-window-destroyed"
 
 class nsIPrincipal;
-class nsICSSDeclaration;
-class nsComputedDOMStyle;
 
 // Popup control state enum. The values in this enum must go from most
 // permissive to least permissive so that it's safe to push state in
 // all situations. Pushing popup state onto the stack never makes the
 // current popup state less permissive (see
 // nsGlobalWindow::PushPopupControlState()).
 enum PopupControlState {
   openAllowed = 0,  // open that window without worries
@@ -75,18 +73,18 @@ class nsIDocument;
 class nsIScriptTimeoutHandler;
 class nsPresContext;
 struct nsTimeout;
 class nsScriptObjectHolder;
 class nsXBLPrototypeHandler;
 class nsIArray;
 
 #define NS_PIDOMWINDOW_IID \
-{ 0x70c9f57f, 0xf7b3, 0x4a37, \
-  { 0xbe, 0x36, 0xbb, 0xb2, 0xd7, 0xe9, 0x40, 0x13 } }
+{ 0xeee92d9a, 0xae9f, 0x41e5, \
+  { 0x95, 0x5f, 0xaf, 0x1c, 0xe7, 0x66, 0x42, 0xe6 } }
 
 class nsPIDOMWindow : public nsIDOMWindowInternal
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_PIDOMWINDOW_IID)
 
   virtual nsPIDOMWindow* GetPrivateRoot() = 0;
 
@@ -246,20 +244,16 @@ public:
       }
 
       win = this;
     }
 
     return win->mIsHandlingResizeEvent;
   }
 
-  // Convenience method for getting an element's computed style
-  virtual already_AddRefed<nsComputedDOMStyle>
-    LookupComputedStyleFor(nsIContent* aElem) = 0;
-
   // Tell this window who opened it.  This only has an effect if there is
   // either no document currently in the window or if the document is the
   // original document this window came with (an about:blank document either
   // preloaded into it when it was created, or created by
   // CreateAboutBlankContentViewer()).
   virtual void SetOpenerScriptPrincipal(nsIPrincipal* aPrincipal) = 0;
   // Ask this window who opened it.
   virtual nsIPrincipal* GetOpenerScriptPrincipal() = 0;