merge mozilla-inbound to mozilla-central. r=merge a=merge
authorSebastian Hengst <archaeopteryx@coole-files.de>
Sun, 16 Apr 2017 20:00:50 +0200
changeset 403851 c697e756f738ce37abc56f31bfbc48f55625d617
parent 403844 d3551474de3d6fdb8b58e770c658efe39d24f15f (current diff)
parent 403850 364c11f78435c92541485253850a6087363f39a7 (diff)
child 403852 2e41b230bb9a346f6a2f97edcce5f22f4fbf5cdb
child 403873 dc3d434b43e5230ea4480816c02b94b41ddf80f7
child 403901 5854dacc5d723c2b2b3b3c04cb2f96e500f4eb4f
push id1490
push usermtabara@mozilla.com
push dateMon, 31 Jul 2017 14:08:16 +0000
treeherdermozilla-release@70e32e6bf15e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone55.0a1
first release with
nightly linux32
c697e756f738 / 55.0a1 / 20170417100236 / files
nightly linux64
c697e756f738 / 55.0a1 / 20170417100236 / files
nightly mac
c697e756f738 / 55.0a1 / 20170417030204 / files
nightly win32
c697e756f738 / 55.0a1 / 20170417030204 / files
nightly win64
c697e756f738 / 55.0a1 / 20170417030204 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central. r=merge a=merge MozReview-Commit-ID: D039X4edhVO
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -1157,16 +1157,18 @@ public:
   /**
    * Called when we have been adopted, and the information of the
    * node has been changed.
    *
    * The new document can be reached via OwnerDoc().
    *
    * If you override this method,
    * please call up to the parent NodeInfoChanged.
+   *
+   * If you change this, change also the similar method in Link.
    */
   virtual void NodeInfoChanged(nsIDocument* aOldDoc) {}
 
   /**
    * Parse a string into an nsAttrValue for a CORS attribute.  This
    * never fails.  The resulting value is an enumerated value whose
    * GetEnumValue() returns one of the above constants.
    */
--- a/dom/base/Link.cpp
+++ b/dom/base/Link.cpp
@@ -28,26 +28,28 @@ namespace mozilla {
 namespace dom {
 
 Link::Link(Element *aElement)
   : mElement(aElement)
   , mHistory(services::GetHistoryService())
   , mLinkState(eLinkState_NotLink)
   , mNeedsRegistration(false)
   , mRegistered(false)
+  , mHasPendingLinkUpdate(false)
 {
   MOZ_ASSERT(mElement, "Must have an element");
 }
 
 Link::Link()
   : mElement(nullptr)
   , mHistory(nullptr)
   , mLinkState(eLinkState_NotLink)
   , mNeedsRegistration(false)
   , mRegistered(false)
+  , mHasPendingLinkUpdate(false)
 {
 }
 
 Link::~Link()
 {
   UnregisterFromHistory();
 }
 
--- a/dom/base/Link.h
+++ b/dom/base/Link.h
@@ -121,16 +121,26 @@ public:
   void TryDNSPrefetch();
   void CancelDNSPrefetch(nsWrapperCache::FlagsType aDeferredFlag,
                          nsWrapperCache::FlagsType aRequestedFlag);
 
   // This is called by HTMLLinkElement.
   void TryDNSPrefetchPreconnectOrPrefetchOrPrerender();
   void CancelPrefetch();
 
+  bool HasPendingLinkUpdate() { return mHasPendingLinkUpdate; }
+  void SetHasPendingLinkUpdate() { mHasPendingLinkUpdate = true; }
+  void ClearHasPendingLinkUpdate() { mHasPendingLinkUpdate = false; }
+
+  // To ensure correct mHasPendingLinkUpdate handling, we have this method
+  // similar to the one in Element. Overriders must call
+  // ClearHasPendingLinkUpdate().
+  // If you change this, change also the method in Element.
+  virtual void NodeInfoChanged(nsIDocument* aOldDoc) = 0;
+
 protected:
   virtual ~Link();
 
   /**
    * Return true if the link has associated URI.
    */
   bool HasURI() const
   {
@@ -159,19 +169,21 @@ private:
   Element * const mElement;
 
   // Strong reference to History.  The link has to unregister before History
   // can disappear.
   nsCOMPtr<IHistory> mHistory;
 
   uint16_t mLinkState;
 
-  bool mNeedsRegistration;
+  bool mNeedsRegistration : 1;
 
-  bool mRegistered;
+  bool mRegistered : 1;
+
+  bool mHasPendingLinkUpdate : 1;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(Link, MOZILLA_DOM_LINK_IMPLEMENTATION_IID)
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_Link_h__
--- a/dom/base/nsContentPolicy.cpp
+++ b/dom/base/nsContentPolicy.cpp
@@ -40,16 +40,18 @@ NS_NewContentPolicy(nsIContentPolicy **a
   *aResult = new nsContentPolicy;
   NS_ADDREF(*aResult);
   return NS_OK;
 }
 
 nsContentPolicy::nsContentPolicy()
     : mPolicies(NS_CONTENTPOLICY_CATEGORY)
     , mSimplePolicies(NS_SIMPLECONTENTPOLICY_CATEGORY)
+    , mMixedContentBlocker(do_GetService(NS_MIXEDCONTENTBLOCKER_CONTRACTID))
+    , mCSPService(do_GetService(CSPSERVICE_CONTRACTID))
 {
 }
 
 nsContentPolicy::~nsContentPolicy()
 {
 }
 
 #ifdef DEBUG
@@ -113,22 +115,16 @@ nsContentPolicy::CheckPolicy(CPMethod   
         if (doc) {
             requestingLocation = doc->GetDocumentURI();
         }
     }
 
     nsContentPolicyType externalType =
         nsContentUtils::InternalContentPolicyTypeToExternal(contentType);
 
-    nsCOMPtr<nsIContentPolicy> mixedContentBlocker =
-        do_GetService(NS_MIXEDCONTENTBLOCKER_CONTRACTID);
-
-    nsCOMPtr<nsIContentPolicy> cspService =
-      do_GetService(CSPSERVICE_CONTRACTID);
-
     /* 
      * Enumerate mPolicies and ask each of them, taking the logical AND of
      * their permissions.
      */
     nsresult rv;
     nsCOMArray<nsIContentPolicy> entries;
     mPolicies.GetEntries(entries);
 
@@ -147,17 +143,17 @@ nsContentPolicy::CheckPolicy(CPMethod   
         }
     }
 
     int32_t count = entries.Count();
     for (int32_t i = 0; i < count; i++) {
         /* check the appropriate policy */
         // Send internal content policy type to CSP and mixed content blocker
         nsContentPolicyType type = externalType;
-        if (mixedContentBlocker == entries[i] || cspService == entries[i]) {
+        if (mMixedContentBlocker == entries[i] || mCSPService == entries[i]) {
           type = contentType;
         }
         rv = (entries[i]->*policyMethod)(type, contentLocation,
                                          requestingLocation, requestingContext,
                                          mimeType, extra, requestPrincipal,
                                          decision);
 
         if (NS_SUCCEEDED(rv) && NS_CP_REJECTED(*decision)) {
--- a/dom/base/nsContentPolicy.h
+++ b/dom/base/nsContentPolicy.h
@@ -26,16 +26,19 @@ class nsContentPolicy : public nsIConten
  protected:
     virtual ~nsContentPolicy();
 
  private:
     //Array of policies
     nsCategoryCache<nsIContentPolicy> mPolicies;
     nsCategoryCache<nsISimpleContentPolicy> mSimplePolicies;
 
+    nsCOMPtr<nsIContentPolicy> mMixedContentBlocker;
+    nsCOMPtr<nsIContentPolicy> mCSPService;
+
     //Helper type for CheckPolicy
     typedef
     NS_STDCALL_FUNCPROTO(nsresult, CPMethod, nsIContentPolicy,
                          ShouldProcess,
                          (uint32_t, nsIURI*, nsIURI*, nsISupports*,
                            const nsACString &, nsISupports*, nsIPrincipal*,
                            int16_t*));
 
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1312,16 +1312,17 @@ nsIDocument::nsIDocument()
     mAllowDNSPrefetch(true),
     mIsStaticDocument(false),
     mCreatingStaticClone(false),
     mInUnlinkOrDeletion(false),
     mHasHadScriptHandlingObject(false),
     mIsBeingUsedAsImage(false),
     mIsSyntheticDocument(false),
     mHasLinksToUpdate(false),
+    mHasLinksToUpdateRunnable(false),
     mMayHaveDOMMutationObservers(false),
     mMayHaveAnimationObservers(false),
     mHasMixedActiveContentLoaded(false),
     mHasMixedActiveContentBlocked(false),
     mHasMixedDisplayContentLoaded(false),
     mHasMixedDisplayContentBlocked(false),
     mHasMixedContentObjectSubrequest(false),
     mHasCSP(false),
@@ -10000,44 +10001,69 @@ nsIDocument::EnumerateActivityObservers(
     aEnumerator(iter.Get()->GetKey(), aData);
   }
 }
 
 void
 nsIDocument::RegisterPendingLinkUpdate(Link* aLink)
 {
   MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden);
-  mLinksToUpdate.PutEntry(aLink);
+
+  if (aLink->HasPendingLinkUpdate()) {
+    return;
+  }
+
+  aLink->SetHasPendingLinkUpdate();
+
+  if (!mHasLinksToUpdateRunnable) {
+    nsCOMPtr<nsIRunnable> event =
+      NewRunnableMethod(this, &nsIDocument::FlushPendingLinkUpdatesFromRunnable);
+    nsresult rv =
+      Dispatch("nsIDocument::FlushPendingLinkUpdatesFromRunnable",
+               TaskCategory::Other, event.forget());
+    if (NS_FAILED(rv)) {
+      // If during shutdown posting a runnable doesn't succeed, we probably
+      // don't need to update link states.
+      return;
+    }
+    mHasLinksToUpdateRunnable = true;
+  }
+
+  mLinksToUpdate.InfallibleAppend(aLink);
   mHasLinksToUpdate = true;
 }
 
 void
-nsIDocument::UnregisterPendingLinkUpdate(Link* aLink)
-{
-  MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden);
-  if (!mHasLinksToUpdate)
-    return;
-
-  mLinksToUpdate.RemoveEntry(aLink);
+nsIDocument::FlushPendingLinkUpdatesFromRunnable()
+{
+  MOZ_ASSERT(mHasLinksToUpdateRunnable);
+  mHasLinksToUpdateRunnable = false;
+  FlushPendingLinkUpdates();
 }
 
 void
 nsIDocument::FlushPendingLinkUpdates()
 {
   MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden);
   if (!mHasLinksToUpdate)
     return;
 
 #ifdef DEBUG
   AutoRestore<bool> saved(mIsLinkUpdateRegistrationsForbidden);
   mIsLinkUpdateRegistrationsForbidden = true;
 #endif
-  for (auto iter = mLinksToUpdate.ConstIter(); !iter.Done(); iter.Next()) {
-    Link* link = iter.Get()->GetKey();
-    link->GetElement()->UpdateLinkState(link->LinkState());
+  for (auto iter = mLinksToUpdate.Iter(); !iter.Done(); iter.Next()) {
+    Link* link = iter.Get();
+    Element* element = link->GetElement();
+    if (element->OwnerDoc() == this) {
+      link->ClearHasPendingLinkUpdate();
+      if (element->IsInComposedDoc()) {
+        element->UpdateLinkState(link->LinkState());
+      }
+    }
   }
   mLinksToUpdate.Clear();
   mHasLinksToUpdate = false;
 }
 
 already_AddRefed<nsIDocument>
 nsIDocument::CreateStaticClone(nsIDocShell* aCloneContainer)
 {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -10475,17 +10475,19 @@ NotifyDocumentTree(nsIDocument* aDocumen
   aDocument->DocumentStatesChanged(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
   return true;
 }
 
 void
 nsGlobalWindow::SetActive(bool aActive)
 {
   nsPIDOMWindow::SetActive(aActive);
-  NotifyDocumentTree(mDoc, nullptr);
+  if (mDoc) {
+    NotifyDocumentTree(mDoc, nullptr);
+  }
 }
 
 bool
 nsGlobalWindow::IsTopLevelWindowActive()
 {
    nsCOMPtr<nsIDocShellTreeItem> treeItem(GetDocShell());
    if (!treeItem) {
      return false;
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -30,16 +30,17 @@
 #include "Units.h"
 #include "nsContentListDeclarations.h"
 #include "nsExpirationTracker.h"
 #include "nsClassHashtable.h"
 #include "prclist.h"
 #include "mozilla/CORSMode.h"
 #include "mozilla/dom/DispatcherTrait.h"
 #include "mozilla/LinkedList.h"
+#include "mozilla/SegmentedVector.h"
 #include "mozilla/StyleBackendType.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/UniquePtr.h"
 #include <bitset>                        // for member
 
 #ifdef MOZILLA_INTERNAL_API
 #include "mozilla/dom/DocumentBinding.h"
@@ -2457,24 +2458,22 @@ public:
 
   virtual nsresult SetNavigationTiming(nsDOMNavigationTiming* aTiming) = 0;
 
   virtual Element* FindImageMap(const nsAString& aNormalizedMapName) = 0;
 
   // Add aLink to the set of links that need their status resolved.
   void RegisterPendingLinkUpdate(mozilla::dom::Link* aLink);
 
-  // Remove aLink from the set of links that need their status resolved.
-  // This function must be called when links are removed from the document.
-  void UnregisterPendingLinkUpdate(mozilla::dom::Link* aElement);
-
   // Update state on links in mLinksToUpdate.  This function must
   // be called prior to selector matching.
   void FlushPendingLinkUpdates();
 
+  void FlushPendingLinkUpdatesFromRunnable();
+
 #define DEPRECATED_OPERATION(_op) e##_op,
   enum DeprecatedOperations {
 #include "nsDeprecatedOperationList.h"
     eDeprecatedOperationCount
   };
 #undef DEPRECATED_OPERATION
   bool HasWarnedAbout(DeprecatedOperations aOperation) const;
   void WarnOnceAbout(DeprecatedOperations aOperation,
@@ -3038,20 +3037,23 @@ protected:
 
   // The set of all object, embed, applet, video/audio elements or
   // nsIObjectLoadingContent or nsIDocumentActivity for which this is the
   // owner document. (They might not be in the document.)
   // These are non-owning pointers, the elements are responsible for removing
   // themselves when they go away.
   nsAutoPtr<nsTHashtable<nsPtrHashKey<nsISupports> > > mActivityObservers;
 
-  // The set of all links that need their status resolved.  Links must add themselves
-  // to this set by calling RegisterPendingLinkUpdate when added to a document and must
-  // remove themselves by calling UnregisterPendingLinkUpdate when removed from a document.
-  nsTHashtable<nsPtrHashKey<mozilla::dom::Link> > mLinksToUpdate;
+  // The array of all links that need their status resolved.  Links must add themselves
+  // to this set by calling RegisterPendingLinkUpdate when added to a document.
+  static const size_t kSegmentSize = 128;
+  mozilla::SegmentedVector<nsCOMPtr<mozilla::dom::Link>,
+                           kSegmentSize,
+                           InfallibleAllocPolicy>
+    mLinksToUpdate;
 
   // SMIL Animation Controller, lazily-initialized in GetAnimationController
   RefPtr<nsSMILAnimationController> mAnimationController;
 
   // Table of element properties for this document.
   nsPropertyTable mPropertyTable;
   nsTArray<nsAutoPtr<nsPropertyTable> > mExtraPropertyTables;
 
@@ -3134,16 +3136,19 @@ protected:
 
   // True is this document is synthetic : stand alone image, video, audio
   // file, etc.
   bool mIsSyntheticDocument : 1;
 
   // True if this document has links whose state needs updating
   bool mHasLinksToUpdate : 1;
 
+  // True is there is a pending runnable which will call FlushPendingLinkUpdates().
+  bool mHasLinksToUpdateRunnable : 1;
+
   // True if a DOMMutationObserver is perhaps attached to a node in the document.
   bool mMayHaveDOMMutationObservers : 1;
 
   // True if an nsIAnimationObserver is perhaps attached to a node in the document.
   bool mMayHaveAnimationObservers : 1;
 
   // True if a document has loaded Mixed Active Script (see nsMixedContentBlocker.cpp)
   bool mHasMixedActiveContentLoaded : 1;
--- a/dom/html/HTMLAnchorElement.cpp
+++ b/dom/html/HTMLAnchorElement.cpp
@@ -167,23 +167,16 @@ HTMLAnchorElement::UnbindFromTree(bool a
   // mCachedURI based on data that is invalid - due to a call to GetHostname.
   CancelDNSPrefetch(HTML_ANCHOR_DNS_PREFETCH_DEFERRED,
                     HTML_ANCHOR_DNS_PREFETCH_REQUESTED);
 
   // If this link is ever reinserted into a document, it might
   // be under a different xml:base, so forget the cached state now.
   Link::ResetLinkState(false, Link::ElementHasHref());
 
-  // Note, we need to use OwnerDoc() here, since GetComposedDoc() might
-  // return null.
-  nsIDocument* doc = OwnerDoc();
-  if (doc) {
-    doc->UnregisterPendingLinkUpdate(this);
-  }
-
   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
 }
 
 static bool
 IsNodeInEditableRegion(nsINode* aNode)
 {
   while (aNode) {
     if (aNode->IsEditable()) {
--- a/dom/html/HTMLAnchorElement.h
+++ b/dom/html/HTMLAnchorElement.h
@@ -223,16 +223,22 @@ public:
   {
     SetHTMLAttr(nsGkAtoms::shape, aValue, rv);
   }
   void Stringify(nsAString& aResult)
   {
     GetHref(aResult);
   }
 
+  virtual void NodeInfoChanged(nsIDocument* aOldDoc) final override
+  {
+    ClearHasPendingLinkUpdate();
+    nsGenericHTMLElement::NodeInfoChanged(aOldDoc);
+  }
+
   static DOMTokenListSupportedToken sSupportedRelValues[];
 
 protected:
   virtual ~HTMLAnchorElement();
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
   RefPtr<nsDOMTokenList > mRelList;
 };
--- a/dom/html/HTMLAreaElement.cpp
+++ b/dom/html/HTMLAreaElement.cpp
@@ -137,23 +137,16 @@ HTMLAreaElement::BindToTree(nsIDocument*
 
 void
 HTMLAreaElement::UnbindFromTree(bool aDeep, bool aNullParent)
 {
   // If this link is ever reinserted into a document, it might
   // be under a different xml:base, so forget the cached state now.
   Link::ResetLinkState(false, Link::ElementHasHref());
 
-  // Note, we need to use OwnerDoc() here, since GetComposedDoc() might
-  // return null.
-  nsIDocument* doc = OwnerDoc();
-  if (doc) {
-    doc->UnregisterPendingLinkUpdate(this);
-  }
-
   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
 }
 
 nsresult
 HTMLAreaElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                          nsIAtom* aPrefix, const nsAString& aValue,
                          bool aNotify)
 {
--- a/dom/html/HTMLAreaElement.h
+++ b/dom/html/HTMLAreaElement.h
@@ -176,16 +176,22 @@ public:
     SetHTMLBoolAttr(nsGkAtoms::nohref, aValue, aError);
   }
 
   void Stringify(nsAString& aResult)
   {
     GetHref(aResult);
   }
 
+  virtual void NodeInfoChanged(nsIDocument* aOldDoc) final override
+  {
+    ClearHasPendingLinkUpdate();
+    nsGenericHTMLElement::NodeInfoChanged(aOldDoc);
+  }
+
 protected:
   virtual ~HTMLAreaElement();
 
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   RefPtr<nsDOMTokenList > mRelList;
 };
 
--- a/dom/html/HTMLLinkElement.cpp
+++ b/dom/html/HTMLLinkElement.cpp
@@ -213,18 +213,16 @@ HTMLLinkElement::UnbindFromTree(bool aDe
   // from the parser.
   nsCOMPtr<nsIDocument> oldDoc = GetUncomposedDoc();
 
   // Check for a ShadowRoot because link elements are inert in a
   // ShadowRoot.
   ShadowRoot* oldShadowRoot = GetBindingParent() ?
     GetBindingParent()->GetShadowRoot() : nullptr;
 
-  OwnerDoc()->UnregisterPendingLinkUpdate(this);
-
   CreateAndDispatchEvent(oldDoc, NS_LITERAL_STRING("DOMLinkRemoved"));
   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
 
   UpdateStyleSheetInternal(oldDoc, oldShadowRoot);
   UpdateImport();
 }
 
 bool
--- a/dom/html/HTMLLinkElement.h
+++ b/dom/html/HTMLLinkElement.h
@@ -166,16 +166,23 @@ public:
 
   already_AddRefed<nsIDocument> GetImport();
   already_AddRefed<ImportLoader> GetImportLoader()
   {
     return RefPtr<ImportLoader>(mImportLoader).forget();
   }
 
   virtual CORSMode GetCORSMode() const override;
+
+  virtual void NodeInfoChanged(nsIDocument* aOldDoc) final override
+  {
+    ClearHasPendingLinkUpdate();
+    nsGenericHTMLElement::NodeInfoChanged(aOldDoc);
+  }
+
 protected:
   virtual ~HTMLLinkElement();
 
   // nsStyleLinkElement
   virtual already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline) override;
   virtual void GetStyleSheetInfo(nsAString& aTitle,
                                  nsAString& aType,
                                  nsAString& aMedia,
--- a/dom/mathml/nsMathMLElement.cpp
+++ b/dom/mathml/nsMathMLElement.cpp
@@ -131,21 +131,16 @@ nsMathMLElement::BindToTree(nsIDocument*
 }
 
 void
 nsMathMLElement::UnbindFromTree(bool aDeep, bool aNullParent)
 {
   // If this link is ever reinserted into a document, it might
   // be under a different xml:base, so forget the cached state now.
   Link::ResetLinkState(false, Link::ElementHasHref());
-  
-  nsIDocument* doc = GetUncomposedDoc();
-  if (doc) {
-    doc->UnregisterPendingLinkUpdate(this);
-  }
 
   nsMathMLElementBase::UnbindFromTree(aDeep, aNullParent);
 }
 
 bool
 nsMathMLElement::ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
--- a/dom/mathml/nsMathMLElement.h
+++ b/dom/mathml/nsMathMLElement.h
@@ -101,16 +101,22 @@ public:
   virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                            nsIAtom* aPrefix, const nsAString& aValue,
                            bool aNotify) override;
   virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify) override;
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
 
+  virtual void NodeInfoChanged(nsIDocument* aOldDoc) override
+  {
+    ClearHasPendingLinkUpdate();
+    nsMathMLElementBase::NodeInfoChanged(aOldDoc);
+  }
+
 protected:
   virtual ~nsMathMLElement() {}
 
   virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   bool mIncrementScriptLevel;
 };
--- a/dom/svg/SVGAElement.cpp
+++ b/dom/svg/SVGAElement.cpp
@@ -146,23 +146,16 @@ SVGAElement::BindToTree(nsIDocument *aDo
 
 void
 SVGAElement::UnbindFromTree(bool aDeep, bool aNullParent)
 {
   // If this link is ever reinserted into a document, it might
   // be under a different xml:base, so forget the cached state now.
   Link::ResetLinkState(false, Link::ElementHasHref());
 
-  // Note, we need to use OwnerDoc() here since GetComposedDoc() may
-  // return null already at this point.
-  nsIDocument* doc = OwnerDoc();
-  if (doc) {
-    doc->UnregisterPendingLinkUpdate(this);
-  }
-
   SVGAElementBase::UnbindFromTree(aDeep, aNullParent);
 }
 
 already_AddRefed<nsIURI>
 SVGAElement::GetHrefURI() const
 {
   nsCOMPtr<nsIURI> hrefURI;
   return IsLink(getter_AddRefs(hrefURI)) ? hrefURI.forget() : nullptr;
--- a/dom/svg/SVGAElement.h
+++ b/dom/svg/SVGAElement.h
@@ -68,16 +68,22 @@ public:
                              bool aNotify) override;
 
   // WebIDL
   already_AddRefed<SVGAnimatedString> Href();
   already_AddRefed<SVGAnimatedString> Target();
   void GetDownload(nsAString & aDownload);
   void SetDownload(const nsAString & aDownload, ErrorResult& rv);
 
+  virtual void NodeInfoChanged(nsIDocument* aOldDoc) final override
+  {
+    ClearHasPendingLinkUpdate();
+    SVGAElementBase::NodeInfoChanged(aOldDoc);
+  }
+
 protected:
   virtual ~SVGAElement();
 
   virtual StringAttributesInfo GetStringInfo() override;
 
   enum { HREF, XLINK_HREF, TARGET };
   nsSVGString mStringAttributes[3];
   static StringInfo sStringInfo[3];
--- a/dom/svg/nsSVGElement.h
+++ b/dom/svg/nsSVGElement.h
@@ -113,17 +113,17 @@ public:
                                               int32_t aModType) const override;
 
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
 
   /**
    * We override the default to unschedule computation of Servo declaration blocks
    * when adopted across documents.
    */
-  virtual void NodeInfoChanged(nsIDocument* aOldDoc) final;
+  virtual void NodeInfoChanged(nsIDocument* aOldDoc) override;
 
   NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
   void WalkAnimatedContentStyleRules(nsRuleWalker* aRuleWalker);
 
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const override;
 
   static const MappedAttributeEntry sFillStrokeMap[];
   static const MappedAttributeEntry sGraphicsMap[];
--- a/image/imgLoader.cpp
+++ b/image/imgLoader.cpp
@@ -10,17 +10,16 @@
 #include "ImageLogging.h"
 #include "imgLoader.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/Move.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ChaosMode.h"
-#include "mozilla/Telemetry.h"
 
 #include "nsImageModule.h"
 #include "imgRequestProxy.h"
 
 #include "nsCOMPtr.h"
 
 #include "nsContentPolicyUtils.h"
 #include "nsContentUtils.h"
@@ -2085,22 +2084,16 @@ imgLoader::LoadImage(nsIURI* aURI,
                      nsINode *aContext,
                      nsIDocument* aLoadingDocument,
                      nsLoadFlags aLoadFlags,
                      nsISupports* aCacheKey,
                      nsContentPolicyType aContentPolicyType,
                      const nsAString& initiatorType,
                      imgRequestProxy** _retval)
 {
-  // Note: We round the time to the nearest milliseconds.  Due to this rounding,
-  // the actual minimum value is 500 microseconds.
-  static const uint32_t kMinTelemetryLatencyMs = 1;
-
-  mozilla::TimeStamp start = TimeStamp::Now();
-
   VerifyCacheSizes();
 
   NS_ASSERTION(aURI, "imgLoader::LoadImage -- NULL URI pointer");
 
   if (!aURI) {
     return NS_ERROR_NULL_POINTER;
   }
 
@@ -2338,21 +2331,18 @@ imgLoader::LoadImage(nsIURI* aURI,
     // If we're loading off the network, explicitly don't notify our proxy,
     // because necko (or things called from necko, such as imgCacheValidator)
     // are going to call our notifications asynchronously, and we can't make it
     // further asynchronous because observers might rely on imagelib completing
     // its work between the channel's OnStartRequest and OnStopRequest.
     if (!newChannel) {
       proxy->NotifyListener();
     }
-  }
-
-  uint32_t latencyMs = round((TimeStamp::Now() - start).ToMilliseconds());
-  if (XRE_IsContentProcess() && latencyMs >= kMinTelemetryLatencyMs) {
-    Telemetry::Accumulate(Telemetry::IMAGE_LOAD_TRIGGER_LATENCY_MS, latencyMs);
+
+    return rv;
   }
 
   NS_ASSERTION(*_retval, "imgLoader::LoadImage -- no return value");
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/toolkit/components/places/tests/gtest/mock_Link.h
+++ b/toolkit/components/places/tests/gtest/mock_Link.h
@@ -42,16 +42,18 @@ public:
     mDeathGrip = nullptr;
   }
 
   virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override
   {
     return 0;   // the value shouldn't matter
   }
 
+  virtual void NodeInfoChanged(nsIDocument* aOldDoc) final override {}
+
 protected:
   ~mock_Link() {
     // Run the next test if we are supposed to.
     if (mRunNextTest) {
       run_next_test();
     }
   }
 
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -1603,26 +1603,16 @@
     "alert_emails": ["gfx-telemetry-alerts@mozilla.com"],
     "expires_in_version": "never",
     "kind": "exponential",
     "low": 500,
     "high": 50000000,
     "n_buckets": 50,
     "description": "GIF image decode speed (Kbytes/sec)"
   },
-  "IMAGE_LOAD_TRIGGER_LATENCY_MS": {
-    "alert_emails": ["ehsan@mozilla.com", "gfx-telemetry-alerts@mozilla.com"],
-    "expires_in_version": "60",
-    "bug_numbers": [1347376],
-    "kind": "exponential",
-    "low": 1,
-    "high": 1000,
-    "n_buckets": 50,
-    "description": "Measures the number of milliseconds we spend inside imgLoader::LoadImage(). Note: only calls that take more than 500 microseconds and happen in the content process are included in this probe."
-  },
   "IMAGE_DECODE_SPEED_PNG": {
     "alert_emails": ["gfx-telemetry-alerts@mozilla.com"],
     "expires_in_version": "never",
     "kind": "exponential",
     "low": 500,
     "high": 50000000,
     "n_buckets": 50,
     "description": "PNG image decode speed (Kbytes/sec)"
--- a/toolkit/themes/linux/global/tabbox.css
+++ b/toolkit/themes/linux/global/tabbox.css
@@ -15,50 +15,34 @@ tabs {
   position: relative;
   z-index: 0;
 }
 
 /* ::::: tabpanels ::::: */
 
 tabpanels {
   -moz-appearance: tabpanels;
-  border: 2px solid;
-  -moz-border-right-colors: ThreeDDarkShadow ThreeDShadow;
-  -moz-border-bottom-colors: ThreeDDarkShadow ThreeDShadow;
-  -moz-border-left-colors: ThreeDHighlight ThreeDLightShadow;
-  -moz-border-top-colors: ThreeDHighlight ThreeDLightShadow;
   padding: 8px;
-  background-color: -moz-Dialog;
   color: -moz-DialogText;
 }
 
 /* ::::: tab ::::: */
 
 tab {
   position: relative;
   -moz-appearance: tab;
   margin-top: 2px;
-  border: 2px solid;
-  border-bottom: none;
-  -moz-border-top-colors: ThreeDHighlight ThreeDLightShadow;
-  -moz-border-right-colors: ThreeDDarkShadow ThreeDShadow;
-  -moz-border-left-colors: ThreeDHighlight ThreeDLightShadow;
-  border-top-left-radius: 2px;
-  border-top-right-radius: 2px;
   padding: 3px 4px;
-  background-color: -moz-Dialog;
   color: -moz-DialogText;
 }
 
 tab[visuallyselected="true"] {
   z-index: 1;
   margin-top: 0;
   margin-bottom: -2px;
-  border-bottom-left-radius: 3px;
-  border-bottom-right-radius: 3px;
   padding-top: 4px;
   padding-bottom: 6px;
 }
 
 tab + tab {
   margin-inline-start: -2px;
 }
 
@@ -69,23 +53,16 @@ tab + tab {
 /* ::::: tab-bottom ::::::::::
    :: Tabs that are attached to the bottom of a panel, but not necessarily
    :: a tabpanels.
    ::::: */
 
 .tab-bottom {
   margin-top: 0;
   margin-bottom: 2px;
-  border-top: none;
-  border-bottom: 2px solid;
-  -moz-border-bottom-colors: ThreeDDarkShadow ThreeDShadow;
-  border-top-left-radius: 0;
-  border-top-right-radius: 0;
-  border-bottom-right-radius: 2px;
-  border-bottom-left-radius: 2px;
 }
 
 .tab-bottom[visuallyselected="true"] {
   margin-bottom: 0;
   margin-top: -2px;
   padding-top: 6px;
   padding-bottom: 4px;
 }
--- a/toolkit/themes/windows/global/tabbox.css
+++ b/toolkit/themes/windows/global/tabbox.css
@@ -14,120 +14,64 @@
 .tabs-right {
   border-bottom: 2px solid;
   -moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
 }
 
 /* ::::: tabpanels ::::: */
 
 tabpanels {
-  -moz-appearance: tabpanels; 
-  border-right: 2px solid;
-  border-bottom: 2px solid;
-  border-left: 2px solid;
-  -moz-border-right-colors: ThreeDDarkShadow ThreeDShadow;
-  -moz-border-bottom-colors: ThreeDDarkShadow ThreeDShadow;
-  -moz-border-left-colors: ThreeDHighlight ThreeDLightShadow;
+  -moz-appearance: tabpanels;
   padding: 8px;
-  background-color: -moz-Dialog;
   color: -moz-DialogText;
 }
 
 /* ::::: tab ::::: */
 
-tab 
-{
+tab {
   -moz-appearance: tab;
   margin-top: 2px;
-  border-top: 2px solid;
-  border-right: 2px solid;
-  border-left: 2px solid;
-  border-bottom: 1px solid ThreeDHighlight;
-  -moz-border-top-colors: ThreeDHighlight ThreeDLightShadow;
-  -moz-border-right-colors: ThreeDDarkShadow ThreeDShadow;
-  -moz-border-left-colors: ThreeDHighlight ThreeDLightShadow;
-  border-top-left-radius: 2px;
-  border-top-right-radius: 2px;
   padding: 1px 4px 2px 4px;
-  background-color: -moz-Dialog;
   color: -moz-DialogText;
 }
 
-tab:-moz-locale-dir(rtl) {
-  border-bottom-left-radius: 1px;
-  border-bottom-right-radius: 0px;
-}
-
 .tab-text {
   margin: 0 !important;
 }
 
 tab[visuallyselected="true"] {
   margin-top: 0;
-  border-bottom-color: transparent;
   padding: 1px 6px 4px 6px;
 }
 
 tab:-moz-focusring > .tab-middle {
   /* Don't specify the outline-color, we should always use initial value. */
   outline: 1px dotted;
 }
 
-tab[beforeselected="true"]:-moz-locale-dir(ltr),
-tab[visuallyselected="true"]:-moz-locale-dir(rtl) + tab {
-  border-right: none;
-  border-top-right-radius: 0;
-}
-
-tab[visuallyselected="true"]:-moz-locale-dir(ltr) + tab,
-tab[beforeselected="true"]:-moz-locale-dir(rtl) {
-  border-left: none;
-  border-top-left-radius: 0;
-}
-
 tab:first-of-type[visuallyselected="true"] {
   padding-right: 5px;
   padding-left: 5px;
 }
 
 /* ::::: tab-bottom ::::::::::
    :: Tabs that are attached to the bottom of a panel, but not necessarily
    :: a tabpanels.
    ::::: */
 
 .tab-bottom {
   margin-top: 0;
   margin-bottom: 2px;
-  border-top: 1px solid;
-  border-bottom: 2px solid;
-  -moz-border-top-colors: ThreeDShadow;
-  -moz-border-bottom-colors: ThreeDShadow ThreeDLightShadow;
-  border-top-left-radius: 0;
-  border-top-right-radius: 0;
-  border-bottom-right-radius: 2px;
-  border-bottom-left-radius: 2px;
   padding: 2px 4px 1px 4px;
 }
 
 .tab-bottom[visuallyselected="true"] {
   margin-bottom: 0;
-  -moz-border-top-colors: -moz-Dialog;
   padding: 4px 6px 1px 6px;
 }
 
-.tab-bottom[beforeselected="true"]:-moz-locale-dir(ltr),
-.tab-bottom[visuallyselected="true"]:-moz-locale-dir(rtl) + .tab-bottom {
-  border-bottom-right-radius: 0;
-}
-
-.tab-bottom[visuallyselected="true"]:-moz-locale-dir(ltr) + .tab-bottom,
-.tab-bottom[beforeselected="true"]:-moz-locale-dir(rtl) {
-  border-bottom-left-radius: 0;
-}
-
 /* ::::: tabs-bottom ::::: */
 
 .tabs-bottom > .tabs-left,
 .tabs-bottom > .tabs-right {
   border-top: 1px solid ThreeDShadow;
   border-bottom: none;
 }
-