Merge mozilla-central to mozilla-inbound
authorEd Morley <bmo@edmorley.co.uk>
Sun, 08 Jan 2012 22:23:21 +0000
changeset 85250 0dd51bebba24a46d3bfe8ee77938424a1806ef31
parent 85249 db09603b41863e5a84628b520ac08ab91ff26198 (current diff)
parent 85242 9a230265bad5fb7d2c4ead3c9e4173081d8e90a7 (diff)
child 85251 20ae82960dc3e9608065eac60bc3e5294dde39b2
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone12.0a1
Merge mozilla-central to mozilla-inbound
--- a/browser/base/content/test/test_contextmenu.html
+++ b/browser/base/content/test/test_contextmenu.html
@@ -1,13 +1,13 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Tests for browser context menu</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>  
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 Browser context menu tests.
 <p id="display"></p>
 
 <div id="content">
@@ -23,39 +23,31 @@ Components.utils.import("resource://gre/
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 function openContextMenuFor(element, shiftkey, shouldWaitForFocus) {
     // Context menu should be closed before we open it again.
     is(contextMenu.state, "closed", "checking if popup is closed");
 
-    //Some elements need time to focus and spellcheck before any tests are
-    //run on them.
-    if(shouldWaitForFocus)
-    {
-      if (lastElement)
-        lastElement.blur();
-      element.focus();
-      
-      SimpleTest.executeSoon(function() {
-        lastElement = element;
-        var eventDetails = { type : "contextmenu", button : 2, shiftKey : shiftkey };
-        synthesizeMouse(element, 2, 2, eventDetails, element.ownerDocument.defaultView);
-      });
-    }
-    else
-    {
-      if (lastElement)
-          lastElement.blur();
-      element.focus();
+    if (lastElement)
+      lastElement.blur();
+    element.focus();
+
+    // Some elements need time to focus and spellcheck before any tests are
+    // run on them.
+    function actuallyOpenContextMenuFor() {
       lastElement = element;
       var eventDetails = { type : "contextmenu", button : 2, shiftKey : shiftkey };
       synthesizeMouse(element, 2, 2, eventDetails, element.ownerDocument.defaultView);
     }
+    if (shouldWaitForFocus)
+      SimpleTest.executeSoon(actuallyOpenContextMenuFor);
+    else
+      actuallyOpenContextMenuFor();
 }
 
 function closeContextMenu() {
     contextMenu.hidePopup();
 }
 
 function executeCopyCommand(command, expectedValue)
 {
@@ -72,17 +64,17 @@ function executeCopyCommand(command, exp
 }
 
 function invokeItemAction(generatedItemId)
 {
   var item = contextMenu.getElementsByAttribute("generateditemid",
                                                 generatedItemId)[0];
   ok(item, "Got generated XUL menu item");
   item.doCommand();
-  is(pagemenu.hasAttribute("hopeless"), false, "attribute got removed");
+  ok(!pagemenu.hasAttribute("hopeless"), "attribute got removed");
 }
 
 function getVisibleMenuItems(aMenu, aData) {
     var items = [];
     var accessKeys = {};
     for (var i = 0; i < aMenu.childNodes.length; i++) {
         var item = aMenu.childNodes[i];
         if (item.hidden)
@@ -173,32 +165,36 @@ function checkContextMenu(expectedItems)
  * expectedItems is a array of (1) item IDs and (2) a boolean specifying if
  * the item is enabled or not (or null to ignore it). Submenus can be checked
  * by providing a nested array entry after the expected <menu> ID.
  * For example: ["blah", true,              // item enabled
  *               "submenu", null,           // submenu
  *                   ["sub1", true,         // submenu contents
  *                    "sub2", false], null, // submenu contents
  *               "lol", false]              // item disabled
- * 
+ *
  */
 function checkMenu(menu, expectedItems, data) {
     var actualItems = getVisibleMenuItems(menu, data);
     //ok(false, "Items are: " + actualItems);
     for (var i = 0; i < expectedItems.length; i+=2) {
         var actualItem   = actualItems[i];
         var actualEnabled = actualItems[i + 1];
         var expectedItem = expectedItems[i];
         var expectedEnabled = expectedItems[i + 1];
         if (expectedItem instanceof Array) {
             ok(true, "Checking submenu...");
             var menuID = expectedItems[i - 2]; // The last item was the menu ID.
             var submenu = menu.getElementsByAttribute("id", menuID)[0];
-            ok(submenu && submenu.nodeName == "menu", "got expected submenu element");
-            checkMenu(submenu.menupopup, expectedItem, data);
+            ok(submenu, "got a submenu element of id='" + menuID + "'");
+            if (submenu) {
+              is(submenu.nodeName, "menu", "submenu element of id='" + menuID +
+                                           "' has expected nodeName");
+              checkMenu(submenu.menupopup, expectedItem, data);
+            }
         } else {
             is(actualItem, expectedItem,
                "checking item #" + i/2 + " (" + expectedItem + ") name");
 
             if (typeof expectedEnabled == "object" && expectedEnabled != null ||
                 typeof actualEnabled == "object" && actualEnabled != null) {
 
                 ok(!(actualEnabled == null), "actualEnabled is not null");
@@ -508,17 +504,17 @@ function runTest(testNum) {
                           "context-delete",      false,
                           "---",                 null,
                           "context-selectall",   true,
                           "---",                 null,
                           "spell-check-enabled", true,
                           "spell-dictionaries",  true,
                               ["spell-check-dictionary-en-US", true,
                                "---",                          null,
-                               "spell-add-dictionaries",       true], null,
+                               "spell-add-dictionaries",       true], null
                          ].concat(inspectItems));
         contextMenu.ownerDocument.getElementById("spell-add-to-dictionary").doCommand(); // Add to dictionary
         closeContextMenu();
         openContextMenuFor(textarea, false, true); // Invoke context menu for next test.
         break;
     
     case 15:    
         // Context menu for textarea after a word has been added
@@ -532,17 +528,17 @@ function runTest(testNum) {
                           "context-delete",      false,
                           "---",                 null,
                           "context-selectall",   true,
                           "---",                 null,
                           "spell-check-enabled", true,
                           "spell-dictionaries",  true,
                               ["spell-check-dictionary-en-US", true,
                                "---",                          null,
-                               "spell-add-dictionaries",       true], null,
+                               "spell-add-dictionaries",       true], null
                          ].concat(inspectItems));
         contextMenu.ownerDocument.getElementById("spell-undo-add-to-dictionary").doCommand(); // Undo add to dictionary
         closeContextMenu();
         openContextMenuFor(contenteditable);
         break;
 
     case 16:
         // Context menu for contenteditable
@@ -656,16 +652,17 @@ function runTest(testNum) {
                           "context-sendpage",     true,
                           "---",                  null,
                           "context-viewbgimage",  false,
                           "context-selectall",    true,
                           "---",                  null,
                           "context-viewsource",   true,
                           "context-viewinfo",     true
                          ].concat(inspectItems));
+        closeContextMenu();
 
         subwindow.close();
         SimpleTest.finish();
         return;
 
     /*
      * Other things that would be nice to test:
      *  - selected text
@@ -698,16 +695,17 @@ function startTest() {
                     .rootTreeItem
                     .QueryInterface(Ci.nsIInterfaceRequestor)
                     .getInterface(Ci.nsIDOMWindow)
                     .QueryInterface(Ci.nsIDOMChromeWindow);
     contextMenu = chromeWin.document.getElementById("contentAreaContextMenu");
     ok(contextMenu, "Got context menu XUL");
 
     if (chromeWin.document.getElementById("Browser:Stop").getAttribute("disabled") != "true") {
+      todo(false, "Wait for subwindow to load... (This should usually happen once.)");
       SimpleTest.executeSoon(startTest);
       return;
     }
 
     lastElement = null;
 
     text   = subwindow.document.getElementById("test-text");
     link   = subwindow.document.getElementById("test-link");
--- a/browser/components/migration/src/nsIEProfileMigrator.cpp
+++ b/browser/components/migration/src/nsIEProfileMigrator.cpp
@@ -94,16 +94,18 @@
 #include "nsBrowserCompsCID.h"
 #include "nsIStringBundle.h"
 #include "nsNetUtil.h"
 #include "nsToolkitCompsCID.h"
 #include "nsUnicharUtils.h"
 #include "nsIWindowsRegKey.h"
 #include "nsISupportsPrimitives.h"
 
+#define kNotFound -1
+
 #define TRIDENTPROFILE_BUNDLE       "chrome://browser/locale/migration/migration.properties"
 
 #define REGISTRY_IE_MAIN_KEY \
   NS_LITERAL_STRING("Software\\Microsoft\\Internet Explorer\\Main")
 #define REGISTRY_IE_TYPEDURL_KEY \
   NS_LITERAL_STRING("Software\\Microsoft\\Internet Explorer\\TypedURLs")
 #define REGISTRY_IE_TOOLBAR_KEY \
   NS_LITERAL_STRING("Software\\Microsoft\\Internet Explorer\\Toolbar")
@@ -597,37 +599,41 @@ nsIEProfileMigrator::TestForIE7()
 
   if (!::ExpandEnvironmentStringsW(iePath.get(), 
                                    destination, 
                                    bufLength)) 
     return false; 
 
   iePath = destination; 
 
+  // Check if the path is enclosed in quotation marks.
   if (StringBeginsWith(iePath, NS_LITERAL_STRING("\""))) {
     iePath.Cut(0,1);
-    PRUint32 index = iePath.FindChar('\"', 0);
+    PRInt32 index = iePath.FindChar('\"', 0);
+
+    // After removing the opening quoation mark,
+    // remove the closing one and everything after it.
     if (index > 0)
       iePath.Cut(index,iePath.Length());
   }
 
   nsCOMPtr<nsILocalFile> lf; 
   NS_NewLocalFile(iePath, true, getter_AddRefs(lf)); 
 
   nsCOMPtr<nsILocalFileWin> lfw = do_QueryInterface(lf); 
   if (!lfw)
    return false;
    
   nsAutoString ieVersion;
   if (NS_FAILED(lfw->GetVersionInfoField("FileVersion", ieVersion)))
    return false;
 
   if (ieVersion.Length() > 2) {
-    PRUint32 index = ieVersion.FindChar('.', 0);
-    if (index < 0)
+    PRInt32 index = ieVersion.FindChar('.', 0);
+    if (index == kNotFound)
       return false;
     ieVersion.Cut(index, ieVersion.Length());
     PRInt32 ver = wcstol(ieVersion.get(), nsnull, 0);
     if (ver >= 7) // Found 7 or greater major version
       return true;
   }
 
   return false;
--- a/content/base/public/nsDOMEventTargetWrapperCache.h
+++ b/content/base/public/nsDOMEventTargetWrapperCache.h
@@ -85,17 +85,17 @@ public:
 
     return static_cast<nsDOMEventTargetWrapperCache*>(target);
   }
 
   void Init(JSContext* aCx = nsnull);
 
 protected:
   nsDOMEventTargetWrapperCache() : nsDOMEventTargetHelper(), nsWrapperCache() {}
-  virtual ~nsDOMEventTargetWrapperCache() {}
+  virtual ~nsDOMEventTargetWrapperCache();
 };
 
 #define NS_DECL_EVENT_HANDLER(_event)                                         \
   protected:                                                                  \
     nsRefPtr<nsDOMEventListenerWrapper> mOn##_event##Listener;                \
   public:
 
 #define NS_DECL_AND_IMPL_EVENT_HANDLER(_event)                                \
--- a/content/base/src/nsDOMEventTargetWrapperCache.cpp
+++ b/content/base/src/nsDOMEventTargetWrapperCache.cpp
@@ -88,8 +88,13 @@ nsDOMEventTargetWrapperCache::Init(JSCon
   if (context) {
     mScriptContext = context;
     nsCOMPtr<nsPIDOMWindow> window =
       do_QueryInterface(context->GetGlobalObject());
     if (window)
       mOwner = window->GetCurrentInnerWindow();
   }
 }
+
+nsDOMEventTargetWrapperCache::~nsDOMEventTargetWrapperCache()
+{
+  nsContentUtils::ReleaseWrapper(this, this);
+}
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -1198,23 +1198,29 @@ nsFrameLoader::SwapWithOtherLoader(nsFra
     otherTabChild->SetOwner(ourContent);
     otherTabChild->SetChromeMessageManager(ourMessageManager);
   }
   // Swap and setup things in parent message managers.
   nsFrameMessageManager* ourParentManager = mMessageManager ?
     mMessageManager->GetParentManager() : nsnull;
   nsFrameMessageManager* otherParentManager = aOther->mMessageManager ?
     aOther->mMessageManager->GetParentManager() : nsnull;
+  JSContext* thisCx =
+    mMessageManager ? mMessageManager->GetJSContext() : nsnull;
+  JSContext* otherCx = 
+    aOther->mMessageManager ? aOther->mMessageManager->GetJSContext() : nsnull;
   if (mMessageManager) {
-    mMessageManager->Disconnect();
+    mMessageManager->RemoveFromParent();
+    mMessageManager->SetJSContext(otherCx);
     mMessageManager->SetParentManager(otherParentManager);
     mMessageManager->SetCallbackData(aOther, false);
   }
   if (aOther->mMessageManager) {
-    aOther->mMessageManager->Disconnect();
+    aOther->mMessageManager->RemoveFromParent();
+    aOther->mMessageManager->SetJSContext(thisCx);
     aOther->mMessageManager->SetParentManager(ourParentManager);
     aOther->mMessageManager->SetCallbackData(this, false);
   }
   mMessageManager.swap(aOther->mMessageManager);
 
   aFirstToSwap.swap(aSecondToSwap);
 
   // Drop any cached content viewers in the two session histories.
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -341,31 +341,53 @@ nsFrameMessageManager::Btoa(const nsAStr
 
 NS_IMETHODIMP
 nsFrameMessageManager::Atob(const nsAString& aAsciiString,
                             nsAString& aBinaryData)
 {
   return NS_OK;
 }
 
+class MMListenerRemover
+{
+public:
+  MMListenerRemover(nsFrameMessageManager* aMM)
+  : mMM(aMM), mWasHandlingMessage(aMM->mHandlingMessage)
+  {
+    mMM->mHandlingMessage = true;
+  }
+  ~MMListenerRemover()
+  {
+    if (!mWasHandlingMessage) {
+      mMM->mHandlingMessage = false;
+      if (mMM->mDisconnected) {
+        mMM->mListeners.Clear();
+      }
+    }
+  }
+
+  bool mWasHandlingMessage;
+  nsRefPtr<nsFrameMessageManager> mMM;
+};
+
 nsresult
 nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
                                       const nsAString& aMessage,
                                       bool aSync, const nsAString& aJSON,
                                       JSObject* aObjectsArray,
                                       InfallibleTArray<nsString>* aJSONRetVal,
                                       JSContext* aContext)
 {
   JSContext* ctx = mContext ? mContext : aContext;
   if (!ctx) {
     nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(&ctx);
   }
   if (mListeners.Length()) {
     nsCOMPtr<nsIAtom> name = do_GetAtom(aMessage);
-    nsRefPtr<nsFrameMessageManager> kungfuDeathGrip(this);
+    MMListenerRemover lr(this);
 
     for (PRUint32 i = 0; i < mListeners.Length(); ++i) {
       if (mListeners[i].mMessage == name) {
         nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS =
           do_QueryInterface(mListeners[i].mListener);
         if (!wrappedJS) {
           continue;
         }
@@ -526,24 +548,39 @@ nsFrameMessageManager::SetCallbackData(v
       for (PRUint32 i = 0; i < mPendingScripts.Length(); ++i) {
         LoadFrameScript(mPendingScripts[i], false);
       }
     }
   }
 }
 
 void
+nsFrameMessageManager::RemoveFromParent()
+{
+  if (mParentManager) {
+    mParentManager->RemoveChildManager(this);
+  }
+  mParentManager = nsnull;
+  mCallbackData = nsnull;
+  mContext = nsnull;
+}
+
+void
 nsFrameMessageManager::Disconnect(bool aRemoveFromParent)
 {
   if (mParentManager && aRemoveFromParent) {
     mParentManager->RemoveChildManager(this);
   }
+  mDisconnected = true;
   mParentManager = nsnull;
   mCallbackData = nsnull;
   mContext = nsnull;
+  if (!mHandlingMessage) {
+    mListeners.Clear();
+  }
 }
 
 nsresult
 NS_NewGlobalMessageManager(nsIChromeFrameMessageManager** aResult)
 {
   NS_ENSURE_TRUE(IsChromeProcess(), NS_ERROR_NOT_AVAILABLE);
   nsFrameMessageManager* mm = new nsFrameMessageManager(true,
                                                         nsnull,
--- a/content/base/src/nsFrameMessageManager.h
+++ b/content/base/src/nsFrameMessageManager.h
@@ -87,17 +87,17 @@ public:
                         nsAsyncMessageCallback aAsyncCallback,
                         nsLoadScriptCallback aLoadScriptCallback,
                         void* aCallbackData,
                         nsFrameMessageManager* aParentManager,
                         JSContext* aContext,
                         bool aGlobal = false,
                         bool aProcessManager = false)
   : mChrome(aChrome), mGlobal(aGlobal), mIsProcessManager(aProcessManager),
-    mParentManager(aParentManager),
+    mHandlingMessage(false), mDisconnected(false), mParentManager(aParentManager),
     mSyncCallback(aSyncCallback), mAsyncCallback(aAsyncCallback),
     mLoadScriptCallback(aLoadScriptCallback), mCallbackData(aCallbackData),
     mContext(aContext)
   {
     NS_ASSERTION(mContext || (aChrome && !aParentManager) || aProcessManager,
                  "Should have mContext in non-global/non-process manager!");
     NS_ASSERTION(aChrome || !aParentManager, "Should not set parent manager!");
     // This is a bit hackish. When parent manager is global, we want
@@ -157,16 +157,18 @@ public:
   void Disconnect(bool aRemoveFromParent = true);
   void SetCallbackData(void* aData, bool aLoadScripts = true);
   void GetParamsForMessage(const jsval& aObject,
                            JSContext* aCx,
                            nsAString& aJSON);
   nsresult SendAsyncMessageInternal(const nsAString& aMessage,
                                     const nsAString& aJSON);
   JSContext* GetJSContext() { return mContext; }
+  void SetJSContext(JSContext* aCx) { mContext = aCx; }
+  void RemoveFromParent();
   nsFrameMessageManager* GetParentManager() { return mParentManager; }
   void SetParentManager(nsFrameMessageManager* aParent)
   {
     NS_ASSERTION(!mParentManager, "We have parent manager already!");
     NS_ASSERTION(mChrome, "Should not set parent manager!");
     mParentManager = aParent;
   }
   bool IsGlobal() { return mGlobal; }
@@ -176,21 +178,24 @@ public:
   {
     return sParentProcessManager;
   }
   static nsFrameMessageManager* GetChildProcessManager()
   {
     return sChildProcessManager;
   }
 protected:
+  friend class MMListenerRemover;
   nsTArray<nsMessageListenerInfo> mListeners;
   nsCOMArray<nsIContentFrameMessageManager> mChildManagers;
   bool mChrome;
   bool mGlobal;
   bool mIsProcessManager;
+  bool mHandlingMessage;
+  bool mDisconnected;
   nsFrameMessageManager* mParentManager;
   nsSyncMessageCallback mSyncCallback;
   nsAsyncMessageCallback mAsyncCallback;
   nsLoadScriptCallback mLoadScriptCallback;
   void* mCallbackData;
   JSContext* mContext;
   nsTArray<nsString> mPendingScripts;
 public:
--- a/content/base/src/nsInProcessTabChildGlobal.cpp
+++ b/content/base/src/nsInProcessTabChildGlobal.cpp
@@ -245,16 +245,18 @@ nsInProcessTabChildGlobal::DelayedDiscon
     static_cast<nsFrameMessageManager*>(mMessageManager.get())->Disconnect();
     mMessageManager = nsnull;
   }
   if (mListenerManager) {
     mListenerManager->Disconnect();
   }
   
   if (!mLoadingScript) {
+    nsContentUtils::ReleaseWrapper(static_cast<nsIDOMEventTarget*>(this),
+                                   this);
     if (mCx) {
       DestroyCx();
     }
   } else {
     mDelayedDisconnect = true;
   }
 }
 
--- a/content/base/src/nsNodeInfoManager.cpp
+++ b/content/base/src/nsNodeInfoManager.cpp
@@ -49,16 +49,17 @@
 #include "nsIURI.h"
 #include "nsContentUtils.h"
 #include "nsReadableUtils.h"
 #include "nsGkAtoms.h"
 #include "nsComponentManagerUtils.h"
 #include "nsLayoutStatics.h"
 #include "nsBindingManager.h"
 #include "nsHashKeys.h"
+#include "nsCCUncollectableMarker.h"
 
 #ifdef MOZ_LOGGING
 // so we can get logging even in release builds
 #define FORCE_PR_LOG 1
 #endif
 #include "prlog.h"
 
 #ifdef PR_LOGGING
@@ -156,16 +157,21 @@ nsNodeInfoManager::~nsNodeInfoManager()
 }
 
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsNodeInfoManager)
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsNodeInfoManager, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsNodeInfoManager, Release)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_NATIVE_0(nsNodeInfoManager)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsNodeInfoManager)
+  if (tmp->mDocument &&
+      nsCCUncollectableMarker::InGeneration(cb,
+                                            tmp->mDocument->GetMarkedCCGeneration())) {
+    return NS_SUCCESS_INTERRUPTED_TRAVERSE;
+  }
   if (tmp->mNonDocumentNodeInfos) {
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mDocument)
   }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mBindingManager)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 nsresult
 nsNodeInfoManager::Init(nsIDocument *aDocument)
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -445,24 +445,16 @@ nsXMLHttpRequest::~nsXMLHttpRequest()
                 XML_HTTP_REQUEST_SENT |
                 XML_HTTP_REQUEST_LOADING)) {
     Abort();
   }
 
   NS_ABORT_IF_FALSE(!(mState & XML_HTTP_REQUEST_SYNCLOOPING), "we rather crash than hang");
   mState &= ~XML_HTTP_REQUEST_SYNCLOOPING;
 
-  // This can happen if the XHR was only used by C++ (and so never created a JS
-  // wrapper) that also made an ArrayBuffer.
-  if (PreservingWrapper()) {
-    nsContentUtils::ReleaseWrapper(
-      static_cast<nsIDOMEventTarget*>(
-        static_cast<nsDOMEventTargetHelper*>(this)), this);
-  }
-
   nsLayoutStatics::Release();
 }
 
 void
 nsXMLHttpRequest::RootResultArrayBuffer()
 {
   nsContentUtils::PreserveWrapper(
     static_cast<nsIDOMEventTarget*>(
--- a/content/html/content/src/nsHTMLTableElement.cpp
+++ b/content/html/content/src/nsHTMLTableElement.cpp
@@ -118,16 +118,17 @@ TableRowsCollection::~TableRowsCollectio
   // release it!  this is to avoid circular references.  The
   // instantiator who provided mParent is responsible for managing our
   // reference for us.
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(TableRowsCollection)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(TableRowsCollection)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOrphanRows)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(TableRowsCollection)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mOrphanRows,
                                                        nsIDOMNodeList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(TableRowsCollection)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
@@ -339,16 +340,23 @@ nsHTMLTableElement::~nsHTMLTableElement(
   if (mRows) {
     mRows->ParentDestroyed();
   }
   ReleaseInheritedAttributes();
 }
 
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLTableElement)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLTableElement, nsGenericHTMLElement)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTBodies)
+  if (tmp->mRows) {
+    tmp->mRows->ParentDestroyed();
+  }
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRows)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLTableElement,
                                                   nsGenericHTMLElement)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mTBodies,
                                                        nsIDOMNodeList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRows)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_ADDREF_INHERITED(nsHTMLTableElement, nsGenericElement) 
--- a/content/html/content/src/nsHTMLTableElement.h
+++ b/content/html/content/src/nsHTMLTableElement.h
@@ -86,18 +86,18 @@ public:
   virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                  const nsAString* aValue, bool aNotify);
   /**
    * Called when an attribute has just been changed
    */
   virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                                 const nsAString* aValue, bool aNotify);
 
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLTableElement,
-                                                     nsGenericHTMLElement)
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLTableElement,
+                                           nsGenericHTMLElement)
   nsMappedAttributes* GetAttributesMappedForCell();
   already_AddRefed<nsIDOMHTMLTableSectionElement> GetTHead() {
     return GetSection(nsGkAtoms::thead);
   }
   already_AddRefed<nsIDOMHTMLTableSectionElement> GetTFoot() {
     return GetSection(nsGkAtoms::tfoot);
   }
   already_AddRefed<nsIDOMHTMLTableCaptionElement> GetCaption();
--- a/content/html/document/src/ImageDocument.cpp
+++ b/content/html/document/src/ImageDocument.cpp
@@ -376,16 +376,20 @@ ImageDocument::SetScriptGlobalObject(nsI
 
       target = do_QueryInterface(mImageContent);
       target->AddEventListener(NS_LITERAL_STRING("click"), this, false);
     }
 
     target = do_QueryInterface(aScriptGlobalObject);
     target->AddEventListener(NS_LITERAL_STRING("resize"), this, false);
     target->AddEventListener(NS_LITERAL_STRING("keypress"), this, false);
+
+    if (!nsContentUtils::IsChildOfSameType(this)) {
+      LinkStylesheet(NS_LITERAL_STRING("resource://gre/res/TopLevelImageDocument.css"));
+    }
   }
 }
 
 void
 ImageDocument::OnPageShow(bool aPersisted,
                           nsIDOMEventTarget* aDispatchStartTarget)
 {
   if (aPersisted) {
@@ -660,18 +664,16 @@ ImageDocument::CreateSyntheticDocument()
                                              kNameSpaceID_XHTML,
                                              nsIDOMNode::ELEMENT_NODE);
     NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
     nsRefPtr<nsGenericHTMLElement> styleContent = NS_NewHTMLStyleElement(nodeInfo.forget());
     NS_ENSURE_TRUE(styleContent, NS_ERROR_OUT_OF_MEMORY);
 
     styleContent->SetTextContent(NS_LITERAL_STRING("img { display: block; }"));
     head->AppendChildTo(styleContent, false);
-  } else {
-    LinkStylesheet(NS_LITERAL_STRING("resource://gre/res/TopLevelImageDocument.css"));
   }
 
   // Add the image element
   Element* body = GetBodyElement();
   if (!body) {
     NS_WARNING("no body on image document!");
     return NS_ERROR_FAILURE;
   }
--- a/content/html/document/src/VideoDocument.cpp
+++ b/content/html/document/src/VideoDocument.cpp
@@ -52,16 +52,17 @@ class VideoDocument : public MediaDocume
 public:
   virtual nsresult StartDocumentLoad(const char*         aCommand,
                                      nsIChannel*         aChannel,
                                      nsILoadGroup*       aLoadGroup,
                                      nsISupports*        aContainer,
                                      nsIStreamListener** aDocListener,
                                      bool                aReset = true,
                                      nsIContentSink*     aSink = nsnull);
+  virtual void SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject);
 
 protected:
 
   // Sets document <title> to reflect the file name and description.
   void UpdateTitle(nsIChannel* aChannel);
 
   nsresult CreateSyntheticVideoDocument(nsIChannel* aChannel,
                                         nsIStreamListener** aListener);
@@ -89,16 +90,28 @@ VideoDocument::StartDocumentLoad(const c
   rv = CreateSyntheticVideoDocument(aChannel,
       getter_AddRefs(mStreamListener->mNextStream));
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ADDREF(*aDocListener = mStreamListener);
   return rv;
 }
 
+void
+VideoDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject)
+{
+  // Set the script global object on the superclass before doing
+  // anything that might require it....
+  MediaDocument::SetScriptGlobalObject(aScriptGlobalObject);
+
+  if (aScriptGlobalObject && !nsContentUtils::IsChildOfSameType(this)) {
+    LinkStylesheet(NS_LITERAL_STRING("resource://gre/res/TopLevelVideoDocument.css"));
+  }
+}
+
 nsresult
 VideoDocument::CreateSyntheticVideoDocument(nsIChannel* aChannel,
                                             nsIStreamListener** aListener)
 {
   // make our generic document
   nsresult rv = MediaDocument::CreateSyntheticDocument();
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -126,18 +139,16 @@ VideoDocument::CreateSyntheticVideoDocum
   UpdateTitle(aChannel);
 
   if (nsContentUtils::IsChildOfSameType(this)) {
     // Video documents that aren't toplevel should fill their frames and
     // not have margins
     element->SetAttr(kNameSpaceID_None, nsGkAtoms::style,
         NS_LITERAL_STRING("position:absolute; top:0; left:0; width:100%; height:100%"),
         true);
-  } else {
-    LinkStylesheet(NS_LITERAL_STRING("resource://gre/res/TopLevelVideoDocument.css"));
   }
 
   return body->AppendChildTo(element, false);
 }
 
 void
 VideoDocument::UpdateTitle(nsIChannel* aChannel)
 {