Bug 1367923 - Store Servo decls when link preshints change. r=Manishearth draft
authorJ. Ryan Stinnett <jryans@gmail.com>
Thu, 01 Jun 2017 13:37:02 -0500
changeset 587967 2d9a87b54fef82b250192d678acde889f5631fd6
parent 587956 a34f9043e5aae7c1b350668294606ad9f7b5a2a3
child 587968 b240e75f2b800243eb81d543bb40d3b942a67280
push id61869
push userbmo:jryans@gmail.com
push dateThu, 01 Jun 2017 23:22:51 +0000
reviewersManishearth
bugs1367923
milestone55.0a1
Bug 1367923 - Store Servo decls when link preshints change. r=Manishearth When any of the link preshints (link, vlink, alink) on <body> are set, we store a Servo declaration block to hold the color from the hint. This uses a one-off approach instead of `nsMappedAttributes` that is used for other preshints because it depends on element state and also it affects links through the document (as opposed to the element where the attribute is set). MozReview-Commit-ID: KUvyCq9KfHT
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
layout/style/nsHTMLStyleSheet.cpp
layout/style/nsHTMLStyleSheet.h
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -28,16 +28,17 @@
 #include "nsIDocumentInlines.h"
 #include "nsIFrame.h"
 #include "nsINode.h"
 #include "nsIPresShell.h"
 #include "nsIPresShellInlines.h"
 #include "nsIPrincipal.h"
 #include "nsIURI.h"
 #include "nsFontMetrics.h"
+#include "nsHTMLStyleSheet.h"
 #include "nsMappedAttributes.h"
 #include "nsMediaFeatures.h"
 #include "nsNameSpaceManager.h"
 #include "nsNetUtil.h"
 #include "nsRuleNode.h"
 #include "nsString.h"
 #include "nsStyleStruct.h"
 #include "nsStyleUtil.h"
@@ -482,16 +483,61 @@ Gecko_GetExtraContentStyleDeclarations(R
   const HTMLTableCellElement* cell = static_cast<const HTMLTableCellElement*>(aElement);
   if (nsMappedAttributes* attrs = cell->GetMappedAttributesInheritedFromTable()) {
     const RefPtr<RawServoDeclarationBlock>& servo = attrs->GetServoStyle();
     return reinterpret_cast<const RawServoDeclarationBlockStrong*>(&servo);
   }
   return nullptr;
 }
 
+RawServoDeclarationBlockStrongBorrowedOrNull
+Gecko_GetUnvisitedLinkAttrDeclarationBlock(RawGeckoElementBorrowed aElement)
+{
+  static_assert(sizeof(RefPtr<RawServoDeclarationBlock>) ==
+                sizeof(RawServoDeclarationBlockStrong),
+                "RefPtr should just be a pointer");
+  nsHTMLStyleSheet* sheet = aElement->OwnerDoc()->GetAttributeStyleSheet();
+  if (!sheet) {
+    return nullptr;
+  }
+
+  return reinterpret_cast<const RawServoDeclarationBlockStrong*>
+      (&sheet->GetServoUnvisitedLinkDecl());
+}
+
+RawServoDeclarationBlockStrongBorrowedOrNull
+Gecko_GetVisitedLinkAttrDeclarationBlock(RawGeckoElementBorrowed aElement)
+{
+  static_assert(sizeof(RefPtr<RawServoDeclarationBlock>) ==
+                sizeof(RawServoDeclarationBlockStrong),
+                "RefPtr should just be a pointer");
+  nsHTMLStyleSheet* sheet = aElement->OwnerDoc()->GetAttributeStyleSheet();
+  if (!sheet) {
+    return nullptr;
+  }
+
+  return reinterpret_cast<const RawServoDeclarationBlockStrong*>
+      (&sheet->GetServoVisitedLinkDecl());
+}
+
+RawServoDeclarationBlockStrongBorrowedOrNull
+Gecko_GetActiveLinkAttrDeclarationBlock(RawGeckoElementBorrowed aElement)
+{
+  static_assert(sizeof(RefPtr<RawServoDeclarationBlock>) ==
+                sizeof(RawServoDeclarationBlockStrong),
+                "RefPtr should just be a pointer");
+  nsHTMLStyleSheet* sheet = aElement->OwnerDoc()->GetAttributeStyleSheet();
+  if (!sheet) {
+    return nullptr;
+  }
+
+  return reinterpret_cast<const RawServoDeclarationBlockStrong*>
+      (&sheet->GetServoActiveLinkDecl());
+}
+
 static nsIAtom*
 PseudoTagAndCorrectElementForAnimation(const Element*& aElementOrPseudo) {
   if (aElementOrPseudo->IsGeneratedContentContainerForBefore()) {
     aElementOrPseudo = aElementOrPseudo->GetParent()->AsElement();
     return nsCSSPseudoElements::before;
   }
 
   if (aElementOrPseudo->IsGeneratedContentContainerForAfter()) {
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -192,16 +192,22 @@ SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNC
 // Style attributes.
 RawServoDeclarationBlockStrongBorrowedOrNull
 Gecko_GetStyleAttrDeclarationBlock(RawGeckoElementBorrowed element);
 void Gecko_UnsetDirtyStyleAttr(RawGeckoElementBorrowed element);
 RawServoDeclarationBlockStrongBorrowedOrNull
 Gecko_GetHTMLPresentationAttrDeclarationBlock(RawGeckoElementBorrowed element);
 RawServoDeclarationBlockStrongBorrowedOrNull
 Gecko_GetExtraContentStyleDeclarations(RawGeckoElementBorrowed element);
+RawServoDeclarationBlockStrongBorrowedOrNull
+Gecko_GetUnvisitedLinkAttrDeclarationBlock(RawGeckoElementBorrowed element);
+RawServoDeclarationBlockStrongBorrowedOrNull
+Gecko_GetVisitedLinkAttrDeclarationBlock(RawGeckoElementBorrowed element);
+RawServoDeclarationBlockStrongBorrowedOrNull
+Gecko_GetActiveLinkAttrDeclarationBlock(RawGeckoElementBorrowed element);
 
 // Animations
 bool
 Gecko_GetAnimationRule(RawGeckoElementBorrowed aElementOrPseudo,
                        mozilla::EffectCompositor::CascadeLevel aCascadeLevel,
                        RawServoAnimationValueMapBorrowedMut aAnimationValues);
 RawServoDeclarationBlockStrongBorrowedOrNull
 Gecko_GetSMILOverrideDeclarationBlock(RawGeckoElementBorrowed element);
--- a/layout/style/nsHTMLStyleSheet.cpp
+++ b/layout/style/nsHTMLStyleSheet.cpp
@@ -1,15 +1,15 @@
 /* -*- 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/.
  *
- * This Original Code has been modified by IBM Corporation. Modifications made by IBM 
+ * This Original Code has been modified by IBM Corporation. Modifications made by IBM
  * described herein are Copyright (c) International Business Machines Corporation, 2000.
  * Modifications to Mozilla code or documentation identified per MPL Section 3.3
  *
  * Date             Modified by     Description of modification
  * 04/20/2000       IBM Corp.      OS/2 VisualAge build.
  */
 
 /*
@@ -31,16 +31,17 @@
 #include "nsRuleProcessorData.h"
 #include "nsCSSRuleProcessor.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/Element.h"
 #include "nsHashKeys.h"
 #include "mozilla/OperatorNewExtensions.h"
 #include "mozilla/RestyleManager.h"
 #include "mozilla/RestyleManagerInlines.h"
+#include "mozilla/ServoStyleSet.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_ISUPPORTS(nsHTMLStyleSheet::HTMLColorRule, nsIStyleRule)
 
 /* virtual */ void
 nsHTMLStyleSheet::HTMLColorRule::MapRuleInfoInto(nsRuleData* aRuleData)
@@ -471,61 +472,80 @@ nsHTMLStyleSheet::SetOwningDocument(nsID
 
 void
 nsHTMLStyleSheet::Reset()
 {
   mLinkRule          = nullptr;
   mVisitedRule       = nullptr;
   mActiveRule        = nullptr;
 
+  mServoUnvisitedLinkDecl = nullptr;
+  mServoVisitedLinkDecl = nullptr;
+  mServoActiveLinkDecl = nullptr;
+
   mLangRuleTable.Clear();
   mMappedAttrTable.Clear();
   mMappedAttrsDirty = false;
 }
 
 nsresult
-nsHTMLStyleSheet::ImplLinkColorSetter(RefPtr<HTMLColorRule>& aRule, nscolor aColor)
+nsHTMLStyleSheet::ImplLinkColorSetter(
+    RefPtr<HTMLColorRule>& aRule,
+    RefPtr<RawServoDeclarationBlock>& aDecl,
+    nscolor aColor)
 {
-  if (aRule && aRule->mColor == aColor) {
+  if (!mDocument || !mDocument->GetShell()) {
     return NS_OK;
   }
 
-  aRule = new HTMLColorRule(aColor);
-  if (!aRule)
-    return NS_ERROR_OUT_OF_MEMORY;
+  RestyleManager* restyle =
+    mDocument->GetShell()->GetPresContext()->RestyleManager();
+
+  if (restyle->IsServo()) {
+    MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
+    aDecl = Servo_DeclarationBlock_CreateEmpty().Consume();
+    Servo_DeclarationBlock_SetColorValue(aDecl.get(), eCSSProperty_color,
+                                         aColor);
+  } else {
+    if (aRule && aRule->mColor == aColor) {
+      return NS_OK;
+    }
+
+    aRule = new HTMLColorRule(aColor);
+    if (!aRule) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+  }
 
   // Now make sure we restyle any links that might need it.  This
   // shouldn't happen often, so just rebuilding everything is ok.
-  if (mDocument && mDocument->GetShell()) {
-    Element* root = mDocument->GetRootElement();
-    if (root) {
-      mDocument->GetShell()->GetPresContext()->RestyleManager()->
-        PostRestyleEvent(root, eRestyle_Subtree, nsChangeHint(0));
-    }
+  Element* root = mDocument->GetRootElement();
+  if (root) {
+    restyle->PostRestyleEvent(root, eRestyle_Subtree, nsChangeHint(0));
   }
   return NS_OK;
 }
 
 nsresult
 nsHTMLStyleSheet::SetLinkColor(nscolor aColor)
 {
-  return ImplLinkColorSetter(mLinkRule, aColor);
+  return ImplLinkColorSetter(mLinkRule, mServoUnvisitedLinkDecl, aColor);
 }
 
 
 nsresult
 nsHTMLStyleSheet::SetActiveLinkColor(nscolor aColor)
 {
-  return ImplLinkColorSetter(mActiveRule, aColor);
+  return ImplLinkColorSetter(mActiveRule, mServoActiveLinkDecl, aColor);
 }
 
 nsresult
 nsHTMLStyleSheet::SetVisitedLinkColor(nscolor aColor)
 {
-  return ImplLinkColorSetter(mVisitedRule, aColor);
+  return ImplLinkColorSetter(mVisitedRule, mServoVisitedLinkDecl, aColor);
 }
 
 already_AddRefed<nsMappedAttributes>
 nsHTMLStyleSheet::UniqueMappedAttributes(nsMappedAttributes* aMapped)
 {
   mMappedAttrsDirty = true;
   auto entry = static_cast<MappedAttrTableEntry*>
                           (mMappedAttrTable.Add(aMapped, fallible));
--- a/layout/style/nsHTMLStyleSheet.h
+++ b/layout/style/nsHTMLStyleSheet.h
@@ -18,16 +18,17 @@
 #include "nsIStyleRuleProcessor.h"
 #include "PLDHashTable.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsString.h"
 
 class nsIDocument;
 class nsMappedAttributes;
+struct RawServoDeclarationBlock;
 
 class nsHTMLStyleSheet final : public nsIStyleRuleProcessor
 {
 public:
   explicit nsHTMLStyleSheet(nsIDocument* aDocument);
 
   void SetOwningDocument(nsIDocument* aDocument);
 
@@ -53,16 +54,26 @@ public:
     const MOZ_MUST_OVERRIDE override;
   size_t DOMSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
   void Reset();
   nsresult SetLinkColor(nscolor aColor);
   nsresult SetActiveLinkColor(nscolor aColor);
   nsresult SetVisitedLinkColor(nscolor aColor);
 
+  RefPtr<RawServoDeclarationBlock>& GetServoUnvisitedLinkDecl() {
+    return mServoUnvisitedLinkDecl;
+  }
+  RefPtr<RawServoDeclarationBlock>& GetServoVisitedLinkDecl() {
+    return mServoVisitedLinkDecl;
+  }
+  RefPtr<RawServoDeclarationBlock>& GetServoActiveLinkDecl() {
+    return mServoActiveLinkDecl;
+  }
+
   // Mapped Attribute management methods
   already_AddRefed<nsMappedAttributes>
     UniqueMappedAttributes(nsMappedAttributes* aMapped);
   void DropMappedAttributes(nsMappedAttributes* aMapped);
   // For each mapped presentation attribute in the cache, resolve
   // the attached ServoDeclarationBlock by running the mapping
   // and converting the ruledata to Servo specified values.
   void CalculateMappedServoDeclarations(nsPresContext* aPresContext);
@@ -95,17 +106,19 @@ private:
   #ifdef DEBUG
     virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
   #endif
 
     nscolor mColor;
   };
 
   // Implementation of SetLink/VisitedLink/ActiveLinkColor
-  nsresult ImplLinkColorSetter(RefPtr<HTMLColorRule>& aRule, nscolor aColor);
+  nsresult ImplLinkColorSetter(RefPtr<HTMLColorRule>& aRule,
+                               RefPtr<RawServoDeclarationBlock>& aDecl,
+                               nscolor aColor);
 
   class GenericTableRule;
   friend class GenericTableRule;
   class GenericTableRule : public nsIStyleRule {
   protected:
     virtual ~GenericTableRule() {}
   public:
     GenericTableRule() {}
@@ -172,16 +185,19 @@ public: // for mLangRuleTable structures
     nsString mLang;
   };
 
 private:
   nsIDocument*            mDocument;
   RefPtr<HTMLColorRule> mLinkRule;
   RefPtr<HTMLColorRule> mVisitedRule;
   RefPtr<HTMLColorRule> mActiveRule;
+  RefPtr<RawServoDeclarationBlock> mServoUnvisitedLinkDecl;
+  RefPtr<RawServoDeclarationBlock> mServoVisitedLinkDecl;
+  RefPtr<RawServoDeclarationBlock> mServoActiveLinkDecl;
   RefPtr<TableQuirkColorRule> mTableQuirkColorRule;
   RefPtr<TableTHRule>   mTableTHRule;
 
   PLDHashTable            mMappedAttrTable;
   // Whether or not the mapped attributes table
   // has been changed since the last call to
   // CalculateMappedServoDeclarations()
   bool                    mMappedAttrsDirty;