Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / layout / style / nsStyleContext.h
blobea7a70345606c6ddccea959fa4c8efa708c90087
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * David Hyatt <hyatt@netscape.com>
24 * Pierre Phaneuf <pp@ludusdesign.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 /* the interface (to internal code) for retrieving computed style data */
42 #ifndef _nsStyleContext_h_
43 #define _nsStyleContext_h_
45 #include "nsRuleNode.h"
46 #include "nsIAtom.h"
47 #include "nsCSSPseudoElements.h"
49 class nsPresContext;
51 /**
52 * An nsStyleContext represents the computed style data for an element.
53 * The computed style data are stored in a set of structs (see
54 * nsStyleStruct.h) that are cached either on the style context or in
55 * the rule tree (see nsRuleNode.h for a description of this caching and
56 * how the cached structs are shared).
58 * Since the data in |nsIStyleRule|s and |nsRuleNode|s are immutable
59 * (with a few exceptions, like system color changes), the data in an
60 * nsStyleContext are also immutable (with the additional exception of
61 * GetUniqueStyleData). When style data change,
62 * nsFrameManager::ReResolveStyleContext creates a new style context.
64 * Style contexts are reference counted. References are generally held
65 * by:
66 * 1. the |nsIFrame|s that are using the style context and
67 * 2. any *child* style contexts (this might be the reverse of
68 * expectation, but it makes sense in this case)
69 * Style contexts participate in the mark phase of rule node garbage
70 * collection.
73 class nsStyleContext
75 public:
76 nsStyleContext(nsStyleContext* aParent, nsIAtom* aPseudoTag,
77 nsCSSPseudoElements::Type aPseudoType,
78 nsRuleNode* aRuleNode, nsPresContext* aPresContext);
79 ~nsStyleContext();
81 void* operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW;
82 void Destroy();
84 nsrefcnt AddRef() {
85 if (mRefCnt == PR_UINT32_MAX) {
86 NS_WARNING("refcount overflow, leaking object");
87 return mRefCnt;
89 ++mRefCnt;
90 NS_LOG_ADDREF(this, mRefCnt, "nsStyleContext", sizeof(nsStyleContext));
91 return mRefCnt;
94 nsrefcnt Release() {
95 if (mRefCnt == PR_UINT32_MAX) {
96 NS_WARNING("refcount overflow, leaking object");
97 return mRefCnt;
99 --mRefCnt;
100 NS_LOG_RELEASE(this, mRefCnt, "nsStyleContext");
101 if (mRefCnt == 0) {
102 Destroy();
103 return 0;
105 return mRefCnt;
108 nsPresContext* PresContext() const { return mRuleNode->GetPresContext(); }
110 nsStyleContext* GetParent() const { return mParent; }
112 nsIAtom* GetPseudo() const { return mPseudoTag; }
113 nsCSSPseudoElements::Type GetPseudoType() const {
114 return static_cast<nsCSSPseudoElements::Type>(mBits >>
115 NS_STYLE_CONTEXT_TYPE_SHIFT);
118 // Find, if it already exists *and is easily findable* (i.e., near the
119 // start of the child list), a style context whose:
120 // * GetPseudo() matches aPseudoTag
121 // * GetRuleNode() matches aRules
122 // * !GetStyleIfVisited() == !aRulesIfVisited, and, if they're
123 // non-null, GetStyleIfVisited()->GetRuleNode() == aRulesIfVisited
124 // * RelevantLinkVisited() == aRelevantLinkVisited
125 already_AddRefed<nsStyleContext>
126 FindChildWithRules(const nsIAtom* aPseudoTag, nsRuleNode* aRules,
127 nsRuleNode* aRulesIfVisited,
128 PRBool aRelevantLinkVisited);
130 // Does this style context or any of its ancestors have text
131 // decorations?
132 PRBool HasTextDecorations() const
133 { return !!(mBits & NS_STYLE_HAS_TEXT_DECORATIONS); }
135 // Does this style context represent the style for a pseudo-element or
136 // inherit data from such a style context? Whether this returns true
137 // is equivalent to whether it or any of its ancestors returns
138 // non-null for GetPseudo.
139 PRBool HasPseudoElementData() const
140 { return !!(mBits & NS_STYLE_HAS_PSEUDO_ELEMENT_DATA); }
142 // Is the only link whose visitedness is allowed to influence the
143 // style of the node this style context is for (which is that element
144 // or its nearest ancestor that is a link) visited?
145 PRBool RelevantLinkVisited() const
146 { return !!(mBits & NS_STYLE_RELEVANT_LINK_VISITED); }
148 // Is this a style context for a link?
149 PRBool IsLinkContext() const {
150 return
151 GetStyleIfVisited() && GetStyleIfVisited()->GetParent() == GetParent();
154 // Is this style context the GetStyleIfVisited() for some other style
155 // context?
156 PRBool IsStyleIfVisited() const
157 { return !!(mBits & NS_STYLE_IS_STYLE_IF_VISITED); }
159 // Tells this style context that it should return true from
160 // IsStyleIfVisited.
161 void SetIsStyleIfVisited()
162 { mBits |= NS_STYLE_IS_STYLE_IF_VISITED; }
164 // Return the style context whose style data should be used for the R,
165 // G, and B components of color, background-color, and border-*-color
166 // if RelevantLinkIsVisited().
168 // GetPseudo() and GetPseudoType() on this style context return the
169 // same as on |this|, and its depth in the tree (number of GetParent()
170 // calls until null is returned) is the same as |this|, since its
171 // parent is either |this|'s parent or |this|'s parent's
172 // style-if-visited.
174 // Structs on this context should never be examined without also
175 // examining the corresponding struct on |this|. Doing so will likely
176 // both (1) lead to a privacy leak and (2) lead to dynamic change bugs
177 // related to the Peek code in nsStyleContext::CalcStyleDifference.
178 nsStyleContext* GetStyleIfVisited() const
179 { return mStyleIfVisited; }
181 // To be called only from nsStyleSet.
182 void SetStyleIfVisited(already_AddRefed<nsStyleContext> aStyleIfVisited)
184 NS_ABORT_IF_FALSE(!IsStyleIfVisited(), "this context is not visited data");
185 NS_ABORT_IF_FALSE(aStyleIfVisited.get()->IsStyleIfVisited(),
186 "other context is visited data");
187 NS_ABORT_IF_FALSE(!aStyleIfVisited.get()->GetStyleIfVisited(),
188 "other context does not have visited data");
189 NS_ASSERTION(!mStyleIfVisited, "should only be set once");
190 mStyleIfVisited = aStyleIfVisited;
192 NS_ASSERTION(GetStyleIfVisited()->GetPseudo() == GetPseudo(),
193 "pseudo tag mismatch");
194 if (GetParent() && GetParent()->GetStyleIfVisited()) {
195 NS_ASSERTION(GetStyleIfVisited()->GetParent() ==
196 GetParent()->GetStyleIfVisited() ||
197 GetStyleIfVisited()->GetParent() == GetParent(),
198 "parent mismatch");
199 } else {
200 NS_ASSERTION(GetStyleIfVisited()->GetParent() == GetParent(),
201 "parent mismatch");
205 // Tell this style context to cache aStruct as the struct for aSID
206 void SetStyle(nsStyleStructID aSID, void* aStruct);
208 // Setters for inherit structs only, since rulenode only sets those eagerly.
209 #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_, ctor_args_) \
210 void SetStyle##name_ (nsStyle##name_ * aStruct) { \
211 NS_ASSERTION(!mCachedInheritedData.m##name_##Data || \
212 (mBits & \
213 nsCachedStyleData::GetBitForSID(eStyleStruct_##name_)), \
214 "Going to leak styledata"); \
215 mCachedInheritedData.m##name_##Data = aStruct; \
217 #define STYLE_STRUCT_RESET(name_, checkdata_cb_, ctor_args_) /* nothing */
218 #include "nsStyleStructList.h"
219 #undef STYLE_STRUCT_RESET
220 #undef STYLE_STRUCT_INHERITED
222 nsRuleNode* GetRuleNode() { return mRuleNode; }
223 void AddStyleBit(const PRUint32& aBit) { mBits |= aBit; }
226 * Mark this style context's rule node (and its ancestors) to prevent
227 * it from being garbage collected.
229 void Mark();
232 * Get the style data for a style struct. This is the most important
233 * member function of nsIStyleContext. It fills in a const pointer
234 * to a style data struct that is appropriate for the style context's
235 * frame. This struct may be shared with other contexts (either in
236 * the rule tree or the style context tree), so it should not be
237 * modified.
239 * This function will NOT return null (even when out of memory) when
240 * given a valid style struct ID, so the result does not need to be
241 * null-checked.
243 * The typesafe functions below are preferred to the use of this
244 * function, bothe because they're easier to read and because they're
245 * faster.
247 const void* NS_FASTCALL GetStyleData(nsStyleStructID aSID);
250 * Define typesafe getter functions for each style struct by
251 * preprocessing the list of style structs. These functions are the
252 * preferred way to get style data. The macro creates functions like:
253 * const nsStyleBorder* GetStyleBorder();
254 * const nsStyleColor* GetStyleColor();
256 #define STYLE_STRUCT(name_, checkdata_cb_, ctor_args_) \
257 const nsStyle##name_ * GetStyle##name_() { \
258 return DoGetStyle##name_(PR_TRUE); \
260 #include "nsStyleStructList.h"
261 #undef STYLE_STRUCT
264 * PeekStyle* is like GetStyle* but doesn't trigger style
265 * computation if the data is not cached on either the style context
266 * or the rule node.
268 * Perhaps this shouldn't be a public nsStyleContext API.
270 #define STYLE_STRUCT(name_, checkdata_cb_, ctor_args_) \
271 const nsStyle##name_ * PeekStyle##name_() { \
272 return DoGetStyle##name_(PR_FALSE); \
274 #include "nsStyleStructList.h"
275 #undef STYLE_STRUCT
277 void* GetUniqueStyleData(const nsStyleStructID& aSID);
279 nsChangeHint CalcStyleDifference(nsStyleContext* aOther);
282 * Get a color that depends on link-visitedness using this and
283 * this->GetStyleIfVisited().
285 * aProperty must be a color-valued property that nsStyleAnimation
286 * knows how to extract. It must also be a property that we know to
287 * do change handling for in nsStyleContext::CalcDifference.
289 * Note that if aProperty is eCSSProperty_border_*_color, this
290 * function handles -moz-use-text-color.
292 nscolor GetVisitedDependentColor(nsCSSProperty aProperty);
295 * aColors should be a two element array of nscolor in which the first
296 * color is the unvisited color and the second is the visited color.
298 * Combine the R, G, and B components of whichever of aColors should
299 * be used based on aLinkIsVisited with the A component of aColors[0].
301 static nscolor CombineVisitedColors(nscolor *aColors,
302 PRBool aLinkIsVisited);
305 * Allocate a chunk of memory that is scoped to the lifetime of this
306 * style context, i.e., memory that will automatically be freed when
307 * this style context is destroyed. This is intended for allocations
308 * that are stored on this style context or its style structs. (Use
309 * on style structs is fine since any style context to which this
310 * context's style structs are shared will be a descendant of this
311 * style context and thus keep it alive.)
313 * This currently allocates the memory out of the pres shell arena.
315 * It would be relatively straightforward to write a Free method
316 * for the underlying implementation, but we don't need it (or the
317 * overhead of making a doubly-linked list or other structure to
318 * support it).
320 * WARNING: Memory allocated using this method cannot be stored in the
321 * rule tree, since rule nodes may outlive the style context.
323 void* Alloc(size_t aSize);
326 * Start the background image loads for this style context.
328 void StartBackgroundImageLoads() {
329 // Just get our background struct; that should do the trick
330 GetStyleBackground();
333 #ifdef DEBUG
334 void List(FILE* out, PRInt32 aIndent);
335 #endif
337 protected:
338 void AddChild(nsStyleContext* aChild);
339 void RemoveChild(nsStyleContext* aChild);
341 void ApplyStyleFixups(nsPresContext* aPresContext);
343 void FreeAllocations(nsPresContext* aPresContext);
345 // Helper function that GetStyleData and GetUniqueStyleData use. Only
346 // returns the structs we cache ourselves; never consults the ruletree.
347 inline const void* GetCachedStyleData(nsStyleStructID aSID);
349 // Helper functions for GetStyle* and PeekStyle*
350 #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_, ctor_args_) \
351 const nsStyle##name_ * DoGetStyle##name_(PRBool aComputeData) { \
352 const nsStyle##name_ * cachedData = \
353 mCachedInheritedData.m##name_##Data; \
354 if (cachedData) /* Have it cached already, yay */ \
355 return cachedData; \
356 /* Have the rulenode deal */ \
357 return mRuleNode->GetStyle##name_(this, aComputeData); \
359 #define STYLE_STRUCT_RESET(name_, checkdata_cb_, ctor_args_) \
360 const nsStyle##name_ * DoGetStyle##name_(PRBool aComputeData) { \
361 const nsStyle##name_ * cachedData = \
362 mCachedResetData ? mCachedResetData->m##name_##Data : nsnull; \
363 if (cachedData) /* Have it cached already, yay */ \
364 return cachedData; \
365 /* Have the rulenode deal */ \
366 return mRuleNode->GetStyle##name_(this, aComputeData); \
368 #include "nsStyleStructList.h"
369 #undef STYLE_STRUCT_RESET
370 #undef STYLE_STRUCT_INHERITED
372 nsStyleContext* const mParent; // STRONG
374 // Children are kept in two circularly-linked lists. The list anchor
375 // is not part of the list (null for empty), and we point to the first
376 // child.
377 // mEmptyChild for children whose rule node is the root rule node, and
378 // mChild for other children. The order of children is not
379 // meaningful.
380 nsStyleContext* mChild;
381 nsStyleContext* mEmptyChild;
382 nsStyleContext* mPrevSibling;
383 nsStyleContext* mNextSibling;
385 // Style to be used instead for the R, G, and B components of color,
386 // background-color, and border-*-color if the nearest ancestor link
387 // element is visited (see RelevantLinkVisited()).
388 nsRefPtr<nsStyleContext> mStyleIfVisited;
390 // If this style context is for a pseudo-element or anonymous box,
391 // the relevant atom.
392 nsCOMPtr<nsIAtom> mPseudoTag;
394 // The rule node is the node in the lexicographic tree of rule nodes
395 // (the "rule tree") that indicates which style rules are used to
396 // compute the style data, and in what cascading order. The least
397 // specific rule matched is the one whose rule node is a child of the
398 // root of the rule tree, and the most specific rule matched is the
399 // |mRule| member of |mRuleNode|.
400 nsRuleNode* const mRuleNode;
402 // Private to nsStyleContext::Alloc and FreeAllocations.
403 struct AllocationHeader {
404 AllocationHeader* mNext;
405 size_t mSize;
407 void* mStorageStart; // ensure the storage is at least pointer-aligned
409 AllocationHeader* mAllocations;
411 // mCachedInheritedData and mCachedResetData point to both structs that
412 // are owned by this style context and structs that are owned by one of
413 // this style context's ancestors (which are indirectly owned since this
414 // style context owns a reference to its parent). If the bit in |mBits|
415 // is set for a struct, that means that the pointer for that struct is
416 // owned by an ancestor or by mRuleNode rather than by this style context.
417 // Since style contexts typically have some inherited data but only sometimes
418 // have reset data, we always allocate the mCachedInheritedData, but only
419 // sometimes allocate the mCachedResetData.
420 nsResetStyleData* mCachedResetData; // Cached reset style data.
421 nsInheritedStyleData mCachedInheritedData; // Cached inherited style data
422 PRUint32 mBits; // Which structs are inherited from the
423 // parent context or owned by mRuleNode.
424 PRUint32 mRefCnt;
427 already_AddRefed<nsStyleContext>
428 NS_NewStyleContext(nsStyleContext* aParentContext,
429 nsIAtom* aPseudoTag,
430 nsCSSPseudoElements::Type aPseudoType,
431 nsRuleNode* aRuleNode,
432 nsPresContext* aPresContext);
433 #endif