|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* the interface (to internal code) for retrieving computed style data */ |
|
7 |
|
8 #ifndef _nsStyleContext_h_ |
|
9 #define _nsStyleContext_h_ |
|
10 |
|
11 #include "nsRuleNode.h" |
|
12 #include "nsCSSPseudoElements.h" |
|
13 |
|
14 class nsIAtom; |
|
15 class nsPresContext; |
|
16 |
|
17 /** |
|
18 * An nsStyleContext represents the computed style data for an element. |
|
19 * The computed style data are stored in a set of structs (see |
|
20 * nsStyleStruct.h) that are cached either on the style context or in |
|
21 * the rule tree (see nsRuleNode.h for a description of this caching and |
|
22 * how the cached structs are shared). |
|
23 * |
|
24 * Since the data in |nsIStyleRule|s and |nsRuleNode|s are immutable |
|
25 * (with a few exceptions, like system color changes), the data in an |
|
26 * nsStyleContext are also immutable (with the additional exception of |
|
27 * GetUniqueStyleData). When style data change, |
|
28 * nsFrameManager::ReResolveStyleContext creates a new style context. |
|
29 * |
|
30 * Style contexts are reference counted. References are generally held |
|
31 * by: |
|
32 * 1. the |nsIFrame|s that are using the style context and |
|
33 * 2. any *child* style contexts (this might be the reverse of |
|
34 * expectation, but it makes sense in this case) |
|
35 * Style contexts participate in the mark phase of rule node garbage |
|
36 * collection. |
|
37 */ |
|
38 |
|
39 class nsStyleContext |
|
40 { |
|
41 public: |
|
42 /** |
|
43 * Create a new style context. |
|
44 * @param aParent The parent of a style context is used for CSS |
|
45 * inheritance. When the element or pseudo-element |
|
46 * this style context represents the style data of |
|
47 * inherits a CSS property, the value comes from the |
|
48 * parent style context. This means style context |
|
49 * parentage must match the definitions of inheritance |
|
50 * in the CSS specification. |
|
51 * @param aPseudoTag The pseudo-element or anonymous box for which |
|
52 * this style context represents style. Null if |
|
53 * this style context is for a normal DOM element. |
|
54 * @param aPseudoType Must match aPseudoTag. |
|
55 * @param aRuleNode A rule node representing the ordered sequence of |
|
56 * rules that any element, pseudo-element, or |
|
57 * anonymous box that this style context is for |
|
58 * matches. See |nsRuleNode| and |nsIStyleRule|. |
|
59 * @param aSkipFlexItemStyleFixup |
|
60 * If set, this flag indicates that we should skip |
|
61 * the chunk of ApplyStyleFixups() that modifies flex |
|
62 * items' display values. |
|
63 */ |
|
64 nsStyleContext(nsStyleContext* aParent, nsIAtom* aPseudoTag, |
|
65 nsCSSPseudoElements::Type aPseudoType, |
|
66 nsRuleNode* aRuleNode, |
|
67 bool aSkipFlexItemStyleFixup); |
|
68 ~nsStyleContext(); |
|
69 |
|
70 void* operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW; |
|
71 void Destroy(); |
|
72 |
|
73 nsrefcnt AddRef() { |
|
74 if (mRefCnt == UINT32_MAX) { |
|
75 NS_WARNING("refcount overflow, leaking object"); |
|
76 return mRefCnt; |
|
77 } |
|
78 ++mRefCnt; |
|
79 NS_LOG_ADDREF(this, mRefCnt, "nsStyleContext", sizeof(nsStyleContext)); |
|
80 return mRefCnt; |
|
81 } |
|
82 |
|
83 nsrefcnt Release() { |
|
84 if (mRefCnt == UINT32_MAX) { |
|
85 NS_WARNING("refcount overflow, leaking object"); |
|
86 return mRefCnt; |
|
87 } |
|
88 --mRefCnt; |
|
89 NS_LOG_RELEASE(this, mRefCnt, "nsStyleContext"); |
|
90 if (mRefCnt == 0) { |
|
91 Destroy(); |
|
92 return 0; |
|
93 } |
|
94 return mRefCnt; |
|
95 } |
|
96 |
|
97 nsPresContext* PresContext() const { return mRuleNode->PresContext(); } |
|
98 |
|
99 nsStyleContext* GetParent() const { return mParent; } |
|
100 |
|
101 nsIAtom* GetPseudo() const { return mPseudoTag; } |
|
102 nsCSSPseudoElements::Type GetPseudoType() const { |
|
103 return static_cast<nsCSSPseudoElements::Type>(mBits >> |
|
104 NS_STYLE_CONTEXT_TYPE_SHIFT); |
|
105 } |
|
106 |
|
107 // Find, if it already exists *and is easily findable* (i.e., near the |
|
108 // start of the child list), a style context whose: |
|
109 // * GetPseudo() matches aPseudoTag |
|
110 // * RuleNode() matches aRules |
|
111 // * !GetStyleIfVisited() == !aRulesIfVisited, and, if they're |
|
112 // non-null, GetStyleIfVisited()->RuleNode() == aRulesIfVisited |
|
113 // * RelevantLinkVisited() == aRelevantLinkVisited |
|
114 already_AddRefed<nsStyleContext> |
|
115 FindChildWithRules(const nsIAtom* aPseudoTag, nsRuleNode* aRules, |
|
116 nsRuleNode* aRulesIfVisited, |
|
117 bool aRelevantLinkVisited); |
|
118 |
|
119 // Does this style context or any of its ancestors have text |
|
120 // decoration lines? |
|
121 bool HasTextDecorationLines() const |
|
122 { return !!(mBits & NS_STYLE_HAS_TEXT_DECORATION_LINES); } |
|
123 |
|
124 // Does this style context represent the style for a pseudo-element or |
|
125 // inherit data from such a style context? Whether this returns true |
|
126 // is equivalent to whether it or any of its ancestors returns |
|
127 // non-null for GetPseudo. |
|
128 bool HasPseudoElementData() const |
|
129 { return !!(mBits & NS_STYLE_HAS_PSEUDO_ELEMENT_DATA); } |
|
130 |
|
131 // Is the only link whose visitedness is allowed to influence the |
|
132 // style of the node this style context is for (which is that element |
|
133 // or its nearest ancestor that is a link) visited? |
|
134 bool RelevantLinkVisited() const |
|
135 { return !!(mBits & NS_STYLE_RELEVANT_LINK_VISITED); } |
|
136 |
|
137 // Is this a style context for a link? |
|
138 bool IsLinkContext() const { |
|
139 return |
|
140 GetStyleIfVisited() && GetStyleIfVisited()->GetParent() == GetParent(); |
|
141 } |
|
142 |
|
143 // Is this style context the GetStyleIfVisited() for some other style |
|
144 // context? |
|
145 bool IsStyleIfVisited() const |
|
146 { return !!(mBits & NS_STYLE_IS_STYLE_IF_VISITED); } |
|
147 |
|
148 // Tells this style context that it should return true from |
|
149 // IsStyleIfVisited. |
|
150 void SetIsStyleIfVisited() |
|
151 { mBits |= NS_STYLE_IS_STYLE_IF_VISITED; } |
|
152 |
|
153 // Return the style context whose style data should be used for the R, |
|
154 // G, and B components of color, background-color, and border-*-color |
|
155 // if RelevantLinkIsVisited(). |
|
156 // |
|
157 // GetPseudo() and GetPseudoType() on this style context return the |
|
158 // same as on |this|, and its depth in the tree (number of GetParent() |
|
159 // calls until null is returned) is the same as |this|, since its |
|
160 // parent is either |this|'s parent or |this|'s parent's |
|
161 // style-if-visited. |
|
162 // |
|
163 // Structs on this context should never be examined without also |
|
164 // examining the corresponding struct on |this|. Doing so will likely |
|
165 // both (1) lead to a privacy leak and (2) lead to dynamic change bugs |
|
166 // related to the Peek code in nsStyleContext::CalcStyleDifference. |
|
167 nsStyleContext* GetStyleIfVisited() const |
|
168 { return mStyleIfVisited; } |
|
169 |
|
170 // To be called only from nsStyleSet. |
|
171 void SetStyleIfVisited(already_AddRefed<nsStyleContext> aStyleIfVisited) |
|
172 { |
|
173 NS_ABORT_IF_FALSE(!IsStyleIfVisited(), "this context is not visited data"); |
|
174 NS_ASSERTION(!mStyleIfVisited, "should only be set once"); |
|
175 |
|
176 mStyleIfVisited = aStyleIfVisited; |
|
177 |
|
178 NS_ABORT_IF_FALSE(mStyleIfVisited->IsStyleIfVisited(), |
|
179 "other context is visited data"); |
|
180 NS_ABORT_IF_FALSE(!mStyleIfVisited->GetStyleIfVisited(), |
|
181 "other context does not have visited data"); |
|
182 NS_ASSERTION(GetStyleIfVisited()->GetPseudo() == GetPseudo(), |
|
183 "pseudo tag mismatch"); |
|
184 if (GetParent() && GetParent()->GetStyleIfVisited()) { |
|
185 NS_ASSERTION(GetStyleIfVisited()->GetParent() == |
|
186 GetParent()->GetStyleIfVisited() || |
|
187 GetStyleIfVisited()->GetParent() == GetParent(), |
|
188 "parent mismatch"); |
|
189 } else { |
|
190 NS_ASSERTION(GetStyleIfVisited()->GetParent() == GetParent(), |
|
191 "parent mismatch"); |
|
192 } |
|
193 } |
|
194 |
|
195 // Tell this style context to cache aStruct as the struct for aSID |
|
196 void SetStyle(nsStyleStructID aSID, void* aStruct); |
|
197 |
|
198 // Setters for inherit structs only, since rulenode only sets those eagerly. |
|
199 #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_) \ |
|
200 void SetStyle##name_ (nsStyle##name_ * aStruct) { \ |
|
201 void *& slot = \ |
|
202 mCachedInheritedData.mStyleStructs[eStyleStruct_##name_]; \ |
|
203 NS_ASSERTION(!slot || \ |
|
204 (mBits & \ |
|
205 nsCachedStyleData::GetBitForSID(eStyleStruct_##name_)), \ |
|
206 "Going to leak styledata"); \ |
|
207 slot = aStruct; \ |
|
208 } |
|
209 #define STYLE_STRUCT_RESET(name_, checkdata_cb_) /* nothing */ |
|
210 #include "nsStyleStructList.h" |
|
211 #undef STYLE_STRUCT_RESET |
|
212 #undef STYLE_STRUCT_INHERITED |
|
213 |
|
214 nsRuleNode* RuleNode() { return mRuleNode; } |
|
215 void AddStyleBit(const uint64_t& aBit) { mBits |= aBit; } |
|
216 |
|
217 /* |
|
218 * Mark this style context's rule node (and its ancestors) to prevent |
|
219 * it from being garbage collected. |
|
220 */ |
|
221 void Mark(); |
|
222 |
|
223 /* |
|
224 * Get the style data for a style struct. This is the most important |
|
225 * member function of nsIStyleContext. It fills in a const pointer |
|
226 * to a style data struct that is appropriate for the style context's |
|
227 * frame. This struct may be shared with other contexts (either in |
|
228 * the rule tree or the style context tree), so it should not be |
|
229 * modified. |
|
230 * |
|
231 * This function will NOT return null (even when out of memory) when |
|
232 * given a valid style struct ID, so the result does not need to be |
|
233 * null-checked. |
|
234 * |
|
235 * The typesafe functions below are preferred to the use of this |
|
236 * function, both because they're easier to read and because they're |
|
237 * faster. |
|
238 */ |
|
239 const void* NS_FASTCALL StyleData(nsStyleStructID aSID); |
|
240 |
|
241 /** |
|
242 * Define typesafe getter functions for each style struct by |
|
243 * preprocessing the list of style structs. These functions are the |
|
244 * preferred way to get style data. The macro creates functions like: |
|
245 * const nsStyleBorder* StyleBorder(); |
|
246 * const nsStyleColor* StyleColor(); |
|
247 */ |
|
248 #define STYLE_STRUCT(name_, checkdata_cb_) \ |
|
249 const nsStyle##name_ * Style##name_() { \ |
|
250 return DoGetStyle##name_(true); \ |
|
251 } |
|
252 #include "nsStyleStructList.h" |
|
253 #undef STYLE_STRUCT |
|
254 |
|
255 /** |
|
256 * PeekStyle* is like GetStyle* but doesn't trigger style |
|
257 * computation if the data is not cached on either the style context |
|
258 * or the rule node. |
|
259 * |
|
260 * Perhaps this shouldn't be a public nsStyleContext API. |
|
261 */ |
|
262 #define STYLE_STRUCT(name_, checkdata_cb_) \ |
|
263 const nsStyle##name_ * PeekStyle##name_() { \ |
|
264 return DoGetStyle##name_(false); \ |
|
265 } |
|
266 #include "nsStyleStructList.h" |
|
267 #undef STYLE_STRUCT |
|
268 |
|
269 void* GetUniqueStyleData(const nsStyleStructID& aSID); |
|
270 |
|
271 /** |
|
272 * Compute the style changes needed during restyling when this style |
|
273 * context is being replaced by aOther. (This is nonsymmetric since |
|
274 * we optimize by skipping comparison for styles that have never been |
|
275 * requested.) |
|
276 * |
|
277 * This method returns a change hint (see nsChangeHint.h). All change |
|
278 * hints apply to the frame and its later continuations or ib-split |
|
279 * siblings. Most (all of those except the "NotHandledForDescendants" |
|
280 * hints) also apply to all descendants. The caller must pass in any |
|
281 * non-inherited hints that resulted from the parent style context's |
|
282 * style change. The caller *may* pass more hints than needed, but |
|
283 * must not pass less than needed; therefore if the caller doesn't |
|
284 * know, the caller should pass |
|
285 * nsChangeHint_Hints_NotHandledForDescendants. |
|
286 */ |
|
287 nsChangeHint CalcStyleDifference(nsStyleContext* aOther, |
|
288 nsChangeHint aParentHintsNotHandledForDescendants); |
|
289 |
|
290 /** |
|
291 * Get a color that depends on link-visitedness using this and |
|
292 * this->GetStyleIfVisited(). |
|
293 * |
|
294 * aProperty must be a color-valued property that nsStyleAnimation |
|
295 * knows how to extract. It must also be a property that we know to |
|
296 * do change handling for in nsStyleContext::CalcDifference. |
|
297 * |
|
298 * Note that if aProperty is eCSSProperty_border_*_color, this |
|
299 * function handles -moz-use-text-color. |
|
300 */ |
|
301 nscolor GetVisitedDependentColor(nsCSSProperty aProperty); |
|
302 |
|
303 /** |
|
304 * aColors should be a two element array of nscolor in which the first |
|
305 * color is the unvisited color and the second is the visited color. |
|
306 * |
|
307 * Combine the R, G, and B components of whichever of aColors should |
|
308 * be used based on aLinkIsVisited with the A component of aColors[0]. |
|
309 */ |
|
310 static nscolor CombineVisitedColors(nscolor *aColors, |
|
311 bool aLinkIsVisited); |
|
312 |
|
313 /** |
|
314 * Allocate a chunk of memory that is scoped to the lifetime of this |
|
315 * style context, i.e., memory that will automatically be freed when |
|
316 * this style context is destroyed. This is intended for allocations |
|
317 * that are stored on this style context or its style structs. (Use |
|
318 * on style structs is fine since any style context to which this |
|
319 * context's style structs are shared will be a descendant of this |
|
320 * style context and thus keep it alive.) |
|
321 * |
|
322 * This currently allocates the memory out of the pres shell arena. |
|
323 * |
|
324 * It would be relatively straightforward to write a Free method |
|
325 * for the underlying implementation, but we don't need it (or the |
|
326 * overhead of making a doubly-linked list or other structure to |
|
327 * support it). |
|
328 * |
|
329 * WARNING: Memory allocated using this method cannot be stored in the |
|
330 * rule tree, since rule nodes may outlive the style context. |
|
331 */ |
|
332 void* Alloc(size_t aSize); |
|
333 |
|
334 /** |
|
335 * Start the background image loads for this style context. |
|
336 */ |
|
337 void StartBackgroundImageLoads() { |
|
338 // Just get our background struct; that should do the trick |
|
339 StyleBackground(); |
|
340 } |
|
341 |
|
342 #ifdef DEBUG |
|
343 void List(FILE* out, int32_t aIndent); |
|
344 static void AssertStyleStructMaxDifferenceValid(); |
|
345 #endif |
|
346 |
|
347 protected: |
|
348 void AddChild(nsStyleContext* aChild); |
|
349 void RemoveChild(nsStyleContext* aChild); |
|
350 |
|
351 void ApplyStyleFixups(bool aSkipFlexItemStyleFixup); |
|
352 |
|
353 void FreeAllocations(nsPresContext* aPresContext); |
|
354 |
|
355 // Helper function that GetStyleData and GetUniqueStyleData use. Only |
|
356 // returns the structs we cache ourselves; never consults the ruletree. |
|
357 inline const void* GetCachedStyleData(nsStyleStructID aSID); |
|
358 |
|
359 // Helper functions for GetStyle* and PeekStyle* |
|
360 #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_) \ |
|
361 const nsStyle##name_ * DoGetStyle##name_(bool aComputeData) { \ |
|
362 const nsStyle##name_ * cachedData = \ |
|
363 static_cast<nsStyle##name_*>( \ |
|
364 mCachedInheritedData.mStyleStructs[eStyleStruct_##name_]); \ |
|
365 if (cachedData) /* Have it cached already, yay */ \ |
|
366 return cachedData; \ |
|
367 /* Have the rulenode deal */ \ |
|
368 return mRuleNode->GetStyle##name_(this, aComputeData); \ |
|
369 } |
|
370 #define STYLE_STRUCT_RESET(name_, checkdata_cb_) \ |
|
371 const nsStyle##name_ * DoGetStyle##name_(bool aComputeData) { \ |
|
372 const nsStyle##name_ * cachedData = mCachedResetData \ |
|
373 ? static_cast<nsStyle##name_*>( \ |
|
374 mCachedResetData->mStyleStructs[eStyleStruct_##name_]) \ |
|
375 : nullptr; \ |
|
376 if (cachedData) /* Have it cached already, yay */ \ |
|
377 return cachedData; \ |
|
378 /* Have the rulenode deal */ \ |
|
379 return mRuleNode->GetStyle##name_(this, aComputeData); \ |
|
380 } |
|
381 #include "nsStyleStructList.h" |
|
382 #undef STYLE_STRUCT_RESET |
|
383 #undef STYLE_STRUCT_INHERITED |
|
384 |
|
385 nsStyleContext* const mParent; // STRONG |
|
386 |
|
387 // Children are kept in two circularly-linked lists. The list anchor |
|
388 // is not part of the list (null for empty), and we point to the first |
|
389 // child. |
|
390 // mEmptyChild for children whose rule node is the root rule node, and |
|
391 // mChild for other children. The order of children is not |
|
392 // meaningful. |
|
393 nsStyleContext* mChild; |
|
394 nsStyleContext* mEmptyChild; |
|
395 nsStyleContext* mPrevSibling; |
|
396 nsStyleContext* mNextSibling; |
|
397 |
|
398 // Style to be used instead for the R, G, and B components of color, |
|
399 // background-color, and border-*-color if the nearest ancestor link |
|
400 // element is visited (see RelevantLinkVisited()). |
|
401 nsRefPtr<nsStyleContext> mStyleIfVisited; |
|
402 |
|
403 // If this style context is for a pseudo-element or anonymous box, |
|
404 // the relevant atom. |
|
405 nsCOMPtr<nsIAtom> mPseudoTag; |
|
406 |
|
407 // The rule node is the node in the lexicographic tree of rule nodes |
|
408 // (the "rule tree") that indicates which style rules are used to |
|
409 // compute the style data, and in what cascading order. The least |
|
410 // specific rule matched is the one whose rule node is a child of the |
|
411 // root of the rule tree, and the most specific rule matched is the |
|
412 // |mRule| member of |mRuleNode|. |
|
413 nsRuleNode* const mRuleNode; |
|
414 |
|
415 // Private to nsStyleContext::Alloc and FreeAllocations. |
|
416 struct AllocationHeader { |
|
417 AllocationHeader* mNext; |
|
418 size_t mSize; |
|
419 |
|
420 void* mStorageStart; // ensure the storage is at least pointer-aligned |
|
421 }; |
|
422 AllocationHeader* mAllocations; |
|
423 |
|
424 // mCachedInheritedData and mCachedResetData point to both structs that |
|
425 // are owned by this style context and structs that are owned by one of |
|
426 // this style context's ancestors (which are indirectly owned since this |
|
427 // style context owns a reference to its parent). If the bit in |mBits| |
|
428 // is set for a struct, that means that the pointer for that struct is |
|
429 // owned by an ancestor or by mRuleNode rather than by this style context. |
|
430 // Since style contexts typically have some inherited data but only sometimes |
|
431 // have reset data, we always allocate the mCachedInheritedData, but only |
|
432 // sometimes allocate the mCachedResetData. |
|
433 nsResetStyleData* mCachedResetData; // Cached reset style data. |
|
434 nsInheritedStyleData mCachedInheritedData; // Cached inherited style data |
|
435 uint64_t mBits; // Which structs are inherited from the |
|
436 // parent context or owned by mRuleNode. |
|
437 uint32_t mRefCnt; |
|
438 }; |
|
439 |
|
440 already_AddRefed<nsStyleContext> |
|
441 NS_NewStyleContext(nsStyleContext* aParentContext, |
|
442 nsIAtom* aPseudoTag, |
|
443 nsCSSPseudoElements::Type aPseudoType, |
|
444 nsRuleNode* aRuleNode, |
|
445 bool aSkipFlexItemStyleFixup); |
|
446 #endif |