1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_RestyleManagerHandle_h
8 #define mozilla_RestyleManagerHandle_h
9 
10 #include "mozilla/Assertions.h"
11 #include "mozilla/EventStates.h"
12 #include "mozilla/HandleRefPtr.h"
13 #include "mozilla/RefCountType.h"
14 #include "mozilla/StyleBackendType.h"
15 #include "nsChangeHint.h"
16 
17 namespace mozilla {
18 class RestyleManager;
19 class ServoRestyleManager;
20 namespace dom {
21 class Element;
22 } // namespace dom
23 } // namespace mozilla
24 class nsAttrValue;
25 class nsIAtom;
26 class nsIContent;
27 class nsIFrame;
28 class nsStyleChangeList;
29 
30 namespace mozilla {
31 
32 #define SERVO_BIT 0x1
33 
34 /**
35  * Smart pointer class that can hold a pointer to either a RestyleManager
36  * or a ServoRestyleManager.
37  */
38 class RestyleManagerHandle
39 {
40 public:
41   typedef HandleRefPtr<RestyleManagerHandle> RefPtr;
42 
43   // We define this Ptr class with a RestyleManager API that forwards on to the
44   // wrapped pointer, rather than putting these methods on RestyleManagerHandle
45   // itself, so that we can have RestyleManagerHandle behave like a smart
46   // pointer and be dereferenced with operator->.
47   class Ptr
48   {
49   public:
50     friend class ::mozilla::RestyleManagerHandle;
51 
IsGecko()52     bool IsGecko() const { return !IsServo(); }
IsServo()53     bool IsServo() const
54     {
55       MOZ_ASSERT(mValue, "RestyleManagerHandle null pointer dereference");
56 #ifdef MOZ_STYLO
57       return mValue & SERVO_BIT;
58 #else
59       return false;
60 #endif
61     }
62 
BackendType()63     StyleBackendType BackendType() const
64     {
65       return IsGecko() ? StyleBackendType::Gecko :
66                          StyleBackendType::Servo;
67     }
68 
AsGecko()69     RestyleManager* AsGecko()
70     {
71       MOZ_ASSERT(IsGecko());
72       return reinterpret_cast<RestyleManager*>(mValue);
73     }
74 
AsServo()75     ServoRestyleManager* AsServo()
76     {
77       MOZ_ASSERT(IsServo());
78       return reinterpret_cast<ServoRestyleManager*>(mValue & ~SERVO_BIT);
79     }
80 
GetAsGecko()81     RestyleManager* GetAsGecko() { return IsGecko() ? AsGecko() : nullptr; }
GetAsServo()82     ServoRestyleManager* GetAsServo() { return IsServo() ? AsServo() : nullptr; }
83 
AsGecko()84     const RestyleManager* AsGecko() const
85     {
86       return const_cast<Ptr*>(this)->AsGecko();
87     }
88 
AsServo()89     const ServoRestyleManager* AsServo() const
90     {
91       MOZ_ASSERT(IsServo());
92       return const_cast<Ptr*>(this)->AsServo();
93     }
94 
GetAsGecko()95     const RestyleManager* GetAsGecko() const { return IsGecko() ? AsGecko() : nullptr; }
GetAsServo()96     const ServoRestyleManager* GetAsServo() const { return IsServo() ? AsServo() : nullptr; }
97 
98     // These inline methods are defined in RestyleManagerHandleInlines.h.
99     inline MozExternalRefCountType AddRef();
100     inline MozExternalRefCountType Release();
101 
102     // Restyle manager interface.  These inline methods are defined in
103     // RestyleManagerHandleInlines.h and just forward to the underlying
104     // RestyleManager or ServoRestyleManager.  See corresponding comments in
105     // RestyleManager.h for descriptions of these methods.
106 
107     inline void Disconnect();
108     inline void PostRestyleEvent(dom::Element* aElement,
109                                  nsRestyleHint aRestyleHint,
110                                  nsChangeHint aMinChangeHint);
111     inline void PostRestyleEventForLazyConstruction();
112     inline void RebuildAllStyleData(nsChangeHint aExtraHint,
113                                     nsRestyleHint aRestyleHint);
114     inline void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
115                                              nsRestyleHint aRestyleHint);
116     inline void ProcessPendingRestyles();
117     inline void ContentInserted(nsINode* aContainer,
118                                 nsIContent* aChild);
119     inline void ContentAppended(nsIContent* aContainer,
120                                 nsIContent* aFirstNewContent);
121     inline void ContentRemoved(nsINode* aContainer,
122                                nsIContent* aOldChild,
123                                nsIContent* aFollowingSibling);
124     inline void RestyleForInsertOrChange(nsINode* aContainer,
125                                          nsIContent* aChild);
126     inline void RestyleForAppend(nsIContent* aContainer,
127                                  nsIContent* aFirstNewContent);
128     inline nsresult ContentStateChanged(nsIContent* aContent,
129                                         EventStates aStateMask);
130     inline void AttributeWillChange(dom::Element* aElement,
131                                     int32_t aNameSpaceID,
132                                     nsIAtom* aAttribute,
133                                     int32_t aModType,
134                                     const nsAttrValue* aNewValue);
135     inline void AttributeChanged(dom::Element* aElement,
136                                  int32_t aNameSpaceID,
137                                  nsIAtom* aAttribute,
138                                  int32_t aModType,
139                                  const nsAttrValue* aOldValue);
140     inline nsresult ReparentStyleContext(nsIFrame* aFrame);
141     inline bool HasPendingRestyles();
142     inline uint64_t GetRestyleGeneration() const;
143     inline uint32_t GetHoverGeneration() const;
144     inline void SetObservingRefreshDriver(bool aObserving);
145     inline nsresult ProcessRestyledFrames(nsStyleChangeList& aChangeList);
146     inline void FlushOverflowChangedTracker();
147     inline void NotifyDestroyingFrame(nsIFrame* aFrame);
148 
149   private:
150     // Stores a pointer to an RestyleManager or a ServoRestyleManager.  The least
151     // significant bit is 0 for the former, 1 for the latter.  This is
152     // valid as the least significant bit will never be used for a pointer
153     // value on platforms we care about.
154     uintptr_t mValue;
155   };
156 
decltype(nullptr)157   MOZ_IMPLICIT RestyleManagerHandle(decltype(nullptr) = nullptr)
158   {
159     mPtr.mValue = 0;
160   }
RestyleManagerHandle(const RestyleManagerHandle & aOth)161   RestyleManagerHandle(const RestyleManagerHandle& aOth)
162   {
163     mPtr.mValue = aOth.mPtr.mValue;
164   }
RestyleManagerHandle(RestyleManager * aManager)165   MOZ_IMPLICIT RestyleManagerHandle(RestyleManager* aManager)
166   {
167     *this = aManager;
168   }
RestyleManagerHandle(ServoRestyleManager * aManager)169   MOZ_IMPLICIT RestyleManagerHandle(ServoRestyleManager* aManager)
170   {
171     *this = aManager;
172   }
173 
decltype(nullptr)174   RestyleManagerHandle& operator=(decltype(nullptr))
175   {
176     mPtr.mValue = 0;
177     return *this;
178   }
179 
180   RestyleManagerHandle& operator=(RestyleManager* aManager)
181   {
182     MOZ_ASSERT(!(reinterpret_cast<uintptr_t>(aManager) & SERVO_BIT),
183                "least significant bit shouldn't be set; we use it for state");
184     mPtr.mValue = reinterpret_cast<uintptr_t>(aManager);
185     return *this;
186   }
187 
188   RestyleManagerHandle& operator=(ServoRestyleManager* aManager)
189   {
190 #ifdef MOZ_STYLO
191     MOZ_ASSERT(!(reinterpret_cast<uintptr_t>(aManager) & SERVO_BIT),
192                "least significant bit shouldn't be set; we use it for state");
193     mPtr.mValue =
194       aManager ? (reinterpret_cast<uintptr_t>(aManager) | SERVO_BIT) : 0;
195     return *this;
196 #else
197     MOZ_CRASH("should not have a ServoRestyleManager object when MOZ_STYLO is "
198               "disabled");
199 #endif
200   }
201 
202   // Make RestyleManagerHandle usable in boolean contexts.
203   explicit operator bool() const { return !!mPtr.mValue; }
204   bool operator!() const { return !mPtr.mValue; }
205 
206   // Make RestyleManagerHandle behave like a smart pointer.
207   Ptr* operator->() { return &mPtr; }
208   const Ptr* operator->() const { return &mPtr; }
209 
210 private:
211   Ptr mPtr;
212 };
213 
214 #undef SERVO_BIT
215 
216 } // namespace mozilla
217 
218 #endif // mozilla_RestyleManagerHandle_h
219