/work/obj-fuzz/dist/include/mozilla/ComputedStyle.h
Line | Count | Source (jump to first uncovered line) |
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 | | /* the interface (to internal code) for retrieving computed style data */ |
8 | | |
9 | | #ifndef _ComputedStyle_h_ |
10 | | #define _ComputedStyle_h_ |
11 | | |
12 | | #include "nsIMemoryReporter.h" |
13 | | #include <algorithm> |
14 | | #include "mozilla/ArenaObjectID.h" |
15 | | #include "mozilla/Assertions.h" |
16 | | #include "mozilla/CachedInheritingStyles.h" |
17 | | #include "mozilla/Maybe.h" |
18 | | #include "mozilla/ServoComputedData.h" |
19 | | #include "mozilla/ServoTypes.h" |
20 | | #include "mozilla/ServoUtils.h" |
21 | | #include "mozilla/StyleComplexColor.h" |
22 | | #include "nsCSSAnonBoxes.h" |
23 | | #include "nsCSSPseudoElements.h" |
24 | | |
25 | | #include "nsStyleStructFwd.h" |
26 | | |
27 | | class nsAtom; |
28 | | enum nsChangeHint : uint32_t; |
29 | | class nsIPresShell; |
30 | | class nsPresContext; |
31 | | class nsWindowSizes; |
32 | | |
33 | | #define STYLE_STRUCT(name_) struct nsStyle##name_; |
34 | | #include "nsStyleStructList.h" |
35 | | #undef STYLE_STRUCT |
36 | | |
37 | | extern "C" { |
38 | | void Servo_ComputedStyle_AddRef(const mozilla::ComputedStyle* aStyle); |
39 | | void Servo_ComputedStyle_Release(const mozilla::ComputedStyle* aStyle); |
40 | | void Gecko_ComputedStyle_Destroy(mozilla::ComputedStyle*); |
41 | | } |
42 | | |
43 | | namespace mozilla { |
44 | | |
45 | | enum class CSSPseudoElementType : uint8_t; |
46 | | class ComputedStyle; |
47 | | |
48 | | /** |
49 | | * A ComputedStyle represents the computed style data for an element. |
50 | | * |
51 | | * The computed style data are stored in a set of reference counted structs |
52 | | * (see nsStyleStruct.h) that are stored directly on the ComputedStyle. |
53 | | * |
54 | | * Style structs are immutable once they have been produced, so when any change |
55 | | * is made that needs a restyle, we create a new ComputedStyle. |
56 | | * |
57 | | * ComputedStyles are reference counted. References are generally held by: |
58 | | * |
59 | | * 1. nsIFrame::mComputedStyle, for every frame |
60 | | * 2. Element::mServoData, for every element not inside a display:none subtree |
61 | | * 3. nsComputedDOMStyle, when created for elements in display:none subtrees |
62 | | * 4. media_queries::Device, which holds the initial value of every property |
63 | | */ |
64 | | |
65 | | enum class ComputedStyleBit : uint8_t |
66 | | { |
67 | | HasTextDecorationLines = 1 << 0, |
68 | | HasPseudoElementData = 1 << 1, |
69 | | SuppressLineBreak = 1 << 2, |
70 | | IsTextCombined = 1 << 3, |
71 | | RelevantLinkVisited = 1 << 4, |
72 | | }; |
73 | | |
74 | | MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ComputedStyleBit) |
75 | | |
76 | | class ComputedStyle |
77 | | { |
78 | | using Bit = ComputedStyleBit; |
79 | | public: |
80 | | ComputedStyle(nsPresContext* aPresContext, |
81 | | nsAtom* aPseudoTag, |
82 | | CSSPseudoElementType aPseudoType, |
83 | | ServoComputedDataForgotten aComputedValues); |
84 | | |
85 | | // FIXME(emilio, bug 548397): This will need to go away. Don't add new callers |
86 | | // of this methed. |
87 | 0 | nsPresContext* PresContextForFrame() const { return mPresContext; } |
88 | 0 | const ServoComputedData* ComputedData() const { return &mSource; } |
89 | | |
90 | | // These two methods are for use by ArenaRefPtr. |
91 | | // |
92 | | // FIXME(emilio): Think this can go away. |
93 | | static mozilla::ArenaObjectID ArenaObjectID() |
94 | 0 | { |
95 | 0 | return mozilla::eArenaObjectID_GeckoComputedStyle; |
96 | 0 | } |
97 | | nsIPresShell* Arena(); |
98 | | |
99 | 0 | void AddRef() { Servo_ComputedStyle_AddRef(this); } |
100 | 0 | void Release() { Servo_ComputedStyle_Release(this); } |
101 | | |
102 | | // Return the ComputedStyle whose style data should be used for the R, |
103 | | // G, and B components of color, background-color, and border-*-color |
104 | | // if RelevantLinkIsVisited(). |
105 | | // |
106 | | // GetPseudo() and GetPseudoType() on this ComputedStyle return the |
107 | | // same as on |this|, and its depth in the tree (number of GetParent() |
108 | | // calls until null is returned) is the same as |this|, since its |
109 | | // parent is either |this|'s parent or |this|'s parent's |
110 | | // style-if-visited. |
111 | | // |
112 | | // Structs on this context should never be examined without also |
113 | | // examining the corresponding struct on |this|. Doing so will likely |
114 | | // both (1) lead to a privacy leak and (2) lead to dynamic change bugs |
115 | | // related to the Peek code in ComputedStyle::CalcStyleDifference. |
116 | | ComputedStyle* GetStyleIfVisited() const |
117 | 0 | { |
118 | 0 | return ComputedData()->visited_style.mPtr; |
119 | 0 | } |
120 | | |
121 | | bool IsLazilyCascadedPseudoElement() const |
122 | 0 | { |
123 | 0 | return IsPseudoElement() && |
124 | 0 | !nsCSSPseudoElements::IsEagerlyCascadedInServo(GetPseudoType()); |
125 | 0 | } |
126 | | |
127 | 0 | nsAtom* GetPseudo() const { return mPseudoTag; } |
128 | | mozilla::CSSPseudoElementType GetPseudoType() const |
129 | 0 | { |
130 | 0 | return mPseudoType; |
131 | 0 | } |
132 | | |
133 | 0 | bool IsInheritingAnonBox() const { |
134 | 0 | return GetPseudoType() == mozilla::CSSPseudoElementType::InheritingAnonBox; |
135 | 0 | } |
136 | | |
137 | 0 | bool IsNonInheritingAnonBox() const { |
138 | 0 | return GetPseudoType() == mozilla::CSSPseudoElementType::NonInheritingAnonBox; |
139 | 0 | } |
140 | | |
141 | | // This function is rather slow; you probably don't want to use it outside |
142 | | // asserts unless you have to. We _could_ add a new CSSPseudoElementType for |
143 | | // wrapper anon boxes, but that adds a bunch of complexity everywhere we |
144 | | // resolve anonymous box styles... |
145 | 0 | bool IsWrapperAnonBox() const { |
146 | 0 | return nsCSSAnonBoxes::IsWrapperAnonBox(GetPseudo()); |
147 | 0 | } |
148 | | |
149 | 0 | bool IsAnonBox() const { |
150 | 0 | return IsInheritingAnonBox() || IsNonInheritingAnonBox(); |
151 | 0 | } |
152 | | |
153 | 0 | bool IsPseudoElement() const { return mPseudoTag && !IsAnonBox(); } |
154 | | |
155 | | // Does this ComputedStyle or any of its ancestors have text |
156 | | // decoration lines? |
157 | | // Differs from nsStyleTextReset::HasTextDecorationLines, which tests |
158 | | // only the data for a single context. |
159 | | bool HasTextDecorationLines() const |
160 | 0 | { |
161 | 0 | return bool(mBits & Bit::HasTextDecorationLines); |
162 | 0 | } |
163 | | |
164 | | // Whether any line break inside should be suppressed? If this returns |
165 | | // true, the line should not be broken inside, which means inlines act |
166 | | // as if nowrap is set, <br> is suppressed, and blocks are inlinized. |
167 | | // This bit is propogated to all children of line partitipants. It is |
168 | | // currently used by ruby to make its content frames unbreakable. |
169 | | // NOTE: for nsTextFrame, use nsTextFrame::ShouldSuppressLineBreak() |
170 | | // instead of this method. |
171 | | bool ShouldSuppressLineBreak() const |
172 | 0 | { |
173 | 0 | return bool(mBits & Bit::SuppressLineBreak); |
174 | 0 | } |
175 | | |
176 | | // Is this horizontal-in-vertical (tate-chu-yoko) text? This flag is |
177 | | // only set on ComputedStyles whose pseudo is nsCSSAnonBoxes::mozText(). |
178 | | bool IsTextCombined() const |
179 | 0 | { |
180 | 0 | return bool(mBits & Bit::IsTextCombined); |
181 | 0 | } |
182 | | |
183 | | // Does this ComputedStyle represent the style for a pseudo-element or |
184 | | // inherit data from such a ComputedStyle? Whether this returns true |
185 | | // is equivalent to whether it or any of its ancestors returns |
186 | | // non-null for IsPseudoElement(). |
187 | | bool HasPseudoElementData() const |
188 | 0 | { |
189 | 0 | return bool(mBits & Bit::HasPseudoElementData); |
190 | 0 | } |
191 | | |
192 | | // Is the only link whose visitedness is allowed to influence the |
193 | | // style of the node this ComputedStyle is for (which is that element |
194 | | // or its nearest ancestor that is a link) visited? |
195 | | bool RelevantLinkVisited() const |
196 | 0 | { |
197 | 0 | return bool(mBits & Bit::RelevantLinkVisited); |
198 | 0 | } |
199 | | |
200 | | ComputedStyle* GetCachedInheritingAnonBoxStyle(nsAtom* aAnonBox) const |
201 | 0 | { |
202 | 0 | MOZ_ASSERT(nsCSSAnonBoxes::IsInheritingAnonBox(aAnonBox)); |
203 | 0 | return mCachedInheritingStyles.Lookup(aAnonBox); |
204 | 0 | } |
205 | | |
206 | | void SetCachedInheritedAnonBoxStyle(nsAtom* aAnonBox, ComputedStyle* aStyle) |
207 | 0 | { |
208 | 0 | MOZ_ASSERT(!GetCachedInheritingAnonBoxStyle(aAnonBox)); |
209 | 0 | mCachedInheritingStyles.Insert(aStyle); |
210 | 0 | } |
211 | | |
212 | | ComputedStyle* GetCachedLazyPseudoStyle(CSSPseudoElementType aPseudo) const; |
213 | | |
214 | | void SetCachedLazyPseudoStyle(ComputedStyle* aStyle) |
215 | 0 | { |
216 | 0 | MOZ_ASSERT(aStyle->GetPseudo() && !aStyle->IsAnonBox()); |
217 | 0 | MOZ_ASSERT(!GetCachedLazyPseudoStyle(aStyle->GetPseudoType())); |
218 | 0 | MOZ_ASSERT(!IsLazilyCascadedPseudoElement(), "lazy pseudos can't inherit lazy pseudos"); |
219 | 0 | MOZ_ASSERT(aStyle->IsLazilyCascadedPseudoElement()); |
220 | 0 |
|
221 | 0 | // Since we're caching lazy pseudo styles on the ComputedValues of the |
222 | 0 | // originating element, we can assume that we either have the same |
223 | 0 | // originating element, or that they were at least similar enough to share |
224 | 0 | // the same ComputedValues, which means that they would match the same |
225 | 0 | // pseudo rules. This allows us to avoid matching selectors and checking |
226 | 0 | // the rule node before deciding to share. |
227 | 0 | // |
228 | 0 | // The one place this optimization breaks is with pseudo-elements that |
229 | 0 | // support state (like :hover). So we just avoid sharing in those cases. |
230 | 0 | if (nsCSSPseudoElements::PseudoElementSupportsUserActionState(aStyle->GetPseudoType())) { |
231 | 0 | return; |
232 | 0 | } |
233 | 0 | |
234 | 0 | mCachedInheritingStyles.Insert(aStyle); |
235 | 0 | } |
236 | | |
237 | | /** |
238 | | * Define typesafe getter functions for each style struct by |
239 | | * preprocessing the list of style structs. These functions are the |
240 | | * preferred way to get style data. The macro creates functions like: |
241 | | * const nsStyleBorder* StyleBorder(); |
242 | | * const nsStyleColor* StyleColor(); |
243 | | */ |
244 | | #define STYLE_STRUCT(name_) \ |
245 | | inline const nsStyle##name_ * Style##name_() MOZ_NONNULL_RETURN; |
246 | | #include "nsStyleStructList.h" |
247 | | #undef STYLE_STRUCT |
248 | | |
249 | | /** |
250 | | * Equivalent to StyleFoo(), except that we skip the cache write during the |
251 | | * servo traversal. This can cause incorrect behavior if used improperly, |
252 | | * since we won't record that layout potentially depends on the values in |
253 | | * this style struct. Use with care. |
254 | | */ |
255 | | |
256 | | #define STYLE_STRUCT(name_) \ |
257 | | inline const nsStyle##name_ * ThreadsafeStyle##name_(); |
258 | | #include "nsStyleStructList.h" |
259 | | #undef STYLE_STRUCT |
260 | | |
261 | | |
262 | | /** |
263 | | * PeekStyle* is like Style* but doesn't trigger style |
264 | | * computation if the data is not cached on either the ComputedStyle |
265 | | * or the rule node. |
266 | | * |
267 | | * Perhaps this shouldn't be a public ComputedStyle API. |
268 | | */ |
269 | | #define STYLE_STRUCT(name_) \ |
270 | | inline const nsStyle##name_ * PeekStyle##name_(); |
271 | | #include "nsStyleStructList.h" |
272 | | #undef STYLE_STRUCT |
273 | | |
274 | | /** |
275 | | * Compute the style changes needed during restyling when this style |
276 | | * context is being replaced by aNewContext. (This is nonsymmetric since |
277 | | * we optimize by skipping comparison for styles that have never been |
278 | | * requested.) |
279 | | * |
280 | | * This method returns a change hint (see nsChangeHint.h). All change |
281 | | * hints apply to the frame and its later continuations or ib-split |
282 | | * siblings. Most (all of those except the "NotHandledForDescendants" |
283 | | * hints) also apply to all descendants. |
284 | | * |
285 | | * aEqualStructs must not be null. Into it will be stored a bitfield |
286 | | * representing which structs were compared to be non-equal. |
287 | | * |
288 | | * CSS Variables are not compared here. Instead, the caller is responsible for |
289 | | * that when needed (basically only for elements). |
290 | | */ |
291 | | nsChangeHint CalcStyleDifference(ComputedStyle* aNewContext, |
292 | | uint32_t* aEqualStructs); |
293 | | |
294 | | public: |
295 | | /** |
296 | | * Get a color that depends on link-visitedness using this and |
297 | | * this->GetStyleIfVisited(). |
298 | | * |
299 | | * @param aField A pointer to a member variable in a style struct. |
300 | | * The member variable and its style struct must have |
301 | | * been listed in nsCSSVisitedDependentPropList.h. |
302 | | */ |
303 | | template<typename T, typename S> |
304 | | nscolor GetVisitedDependentColor(T S::* aField); |
305 | | |
306 | | /** |
307 | | * aColors should be a two element array of nscolor in which the first |
308 | | * color is the unvisited color and the second is the visited color. |
309 | | * |
310 | | * Combine the R, G, and B components of whichever of aColors should |
311 | | * be used based on aLinkIsVisited with the A component of aColors[0]. |
312 | | */ |
313 | | static nscolor CombineVisitedColors(nscolor* aColors, bool aLinkIsVisited); |
314 | | |
315 | | /** |
316 | | * Start the background image loads for this ComputedStyle. |
317 | | */ |
318 | | inline void StartBackgroundImageLoads(); |
319 | | |
320 | | #ifdef DEBUG |
321 | | void List(FILE* out, int32_t aIndent); |
322 | | static const char* StructName(StyleStructID aSID); |
323 | | static Maybe<StyleStructID> LookupStruct(const nsACString& aName); |
324 | | #endif |
325 | | |
326 | | /** |
327 | | * Makes this context match |aOther| in terms of which style structs have |
328 | | * been resolved. |
329 | | */ |
330 | | inline void ResolveSameStructsAs(const ComputedStyle* aOther); |
331 | | |
332 | | // The |aCVsSize| outparam on this function is where the actual CVs size |
333 | | // value is added. It's done that way because the callers know which value |
334 | | // the size should be added to. |
335 | | void AddSizeOfIncludingThis(nsWindowSizes& aSizes, size_t* aCVsSize) const; |
336 | | |
337 | | protected: |
338 | | bool HasRequestedStruct(StyleStructID aID) const |
339 | 0 | { |
340 | 0 | return mRequestedStructs & StyleStructConstants::BitFor(aID); |
341 | 0 | } |
342 | | |
343 | | void SetRequestedStruct(StyleStructID aID) |
344 | 0 | { |
345 | 0 | mRequestedStructs |= StyleStructConstants::BitFor(aID); |
346 | 0 | } |
347 | | |
348 | | // Needs to be friend so that it can call the destructor without making it |
349 | | // public. |
350 | | friend void ::Gecko_ComputedStyle_Destroy(ComputedStyle*); |
351 | | |
352 | 0 | ~ComputedStyle() = default; |
353 | | |
354 | | nsPresContext* const mPresContext; |
355 | | |
356 | | ServoComputedData mSource; |
357 | | |
358 | | // A cache of anonymous box and lazy pseudo styles inheriting from this style. |
359 | | CachedInheritingStyles mCachedInheritingStyles; |
360 | | |
361 | | // Helper functions for GetStyle* and PeekStyle* |
362 | | #define STYLE_STRUCT_INHERITED(name_) \ |
363 | | template<bool aComputeData> \ |
364 | | const nsStyle##name_ * DoGetStyle##name_(); |
365 | | #define STYLE_STRUCT_RESET(name_) \ |
366 | | template<bool aComputeData> \ |
367 | | const nsStyle##name_ * DoGetStyle##name_(); |
368 | | |
369 | | #include "nsStyleStructList.h" |
370 | | #undef STYLE_STRUCT_RESET |
371 | | #undef STYLE_STRUCT_INHERITED |
372 | | |
373 | | // If this ComputedStyle is for a pseudo-element or anonymous box, |
374 | | // the relevant atom. |
375 | | const RefPtr<nsAtom> mPseudoTag; |
376 | | |
377 | | // A bitfield with the structs that have been requested so far. |
378 | | uint32_t mRequestedStructs = 0; |
379 | | const Bit mBits; |
380 | | const CSSPseudoElementType mPseudoType; |
381 | | }; |
382 | | |
383 | | } // namespace mozilla |
384 | | |
385 | | #endif |