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
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.
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"
47 #include "nsCSSPseudoElements.h"
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
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
76 nsStyleContext(nsStyleContext
* aParent
, nsIAtom
* aPseudoTag
,
77 nsCSSPseudoElements::Type aPseudoType
,
78 nsRuleNode
* aRuleNode
, nsPresContext
* aPresContext
);
81 void* operator new(size_t sz
, nsPresContext
* aPresContext
) CPP_THROW_NEW
;
85 if (mRefCnt
== PR_UINT32_MAX
) {
86 NS_WARNING("refcount overflow, leaking object");
90 NS_LOG_ADDREF(this, mRefCnt
, "nsStyleContext", sizeof(nsStyleContext
));
95 if (mRefCnt
== PR_UINT32_MAX
) {
96 NS_WARNING("refcount overflow, leaking object");
100 NS_LOG_RELEASE(this, mRefCnt
, "nsStyleContext");
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
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 {
151 GetStyleIfVisited() && GetStyleIfVisited()->GetParent() == GetParent();
154 // Is this style context the GetStyleIfVisited() for some other style
156 PRBool
IsStyleIfVisited() const
157 { return !!(mBits
& NS_STYLE_IS_STYLE_IF_VISITED
); }
159 // Tells this style context that it should return true from
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
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(),
200 NS_ASSERTION(GetStyleIfVisited()->GetParent() == GetParent(),
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 || \
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.
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
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
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
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"
264 * PeekStyle* is like GetStyle* but doesn't trigger style
265 * computation if the data is not cached on either the style context
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"
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
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();
334 void List(FILE* out
, PRInt32 aIndent
);
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 */ \
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 */ \
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
377 // mEmptyChild for children whose rule node is the root rule node, and
378 // mChild for other children. The order of children is not
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
;
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.
427 already_AddRefed
<nsStyleContext
>
428 NS_NewStyleContext(nsStyleContext
* aParentContext
,
430 nsCSSPseudoElements::Type aPseudoType
,
431 nsRuleNode
* aRuleNode
,
432 nsPresContext
* aPresContext
);