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
--- 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;