Bug 1368290: Cache text styles in ServoStyleContext. r?bholley
The rest of them is trivial with this infrastructure, will do tomorrow morning.
Someone has to sleep for today.
MozReview-Commit-ID: 44YEUs8zANw
--- a/layout/style/ServoStyleContext.cpp
+++ b/layout/style/ServoStyleContext.cpp
@@ -1,15 +1,16 @@
/* -*- 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/. */
#include "mozilla/ServoStyleContext.h"
+#include "nsCSSAnonBoxes.h"
#include "nsStyleConsts.h"
#include "nsStyleStruct.h"
#include "nsPresContext.h"
#include "nsCSSRuleProcessor.h"
#include "mozilla/dom/HTMLBodyElement.h"
#include "mozilla/ServoBindings.h"
@@ -27,9 +28,26 @@ ServoStyleContext::ServoStyleContext(
{
AddStyleBit(Servo_ComputedValues_GetStyleBits(this));
FinishConstruction();
// No need to call ApplyStyleFixups here, since fixups are handled by Servo when
// producing the ServoComputedData.
}
+ServoStyleContext*
+ServoStyleContext::GetCachedInheritingAnonBoxStyle(nsIAtom* aAnonBox) const
+{
+ MOZ_ASSERT(nsCSSAnonBoxes::IsInheritingAnonBox(aAnonBox));
+ if (IsInheritingAnonBox()) {
+ return nullptr;
+ }
+
+ auto* current = mNextInheritingAnonBoxStyle.get();
+
+ while (current && current->GetPseudo() != aAnonBox) {
+ current = current->mNextInheritingAnonBoxStyle.get();
+ }
+
+ return current;
+}
+
} // namespace mozilla
--- a/layout/style/ServoStyleContext.h
+++ b/layout/style/ServoStyleContext.h
@@ -30,22 +30,45 @@ public:
void AddRef() { Servo_StyleContext_AddRef(this); }
void Release() { Servo_StyleContext_Release(this); }
ServoStyleContext* GetStyleIfVisited() const
{
return ComputedData()->visited_style.mPtr;
}
+ ServoStyleContext* GetCachedInheritingAnonBoxStyle(nsIAtom* aAnonBox) const;
+
+ void SetCachedInheritedAnonBoxStyle(nsIAtom* aAnonBox,
+ ServoStyleContext& aStyle)
+ {
+ MOZ_ASSERT(!GetCachedInheritingAnonBoxStyle(aAnonBox));
+ MOZ_ASSERT(!aStyle.mNextInheritingAnonBoxStyle);
+
+ if (IsInheritingAnonBox()) {
+ return;
+ }
+
+ mNextInheritingAnonBoxStyle.swap(aStyle.mNextInheritingAnonBoxStyle);
+ mNextInheritingAnonBoxStyle = &aStyle;
+ }
+
/**
* Makes this context match |aOther| in terms of which style structs have
* been resolved.
*/
inline void ResolveSameStructsAs(const ServoStyleContext* aOther);
private:
nsPresContext* mPresContext;
ServoComputedData mSource;
+
+ // A linked-list cache of inheriting anon boxes inheriting from this style _if
+ // the style isn't an inheriting anon-box_.
+ //
+ // Otherwise it represents the next entry in the cache of the parent style
+ // context.
+ RefPtr<ServoStyleContext> mNextInheritingAnonBoxStyle;
};
} // namespace mozilla
#endif // mozilla_ServoStyleContext_h
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -351,26 +351,33 @@ ServoStyleSet::PrepareAndTraverseSubtree
already_AddRefed<ServoStyleContext>
ServoStyleSet::ResolveStyleForText(nsIContent* aTextNode,
ServoStyleContext* aParentContext)
{
MOZ_ASSERT(aTextNode && aTextNode->IsNodeOfType(nsINode::eTEXT));
MOZ_ASSERT(aTextNode->GetParent());
MOZ_ASSERT(aParentContext);
- // Gecko expects text node style contexts to be like elements that match no
- // rules: inherit the inherit structs, reset the reset structs. This is cheap
- // enough to do on the main thread, which means that the parallel style system
- // can avoid worrying about text nodes.
- RefPtr<ServoStyleContext> computedValues =
- Servo_ComputedValues_Inherit(mRawSet.get(),
- nsCSSAnonBoxes::mozText,
- aParentContext,
- InheritTarget::Text).Consume();
- return computedValues.forget();
+ RefPtr<ServoStyleContext> style =
+ aParentContext->GetCachedInheritingAnonBoxStyle(nsCSSAnonBoxes::mozText);
+
+ if (!style) {
+ // Gecko expects text node style contexts to be like elements that match no
+ // rules: inherit the inherit structs, reset the reset structs. This is
+ // cheap enough to do on the main thread, which means that the parallel
+ // style system can avoid worrying about text nodes.
+ style =
+ Servo_ComputedValues_Inherit(mRawSet.get(),
+ nsCSSAnonBoxes::mozText,
+ aParentContext,
+ InheritTarget::Text).Consume();
+ aParentContext->SetCachedInheritedAnonBoxStyle(nsCSSAnonBoxes::mozText, *style);
+ }
+
+ return style.forget();
}
already_AddRefed<ServoStyleContext>
ServoStyleSet::ResolveStyleForFirstLetterContinuation(ServoStyleContext* aParentContext)
{
RefPtr<ServoStyleContext> computedValues =
Servo_ComputedValues_Inherit(mRawSet.get(),
nsCSSAnonBoxes::firstLetterContinuation,
--- a/layout/style/nsCSSAnonBoxes.h
+++ b/layout/style/nsCSSAnonBoxes.h
@@ -38,16 +38,29 @@ public:
#define CSS_ANON_BOX(_name, _value) /* nothing */
#define CSS_NON_INHERITING_ANON_BOX(_name, _value) _name,
#include "nsCSSAnonBoxList.h"
#undef CSS_NON_INHERITING_ANON_BOX
#undef CSS_ANON_BOX
_Count
};
+#ifdef DEBUG
+ static bool IsInheritingAnonBox(nsIAtom* aPseudo)
+ {
+ return
+#define CSS_ANON_BOX(_name, _value) _name == aPseudo ||
+#define CSS_NON_INHERITING_ANON_BOX(_name, _value) /* nothing */
+#include "nsCSSAnonBoxList.h"
+#undef CSS_NON_INHERITING_ANON_BOX
+#undef CSS_ANON_BOX
+ false;
+ }
+#endif
+
// Be careful using this: if we have a lot of non-inheriting anon box types it
// might not be very fast. We may want to think of ways to handle that
// (e.g. by moving to an enum instead of an atom, like we did for
// pseudo-elements, or by adding a new value of the pseudo-element enum for
// non-inheriting anon boxes or something).
static bool IsNonInheritingAnonBox(nsIAtom* aPseudo)
{
return
--- a/layout/style/nsStyleContext.h
+++ b/layout/style/nsStyleContext.h
@@ -107,16 +107,20 @@ public:
}
nsIAtom* GetPseudo() const { return mPseudoTag; }
mozilla::CSSPseudoElementType GetPseudoType() const {
return static_cast<mozilla::CSSPseudoElementType>(
mBits >> NS_STYLE_CONTEXT_TYPE_SHIFT);
}
+ bool IsInheritingAnonBox() const {
+ return GetPseudoType() == mozilla::CSSPseudoElementType::InheritingAnonBox;
+ }
+
bool IsAnonBox() const {
return
GetPseudoType() == mozilla::CSSPseudoElementType::InheritingAnonBox ||
GetPseudoType() == mozilla::CSSPseudoElementType::NonInheritingAnonBox;
}
bool IsPseudoElement() const { return mPseudoTag && !IsAnonBox(); }