|
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 /* |
|
7 * data structures passed to nsIStyleRuleProcessor methods (to pull loop |
|
8 * invariant computations out of the loop) |
|
9 */ |
|
10 |
|
11 #ifndef nsRuleProcessorData_h_ |
|
12 #define nsRuleProcessorData_h_ |
|
13 |
|
14 #include "nsPresContext.h" // for nsCompatibility |
|
15 #include "nsString.h" |
|
16 #include "nsChangeHint.h" |
|
17 #include "nsCSSPseudoElements.h" |
|
18 #include "nsRuleWalker.h" |
|
19 #include "nsNthIndexCache.h" |
|
20 #include "nsILoadContext.h" |
|
21 #include "nsIDocument.h" |
|
22 #include "mozilla/AutoRestore.h" |
|
23 #include "mozilla/BloomFilter.h" |
|
24 #include "mozilla/EventStates.h" |
|
25 #include "mozilla/GuardObjects.h" |
|
26 |
|
27 class nsAttrValue; |
|
28 class nsIAtom; |
|
29 class nsIContent; |
|
30 class nsICSSPseudoComparator; |
|
31 class nsIStyleSheet; |
|
32 struct TreeMatchContext; |
|
33 |
|
34 /** |
|
35 * An AncestorFilter is used to keep track of ancestors so that we can |
|
36 * quickly tell that a particular selector is not relevant to a given |
|
37 * element. |
|
38 */ |
|
39 class MOZ_STACK_CLASS AncestorFilter { |
|
40 friend struct TreeMatchContext; |
|
41 public: |
|
42 /* Maintenance of our ancestor state */ |
|
43 void PushAncestor(mozilla::dom::Element *aElement); |
|
44 void PopAncestor(); |
|
45 |
|
46 /* Check whether we might have an ancestor matching one of the given |
|
47 atom hashes. |hashes| must have length hashListLength */ |
|
48 template<size_t hashListLength> |
|
49 bool MightHaveMatchingAncestor(const uint32_t* aHashes) const |
|
50 { |
|
51 MOZ_ASSERT(mFilter); |
|
52 for (size_t i = 0; i < hashListLength && aHashes[i]; ++i) { |
|
53 if (!mFilter->mightContain(aHashes[i])) { |
|
54 return false; |
|
55 } |
|
56 } |
|
57 |
|
58 return true; |
|
59 } |
|
60 |
|
61 bool HasFilter() const { return mFilter; } |
|
62 |
|
63 #ifdef DEBUG |
|
64 void AssertHasAllAncestors(mozilla::dom::Element *aElement) const; |
|
65 #endif |
|
66 |
|
67 private: |
|
68 // Using 2^12 slots makes the Bloom filter a nice round page in |
|
69 // size, so let's do that. We get a false positive rate of 1% or |
|
70 // less even with several hundred things in the filter. Note that |
|
71 // we allocate the filter lazily, because not all tree match |
|
72 // contexts can use one effectively. |
|
73 typedef mozilla::BloomFilter<12, nsIAtom> Filter; |
|
74 nsAutoPtr<Filter> mFilter; |
|
75 |
|
76 // Stack of indices to pop to. These are indices into mHashes. |
|
77 nsTArray<uint32_t> mPopTargets; |
|
78 |
|
79 // List of hashes; this is what we pop using mPopTargets. We store |
|
80 // hashes of our ancestor element tag names, ids, and classes in |
|
81 // here. |
|
82 nsTArray<uint32_t> mHashes; |
|
83 |
|
84 // A debug-only stack of Elements for use in assertions |
|
85 #ifdef DEBUG |
|
86 nsTArray<mozilla::dom::Element*> mElements; |
|
87 #endif |
|
88 }; |
|
89 |
|
90 /** |
|
91 * A |TreeMatchContext| has data about a matching operation. The |
|
92 * data are not node-specific but are invariants of the DOM tree the |
|
93 * nodes being matched against are in. |
|
94 * |
|
95 * Most of the members are in parameters to selector matching. The |
|
96 * one out parameter is mHaveRelevantLink. Consumers that use a |
|
97 * TreeMatchContext for more than one matching operation and care |
|
98 * about :visited and mHaveRelevantLink need to |
|
99 * ResetForVisitedMatching() and ResetForUnvisitedMatching() as |
|
100 * needed. |
|
101 */ |
|
102 struct MOZ_STACK_CLASS TreeMatchContext { |
|
103 // Reset this context for matching for the style-if-:visited. |
|
104 void ResetForVisitedMatching() { |
|
105 NS_PRECONDITION(mForStyling, "Why is this being called?"); |
|
106 mHaveRelevantLink = false; |
|
107 mVisitedHandling = nsRuleWalker::eRelevantLinkVisited; |
|
108 } |
|
109 |
|
110 void ResetForUnvisitedMatching() { |
|
111 NS_PRECONDITION(mForStyling, "Why is this being called?"); |
|
112 mHaveRelevantLink = false; |
|
113 mVisitedHandling = nsRuleWalker::eRelevantLinkUnvisited; |
|
114 } |
|
115 |
|
116 void SetHaveRelevantLink() { mHaveRelevantLink = true; } |
|
117 bool HaveRelevantLink() const { return mHaveRelevantLink; } |
|
118 |
|
119 nsRuleWalker::VisitedHandlingType VisitedHandling() const |
|
120 { |
|
121 return mVisitedHandling; |
|
122 } |
|
123 |
|
124 void AddScopeElement(mozilla::dom::Element* aElement) { |
|
125 NS_PRECONDITION(mHaveSpecifiedScope, |
|
126 "Should be set before calling AddScopeElement()"); |
|
127 mScopes.AppendElement(aElement); |
|
128 } |
|
129 bool IsScopeElement(mozilla::dom::Element* aElement) const { |
|
130 return mScopes.Contains(aElement); |
|
131 } |
|
132 void SetHasSpecifiedScope() { |
|
133 mHaveSpecifiedScope = true; |
|
134 } |
|
135 bool HasSpecifiedScope() const { |
|
136 return mHaveSpecifiedScope; |
|
137 } |
|
138 |
|
139 /** |
|
140 * Initialize the ancestor filter and list of style scopes. If aElement is |
|
141 * not null, it and all its ancestors will be passed to |
|
142 * mAncestorFilter.PushAncestor and PushStyleScope, starting from the root and |
|
143 * going down the tree. Must only be called for elements in a document. |
|
144 */ |
|
145 void InitAncestors(mozilla::dom::Element *aElement); |
|
146 |
|
147 /** |
|
148 * Like InitAncestors, but only initializes the style scope list, not the |
|
149 * ancestor filter. May be called for elements outside a document. |
|
150 */ |
|
151 void InitStyleScopes(mozilla::dom::Element* aElement); |
|
152 |
|
153 void PushStyleScope(mozilla::dom::Element* aElement) |
|
154 { |
|
155 NS_PRECONDITION(aElement, "aElement must not be null"); |
|
156 if (aElement->IsScopedStyleRoot()) { |
|
157 mStyleScopes.AppendElement(aElement); |
|
158 } |
|
159 } |
|
160 |
|
161 void PopStyleScope(mozilla::dom::Element* aElement) |
|
162 { |
|
163 NS_PRECONDITION(aElement, "aElement must not be null"); |
|
164 if (mStyleScopes.SafeLastElement(nullptr) == aElement) { |
|
165 mStyleScopes.TruncateLength(mStyleScopes.Length() - 1); |
|
166 } |
|
167 } |
|
168 |
|
169 bool PopStyleScopeForSelectorMatching(mozilla::dom::Element* aElement) |
|
170 { |
|
171 NS_ASSERTION(mForScopedStyle, "only call PopStyleScopeForSelectorMatching " |
|
172 "when mForScopedStyle is true"); |
|
173 |
|
174 if (!mCurrentStyleScope) { |
|
175 return false; |
|
176 } |
|
177 if (mCurrentStyleScope == aElement) { |
|
178 mCurrentStyleScope = nullptr; |
|
179 } |
|
180 return true; |
|
181 } |
|
182 |
|
183 #ifdef DEBUG |
|
184 void AssertHasAllStyleScopes(mozilla::dom::Element* aElement) |
|
185 { |
|
186 nsINode* cur = aElement->GetParentNode(); |
|
187 while (cur) { |
|
188 if (cur->IsScopedStyleRoot()) { |
|
189 MOZ_ASSERT(mStyleScopes.Contains(cur)); |
|
190 } |
|
191 cur = cur->GetParentNode(); |
|
192 } |
|
193 } |
|
194 #endif |
|
195 |
|
196 bool SetStyleScopeForSelectorMatching(mozilla::dom::Element* aSubject, |
|
197 mozilla::dom::Element* aScope) |
|
198 { |
|
199 #ifdef DEBUG |
|
200 AssertHasAllStyleScopes(aSubject); |
|
201 #endif |
|
202 |
|
203 mForScopedStyle = !!aScope; |
|
204 if (!aScope) { |
|
205 // This is not for a scoped style sheet; return true, as we want |
|
206 // selector matching to proceed. |
|
207 mCurrentStyleScope = nullptr; |
|
208 return true; |
|
209 } |
|
210 if (aScope == aSubject) { |
|
211 // Although the subject is the same element as the scope, as soon |
|
212 // as we continue with selector matching up the tree we don't want |
|
213 // to match any more elements. So we return true to indicate that |
|
214 // we want to do the initial selector matching, but set |
|
215 // mCurrentStyleScope to null so that no ancestor elements will match. |
|
216 mCurrentStyleScope = nullptr; |
|
217 return true; |
|
218 } |
|
219 if (mStyleScopes.Contains(aScope)) { |
|
220 // mStyleScopes contains all of the scope elements that are ancestors of |
|
221 // aSubject, so if aScope is in mStyleScopes, then we do want selector |
|
222 // matching to proceed. |
|
223 mCurrentStyleScope = aScope; |
|
224 return true; |
|
225 } |
|
226 // Otherwise, we're not in the scope, and we don't want to proceed |
|
227 // with selector matching. |
|
228 mCurrentStyleScope = nullptr; |
|
229 return false; |
|
230 } |
|
231 |
|
232 bool IsWithinStyleScopeForSelectorMatching() const |
|
233 { |
|
234 NS_ASSERTION(mForScopedStyle, "only call IsWithinScopeForSelectorMatching " |
|
235 "when mForScopedStyle is true"); |
|
236 return mCurrentStyleScope; |
|
237 } |
|
238 |
|
239 /* Helper class for maintaining the ancestor state */ |
|
240 class MOZ_STACK_CLASS AutoAncestorPusher { |
|
241 public: |
|
242 AutoAncestorPusher(TreeMatchContext& aTreeMatchContext |
|
243 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
|
244 : mPushedAncestor(false) |
|
245 , mPushedStyleScope(false) |
|
246 , mTreeMatchContext(aTreeMatchContext) |
|
247 , mElement(nullptr) |
|
248 { |
|
249 MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
|
250 } |
|
251 |
|
252 void PushAncestorAndStyleScope(mozilla::dom::Element* aElement) { |
|
253 MOZ_ASSERT(!mElement); |
|
254 if (aElement) { |
|
255 mElement = aElement; |
|
256 mPushedAncestor = true; |
|
257 mPushedStyleScope = true; |
|
258 mTreeMatchContext.mAncestorFilter.PushAncestor(aElement); |
|
259 mTreeMatchContext.PushStyleScope(aElement); |
|
260 } |
|
261 } |
|
262 |
|
263 void PushAncestorAndStyleScope(nsIContent* aContent) { |
|
264 if (aContent && aContent->IsElement()) { |
|
265 PushAncestorAndStyleScope(aContent->AsElement()); |
|
266 } |
|
267 } |
|
268 |
|
269 void PushStyleScope(mozilla::dom::Element* aElement) { |
|
270 MOZ_ASSERT(!mElement); |
|
271 if (aElement) { |
|
272 mElement = aElement; |
|
273 mPushedStyleScope = true; |
|
274 mTreeMatchContext.PushStyleScope(aElement); |
|
275 } |
|
276 } |
|
277 |
|
278 void PushStyleScope(nsIContent* aContent) { |
|
279 if (aContent && aContent->IsElement()) { |
|
280 PushStyleScope(aContent->AsElement()); |
|
281 } |
|
282 } |
|
283 |
|
284 ~AutoAncestorPusher() { |
|
285 if (mPushedAncestor) { |
|
286 mTreeMatchContext.mAncestorFilter.PopAncestor(); |
|
287 } |
|
288 if (mPushedStyleScope) { |
|
289 mTreeMatchContext.PopStyleScope(mElement); |
|
290 } |
|
291 } |
|
292 |
|
293 private: |
|
294 bool mPushedAncestor; |
|
295 bool mPushedStyleScope; |
|
296 TreeMatchContext& mTreeMatchContext; |
|
297 mozilla::dom::Element* mElement; |
|
298 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER |
|
299 }; |
|
300 |
|
301 /* Helper class for tracking whether we're skipping the ApplyStyleFixups |
|
302 * code for flex items. |
|
303 * |
|
304 * The optional second parameter aSkipFlexItemStyleFixup allows this |
|
305 * class to be instantiated but only conditionally activated (e.g. |
|
306 * in cases where we may or may not want to be skipping flex-item |
|
307 * style fixup for a particular chunk of code). |
|
308 */ |
|
309 class MOZ_STACK_CLASS AutoFlexItemStyleFixupSkipper { |
|
310 public: |
|
311 AutoFlexItemStyleFixupSkipper(TreeMatchContext& aTreeMatchContext, |
|
312 bool aSkipFlexItemStyleFixup = true |
|
313 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
|
314 : mAutoRestorer(aTreeMatchContext.mSkippingFlexItemStyleFixup) |
|
315 { |
|
316 MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
|
317 if (aSkipFlexItemStyleFixup) { |
|
318 aTreeMatchContext.mSkippingFlexItemStyleFixup = true; |
|
319 } |
|
320 } |
|
321 |
|
322 private: |
|
323 mozilla::AutoRestore<bool> mAutoRestorer; |
|
324 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER |
|
325 }; |
|
326 |
|
327 // Is this matching operation for the creation of a style context? |
|
328 // (If it is, we need to set slow selector bits on nodes indicating |
|
329 // that certain restyling needs to happen.) |
|
330 const bool mForStyling; |
|
331 |
|
332 private: |
|
333 // When mVisitedHandling is eRelevantLinkUnvisited, this is set to true if a |
|
334 // relevant link (see explanation in definition of VisitedHandling enum) was |
|
335 // encountered during the matching process, which means that matching needs |
|
336 // to be rerun with eRelevantLinkVisited. Otherwise, its behavior is |
|
337 // undefined (it might get set appropriately, or might not). |
|
338 bool mHaveRelevantLink; |
|
339 |
|
340 // If true, then our contextual reference element set is specified, |
|
341 // and is given by mScopes. |
|
342 bool mHaveSpecifiedScope; |
|
343 |
|
344 // How matching should be performed. See the documentation for |
|
345 // nsRuleWalker::VisitedHandlingType. |
|
346 nsRuleWalker::VisitedHandlingType mVisitedHandling; |
|
347 |
|
348 // For matching :scope |
|
349 nsAutoTArray<mozilla::dom::Element*, 1> mScopes; |
|
350 public: |
|
351 // The document we're working with. |
|
352 nsIDocument* const mDocument; |
|
353 |
|
354 // Root of scoped stylesheet (set and unset by the supplier of the |
|
355 // scoped stylesheet). |
|
356 nsIContent* mScopedRoot; |
|
357 |
|
358 // Whether our document is HTML (as opposed to XML of some sort, |
|
359 // including XHTML). |
|
360 // XXX XBL2 issue: Should we be caching this? What should it be for XBL2? |
|
361 const bool mIsHTMLDocument; |
|
362 |
|
363 // Possibly remove use of mCompatMode in SelectorMatches? |
|
364 // XXX XBL2 issue: Should we be caching this? What should it be for XBL2? |
|
365 const nsCompatibility mCompatMode; |
|
366 |
|
367 // The nth-index cache we should use |
|
368 nsNthIndexCache mNthIndexCache; |
|
369 |
|
370 // An ancestor filter |
|
371 AncestorFilter mAncestorFilter; |
|
372 |
|
373 // Whether this document is using PB mode |
|
374 bool mUsingPrivateBrowsing; |
|
375 |
|
376 // Whether we're currently skipping the flex item chunk of ApplyStyleFixups |
|
377 // when resolving style (e.g. for children of elements that have a mandatory |
|
378 // frame-type and can't be flex containers despite having "display:flex"). |
|
379 bool mSkippingFlexItemStyleFixup; |
|
380 |
|
381 // Whether this TreeMatchContext is being used with an nsCSSRuleProcessor |
|
382 // for an HTML5 scoped style sheet. |
|
383 bool mForScopedStyle; |
|
384 |
|
385 enum MatchVisited { |
|
386 eNeverMatchVisited, |
|
387 eMatchVisitedDefault |
|
388 }; |
|
389 |
|
390 // List of ancestor elements that define a style scope (due to having a |
|
391 // <style scoped> child). |
|
392 nsAutoTArray<mozilla::dom::Element*, 1> mStyleScopes; |
|
393 |
|
394 // The current style scope element for selector matching. |
|
395 mozilla::dom::Element* mCurrentStyleScope; |
|
396 |
|
397 // Constructor to use when creating a tree match context for styling |
|
398 TreeMatchContext(bool aForStyling, |
|
399 nsRuleWalker::VisitedHandlingType aVisitedHandling, |
|
400 nsIDocument* aDocument, |
|
401 MatchVisited aMatchVisited = eMatchVisitedDefault) |
|
402 : mForStyling(aForStyling) |
|
403 , mHaveRelevantLink(false) |
|
404 , mHaveSpecifiedScope(false) |
|
405 , mVisitedHandling(aVisitedHandling) |
|
406 , mDocument(aDocument) |
|
407 , mScopedRoot(nullptr) |
|
408 , mIsHTMLDocument(aDocument->IsHTML()) |
|
409 , mCompatMode(aDocument->GetCompatibilityMode()) |
|
410 , mUsingPrivateBrowsing(false) |
|
411 , mSkippingFlexItemStyleFixup(false) |
|
412 , mForScopedStyle(false) |
|
413 , mCurrentStyleScope(nullptr) |
|
414 { |
|
415 if (aMatchVisited != eNeverMatchVisited) { |
|
416 nsCOMPtr<nsISupports> container = mDocument->GetContainer(); |
|
417 if (container) { |
|
418 nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(container); |
|
419 NS_ASSERTION(loadContext, "Couldn't get loadContext from container; assuming no private browsing."); |
|
420 if (loadContext) { |
|
421 mUsingPrivateBrowsing = loadContext->UsePrivateBrowsing(); |
|
422 } |
|
423 } |
|
424 } |
|
425 } |
|
426 }; |
|
427 |
|
428 struct MOZ_STACK_CLASS RuleProcessorData { |
|
429 RuleProcessorData(nsPresContext* aPresContext, |
|
430 nsRuleWalker* aRuleWalker) |
|
431 : mPresContext(aPresContext), |
|
432 mRuleWalker(aRuleWalker), |
|
433 mScope(nullptr) |
|
434 { |
|
435 NS_PRECONDITION(mPresContext, "Must have prescontext"); |
|
436 } |
|
437 |
|
438 nsPresContext* const mPresContext; |
|
439 nsRuleWalker* const mRuleWalker; // Used to add rules to our results. |
|
440 mozilla::dom::Element* mScope; |
|
441 }; |
|
442 |
|
443 struct MOZ_STACK_CLASS ElementDependentRuleProcessorData : |
|
444 public RuleProcessorData { |
|
445 ElementDependentRuleProcessorData(nsPresContext* aPresContext, |
|
446 mozilla::dom::Element* aElement, |
|
447 nsRuleWalker* aRuleWalker, |
|
448 TreeMatchContext& aTreeMatchContext) |
|
449 : RuleProcessorData(aPresContext, aRuleWalker) |
|
450 , mElement(aElement) |
|
451 , mTreeMatchContext(aTreeMatchContext) |
|
452 { |
|
453 NS_ASSERTION(aElement, "null element leaked into SelectorMatches"); |
|
454 NS_ASSERTION(aElement->OwnerDoc(), "Document-less node here?"); |
|
455 NS_PRECONDITION(aTreeMatchContext.mForStyling == !!aRuleWalker, |
|
456 "Should be styling if and only if we have a rule walker"); |
|
457 } |
|
458 |
|
459 mozilla::dom::Element* const mElement; // weak ref, must not be null |
|
460 TreeMatchContext& mTreeMatchContext; |
|
461 }; |
|
462 |
|
463 struct MOZ_STACK_CLASS ElementRuleProcessorData : |
|
464 public ElementDependentRuleProcessorData { |
|
465 ElementRuleProcessorData(nsPresContext* aPresContext, |
|
466 mozilla::dom::Element* aElement, |
|
467 nsRuleWalker* aRuleWalker, |
|
468 TreeMatchContext& aTreeMatchContext) |
|
469 : ElementDependentRuleProcessorData(aPresContext, aElement, aRuleWalker, |
|
470 aTreeMatchContext) |
|
471 { |
|
472 NS_PRECONDITION(aTreeMatchContext.mForStyling, "Styling here!"); |
|
473 NS_PRECONDITION(aRuleWalker, "Must have rule walker"); |
|
474 } |
|
475 }; |
|
476 |
|
477 struct MOZ_STACK_CLASS PseudoElementRuleProcessorData : |
|
478 public ElementDependentRuleProcessorData { |
|
479 PseudoElementRuleProcessorData(nsPresContext* aPresContext, |
|
480 mozilla::dom::Element* aParentElement, |
|
481 nsRuleWalker* aRuleWalker, |
|
482 nsCSSPseudoElements::Type aPseudoType, |
|
483 TreeMatchContext& aTreeMatchContext, |
|
484 mozilla::dom::Element* aPseudoElement) |
|
485 : ElementDependentRuleProcessorData(aPresContext, aParentElement, aRuleWalker, |
|
486 aTreeMatchContext), |
|
487 mPseudoType(aPseudoType), |
|
488 mPseudoElement(aPseudoElement) |
|
489 { |
|
490 NS_PRECONDITION(aPseudoType < |
|
491 nsCSSPseudoElements::ePseudo_PseudoElementCount, |
|
492 "invalid aPseudoType value"); |
|
493 NS_PRECONDITION(aTreeMatchContext.mForStyling, "Styling here!"); |
|
494 NS_PRECONDITION(aRuleWalker, "Must have rule walker"); |
|
495 } |
|
496 |
|
497 nsCSSPseudoElements::Type mPseudoType; |
|
498 mozilla::dom::Element* const mPseudoElement; // weak ref |
|
499 }; |
|
500 |
|
501 struct MOZ_STACK_CLASS AnonBoxRuleProcessorData : public RuleProcessorData { |
|
502 AnonBoxRuleProcessorData(nsPresContext* aPresContext, |
|
503 nsIAtom* aPseudoTag, |
|
504 nsRuleWalker* aRuleWalker) |
|
505 : RuleProcessorData(aPresContext, aRuleWalker), |
|
506 mPseudoTag(aPseudoTag) |
|
507 { |
|
508 NS_PRECONDITION(aPseudoTag, "Must have pseudo tag"); |
|
509 NS_PRECONDITION(aRuleWalker, "Must have rule walker"); |
|
510 } |
|
511 |
|
512 nsIAtom* mPseudoTag; |
|
513 }; |
|
514 |
|
515 #ifdef MOZ_XUL |
|
516 struct MOZ_STACK_CLASS XULTreeRuleProcessorData : |
|
517 public ElementDependentRuleProcessorData { |
|
518 XULTreeRuleProcessorData(nsPresContext* aPresContext, |
|
519 mozilla::dom::Element* aParentElement, |
|
520 nsRuleWalker* aRuleWalker, |
|
521 nsIAtom* aPseudoTag, |
|
522 nsICSSPseudoComparator* aComparator, |
|
523 TreeMatchContext& aTreeMatchContext) |
|
524 : ElementDependentRuleProcessorData(aPresContext, aParentElement, |
|
525 aRuleWalker, aTreeMatchContext), |
|
526 mPseudoTag(aPseudoTag), |
|
527 mComparator(aComparator) |
|
528 { |
|
529 NS_PRECONDITION(aPseudoTag, "null pointer"); |
|
530 NS_PRECONDITION(aRuleWalker, "Must have rule walker"); |
|
531 NS_PRECONDITION(aComparator, "must have a comparator"); |
|
532 NS_PRECONDITION(aTreeMatchContext.mForStyling, "Styling here!"); |
|
533 } |
|
534 |
|
535 nsIAtom* mPseudoTag; |
|
536 nsICSSPseudoComparator* mComparator; |
|
537 }; |
|
538 #endif |
|
539 |
|
540 struct MOZ_STACK_CLASS StateRuleProcessorData : |
|
541 public ElementDependentRuleProcessorData { |
|
542 StateRuleProcessorData(nsPresContext* aPresContext, |
|
543 mozilla::dom::Element* aElement, |
|
544 mozilla::EventStates aStateMask, |
|
545 TreeMatchContext& aTreeMatchContext) |
|
546 : ElementDependentRuleProcessorData(aPresContext, aElement, nullptr, |
|
547 aTreeMatchContext), |
|
548 mStateMask(aStateMask) |
|
549 { |
|
550 NS_PRECONDITION(!aTreeMatchContext.mForStyling, "Not styling here!"); |
|
551 } |
|
552 // |HasStateDependentStyle| for which state(s)? |
|
553 // Constants defined in mozilla/EventStates.h . |
|
554 const mozilla::EventStates mStateMask; |
|
555 }; |
|
556 |
|
557 struct MOZ_STACK_CLASS PseudoElementStateRuleProcessorData : |
|
558 public StateRuleProcessorData { |
|
559 PseudoElementStateRuleProcessorData(nsPresContext* aPresContext, |
|
560 mozilla::dom::Element* aElement, |
|
561 mozilla::EventStates aStateMask, |
|
562 nsCSSPseudoElements::Type aPseudoType, |
|
563 TreeMatchContext& aTreeMatchContext, |
|
564 mozilla::dom::Element* aPseudoElement) |
|
565 : StateRuleProcessorData(aPresContext, aElement, aStateMask, |
|
566 aTreeMatchContext), |
|
567 mPseudoType(aPseudoType), |
|
568 mPseudoElement(aPseudoElement) |
|
569 { |
|
570 NS_PRECONDITION(!aTreeMatchContext.mForStyling, "Not styling here!"); |
|
571 } |
|
572 |
|
573 // We kind of want to inherit from both StateRuleProcessorData and |
|
574 // PseudoElementRuleProcessorData. Instead we've just copied those |
|
575 // members from PseudoElementRuleProcessorData to this struct. |
|
576 nsCSSPseudoElements::Type mPseudoType; |
|
577 mozilla::dom::Element* const mPseudoElement; // weak ref |
|
578 }; |
|
579 |
|
580 struct MOZ_STACK_CLASS AttributeRuleProcessorData : |
|
581 public ElementDependentRuleProcessorData { |
|
582 AttributeRuleProcessorData(nsPresContext* aPresContext, |
|
583 mozilla::dom::Element* aElement, |
|
584 nsIAtom* aAttribute, |
|
585 int32_t aModType, |
|
586 bool aAttrHasChanged, |
|
587 TreeMatchContext& aTreeMatchContext) |
|
588 : ElementDependentRuleProcessorData(aPresContext, aElement, nullptr, |
|
589 aTreeMatchContext), |
|
590 mAttribute(aAttribute), |
|
591 mModType(aModType), |
|
592 mAttrHasChanged(aAttrHasChanged) |
|
593 { |
|
594 NS_PRECONDITION(!aTreeMatchContext.mForStyling, "Not styling here!"); |
|
595 } |
|
596 nsIAtom* mAttribute; // |HasAttributeDependentStyle| for which attribute? |
|
597 int32_t mModType; // The type of modification (see nsIDOMMutationEvent). |
|
598 bool mAttrHasChanged; // Whether the attribute has already changed. |
|
599 }; |
|
600 |
|
601 #endif /* !defined(nsRuleProcessorData_h_) */ |