--- a/dom/base/ElementInlines.h
+++ b/dom/base/ElementInlines.h
@@ -61,18 +61,17 @@ Element::NoteDirtyDescendantsForServo()
Element* curr = this;
while (curr && !curr->HasDirtyDescendantsForServo()) {
curr->SetHasDirtyDescendantsForServo();
curr = curr->GetFlattenedTreeParentElementForStyle();
}
if (nsIPresShell* shell = OwnerDoc()->GetShell()) {
- shell->SetNeedStyleFlush();
- shell->ObserveStyleFlushes();
+ shell->EnsureStyleFlush();
}
MOZ_ASSERT(DirtyDescendantsBitIsPropagatedForServo());
}
#ifdef DEBUG
inline bool
Element::DirtyDescendantsBitIsPropagatedForServo()
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -6,16 +6,17 @@
#include "mozilla/ServoRestyleManager.h"
#include "mozilla/DocumentStyleRootIterator.h"
#include "mozilla/ServoBindings.h"
#include "mozilla/ServoStyleSet.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/ChildIterator.h"
+#include "mozilla/dom/ElementInlines.h"
#include "nsContentUtils.h"
#include "nsCSSFrameConstructor.h"
#include "nsPrintfCString.h"
#include "nsRefreshDriver.h"
#include "nsStyleChangeList.h"
using namespace mozilla::dom;
@@ -368,16 +369,52 @@ ServoRestyleManager::ProcessPostTraversa
for (nsIFrame* f = primaryFrame; f;
f = GetNextContinuationWithSameStyle(f, oldStyleContext)) {
f->SetStyleContext(&newContext);
}
}
}
+void
+ServoRestyleManager::ClearSnapshots()
+{
+ for (auto iter = mSnapshots.Iter(); !iter.Done(); iter.Next()) {
+ iter.Key()->UnsetFlags(ELEMENT_HAS_SNAPSHOT | ELEMENT_HANDLED_SNAPSHOT);
+ iter.Remove();
+ }
+}
+
+ServoElementSnapshot&
+ServoRestyleManager::SnapshotFor(Element* aElement)
+{
+ MOZ_ASSERT(!mInStyleRefresh);
+
+ // NOTE(emilio): We can handle snapshots from a one-off restyle of those that
+ // we do to restyle stuff for reconstruction, for example.
+ //
+ // It seems to be the case that we always flush in between that happens and
+ // the next attribute change, so we can assert that we haven't handled the
+ // snapshot here yet. If this assertion didn't hold, we'd need to unset that
+ // flag from here too.
+ //
+ // Can't wait to make ProcessPendingRestyles the only entry-point for styling,
+ // so this becomes much easier to reason about. Today is not that day though.
+ MOZ_ASSERT(aElement->HasServoData());
+ MOZ_ASSERT(!aElement->HasFlag(ELEMENT_HANDLED_SNAPSHOT));
+
+ ServoElementSnapshot* snapshot = mSnapshots.LookupOrAdd(aElement, aElement);
+ aElement->SetFlags(ELEMENT_HAS_SNAPSHOT);
+
+ nsIPresShell* presShell = mPresContext->PresShell();
+ presShell->EnsureStyleFlush();
+
+ return *snapshot;
+}
+
/* static */ nsIFrame*
ServoRestyleManager::FrameForPseudoElement(const nsIContent* aContent,
nsIAtom* aPseudoTagOrNull)
{
MOZ_ASSERT_IF(aPseudoTagOrNull, aContent->IsElement());
if (!aPseudoTagOrNull) {
return aContent->GetPrimaryFrame();
}
@@ -395,16 +432,17 @@ ServoRestyleManager::FrameForPseudoEleme
return nullptr;
}
void
ServoRestyleManager::ProcessPendingRestyles()
{
MOZ_ASSERT(PresContext()->Document(), "No document? Pshaw!");
MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(), "Missing a script blocker!");
+ MOZ_ASSERT(!mInStyleRefresh, "Reentrant call?");
if (MOZ_UNLIKELY(!PresContext()->PresShell()->DidInitialize())) {
// PresShell::FlushPendingNotifications doesn't early-return in the case
// where the PreShell hasn't yet been initialized (and therefore we haven't
// yet done the initial style traversal of the DOM tree). We should arguably
// fix up the callers and assert against this case, but we just detect and
// handle it for now.
return;
@@ -425,17 +463,20 @@ ServoRestyleManager::ProcessPendingResty
// Perform the Servo traversal, and the post-traversal if required. We do this
// in a loop because certain rare paths in the frame constructor (like
// uninstalling XBL bindings) can trigger additional style validations.
mInStyleRefresh = true;
if (mHaveNonAnimationRestyles) {
++mAnimationGeneration;
}
+
while (styleSet->StyleDocument()) {
+ ClearSnapshots();
+
// Recreate style contexts, and queue up change hints (which also handle
// lazy frame construction).
nsStyleChangeList currentChanges(StyleBackendType::Servo);
DocumentStyleRootIterator iter(doc);
while (Element* root = iter.GetNextStyleRoot()) {
ProcessPostTraversal(root, nullptr, styleSet, currentChanges);
}
@@ -455,16 +496,17 @@ ServoRestyleManager::ProcessPendingResty
}
newChanges.Clear();
}
mReentrantChanges = nullptr;
IncrementRestyleGeneration();
}
+ ClearSnapshots();
FlushOverflowChangedTracker();
mHaveNonAnimationRestyles = false;
mInStyleRefresh = false;
styleSet->AssertTreeIsClean();
// Note: We are in the scope of |animationsWithDestroyedFrame|, so
// |mAnimationsWithDestroyedFrame| is still valid.
@@ -505,24 +547,30 @@ ServoRestyleManager::ContentRemoved(nsIN
{
NS_WARNING("stylo: ServoRestyleManager::ContentRemoved not implemented");
}
void
ServoRestyleManager::ContentStateChanged(nsIContent* aContent,
EventStates aChangedBits)
{
+ MOZ_ASSERT(!mInStyleRefresh);
+
if (!aContent->IsElement()) {
return;
}
Element* aElement = aContent->AsElement();
nsChangeHint changeHint;
nsRestyleHint restyleHint;
+ if (!aElement->HasServoData()) {
+ return;
+ }
+
// NOTE: restyleHint here is effectively always 0, since that's what
// ServoStyleSet::HasStateDependentStyle returns. Servo computes on
// ProcessPendingRestyles using the ElementSnapshot, but in theory could
// compute it sequentially easily.
//
// Determine what's the best way to do it, and how much work do we save
// processing the restyle hint early (i.e., computing the style hint here
// sequentially, potentially saving the snapshot), vs lazily (snapshot
@@ -535,47 +583,53 @@ ServoRestyleManager::ContentStateChanged
// vs processing the restyle hint in-place, dirtying the nodes on
// PostRestyleEvent.
//
// If we definitely take the snapshot approach, we should take rid of
// HasStateDependentStyle, etc (though right now they're no-ops).
ContentStateChangedInternal(aElement, aChangedBits, &changeHint,
&restyleHint);
+ ServoElementSnapshot& snapshot = SnapshotFor(aElement);
EventStates previousState = aElement->StyleState() ^ aChangedBits;
- ServoElementSnapshot* snapshot = Servo_Element_GetSnapshot(aElement);
- if (snapshot) {
- snapshot->AddState(previousState);
- PostRestyleEvent(aElement, restyleHint, changeHint);
+ snapshot.AddState(previousState);
+
+ if (Element* parent = aElement->GetFlattenedTreeParentElementForStyle()) {
+ parent->NoteDirtyDescendantsForServo();
}
+ PostRestyleEvent(aElement, restyleHint, changeHint);
}
void
ServoRestyleManager::AttributeWillChange(Element* aElement,
int32_t aNameSpaceID,
nsIAtom* aAttribute, int32_t aModType,
const nsAttrValue* aNewValue)
{
- ServoElementSnapshot* snapshot = Servo_Element_GetSnapshot(aElement);
- if (snapshot) {
- snapshot->AddAttrs(aElement);
+ MOZ_ASSERT(!mInStyleRefresh);
+
+ if (!aElement->HasServoData()) {
+ return;
+ }
+
+ ServoElementSnapshot& snapshot = SnapshotFor(aElement);
+ snapshot.AddAttrs(aElement);
+
+ if (Element* parent = aElement->GetFlattenedTreeParentElementForStyle()) {
+ parent->NoteDirtyDescendantsForServo();
}
}
void
ServoRestyleManager::AttributeChanged(Element* aElement, int32_t aNameSpaceID,
nsIAtom* aAttribute, int32_t aModType,
const nsAttrValue* aOldValue)
{
MOZ_ASSERT(!mInStyleRefresh);
-
-#ifdef DEBUG
- ServoElementSnapshot* snapshot = Servo_Element_GetSnapshot(aElement);
- MOZ_ASSERT_IF(snapshot, snapshot->HasAttrs());
-#endif
+ MOZ_ASSERT_IF(mSnapshots.Get(aElement), mSnapshots.Get(aElement)->HasAttrs());
nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
if (primaryFrame) {
primaryFrame->AttributeChanged(aNameSpaceID, aAttribute, aModType);
}
if (aAttribute == nsGkAtoms::style) {
PostRestyleEvent(aElement, eRestyle_StyleAttribute, nsChangeHint(0));
--- a/layout/base/ServoRestyleManager.h
+++ b/layout/base/ServoRestyleManager.h
@@ -2,25 +2,21 @@
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_ServoRestyleManager_h
#define mozilla_ServoRestyleManager_h
-#include "mozilla/DocumentStyleRootIterator.h"
#include "mozilla/EventStates.h"
#include "mozilla/RestyleManager.h"
-#include "mozilla/ServoBindings.h"
#include "mozilla/ServoElementSnapshot.h"
+#include "mozilla/ServoElementSnapshotTable.h"
#include "nsChangeHint.h"
-#include "nsHashKeys.h"
-#include "nsINode.h"
-#include "nsISupportsImpl.h"
#include "nsPresContext.h"
namespace mozilla {
namespace dom {
class Element;
} // namespace dom
} // namespace mozilla
class nsAttrValue;
@@ -32,17 +28,19 @@ class nsStyleChangeList;
namespace mozilla {
/**
* Restyle manager for a Servo-backed style system.
*/
class ServoRestyleManager : public RestyleManager
{
friend class ServoStyleSet;
+
public:
+ typedef ServoElementSnapshotTable SnapshotTable;
typedef RestyleManager base_type;
explicit ServoRestyleManager(nsPresContext* aPresContext);
void PostRestyleEvent(dom::Element* aElement,
nsRestyleHint aRestyleHint,
nsChangeHint aMinChangeHint);
void PostRestyleEventForLazyConstruction();
@@ -131,16 +129,20 @@ private:
inline ServoStyleSet* StyleSet() const
{
MOZ_ASSERT(PresContext()->StyleSet()->IsServo(),
"ServoRestyleManager should only be used with a Servo-flavored "
"style backend");
return PresContext()->StyleSet()->AsServo();
}
+ const SnapshotTable& Snapshots() const { return mSnapshots; }
+ void ClearSnapshots();
+ ServoElementSnapshot& SnapshotFor(mozilla::dom::Element* aElement);
+
// We use a separate data structure from nsStyleChangeList because we need a
// frame to create nsStyleChangeList entries, and the primary frame may not be
// attached yet.
struct ReentrantChange {
nsCOMPtr<nsIContent> mContent;
nsChangeHint mHint;
};
typedef AutoTArray<ReentrantChange, 10> ReentrantChangeList;
@@ -150,13 +152,17 @@ private:
ReentrantChangeList* mReentrantChanges;
// We use this flag to track if the current restyle contains any non-animation
// update, which triggers a normal restyle, and so there might be any new
// transition created later. Therefore, if this flag is true, we need to
// increase mAnimationGeneration before creating new transitions, so their
// creation sequence will be correct.
bool mHaveNonAnimationRestyles = false;
+
+ // A hashtable with the elements that have changed state or attributes, in
+ // order to calculate restyle hints during the traversal.
+ SnapshotTable mSnapshots;
};
} // namespace mozilla
#endif // mozilla_ServoRestyleManager_h
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -625,16 +625,17 @@ public:
return mNeedStyleFlush ||
(mNeedLayoutFlush &&
aType >= mozilla::FlushType::InterruptibleLayout) ||
aType >= mozilla::FlushType::Display ||
mNeedThrottledAnimationFlush ||
mInFlush;
}
+ inline void EnsureStyleFlush();
inline void SetNeedStyleFlush();
inline void SetNeedLayoutFlush();
inline void SetNeedThrottledAnimationFlush();
bool ObservingStyleFlushes() const { return mObservingStyleFlushes; }
bool ObservingLayoutFlushes() const { return mObservingLayoutFlushes; }
void ObserveStyleFlushes()
--- a/layout/base/nsIPresShellInlines.h
+++ b/layout/base/nsIPresShellInlines.h
@@ -21,16 +21,23 @@ nsIPresShell::SetNeedStyleFlush()
if (nsIDocument* doc = mDocument->GetDisplayDocument()) {
if (nsIPresShell* shell = doc->GetShell()) {
shell->mNeedStyleFlush = true;
}
}
}
void
+nsIPresShell::EnsureStyleFlush()
+{
+ SetNeedStyleFlush();
+ ObserveStyleFlushes();
+}
+
+void
nsIPresShell::SetNeedThrottledAnimationFlush()
{
mNeedThrottledAnimationFlush = true;
if (nsIDocument* doc = mDocument->GetDisplayDocument()) {
if (nsIPresShell* shell = doc->GetShell()) {
shell->mNeedThrottledAnimationFlush = true;
}
}
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -359,21 +359,16 @@ SERVO_BINDING_FUNC(Servo_ComputedValues_
mozilla::InheritTarget target)
// Initialize Servo components. Should be called exactly once at startup.
SERVO_BINDING_FUNC(Servo_Initialize, void,
RawGeckoURLExtraData* dummy_url_data)
// Shut down Servo components. Should be called exactly once at shutdown.
SERVO_BINDING_FUNC(Servo_Shutdown, void)
-// Gets the snapshot for the element. This will return null if the element
-// has never been styled, since snapshotting in that case is wasted work.
-SERVO_BINDING_FUNC(Servo_Element_GetSnapshot, ServoElementSnapshot*,
- RawGeckoElementBorrowed element)
-
// Gets the source style rules for the element. This returns the result via
// rules, which would include a list of unowned pointers to RawServoStyleRule.
SERVO_BINDING_FUNC(Servo_Element_GetStyleRuleList, void,
RawGeckoElementBorrowed element,
RawGeckoServoStyleRuleListBorrowedMut rules)
// Restyle and change hints.
SERVO_BINDING_FUNC(Servo_NoteExplicitHints, void, RawGeckoElementBorrowed element,
@@ -399,34 +394,40 @@ SERVO_BINDING_FUNC(Servo_HasAuthorSpecif
// restyles first. The Element and its ancestors may be unstyled, have pending
// restyles, or be in a display:none subtree. Styles are cached when possible,
// though caching is not possible within display:none subtrees, and the styles
// may be invalidated by already-scheduled restyles.
//
// The tree must be in a consistent state such that a normal traversal could be
// performed, and this function maintains that invariant.
SERVO_BINDING_FUNC(Servo_ResolveStyleLazily, ServoComputedValuesStrong,
- RawGeckoElementBorrowed element, nsIAtom* pseudo_tag,
+ RawGeckoElementBorrowed element,
+ nsIAtom* pseudo_tag,
+ const mozilla::ServoElementSnapshotTable* snapshots,
RawServoStyleSetBorrowed set)
// Use ServoStyleSet::PrepareAndTraverseSubtree instead of calling this
// directly
-SERVO_BINDING_FUNC(Servo_TraverseSubtree, bool,
- RawGeckoElementBorrowed root, RawServoStyleSetBorrowed set,
+SERVO_BINDING_FUNC(Servo_TraverseSubtree,
+ bool,
+ RawGeckoElementBorrowed root,
+ RawServoStyleSetBorrowed set,
+ const mozilla::ServoElementSnapshotTable* snapshots,
mozilla::TraversalRootBehavior root_behavior,
mozilla::TraversalRestyleBehavior restyle_behavior)
// Assert that the tree has no pending or unconsumed restyles.
SERVO_BINDING_FUNC(Servo_AssertTreeIsClean, void, RawGeckoElementBorrowed root)
// Returns computed values for the given element without any animations rules.
SERVO_BINDING_FUNC(Servo_StyleSet_GetBaseComputedValuesForElement,
ServoComputedValuesStrong,
RawServoStyleSetBorrowed set,
RawGeckoElementBorrowed element,
+ const mozilla::ServoElementSnapshotTable* snapshots,
nsIAtom* pseudo_tag)
// Style-struct management.
#define STYLE_STRUCT(name, checkdata_cb) \
struct nsStyle##name; \
SERVO_BINDING_FUNC(Servo_GetStyle##name, const nsStyle##name*, \
ServoComputedValuesBorrowedOrNull computed_values)
#include "nsStyleStructList.h"
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -278,18 +278,17 @@ Gecko_UnsetNodeFlags(RawGeckoNodeBorrowe
}
void
Gecko_SetOwnerDocumentNeedsStyleFlush(RawGeckoElementBorrowed aElement)
{
MOZ_ASSERT(NS_IsMainThread());
if (nsIPresShell* shell = aElement->OwnerDoc()->GetShell()) {
- shell->SetNeedStyleFlush();
- shell->ObserveStyleFlushes();
+ shell->EnsureStyleFlush();
}
}
nsStyleContext*
Gecko_GetStyleContext(RawGeckoElementBorrowed aElement,
nsIAtom* aPseudoTagOrNull)
{
nsIFrame* relevantFrame =
@@ -340,37 +339,24 @@ Gecko_CalcStyleDifference(nsStyleContext
}
nsChangeHint
Gecko_HintsHandledForDescendants(nsChangeHint aHint)
{
return aHint & ~NS_HintsNotHandledForDescendantsIn(aHint);
}
-ServoElementSnapshotOwned
-Gecko_CreateElementSnapshot(RawGeckoElementBorrowed aElement)
-{
- MOZ_ASSERT(NS_IsMainThread());
- return new ServoElementSnapshot(aElement);
-}
-
-void
-Gecko_DropElementSnapshot(ServoElementSnapshotOwned aSnapshot)
+const ServoElementSnapshot*
+Gecko_GetElementSnapshot(const ServoElementSnapshotTable* aTable,
+ const Element* aElement)
{
- // Proxy deletes have a lot of overhead, so Servo tries hard to only drop
- // snapshots on the main thread. However, there are certain cases where
- // it's unavoidable (i.e. synchronously dropping the style data for the
- // descendants of a new display:none root).
- if (MOZ_UNLIKELY(!NS_IsMainThread())) {
- nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction([=]() { delete aSnapshot; });
- SystemGroup::Dispatch("Gecko_DropElementSnapshot", TaskCategory::Other,
- task.forget());
- } else {
- delete aSnapshot;
- }
+ MOZ_ASSERT(aTable);
+ MOZ_ASSERT(aElement);
+
+ return aTable->Get(const_cast<Element*>(aElement));
}
RawServoDeclarationBlockStrongBorrowedOrNull
Gecko_GetStyleAttrDeclarationBlock(RawGeckoElementBorrowed aElement)
{
DeclarationBlock* decl = aElement->GetInlineStyleDeclaration();
if (!decl) {
return nullptr;
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -28,28 +28,29 @@
* Functions beginning with Servo_ are implemented in Servo and invoked from Gecko.
*/
class nsIAtom;
class nsIPrincipal;
class nsIURI;
struct nsFont;
namespace mozilla {
- class ServoStyleSheet;
class FontFamilyList;
enum FontFamilyType : uint32_t;
struct Keyframe;
enum Side;
struct StyleTransition;
namespace css {
struct URLValue;
struct ImageValue;
};
enum class UpdateAnimationsTasks : uint8_t;
struct LangGroupFontPrefs;
+ class ServoStyleSheet;
+ class ServoElementSnapshotTable;
}
using mozilla::FontFamilyList;
using mozilla::FontFamilyType;
using mozilla::ServoElementSnapshot;
class nsCSSFontFaceRule;
struct nsMediaFeature;
struct nsStyleList;
struct nsStyleImage;
@@ -314,18 +315,21 @@ void Gecko_SetOwnerDocumentNeedsStyleFlu
// Not if we do them in Gecko...
nsStyleContext* Gecko_GetStyleContext(RawGeckoElementBorrowed element,
nsIAtom* aPseudoTagOrNull);
nsIAtom* Gecko_GetImplementedPseudo(RawGeckoElementBorrowed element);
nsChangeHint Gecko_CalcStyleDifference(nsStyleContext* oldstyle,
ServoComputedValuesBorrowed newstyle);
nsChangeHint Gecko_HintsHandledForDescendants(nsChangeHint aHint);
-// Element snapshot.
-ServoElementSnapshotOwned Gecko_CreateElementSnapshot(RawGeckoElementBorrowed element);
+// Get an element snapshot for a given element from the table.
+const ServoElementSnapshot*
+Gecko_GetElementSnapshot(const mozilla::ServoElementSnapshotTable* table,
+ RawGeckoElementBorrowed element);
+
void Gecko_DropElementSnapshot(ServoElementSnapshotOwned snapshot);
// `array` must be an nsTArray
// If changing this signature, please update the
// friend function declaration in nsTArray.h
void Gecko_EnsureTArrayCapacity(void* array, size_t capacity, size_t elem_size);
// Same here, `array` must be an nsTArray<T>, for some T.
new file mode 100644
--- /dev/null
+++ b/layout/style/ServoElementSnapshotTable.h
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_ServoElementSnapshotTable_h
+#define mozilla_ServoElementSnapshotTable_h
+
+#include "mozilla/dom/Element.h"
+#include "nsClassHashtable.h"
+#include "nsHashKeys.h"
+#include "ServoElementSnapshot.h"
+
+namespace mozilla {
+
+class ServoElementSnapshotTable
+ : public nsClassHashtable<nsRefPtrHashKey<dom::Element>, ServoElementSnapshot>
+{
+};
+
+} // namespace mozilla
+
+#endif
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -8,16 +8,17 @@
#include "gfxPlatformFontList.h"
#include "mozilla/DocumentStyleRootIterator.h"
#include "mozilla/ServoRestyleManager.h"
#include "mozilla/dom/AnonymousContent.h"
#include "mozilla/dom/ChildIterator.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ElementInlines.h"
+#include "mozilla/RestyleManagerInlines.h"
#include "mozilla/ServoComputedValuesWithParent.h"
#include "nsCSSAnonBoxes.h"
#include "nsCSSPseudoElements.h"
#include "nsCSSRuleProcessor.h"
#include "nsDeviceContext.h"
#include "nsHTMLStyleSheet.h"
#include "nsIDocumentInlines.h"
#include "nsPrintfCString.h"
@@ -232,16 +233,22 @@ ServoStyleSet::GetContext(already_AddRef
if (doc && doc->GetBodyElement() == aElementForAnimation) {
// Update the prescontext's body color
mPresContext->SetBodyTextColor(result->StyleColor()->mColor);
}
}
return result.forget();
}
+const ServoElementSnapshotTable&
+ServoStyleSet::Snapshots()
+{
+ return mPresContext->RestyleManager()->AsServo()->Snapshots();
+}
+
void
ServoStyleSet::ResolveMappedAttrDeclarationBlocks()
{
if (nsHTMLStyleSheet* sheet = mPresContext->Document()->GetAttributeStyleSheet()) {
sheet->CalculateMappedServoDeclarations(mPresContext);
}
mPresContext->Document()->ResolveScheduledSVGPresAttrs();
@@ -280,49 +287,51 @@ ServoStyleSet::PreTraverse(Element* aRoo
mPresContext->EffectCompositor()->PreTraverse();
if (smilController) {
smilController->PreTraverse();
}
}
}
bool
-ServoStyleSet::PrepareAndTraverseSubtree(RawGeckoElementBorrowed aRoot,
- TraversalRootBehavior aRootBehavior,
- TraversalRestyleBehavior
- aRestyleBehavior)
+ServoStyleSet::PrepareAndTraverseSubtree(
+ RawGeckoElementBorrowed aRoot,
+ TraversalRootBehavior aRootBehavior,
+ TraversalRestyleBehavior aRestyleBehavior)
{
// Get the Document's root element to ensure that the cache is valid before
// calling into the (potentially-parallel) Servo traversal, where a cache hit
// is necessary to avoid a data race when updating the cache.
mozilla::Unused << aRoot->OwnerDoc()->GetRootElement();
AutoSetInServoTraversal guard(this);
+ const SnapshotTable& snapshots = Snapshots();
+
bool isInitial = !aRoot->HasServoData();
bool forReconstruct =
aRestyleBehavior == TraversalRestyleBehavior::ForReconstruct;
- bool postTraversalRequired =
- Servo_TraverseSubtree(aRoot, mRawSet.get(), aRootBehavior, aRestyleBehavior);
+ bool postTraversalRequired = Servo_TraverseSubtree(
+ aRoot, mRawSet.get(), &snapshots, aRootBehavior, aRestyleBehavior);
MOZ_ASSERT_IF(isInitial || forReconstruct, !postTraversalRequired);
auto root = const_cast<Element*>(aRoot);
// If there are still animation restyles needed, trigger a second traversal to
// update CSS animations or transitions' styles.
//
// We don't need to do this for SMIL since SMIL only updates its animation
// values once at the begin of a tick. As a result, even if the previous
// traversal caused, for example, the font-size to change, the SMIL style
// won't be updated until the next tick anyway.
EffectCompositor* compositor = mPresContext->EffectCompositor();
if (forReconstruct ? compositor->PreTraverseInSubtree(root)
: compositor->PreTraverse()) {
- if (Servo_TraverseSubtree(aRoot, mRawSet.get(),
- aRootBehavior, aRestyleBehavior)) {
+ if (Servo_TraverseSubtree(
+ aRoot, mRawSet.get(), &snapshots, aRootBehavior, aRestyleBehavior)) {
MOZ_ASSERT(!forReconstruct);
if (isInitial) {
// We're doing initial styling, and the additional animation
// traversal changed the styles that were set by the first traversal.
// This would normally require a post-traversal to update the style
// contexts, and the DOM now has dirty descendant bits and RestyleData
// in expectation of that post-traversal. But since this is actually
// the initial styling, there are no style contexts to update and no
@@ -943,16 +952,17 @@ ServoStyleSet::GetComputedKeyframeValues
}
already_AddRefed<ServoComputedValues>
ServoStyleSet::GetBaseComputedValuesForElement(Element* aElement,
nsIAtom* aPseudoTag)
{
return Servo_StyleSet_GetBaseComputedValuesForElement(mRawSet.get(),
aElement,
+ &Snapshots(),
aPseudoTag).Consume();
}
already_AddRefed<RawServoAnimationValue>
ServoStyleSet::ComputeAnimationValue(
RawServoDeclarationBlock* aDeclarations,
const ServoComputedValuesWithParent& aComputedValues)
{
@@ -1014,22 +1024,24 @@ ServoStyleSet::ResolveStyleLazily(Elemen
elementForStyleResolution = pseudo;
pseudoTagForStyleResolution = nullptr;
}
}
RefPtr<ServoComputedValues> computedValues =
Servo_ResolveStyleLazily(elementForStyleResolution,
pseudoTagForStyleResolution,
+ &Snapshots(),
mRawSet.get()).Consume();
if (mPresContext->EffectCompositor()->PreTraverse(aElement, aPseudoTag)) {
computedValues =
Servo_ResolveStyleLazily(elementForStyleResolution,
pseudoTagForStyleResolution,
+ &Snapshots(),
mRawSet.get()).Consume();
}
return computedValues.forget();
}
bool
ServoStyleSet::AppendFontFaceRules(nsTArray<nsFontFaceRuleContainer>& aArray)
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -27,16 +27,17 @@ namespace mozilla {
namespace dom {
class Element;
} // namespace dom
class CSSStyleSheet;
class ServoRestyleManager;
class ServoStyleSheet;
struct Keyframe;
struct ServoComputedValuesWithParent;
+class ServoElementSnapshotTable;
} // namespace mozilla
class nsIContent;
class nsIDocument;
class nsStyleContext;
class nsPresContext;
struct nsTimingFunction;
struct RawServoRuleNode;
struct TreeMatchContext;
@@ -45,16 +46,18 @@ namespace mozilla {
/**
* The set of style sheets that apply to a document, backed by a Servo
* Stylist. A ServoStyleSet contains ServoStyleSheets.
*/
class ServoStyleSet
{
friend class ServoRestyleManager;
+ typedef ServoElementSnapshotTable SnapshotTable;
+
public:
class AutoAllowStaleStyles
{
public:
explicit AutoAllowStaleStyles(ServoStyleSet* aStyleSet)
: mStyleSet(aStyleSet)
{
if (mStyleSet) {
@@ -230,19 +233,22 @@ public:
nsRestyleHint HasStateDependentStyle(dom::Element* aElement,
EventStates aStateMask);
nsRestyleHint HasStateDependentStyle(
dom::Element* aElement, mozilla::CSSPseudoElementType aPseudoType,
dom::Element* aPseudoElement, EventStates aStateMask);
/**
* Performs a Servo traversal to compute style for all dirty nodes in the
- * document. This will traverse all of the document's style roots (that
- * is, its document element, and the roots of the document-level native
- * anonymous content). Returns true if a post-traversal is required.
+ * document.
+ *
+ * This will traverse all of the document's style roots (that is, its document
+ * element, and the roots of the document-level native anonymous content).
+ *
+ * Returns true if a post-traversal is required.
*/
bool StyleDocument();
/**
* Eagerly styles a subtree of unstyled nodes that was just appended to the
* tree. This is used in situations where we need the style immediately and
* cannot wait for a future batch restyle.
*/
@@ -366,34 +372,44 @@ private:
already_AddRefed<nsStyleContext> GetContext(nsIContent* aContent,
nsStyleContext* aParentContext,
nsIAtom* aPseudoTag,
CSSPseudoElementType aPseudoType,
LazyComputeBehavior aMayCompute);
/**
+ * Gets the pending snapshots to handle from the restyle manager.
+ */
+ const SnapshotTable& Snapshots();
+
+ /**
* Resolve all ServoDeclarationBlocks attached to mapped
* presentation attributes cached on the document.
+ *
* Call this before jumping into Servo's style system.
*/
void ResolveMappedAttrDeclarationBlocks();
/**
* Perform all lazy operations required before traversing
- * a subtree. Returns whether a post-traversal is required.
+ * a subtree.
+ *
+ * Returns whether a post-traversal is required.
*/
bool PrepareAndTraverseSubtree(RawGeckoElementBorrowed aRoot,
TraversalRootBehavior aRootBehavior,
TraversalRestyleBehavior aRestyleBehavior);
/**
- * Clear our cached mNonInheritingStyleContexts. We do this when we want to
- * make sure those style contexts won't live too long (e.g. when rebuilding
- * all style data or when shutting down the style set).
+ * Clear our cached mNonInheritingStyleContexts.
+ *
+ * We do this when we want to make sure those style contexts won't live too
+ * long (e.g. when rebuilding all style data or when shutting down the style
+ * set).
*/
void ClearNonInheritingStyleContexts();
/**
* Perform processes that we should do before traversing.
*
* When aRoot is null, the entire document is pre-traversed. Otherwise,
* only the subtree rooted at aRoot is pre-traversed.
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -99,16 +99,17 @@ EXPORTS.mozilla += [
'RuleProcessorCache.h',
'ServoArcTypeList.h',
'ServoBindingList.h',
'ServoBindings.h',
'ServoBindingTypes.h',
'ServoCSSRuleList.h',
'ServoDeclarationBlock.h',
'ServoElementSnapshot.h',
+ 'ServoElementSnapshotTable.h',
'ServoMediaList.h',
'ServoMediaRule.h',
'ServoNamespaceRule.h',
'ServoPageRule.h',
'ServoPropPrefList.h',
'ServoSpecifiedValues.h',
'ServoStyleRule.h',
'ServoStyleSet.h',
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -17,16 +17,17 @@
#include "mozilla/TimeStamp.h"
#include "nsRefreshDriver.h"
#include "nsRuleProcessorData.h"
#include "nsRuleWalker.h"
#include "nsCSSPropertyIDSet.h"
#include "mozilla/EffectCompositor.h"
#include "mozilla/EffectSet.h"
#include "mozilla/EventDispatcher.h"
+#include "mozilla/ServoBindings.h"
#include "mozilla/ServoComputedValuesWithParent.h"
#include "mozilla/StyleAnimationValue.h"
#include "mozilla/dom/DocumentTimeline.h"
#include "mozilla/dom/Element.h"
#include "nsIFrame.h"
#include "Layers.h"
#include "FrameLayerBuilder.h"
#include "nsCSSProps.h"