layout/style/nsStyleContext.h

branch
TOR_BUG_9701
changeset 11
deefc01c0e14
equal deleted inserted replaced
-1:000000000000 0:e563d1e80908
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

mercurial