/* -*- 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_StyleSetHandle_h #define mozilla_StyleSetHandle_h #include "mozilla/EventStates.h" #include "mozilla/RefPtr.h" #include "mozilla/SheetType.h" #include "mozilla/StyleBackendType.h" #include "mozilla/StyleSheet.h" #include "nsChangeHint.h" #include "nsCSSPseudoElements.h" #include "nsTArray.h" namespace mozilla { class CSSStyleSheet; class ServoStyleSet; namespace dom { class Element; } // namespace dom } // namespace mozilla class nsIAtom; class nsIContent; class nsIDocument; class nsStyleContext; class nsStyleSet; class nsPresContext; struct TreeMatchContext; namespace mozilla { #define SERVO_BIT 0x1 /** * Smart pointer class that can hold a pointer to either an nsStyleSet * or a ServoStyleSet. */ class StyleSetHandle { public: // We define this Ptr class with a StyleSet API that forwards on to the // wrapped pointer, rather than putting these methods on StyleSetHandle // itself, so that we can have StyleSetHandle behave like a smart pointer and // be dereferenced with operator->. class Ptr { public: friend class ::mozilla::StyleSetHandle; bool IsGecko() const { return !IsServo(); } bool IsServo() const { MOZ_ASSERT(mValue, "StyleSetHandle null pointer dereference"); #ifdef MOZ_STYLO return mValue & SERVO_BIT; #else return false; #endif } StyleBackendType BackendType() const { return IsGecko() ? StyleBackendType::Gecko : StyleBackendType::Servo; } nsStyleSet* AsGecko() { MOZ_ASSERT(IsGecko()); return reinterpret_cast<nsStyleSet*>(mValue); } ServoStyleSet* AsServo() { MOZ_ASSERT(IsServo()); return reinterpret_cast<ServoStyleSet*>(mValue & ~SERVO_BIT); } nsStyleSet* GetAsGecko() { return IsGecko() ? AsGecko() : nullptr; } ServoStyleSet* GetAsServo() { return IsServo() ? AsServo() : nullptr; } const nsStyleSet* AsGecko() const { return const_cast<Ptr*>(this)->AsGecko(); } const ServoStyleSet* AsServo() const { MOZ_ASSERT(IsServo()); return const_cast<Ptr*>(this)->AsServo(); } const nsStyleSet* GetAsGecko() const { return IsGecko() ? AsGecko() : nullptr; } const ServoStyleSet* GetAsServo() const { return IsServo() ? AsServo() : nullptr; } // These inline methods are defined in StyleSetHandleInlines.h. inline void Delete(); // Style set interface. These inline methods are defined in // StyleSetHandleInlines.h and just forward to the underlying // nsStyleSet or ServoStyleSet. See corresponding comments in // nsStyleSet.h for descriptions of these methods. inline void Init(nsPresContext* aPresContext); inline void BeginShutdown(); inline void Shutdown(); inline bool GetAuthorStyleDisabled() const; inline nsresult SetAuthorStyleDisabled(bool aStyleDisabled); inline void BeginUpdate(); inline nsresult EndUpdate(); inline already_AddRefed<nsStyleContext> ResolveStyleFor(dom::Element* aElement, nsStyleContext* aParentContext); inline already_AddRefed<nsStyleContext> ResolveStyleFor(dom::Element* aElement, nsStyleContext* aParentContext, TreeMatchContext& aTreeMatchContext); inline already_AddRefed<nsStyleContext> ResolveStyleForText(nsIContent* aTextNode, nsStyleContext* aParentContext); inline already_AddRefed<nsStyleContext> ResolveStyleForOtherNonElement(nsStyleContext* aParentContext); inline already_AddRefed<nsStyleContext> ResolvePseudoElementStyle(dom::Element* aParentElement, mozilla::CSSPseudoElementType aType, nsStyleContext* aParentContext, dom::Element* aPseudoElement); inline already_AddRefed<nsStyleContext> ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag, nsStyleContext* aParentContext, uint32_t aFlags = 0); inline nsresult AppendStyleSheet(SheetType aType, StyleSheet* aSheet); inline nsresult PrependStyleSheet(SheetType aType, StyleSheet* aSheet); inline nsresult RemoveStyleSheet(SheetType aType, StyleSheet* aSheet); inline nsresult ReplaceSheets(SheetType aType, const nsTArray<RefPtr<StyleSheet>>& aNewSheets); inline nsresult InsertStyleSheetBefore(SheetType aType, StyleSheet* aNewSheet, StyleSheet* aReferenceSheet); inline int32_t SheetCount(SheetType aType) const; inline StyleSheet* StyleSheetAt(SheetType aType, int32_t aIndex) const; inline nsresult RemoveDocStyleSheet(StyleSheet* aSheet); inline nsresult AddDocStyleSheet(StyleSheet* aSheet, nsIDocument* aDocument); inline already_AddRefed<nsStyleContext> ProbePseudoElementStyle(dom::Element* aParentElement, mozilla::CSSPseudoElementType aType, nsStyleContext* aParentContext); inline already_AddRefed<nsStyleContext> ProbePseudoElementStyle(dom::Element* aParentElement, mozilla::CSSPseudoElementType aType, nsStyleContext* aParentContext, TreeMatchContext& aTreeMatchContext, dom::Element* aPseudoElement = nullptr); inline nsRestyleHint HasStateDependentStyle(dom::Element* aElement, EventStates aStateMask); inline nsRestyleHint HasStateDependentStyle( dom::Element* aElement, mozilla::CSSPseudoElementType aPseudoType, dom::Element* aPseudoElement, EventStates aStateMask); inline void RootStyleContextAdded(); inline void RootStyleContextRemoved(); private: // Stores a pointer to an nsStyleSet or a ServoStyleSet. The least // significant bit is 0 for the former, 1 for the latter. This is // valid as the least significant bit will never be used for a pointer // value on platforms we care about. uintptr_t mValue; }; StyleSetHandle() { mPtr.mValue = 0; } StyleSetHandle(const StyleSetHandle& aOth) { mPtr.mValue = aOth.mPtr.mValue; } MOZ_IMPLICIT StyleSetHandle(nsStyleSet* aSet) { *this = aSet; } MOZ_IMPLICIT StyleSetHandle(ServoStyleSet* aSet) { *this = aSet; } StyleSetHandle& operator=(nsStyleSet* aStyleSet) { MOZ_ASSERT(!(reinterpret_cast<uintptr_t>(aStyleSet) & SERVO_BIT), "least significant bit shouldn't be set; we use it for state"); mPtr.mValue = reinterpret_cast<uintptr_t>(aStyleSet); return *this; } StyleSetHandle& operator=(ServoStyleSet* aStyleSet) { #ifdef MOZ_STYLO MOZ_ASSERT(!(reinterpret_cast<uintptr_t>(aStyleSet) & SERVO_BIT), "least significant bit shouldn't be set; we use it for state"); mPtr.mValue = aStyleSet ? (reinterpret_cast<uintptr_t>(aStyleSet) | SERVO_BIT) : 0; return *this; #else MOZ_CRASH("should not have a ServoStyleSet object when MOZ_STYLO is " "disabled"); #endif } // Make StyleSetHandle usable in boolean contexts. explicit operator bool() const { return !!mPtr.mValue; } bool operator!() const { return !mPtr.mValue; } // Make StyleSetHandle behave like a smart pointer. Ptr* operator->() { return &mPtr; } const Ptr* operator->() const { return &mPtr; } private: Ptr mPtr; }; #undef SERVO_BIT } // namespace mozilla #endif // mozilla_StyleSetHandle_h