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
4 : *
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/
9 : *
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.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
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.
21 : *
22 : * Contributor(s):
23 : * David Hyatt <hyatt@netscape.com>
24 : * Pierre Phaneuf <pp@ludusdesign.com>
25 : *
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.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : /* the interface (to internal code) for retrieving computed style data */
41 :
42 : #ifndef _nsStyleContext_h_
43 : #define _nsStyleContext_h_
44 :
45 : #include "nsRuleNode.h"
46 : #include "nsIAtom.h"
47 : #include "nsCSSPseudoElements.h"
48 :
49 : class nsPresContext;
50 :
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).
57 : *
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.
63 : *
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.
71 : */
72 :
73 : class nsStyleContext
74 : {
75 : public:
76 : nsStyleContext(nsStyleContext* aParent, nsIAtom* aPseudoTag,
77 : nsCSSPseudoElements::Type aPseudoType,
78 : nsRuleNode* aRuleNode, nsPresContext* aPresContext);
79 : ~nsStyleContext();
80 :
81 : void* operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW;
82 : void Destroy();
83 :
84 0 : nsrefcnt AddRef() {
85 0 : if (mRefCnt == PR_UINT32_MAX) {
86 0 : NS_WARNING("refcount overflow, leaking object");
87 0 : return mRefCnt;
88 : }
89 0 : ++mRefCnt;
90 0 : NS_LOG_ADDREF(this, mRefCnt, "nsStyleContext", sizeof(nsStyleContext));
91 0 : return mRefCnt;
92 : }
93 :
94 0 : nsrefcnt Release() {
95 0 : if (mRefCnt == PR_UINT32_MAX) {
96 0 : NS_WARNING("refcount overflow, leaking object");
97 0 : return mRefCnt;
98 : }
99 0 : --mRefCnt;
100 0 : NS_LOG_RELEASE(this, mRefCnt, "nsStyleContext");
101 0 : if (mRefCnt == 0) {
102 0 : Destroy();
103 0 : return 0;
104 : }
105 0 : return mRefCnt;
106 : }
107 :
108 0 : nsPresContext* PresContext() const { return mRuleNode->GetPresContext(); }
109 :
110 0 : nsStyleContext* GetParent() const { return mParent; }
111 :
112 : nsIAtom* GetPseudo() const { return mPseudoTag; }
113 : nsCSSPseudoElements::Type GetPseudoType() const {
114 : return static_cast<nsCSSPseudoElements::Type>(mBits >>
115 : NS_STYLE_CONTEXT_TYPE_SHIFT);
116 : }
117 :
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 : bool aRelevantLinkVisited);
129 :
130 : // Does this style context or any of its ancestors have text
131 : // decoration lines?
132 : bool HasTextDecorationLines() const
133 : { return !!(mBits & NS_STYLE_HAS_TEXT_DECORATION_LINES); }
134 :
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 : bool HasPseudoElementData() const
140 : { return !!(mBits & NS_STYLE_HAS_PSEUDO_ELEMENT_DATA); }
141 :
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 : bool RelevantLinkVisited() const
146 : { return !!(mBits & NS_STYLE_RELEVANT_LINK_VISITED); }
147 :
148 : // Is this a style context for a link?
149 : bool IsLinkContext() const {
150 : return
151 : GetStyleIfVisited() && GetStyleIfVisited()->GetParent() == GetParent();
152 : }
153 :
154 : // Is this style context the GetStyleIfVisited() for some other style
155 : // context?
156 : bool IsStyleIfVisited() const
157 : { return !!(mBits & NS_STYLE_IS_STYLE_IF_VISITED); }
158 :
159 : // Tells this style context that it should return true from
160 : // IsStyleIfVisited.
161 : void SetIsStyleIfVisited()
162 : { mBits |= NS_STYLE_IS_STYLE_IF_VISITED; }
163 :
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().
167 : //
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.
173 : //
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; }
180 :
181 : // To be called only from nsStyleSet.
182 : void SetStyleIfVisited(already_AddRefed<nsStyleContext> aStyleIfVisited)
183 : {
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;
191 :
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");
202 : }
203 : }
204 :
205 : // Tell this style context to cache aStruct as the struct for aSID
206 : void SetStyle(nsStyleStructID aSID, void* aStruct);
207 :
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 : void *& slot = \
212 : mCachedInheritedData.mStyleStructs[eStyleStruct_##name_]; \
213 : NS_ASSERTION(!slot || \
214 : (mBits & \
215 : nsCachedStyleData::GetBitForSID(eStyleStruct_##name_)), \
216 : "Going to leak styledata"); \
217 : slot = aStruct; \
218 : }
219 : #define STYLE_STRUCT_RESET(name_, checkdata_cb_, ctor_args_) /* nothing */
220 : #include "nsStyleStructList.h"
221 : #undef STYLE_STRUCT_RESET
222 : #undef STYLE_STRUCT_INHERITED
223 :
224 0 : nsRuleNode* GetRuleNode() { return mRuleNode; }
225 : void AddStyleBit(const PRUint32& aBit) { mBits |= aBit; }
226 :
227 : /*
228 : * Mark this style context's rule node (and its ancestors) to prevent
229 : * it from being garbage collected.
230 : */
231 : void Mark();
232 :
233 : /*
234 : * Get the style data for a style struct. This is the most important
235 : * member function of nsIStyleContext. It fills in a const pointer
236 : * to a style data struct that is appropriate for the style context's
237 : * frame. This struct may be shared with other contexts (either in
238 : * the rule tree or the style context tree), so it should not be
239 : * modified.
240 : *
241 : * This function will NOT return null (even when out of memory) when
242 : * given a valid style struct ID, so the result does not need to be
243 : * null-checked.
244 : *
245 : * The typesafe functions below are preferred to the use of this
246 : * function, bothe because they're easier to read and because they're
247 : * faster.
248 : */
249 : const void* NS_FASTCALL GetStyleData(nsStyleStructID aSID);
250 :
251 : /**
252 : * Define typesafe getter functions for each style struct by
253 : * preprocessing the list of style structs. These functions are the
254 : * preferred way to get style data. The macro creates functions like:
255 : * const nsStyleBorder* GetStyleBorder();
256 : * const nsStyleColor* GetStyleColor();
257 : */
258 : #define STYLE_STRUCT(name_, checkdata_cb_, ctor_args_) \
259 : const nsStyle##name_ * GetStyle##name_() { \
260 : return DoGetStyle##name_(true); \
261 : }
262 : #include "nsStyleStructList.h"
263 : #undef STYLE_STRUCT
264 :
265 : /**
266 : * PeekStyle* is like GetStyle* but doesn't trigger style
267 : * computation if the data is not cached on either the style context
268 : * or the rule node.
269 : *
270 : * Perhaps this shouldn't be a public nsStyleContext API.
271 : */
272 : #define STYLE_STRUCT(name_, checkdata_cb_, ctor_args_) \
273 : const nsStyle##name_ * PeekStyle##name_() { \
274 : return DoGetStyle##name_(false); \
275 : }
276 : #include "nsStyleStructList.h"
277 : #undef STYLE_STRUCT
278 :
279 : void* GetUniqueStyleData(const nsStyleStructID& aSID);
280 :
281 : nsChangeHint CalcStyleDifference(nsStyleContext* aOther);
282 :
283 : /**
284 : * Get a color that depends on link-visitedness using this and
285 : * this->GetStyleIfVisited().
286 : *
287 : * aProperty must be a color-valued property that nsStyleAnimation
288 : * knows how to extract. It must also be a property that we know to
289 : * do change handling for in nsStyleContext::CalcDifference.
290 : *
291 : * Note that if aProperty is eCSSProperty_border_*_color, this
292 : * function handles -moz-use-text-color.
293 : */
294 : nscolor GetVisitedDependentColor(nsCSSProperty aProperty);
295 :
296 : /**
297 : * aColors should be a two element array of nscolor in which the first
298 : * color is the unvisited color and the second is the visited color.
299 : *
300 : * Combine the R, G, and B components of whichever of aColors should
301 : * be used based on aLinkIsVisited with the A component of aColors[0].
302 : */
303 : static nscolor CombineVisitedColors(nscolor *aColors,
304 : bool aLinkIsVisited);
305 :
306 : /**
307 : * Allocate a chunk of memory that is scoped to the lifetime of this
308 : * style context, i.e., memory that will automatically be freed when
309 : * this style context is destroyed. This is intended for allocations
310 : * that are stored on this style context or its style structs. (Use
311 : * on style structs is fine since any style context to which this
312 : * context's style structs are shared will be a descendant of this
313 : * style context and thus keep it alive.)
314 : *
315 : * This currently allocates the memory out of the pres shell arena.
316 : *
317 : * It would be relatively straightforward to write a Free method
318 : * for the underlying implementation, but we don't need it (or the
319 : * overhead of making a doubly-linked list or other structure to
320 : * support it).
321 : *
322 : * WARNING: Memory allocated using this method cannot be stored in the
323 : * rule tree, since rule nodes may outlive the style context.
324 : */
325 : void* Alloc(size_t aSize);
326 :
327 : /**
328 : * Start the background image loads for this style context.
329 : */
330 : void StartBackgroundImageLoads() {
331 : // Just get our background struct; that should do the trick
332 : GetStyleBackground();
333 : }
334 :
335 : #ifdef DEBUG
336 : void List(FILE* out, PRInt32 aIndent);
337 : #endif
338 :
339 : protected:
340 : void AddChild(nsStyleContext* aChild);
341 : void RemoveChild(nsStyleContext* aChild);
342 :
343 : void ApplyStyleFixups(nsPresContext* aPresContext);
344 :
345 : void FreeAllocations(nsPresContext* aPresContext);
346 :
347 : // Helper function that GetStyleData and GetUniqueStyleData use. Only
348 : // returns the structs we cache ourselves; never consults the ruletree.
349 : inline const void* GetCachedStyleData(nsStyleStructID aSID);
350 :
351 : // Helper functions for GetStyle* and PeekStyle*
352 : #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_, ctor_args_) \
353 : const nsStyle##name_ * DoGetStyle##name_(bool aComputeData) { \
354 : const nsStyle##name_ * cachedData = \
355 : static_cast<nsStyle##name_*>( \
356 : mCachedInheritedData.mStyleStructs[eStyleStruct_##name_]); \
357 : if (cachedData) /* Have it cached already, yay */ \
358 : return cachedData; \
359 : /* Have the rulenode deal */ \
360 : return mRuleNode->GetStyle##name_(this, aComputeData); \
361 : }
362 : #define STYLE_STRUCT_RESET(name_, checkdata_cb_, ctor_args_) \
363 : const nsStyle##name_ * DoGetStyle##name_(bool aComputeData) { \
364 : const nsStyle##name_ * cachedData = mCachedResetData \
365 : ? static_cast<nsStyle##name_*>( \
366 : mCachedResetData->mStyleStructs[eStyleStruct_##name_]) \
367 : : nsnull; \
368 : if (cachedData) /* Have it cached already, yay */ \
369 : return cachedData; \
370 : /* Have the rulenode deal */ \
371 : return mRuleNode->GetStyle##name_(this, aComputeData); \
372 : }
373 : #include "nsStyleStructList.h"
374 : #undef STYLE_STRUCT_RESET
375 : #undef STYLE_STRUCT_INHERITED
376 :
377 : nsStyleContext* const mParent; // STRONG
378 :
379 : // Children are kept in two circularly-linked lists. The list anchor
380 : // is not part of the list (null for empty), and we point to the first
381 : // child.
382 : // mEmptyChild for children whose rule node is the root rule node, and
383 : // mChild for other children. The order of children is not
384 : // meaningful.
385 : nsStyleContext* mChild;
386 : nsStyleContext* mEmptyChild;
387 : nsStyleContext* mPrevSibling;
388 : nsStyleContext* mNextSibling;
389 :
390 : // Style to be used instead for the R, G, and B components of color,
391 : // background-color, and border-*-color if the nearest ancestor link
392 : // element is visited (see RelevantLinkVisited()).
393 : nsRefPtr<nsStyleContext> mStyleIfVisited;
394 :
395 : // If this style context is for a pseudo-element or anonymous box,
396 : // the relevant atom.
397 : nsCOMPtr<nsIAtom> mPseudoTag;
398 :
399 : // The rule node is the node in the lexicographic tree of rule nodes
400 : // (the "rule tree") that indicates which style rules are used to
401 : // compute the style data, and in what cascading order. The least
402 : // specific rule matched is the one whose rule node is a child of the
403 : // root of the rule tree, and the most specific rule matched is the
404 : // |mRule| member of |mRuleNode|.
405 : nsRuleNode* const mRuleNode;
406 :
407 : // Private to nsStyleContext::Alloc and FreeAllocations.
408 : struct AllocationHeader {
409 : AllocationHeader* mNext;
410 : size_t mSize;
411 :
412 : void* mStorageStart; // ensure the storage is at least pointer-aligned
413 : };
414 : AllocationHeader* mAllocations;
415 :
416 : // mCachedInheritedData and mCachedResetData point to both structs that
417 : // are owned by this style context and structs that are owned by one of
418 : // this style context's ancestors (which are indirectly owned since this
419 : // style context owns a reference to its parent). If the bit in |mBits|
420 : // is set for a struct, that means that the pointer for that struct is
421 : // owned by an ancestor or by mRuleNode rather than by this style context.
422 : // Since style contexts typically have some inherited data but only sometimes
423 : // have reset data, we always allocate the mCachedInheritedData, but only
424 : // sometimes allocate the mCachedResetData.
425 : nsResetStyleData* mCachedResetData; // Cached reset style data.
426 : nsInheritedStyleData mCachedInheritedData; // Cached inherited style data
427 : PRUint32 mBits; // Which structs are inherited from the
428 : // parent context or owned by mRuleNode.
429 : PRUint32 mRefCnt;
430 : };
431 :
432 : already_AddRefed<nsStyleContext>
433 : NS_NewStyleContext(nsStyleContext* aParentContext,
434 : nsIAtom* aPseudoTag,
435 : nsCSSPseudoElements::Type aPseudoType,
436 : nsRuleNode* aRuleNode,
437 : nsPresContext* aPresContext);
438 : #endif
|