/* -*- 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_ServoStyleContext_h #define mozilla_ServoStyleContext_h #include "nsIMemoryReporter.h" #include "nsStyleContext.h" #include "nsWindowSizes.h" #include namespace mozilla { namespace dom { class Element; } // namespace dom MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoComputedValuesMallocEnclosingSizeOf) class ServoStyleContext final : public nsStyleContext { public: ServoStyleContext(nsPresContext* aPresContext, nsAtom* aPseudoTag, CSSPseudoElementType aPseudoType, ServoComputedDataForgotten aComputedValues); nsPresContext* PresContext() const { return mPresContext; } const ServoComputedData* ComputedData() const { return &mSource; } void AddRef() { Servo_StyleContext_AddRef(this); } void Release() { Servo_StyleContext_Release(this); } ServoStyleContext* GetStyleIfVisited() const { return ComputedData()->visited_style.mPtr; } bool IsLazilyCascadedPseudoElement() const { return IsPseudoElement() && !nsCSSPseudoElements::IsEagerlyCascadedInServo(GetPseudoType()); } ServoStyleContext* GetCachedInheritingAnonBoxStyle(nsAtom* aAnonBox) const; void SetCachedInheritedAnonBoxStyle(nsAtom* aAnonBox, ServoStyleContext* aStyle) { MOZ_ASSERT(!GetCachedInheritingAnonBoxStyle(aAnonBox)); MOZ_ASSERT(!aStyle->mNextInheritingAnonBoxStyle); // NOTE(emilio): Since we use it to cache inheriting anon boxes in a linked // list, we can't use that cache if the style we're inheriting from is an // inheriting anon box itself, since otherwise our parent would mistakenly // think that the style we're caching inherits from it. // // See the documentation of mNextInheritingAnonBoxStyle. if (IsInheritingAnonBox()) { return; } mNextInheritingAnonBoxStyle.swap(aStyle->mNextInheritingAnonBoxStyle); mNextInheritingAnonBoxStyle = aStyle; } ServoStyleContext* GetCachedLazyPseudoStyle(CSSPseudoElementType aPseudo) const; void SetCachedLazyPseudoStyle(ServoStyleContext* aStyle) { MOZ_ASSERT(aStyle->GetPseudo() && !aStyle->IsAnonBox()); MOZ_ASSERT(!GetCachedLazyPseudoStyle(aStyle->GetPseudoType())); MOZ_ASSERT(!aStyle->mNextLazyPseudoStyle); MOZ_ASSERT(!IsLazilyCascadedPseudoElement(), "lazy pseudos can't inherit lazy pseudos"); MOZ_ASSERT(aStyle->IsLazilyCascadedPseudoElement()); // Since we're caching lazy pseudo styles on the ComputedValues of the // originating element, we can assume that we either have the same // originating element, or that they were at least similar enough to share // the same ComputedValues, which means that they would match the same // pseudo rules. This allows us to avoid matching selectors and checking // the rule node before deciding to share. // // The one place this optimization breaks is with pseudo-elements that // support state (like :hover). So we just avoid sharing in those cases. if (nsCSSPseudoElements::PseudoElementSupportsUserActionState(aStyle->GetPseudoType())) { return; } mNextLazyPseudoStyle.swap(aStyle->mNextLazyPseudoStyle); mNextLazyPseudoStyle = aStyle; } /** * Makes this context match |aOther| in terms of which style structs have * been resolved. */ inline void ResolveSameStructsAs(const ServoStyleContext* aOther); // The |aCVsSize| outparam on this function is where the actual CVs size // value is added. It's done that way because the callers know which value // the size should be added to. void AddSizeOfIncludingThis(nsWindowSizes& aSizes, size_t* aCVsSize) const { // Note: |this| sits within a servo_arc::Arc, i.e. it is preceded by a // refcount. So we need to measure it with a function that can handle an // interior pointer. We use ServoComputedValuesMallocEnclosingSizeOf to // clearly identify in DMD's output the memory measured here. *aCVsSize += ServoComputedValuesMallocEnclosingSizeOf(this); mSource.AddSizeOfExcludingThis(aSizes); if (mNextInheritingAnonBoxStyle && !aSizes.mState.HaveSeenPtr(mNextInheritingAnonBoxStyle)) { mNextInheritingAnonBoxStyle->AddSizeOfIncludingThis(aSizes, aCVsSize); } if (mNextLazyPseudoStyle && !aSizes.mState.HaveSeenPtr(mNextLazyPseudoStyle)) { mNextLazyPseudoStyle->AddSizeOfIncludingThis(aSizes, aCVsSize); } } 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 mNextInheritingAnonBoxStyle; // A linked-list cache of lazy pseudo styles inheriting from this style _if // the style isn't a lazy pseudo style itself_. // // Otherwise it represents the next entry in the cache of the parent style // context. // // Note that we store these separately from inheriting anonymous boxes so that // text nodes inheriting from lazy pseudo styles can share styles, which is // very important on some pages. RefPtr mNextLazyPseudoStyle; }; } // namespace mozilla #endif // mozilla_ServoStyleContext_h