Bumping manifests a=b2g-bump
[gecko.git] / layout / style / nsStyleContext.h
blob403eec5adeda79fb2b37850278ebcaef5c8a424a
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/. */
6 /* the interface (to internal code) for retrieving computed style data */
8 #ifndef _nsStyleContext_h_
9 #define _nsStyleContext_h_
11 #include "mozilla/RestyleLogging.h"
12 #include "nsRuleNode.h"
13 #include "nsCSSPseudoElements.h"
15 class nsIAtom;
16 class nsPresContext;
18 /**
19 * An nsStyleContext represents the computed style data for an element.
20 * The computed style data are stored in a set of structs (see
21 * nsStyleStruct.h) that are cached either on the style context or in
22 * the rule tree (see nsRuleNode.h for a description of this caching and
23 * how the cached structs are shared).
25 * Since the data in |nsIStyleRule|s and |nsRuleNode|s are immutable
26 * (with a few exceptions, like system color changes), the data in an
27 * nsStyleContext are also immutable (with the additional exception of
28 * GetUniqueStyleData). When style data change,
29 * nsFrameManager::ReResolveStyleContext creates a new style context.
31 * Style contexts are reference counted. References are generally held
32 * by:
33 * 1. the |nsIFrame|s that are using the style context and
34 * 2. any *child* style contexts (this might be the reverse of
35 * expectation, but it makes sense in this case)
36 * Style contexts participate in the mark phase of rule node garbage
37 * collection.
40 class nsStyleContext MOZ_FINAL
42 public:
43 /**
44 * Create a new style context.
45 * @param aParent The parent of a style context is used for CSS
46 * inheritance. When the element or pseudo-element
47 * this style context represents the style data of
48 * inherits a CSS property, the value comes from the
49 * parent style context. This means style context
50 * parentage must match the definitions of inheritance
51 * in the CSS specification.
52 * @param aPseudoTag The pseudo-element or anonymous box for which
53 * this style context represents style. Null if
54 * this style context is for a normal DOM element.
55 * @param aPseudoType Must match aPseudoTag.
56 * @param aRuleNode A rule node representing the ordered sequence of
57 * rules that any element, pseudo-element, or
58 * anonymous box that this style context is for
59 * matches. See |nsRuleNode| and |nsIStyleRule|.
60 * @param aSkipParentDisplayBasedStyleFixup
61 * If set, this flag indicates that we should skip
62 * the chunk of ApplyStyleFixups() that applies to
63 * special cases where a child element's style may
64 * need to be modified based on its parent's display
65 * value.
67 nsStyleContext(nsStyleContext* aParent, nsIAtom* aPseudoTag,
68 nsCSSPseudoElements::Type aPseudoType,
69 nsRuleNode* aRuleNode,
70 bool aSkipParentDisplayBasedStyleFixup);
72 void* operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW;
73 void Destroy();
75 nsrefcnt AddRef() {
76 if (mRefCnt == UINT32_MAX) {
77 NS_WARNING("refcount overflow, leaking object");
78 return mRefCnt;
80 ++mRefCnt;
81 NS_LOG_ADDREF(this, mRefCnt, "nsStyleContext", sizeof(nsStyleContext));
82 return mRefCnt;
85 nsrefcnt Release() {
86 if (mRefCnt == UINT32_MAX) {
87 NS_WARNING("refcount overflow, leaking object");
88 return mRefCnt;
90 --mRefCnt;
91 NS_LOG_RELEASE(this, mRefCnt, "nsStyleContext");
92 if (mRefCnt == 0) {
93 Destroy();
94 return 0;
96 return mRefCnt;
99 #ifdef DEBUG
100 void FrameAddRef() {
101 ++mFrameRefCnt;
104 void FrameRelease() {
105 --mFrameRefCnt;
108 uint32_t FrameRefCnt() const {
109 return mFrameRefCnt;
111 #endif
113 bool HasSingleReference() const {
114 NS_ASSERTION(mRefCnt != 0,
115 "do not call HasSingleReference on a newly created "
116 "nsStyleContext with no references yet");
117 return mRefCnt == 1;
120 nsPresContext* PresContext() const { return mRuleNode->PresContext(); }
122 nsStyleContext* GetParent() const { return mParent; }
124 nsIAtom* GetPseudo() const { return mPseudoTag; }
125 nsCSSPseudoElements::Type GetPseudoType() const {
126 return static_cast<nsCSSPseudoElements::Type>(mBits >>
127 NS_STYLE_CONTEXT_TYPE_SHIFT);
130 // Find, if it already exists *and is easily findable* (i.e., near the
131 // start of the child list), a style context whose:
132 // * GetPseudo() matches aPseudoTag
133 // * RuleNode() matches aRules
134 // * !GetStyleIfVisited() == !aRulesIfVisited, and, if they're
135 // non-null, GetStyleIfVisited()->RuleNode() == aRulesIfVisited
136 // * RelevantLinkVisited() == aRelevantLinkVisited
137 already_AddRefed<nsStyleContext>
138 FindChildWithRules(const nsIAtom* aPseudoTag, nsRuleNode* aRules,
139 nsRuleNode* aRulesIfVisited,
140 bool aRelevantLinkVisited);
142 // Does this style context or any of its ancestors have text
143 // decoration lines?
144 bool HasTextDecorationLines() const
145 { return !!(mBits & NS_STYLE_HAS_TEXT_DECORATION_LINES); }
147 // Whether this style context or any of its inline-level ancestors
148 // is directly contained by a ruby box? It is used to inlinize
149 // block-level descendants and suppress line breaks inside ruby.
150 bool IsInlineDescendantOfRuby() const
151 { return !!(mBits & NS_STYLE_IS_INLINE_DESCENDANT_OF_RUBY); }
153 // Does this style context represent the style for a pseudo-element or
154 // inherit data from such a style context? Whether this returns true
155 // is equivalent to whether it or any of its ancestors returns
156 // non-null for GetPseudo.
157 bool HasPseudoElementData() const
158 { return !!(mBits & NS_STYLE_HAS_PSEUDO_ELEMENT_DATA); }
160 // Is the only link whose visitedness is allowed to influence the
161 // style of the node this style context is for (which is that element
162 // or its nearest ancestor that is a link) visited?
163 bool RelevantLinkVisited() const
164 { return !!(mBits & NS_STYLE_RELEVANT_LINK_VISITED); }
166 // Is this a style context for a link?
167 bool IsLinkContext() const {
168 return
169 GetStyleIfVisited() && GetStyleIfVisited()->GetParent() == GetParent();
172 // Is this style context the GetStyleIfVisited() for some other style
173 // context?
174 bool IsStyleIfVisited() const
175 { return !!(mBits & NS_STYLE_IS_STYLE_IF_VISITED); }
177 // Tells this style context that it should return true from
178 // IsStyleIfVisited.
179 void SetIsStyleIfVisited()
180 { mBits |= NS_STYLE_IS_STYLE_IF_VISITED; }
182 // Return the style context whose style data should be used for the R,
183 // G, and B components of color, background-color, and border-*-color
184 // if RelevantLinkIsVisited().
186 // GetPseudo() and GetPseudoType() on this style context return the
187 // same as on |this|, and its depth in the tree (number of GetParent()
188 // calls until null is returned) is the same as |this|, since its
189 // parent is either |this|'s parent or |this|'s parent's
190 // style-if-visited.
192 // Structs on this context should never be examined without also
193 // examining the corresponding struct on |this|. Doing so will likely
194 // both (1) lead to a privacy leak and (2) lead to dynamic change bugs
195 // related to the Peek code in nsStyleContext::CalcStyleDifference.
196 nsStyleContext* GetStyleIfVisited() const
197 { return mStyleIfVisited; }
199 // To be called only from nsStyleSet.
200 void SetStyleIfVisited(already_AddRefed<nsStyleContext> aStyleIfVisited)
202 NS_ABORT_IF_FALSE(!IsStyleIfVisited(), "this context is not visited data");
203 NS_ASSERTION(!mStyleIfVisited, "should only be set once");
205 mStyleIfVisited = aStyleIfVisited;
207 NS_ABORT_IF_FALSE(mStyleIfVisited->IsStyleIfVisited(),
208 "other context is visited data");
209 NS_ABORT_IF_FALSE(!mStyleIfVisited->GetStyleIfVisited(),
210 "other context does not have visited data");
211 NS_ASSERTION(GetStyleIfVisited()->GetPseudo() == GetPseudo(),
212 "pseudo tag mismatch");
213 if (GetParent() && GetParent()->GetStyleIfVisited()) {
214 NS_ASSERTION(GetStyleIfVisited()->GetParent() ==
215 GetParent()->GetStyleIfVisited() ||
216 GetStyleIfVisited()->GetParent() == GetParent(),
217 "parent mismatch");
218 } else {
219 NS_ASSERTION(GetStyleIfVisited()->GetParent() == GetParent(),
220 "parent mismatch");
224 // Does this style context, or any of its descendants, have any style values
225 // that were computed based on this style context's grandparent style context
226 // or any of the grandparent's ancestors?
227 bool UsesGrandancestorStyle() const
228 { return !!(mBits & NS_STYLE_USES_GRANDANCESTOR_STYLE); }
230 // Is this style context shared with a sibling or cousin?
231 // (See nsStyleSet::GetContext.)
232 bool IsShared() const
233 { return !!(mBits & NS_STYLE_IS_SHARED); }
235 // Does this style context have any children that return true for
236 // UsesGrandancestorStyle()?
237 bool HasChildThatUsesGrandancestorStyle() const;
239 // Tell this style context to cache aStruct as the struct for aSID
240 void SetStyle(nsStyleStructID aSID, void* aStruct);
242 // Setters for inherit structs only, since rulenode only sets those eagerly.
243 #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_) \
244 void SetStyle##name_ (nsStyle##name_ * aStruct) { \
245 void *& slot = \
246 mCachedInheritedData.mStyleStructs[eStyleStruct_##name_]; \
247 NS_ASSERTION(!slot || \
248 (mBits & \
249 nsCachedStyleData::GetBitForSID(eStyleStruct_##name_)), \
250 "Going to leak styledata"); \
251 slot = aStruct; \
253 #define STYLE_STRUCT_RESET(name_, checkdata_cb_) /* nothing */
254 #include "nsStyleStructList.h"
255 #undef STYLE_STRUCT_RESET
256 #undef STYLE_STRUCT_INHERITED
259 * Returns whether this style context and aOther both have the same
260 * cached style struct pointer for a given style struct.
262 bool HasSameCachedStyleData(nsStyleContext* aOther, nsStyleStructID aSID);
265 * Returns whether this style context has cached, inherited style data for a
266 * given style struct.
268 bool HasCachedInheritedStyleData(nsStyleStructID aSID)
269 { return mBits & nsCachedStyleData::GetBitForSID(aSID); }
271 nsRuleNode* RuleNode() { return mRuleNode; }
272 void AddStyleBit(const uint64_t& aBit) { mBits |= aBit; }
275 * Mark this style context's rule node (and its ancestors) to prevent
276 * it from being garbage collected.
278 void Mark();
281 * Get the style data for a style struct. This is the most important
282 * member function of nsIStyleContext. It fills in a const pointer
283 * to a style data struct that is appropriate for the style context's
284 * frame. This struct may be shared with other contexts (either in
285 * the rule tree or the style context tree), so it should not be
286 * modified.
288 * This function will NOT return null (even when out of memory) when
289 * given a valid style struct ID, so the result does not need to be
290 * null-checked.
292 * The typesafe functions below are preferred to the use of this
293 * function, both because they're easier to read and because they're
294 * faster.
296 const void* NS_FASTCALL StyleData(nsStyleStructID aSID);
299 * Define typesafe getter functions for each style struct by
300 * preprocessing the list of style structs. These functions are the
301 * preferred way to get style data. The macro creates functions like:
302 * const nsStyleBorder* StyleBorder();
303 * const nsStyleColor* StyleColor();
305 #define STYLE_STRUCT(name_, checkdata_cb_) \
306 const nsStyle##name_ * Style##name_() { \
307 return DoGetStyle##name_(true); \
309 #include "nsStyleStructList.h"
310 #undef STYLE_STRUCT
313 * PeekStyle* is like GetStyle* but doesn't trigger style
314 * computation if the data is not cached on either the style context
315 * or the rule node.
317 * Perhaps this shouldn't be a public nsStyleContext API.
319 #define STYLE_STRUCT(name_, checkdata_cb_) \
320 const nsStyle##name_ * PeekStyle##name_() { \
321 return DoGetStyle##name_(false); \
323 #include "nsStyleStructList.h"
324 #undef STYLE_STRUCT
326 void* GetUniqueStyleData(const nsStyleStructID& aSID);
329 * Compute the style changes needed during restyling when this style
330 * context is being replaced by aOther. (This is nonsymmetric since
331 * we optimize by skipping comparison for styles that have never been
332 * requested.)
334 * This method returns a change hint (see nsChangeHint.h). All change
335 * hints apply to the frame and its later continuations or ib-split
336 * siblings. Most (all of those except the "NotHandledForDescendants"
337 * hints) also apply to all descendants. The caller must pass in any
338 * non-inherited hints that resulted from the parent style context's
339 * style change. The caller *may* pass more hints than needed, but
340 * must not pass less than needed; therefore if the caller doesn't
341 * know, the caller should pass
342 * nsChangeHint_Hints_NotHandledForDescendants.
344 * aEqualStructs must not be null. Into it will be stored a bitfield
345 * representing which structs were compared to be non-equal.
347 nsChangeHint CalcStyleDifference(nsStyleContext* aOther,
348 nsChangeHint aParentHintsNotHandledForDescendants,
349 uint32_t* aEqualStructs);
352 * Get a color that depends on link-visitedness using this and
353 * this->GetStyleIfVisited().
355 * aProperty must be a color-valued property that StyleAnimationValue
356 * knows how to extract. It must also be a property that we know to
357 * do change handling for in nsStyleContext::CalcDifference.
359 * Note that if aProperty is eCSSProperty_border_*_color, this
360 * function handles -moz-use-text-color.
362 nscolor GetVisitedDependentColor(nsCSSProperty aProperty);
365 * aColors should be a two element array of nscolor in which the first
366 * color is the unvisited color and the second is the visited color.
368 * Combine the R, G, and B components of whichever of aColors should
369 * be used based on aLinkIsVisited with the A component of aColors[0].
371 static nscolor CombineVisitedColors(nscolor *aColors,
372 bool aLinkIsVisited);
375 * Start the background image loads for this style context.
377 void StartBackgroundImageLoads() {
378 // Just get our background struct; that should do the trick
379 StyleBackground();
383 * Moves this style context to a new parent.
385 * This function violates style context tree immutability, and
386 * is a very low-level function and should only be used after verifying
387 * many conditions that make it safe to call.
389 void MoveTo(nsStyleContext* aNewParent);
392 * Swaps owned style struct pointers between this and aNewContext, on
393 * the assumption that aNewContext is the new style context for a frame
394 * and this is the old one. aStructs indicates which structs to consider
395 * swapping; only those which are owned in both this and aNewContext
396 * will be swapped.
398 * Additionally, if there are identical struct pointers for one of the
399 * structs indicated by aStructs, and it is not an owned struct on this,
400 * then the cached struct slot on this will be set to null. If the struct
401 * has been swapped on an ancestor, this style context (being the old one)
402 * will be left caching the struct pointer on the new ancestor, despite
403 * inheriting from the old ancestor. This is not normally a problem, as
404 * this style context will usually be destroyed by being released at the
405 * end of ElementRestyler::Restyle; but for style contexts held on to outside
406 * of the frame, we need to clear out the cached pointer so that if we need
407 * it again we'll re-fetch it from the new ancestor.
409 void SwapStyleData(nsStyleContext* aNewContext, uint32_t aStructs);
412 * On each descendant of this style context, clears out any cached inherited
413 * structs indicated in aStructs.
415 void ClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs);
417 #ifdef DEBUG
418 void List(FILE* out, int32_t aIndent, bool aListDescendants = true);
419 static void AssertStyleStructMaxDifferenceValid();
420 static const char* StructName(nsStyleStructID aSID);
421 static bool LookupStruct(const nsACString& aName, nsStyleStructID& aResult);
422 #endif
424 #ifdef RESTYLE_LOGGING
425 nsCString GetCachedStyleDataAsString(uint32_t aStructs);
426 void LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs);
427 int32_t& LoggingDepth();
428 #endif
430 private:
431 // Private destructor, to discourage deletion outside of Release():
432 ~nsStyleContext();
434 void AddChild(nsStyleContext* aChild);
435 void RemoveChild(nsStyleContext* aChild);
437 void ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup);
439 // Helper function for HasChildThatUsesGrandancestorStyle.
440 static bool ListContainsStyleContextThatUsesGrandancestorStyle(
441 const nsStyleContext* aHead);
443 // Helper function that GetStyleData and GetUniqueStyleData use. Only
444 // returns the structs we cache ourselves; never consults the ruletree.
445 inline const void* GetCachedStyleData(nsStyleStructID aSID);
447 // Helper functions for GetStyle* and PeekStyle*
448 #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_) \
449 const nsStyle##name_ * DoGetStyle##name_(bool aComputeData) { \
450 const nsStyle##name_ * cachedData = \
451 static_cast<nsStyle##name_*>( \
452 mCachedInheritedData.mStyleStructs[eStyleStruct_##name_]); \
453 if (cachedData) /* Have it cached already, yay */ \
454 return cachedData; \
455 /* Have the rulenode deal */ \
456 return mRuleNode->GetStyle##name_(this, aComputeData); \
458 #define STYLE_STRUCT_RESET(name_, checkdata_cb_) \
459 const nsStyle##name_ * DoGetStyle##name_(bool aComputeData) { \
460 const nsStyle##name_ * cachedData = mCachedResetData \
461 ? static_cast<nsStyle##name_*>( \
462 mCachedResetData->mStyleStructs[eStyleStruct_##name_]) \
463 : nullptr; \
464 if (cachedData) /* Have it cached already, yay */ \
465 return cachedData; \
466 /* Have the rulenode deal */ \
467 return mRuleNode->GetStyle##name_(this, aComputeData); \
469 #include "nsStyleStructList.h"
470 #undef STYLE_STRUCT_RESET
471 #undef STYLE_STRUCT_INHERITED
473 // Helper for ClearCachedInheritedStyleDataOnDescendants.
474 void DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs);
476 #ifdef DEBUG
477 void AssertStructsNotUsedElsewhere(nsStyleContext* aDestroyingContext,
478 int32_t aLevels) const;
479 #endif
481 #ifdef RESTYLE_LOGGING
482 void LogStyleContextTree(bool aFirst, uint32_t aStructs);
484 // This only gets called under call trees where we've already checked
485 // that PresContext()->RestyleManager()->ShouldLogRestyle() returned true.
486 // It exists here just to satisfy LOG_RESTYLE's expectations.
487 bool ShouldLogRestyle() { return true; }
488 #endif
490 nsStyleContext* mParent; // STRONG
492 // Children are kept in two circularly-linked lists. The list anchor
493 // is not part of the list (null for empty), and we point to the first
494 // child.
495 // mEmptyChild for children whose rule node is the root rule node, and
496 // mChild for other children. The order of children is not
497 // meaningful.
498 nsStyleContext* mChild;
499 nsStyleContext* mEmptyChild;
500 nsStyleContext* mPrevSibling;
501 nsStyleContext* mNextSibling;
503 // Style to be used instead for the R, G, and B components of color,
504 // background-color, and border-*-color if the nearest ancestor link
505 // element is visited (see RelevantLinkVisited()).
506 nsRefPtr<nsStyleContext> mStyleIfVisited;
508 // If this style context is for a pseudo-element or anonymous box,
509 // the relevant atom.
510 nsCOMPtr<nsIAtom> mPseudoTag;
512 // The rule node is the node in the lexicographic tree of rule nodes
513 // (the "rule tree") that indicates which style rules are used to
514 // compute the style data, and in what cascading order. The least
515 // specific rule matched is the one whose rule node is a child of the
516 // root of the rule tree, and the most specific rule matched is the
517 // |mRule| member of |mRuleNode|.
518 nsRuleNode* const mRuleNode;
520 // mCachedInheritedData and mCachedResetData point to both structs that
521 // are owned by this style context and structs that are owned by one of
522 // this style context's ancestors (which are indirectly owned since this
523 // style context owns a reference to its parent). If the bit in |mBits|
524 // is set for a struct, that means that the pointer for that struct is
525 // owned by an ancestor or by mRuleNode rather than by this style context.
526 // Since style contexts typically have some inherited data but only sometimes
527 // have reset data, we always allocate the mCachedInheritedData, but only
528 // sometimes allocate the mCachedResetData.
529 nsResetStyleData* mCachedResetData; // Cached reset style data.
530 nsInheritedStyleData mCachedInheritedData; // Cached inherited style data
531 uint64_t mBits; // Which structs are inherited from the
532 // parent context or owned by mRuleNode.
533 uint32_t mRefCnt;
535 #ifdef DEBUG
536 uint32_t mFrameRefCnt; // number of frames that use this
537 // as their style context
538 #endif
541 already_AddRefed<nsStyleContext>
542 NS_NewStyleContext(nsStyleContext* aParentContext,
543 nsIAtom* aPseudoTag,
544 nsCSSPseudoElements::Type aPseudoType,
545 nsRuleNode* aRuleNode,
546 bool aSkipParentDisplayBasedStyleFixup);
547 #endif