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 : * L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : /*
40 : * data structures passed to nsIStyleRuleProcessor methods (to pull loop
41 : * invariant computations out of the loop)
42 : */
43 :
44 : #ifndef nsRuleProcessorData_h_
45 : #define nsRuleProcessorData_h_
46 :
47 : #include "nsPresContext.h" // for nsCompatibility
48 : #include "nsString.h"
49 : #include "nsChangeHint.h"
50 : #include "nsIContent.h"
51 : #include "nsCSSPseudoElements.h"
52 : #include "nsRuleWalker.h"
53 : #include "nsNthIndexCache.h"
54 : #include "mozilla/BloomFilter.h"
55 : #include "mozilla/GuardObjects.h"
56 :
57 : class nsIStyleSheet;
58 : class nsIAtom;
59 : class nsICSSPseudoComparator;
60 : class nsAttrValue;
61 :
62 : /**
63 : * An AncestorFilter is used to keep track of ancestors so that we can
64 : * quickly tell that a particular selector is not relevant to a given
65 : * element.
66 : */
67 220 : class NS_STACK_CLASS AncestorFilter {
68 : public:
69 : /**
70 : * Initialize the filter. If aElement is not null, it and all its
71 : * ancestors will be passed to PushAncestor, starting from the root
72 : * and going down the tree.
73 : */
74 : void Init(mozilla::dom::Element *aElement);
75 :
76 : /* Maintenance of our ancestor state */
77 : void PushAncestor(mozilla::dom::Element *aElement);
78 : void PopAncestor();
79 :
80 : /* Helper class for maintaining the ancestor state */
81 : class NS_STACK_CLASS AutoAncestorPusher {
82 : public:
83 0 : AutoAncestorPusher(bool aDoPush,
84 : AncestorFilter &aFilter,
85 : mozilla::dom::Element *aElement
86 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
87 0 : : mPushed(aDoPush && aElement), mFilter(aFilter)
88 : {
89 0 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
90 0 : if (mPushed) {
91 0 : mFilter.PushAncestor(aElement);
92 : }
93 0 : }
94 0 : ~AutoAncestorPusher() {
95 0 : if (mPushed) {
96 0 : mFilter.PopAncestor();
97 : }
98 0 : }
99 :
100 : private:
101 : bool mPushed;
102 : AncestorFilter &mFilter;
103 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
104 : };
105 :
106 : /* Check whether we might have an ancestor matching one of the given
107 : atom hashes. |hashes| must have length hashListLength */
108 : template<size_t hashListLength>
109 0 : bool MightHaveMatchingAncestor(const uint32_t* aHashes) const
110 : {
111 0 : MOZ_ASSERT(mFilter);
112 0 : for (size_t i = 0; i < hashListLength && aHashes[i]; ++i) {
113 0 : if (!mFilter->mightContain(aHashes[i])) {
114 0 : return false;
115 : }
116 : }
117 :
118 0 : return true;
119 : }
120 :
121 0 : bool HasFilter() const { return mFilter; }
122 :
123 : #ifdef DEBUG
124 : void AssertHasAllAncestors(mozilla::dom::Element *aElement) const;
125 : #endif
126 :
127 : private:
128 : // Using 2^12 slots makes the Bloom filter a nice round page in
129 : // size, so let's do that. We get a false positive rate of 1% or
130 : // less even with several hundred things in the filter. Note that
131 : // we allocate the filter lazily, because not all tree match
132 : // contexts can use one effectively.
133 : typedef mozilla::BloomFilter<12, nsIAtom> Filter;
134 : nsAutoPtr<Filter> mFilter;
135 :
136 : // Stack of indices to pop to. These are indices into mHashes.
137 : nsTArray<PRUint32> mPopTargets;
138 :
139 : // List of hashes; this is what we pop using mPopTargets. We store
140 : // hashes of our ancestor element tag names, ids, and classes in
141 : // here.
142 : nsTArray<uint32_t> mHashes;
143 :
144 : // A debug-only stack of Elements for use in assertions
145 : #ifdef DEBUG
146 : nsTArray<mozilla::dom::Element*> mElements;
147 : #endif
148 : };
149 :
150 : /**
151 : * A |TreeMatchContext| has data about a matching operation. The
152 : * data are not node-specific but are invariants of the DOM tree the
153 : * nodes being matched against are in.
154 : *
155 : * Most of the members are in parameters to selector matching. The
156 : * one out parameter is mHaveRelevantLink. Consumers that use a
157 : * TreeMatchContext for more than one matching operation and care
158 : * about :visited and mHaveRelevantLink need to
159 : * ResetForVisitedMatching() and ResetForUnvisitedMatching() as
160 : * needed.
161 : */
162 110 : struct NS_STACK_CLASS TreeMatchContext {
163 : // Reset this context for matching for the style-if-:visited.
164 0 : void ResetForVisitedMatching() {
165 0 : NS_PRECONDITION(mForStyling, "Why is this being called?");
166 0 : mHaveRelevantLink = false;
167 0 : mVisitedHandling = nsRuleWalker::eRelevantLinkVisited;
168 0 : }
169 :
170 0 : void ResetForUnvisitedMatching() {
171 0 : NS_PRECONDITION(mForStyling, "Why is this being called?");
172 0 : mHaveRelevantLink = false;
173 0 : mVisitedHandling = nsRuleWalker::eRelevantLinkUnvisited;
174 0 : }
175 :
176 0 : void SetHaveRelevantLink() { mHaveRelevantLink = true; }
177 0 : bool HaveRelevantLink() const { return mHaveRelevantLink; }
178 :
179 0 : nsRuleWalker::VisitedHandlingType VisitedHandling() const
180 : {
181 0 : return mVisitedHandling;
182 : }
183 :
184 : // Is this matching operation for the creation of a style context?
185 : // (If it is, we need to set slow selector bits on nodes indicating
186 : // that certain restyling needs to happen.)
187 : const bool mForStyling;
188 :
189 : private:
190 : // When mVisitedHandling is eRelevantLinkUnvisited, this is set to true if a
191 : // relevant link (see explanation in definition of VisitedHandling enum) was
192 : // encountered during the matching process, which means that matching needs
193 : // to be rerun with eRelevantLinkVisited. Otherwise, its behavior is
194 : // undefined (it might get set appropriately, or might not).
195 : bool mHaveRelevantLink;
196 :
197 : // How matching should be performed. See the documentation for
198 : // nsRuleWalker::VisitedHandlingType.
199 : nsRuleWalker::VisitedHandlingType mVisitedHandling;
200 :
201 : public:
202 : // The document we're working with.
203 : nsIDocument* const mDocument;
204 :
205 : // Root of scoped stylesheet (set and unset by the supplier of the
206 : // scoped stylesheet).
207 : nsIContent* mScopedRoot;
208 :
209 : // Whether our document is HTML (as opposed to XML of some sort,
210 : // including XHTML).
211 : // XXX XBL2 issue: Should we be caching this? What should it be for XBL2?
212 : const bool mIsHTMLDocument;
213 :
214 : // Possibly remove use of mCompatMode in SelectorMatches?
215 : // XXX XBL2 issue: Should we be caching this? What should it be for XBL2?
216 : const nsCompatibility mCompatMode;
217 :
218 : // The nth-index cache we should use
219 : nsNthIndexCache mNthIndexCache;
220 :
221 : // An ancestor filter
222 : AncestorFilter mAncestorFilter;
223 :
224 : // Constructor to use when creating a tree match context for styling
225 110 : TreeMatchContext(bool aForStyling,
226 : nsRuleWalker::VisitedHandlingType aVisitedHandling,
227 : nsIDocument* aDocument)
228 : : mForStyling(aForStyling)
229 : , mHaveRelevantLink(false)
230 : , mVisitedHandling(aVisitedHandling)
231 : , mDocument(aDocument)
232 : , mScopedRoot(nsnull)
233 110 : , mIsHTMLDocument(aDocument->IsHTML())
234 220 : , mCompatMode(aDocument->GetCompatibilityMode())
235 : {
236 110 : }
237 : };
238 :
239 : // The implementation of the constructor and destructor are currently in
240 : // nsCSSRuleProcessor.cpp.
241 :
242 : struct NS_STACK_CLASS RuleProcessorData {
243 0 : RuleProcessorData(nsPresContext* aPresContext,
244 : mozilla::dom::Element* aElement,
245 : nsRuleWalker* aRuleWalker,
246 : TreeMatchContext& aTreeMatchContext)
247 : : mPresContext(aPresContext)
248 : , mElement(aElement)
249 : , mRuleWalker(aRuleWalker)
250 0 : , mTreeMatchContext(aTreeMatchContext)
251 : {
252 0 : NS_ASSERTION(aElement, "null element leaked into SelectorMatches");
253 0 : NS_ASSERTION(aElement->OwnerDoc(), "Document-less node here?");
254 0 : NS_PRECONDITION(aTreeMatchContext.mForStyling == !!aRuleWalker,
255 : "Should be styling if and only if we have a rule walker");
256 0 : }
257 :
258 : nsPresContext* const mPresContext;
259 : mozilla::dom::Element* const mElement; // weak ref, must not be null
260 : nsRuleWalker* const mRuleWalker; // Used to add rules to our results.
261 : TreeMatchContext& mTreeMatchContext;
262 : };
263 :
264 : struct NS_STACK_CLASS ElementRuleProcessorData : public RuleProcessorData {
265 0 : ElementRuleProcessorData(nsPresContext* aPresContext,
266 : mozilla::dom::Element* aElement,
267 : nsRuleWalker* aRuleWalker,
268 : TreeMatchContext& aTreeMatchContext)
269 0 : : RuleProcessorData(aPresContext, aElement, aRuleWalker, aTreeMatchContext)
270 : {
271 0 : NS_PRECONDITION(aPresContext, "null pointer");
272 0 : NS_PRECONDITION(aRuleWalker, "null pointer");
273 0 : NS_PRECONDITION(aTreeMatchContext.mForStyling, "Styling here!");
274 0 : }
275 : };
276 :
277 : struct NS_STACK_CLASS PseudoElementRuleProcessorData : public RuleProcessorData {
278 0 : PseudoElementRuleProcessorData(nsPresContext* aPresContext,
279 : mozilla::dom::Element* aParentElement,
280 : nsRuleWalker* aRuleWalker,
281 : nsCSSPseudoElements::Type aPseudoType,
282 : TreeMatchContext& aTreeMatchContext)
283 : : RuleProcessorData(aPresContext, aParentElement, aRuleWalker,
284 : aTreeMatchContext),
285 0 : mPseudoType(aPseudoType)
286 : {
287 0 : NS_PRECONDITION(aPresContext, "null pointer");
288 0 : NS_PRECONDITION(aPseudoType <
289 : nsCSSPseudoElements::ePseudo_PseudoElementCount,
290 : "null pointer");
291 0 : NS_PRECONDITION(aRuleWalker, "null pointer");
292 0 : NS_PRECONDITION(aTreeMatchContext.mForStyling, "Styling here!");
293 0 : }
294 :
295 : nsCSSPseudoElements::Type mPseudoType;
296 : };
297 :
298 : struct NS_STACK_CLASS AnonBoxRuleProcessorData {
299 0 : AnonBoxRuleProcessorData(nsPresContext* aPresContext,
300 : nsIAtom* aPseudoTag,
301 : nsRuleWalker* aRuleWalker)
302 : : mPresContext(aPresContext),
303 : mPseudoTag(aPseudoTag),
304 0 : mRuleWalker(aRuleWalker)
305 : {
306 0 : NS_PRECONDITION(mPresContext, "Must have prescontext");
307 0 : NS_PRECONDITION(aPseudoTag, "Must have pseudo tag");
308 0 : NS_PRECONDITION(aRuleWalker, "Must have rule walker");
309 0 : }
310 :
311 : nsPresContext* mPresContext;
312 : nsIAtom* mPseudoTag;
313 : nsRuleWalker* mRuleWalker;
314 : };
315 :
316 : #ifdef MOZ_XUL
317 : struct NS_STACK_CLASS XULTreeRuleProcessorData : public RuleProcessorData {
318 0 : XULTreeRuleProcessorData(nsPresContext* aPresContext,
319 : mozilla::dom::Element* aParentElement,
320 : nsRuleWalker* aRuleWalker,
321 : nsIAtom* aPseudoTag,
322 : nsICSSPseudoComparator* aComparator,
323 : TreeMatchContext& aTreeMatchContext)
324 : : RuleProcessorData(aPresContext, aParentElement, aRuleWalker,
325 : aTreeMatchContext),
326 : mPseudoTag(aPseudoTag),
327 0 : mComparator(aComparator)
328 : {
329 0 : NS_PRECONDITION(aPresContext, "null pointer");
330 0 : NS_PRECONDITION(aPseudoTag, "null pointer");
331 0 : NS_PRECONDITION(aRuleWalker, "null pointer");
332 0 : NS_PRECONDITION(aComparator, "must have a comparator");
333 0 : NS_PRECONDITION(aTreeMatchContext.mForStyling, "Styling here!");
334 0 : }
335 :
336 : nsIAtom* mPseudoTag;
337 : nsICSSPseudoComparator* mComparator;
338 : };
339 : #endif
340 :
341 : struct NS_STACK_CLASS StateRuleProcessorData : public RuleProcessorData {
342 0 : StateRuleProcessorData(nsPresContext* aPresContext,
343 : mozilla::dom::Element* aElement,
344 : nsEventStates aStateMask,
345 : TreeMatchContext& aTreeMatchContext)
346 : : RuleProcessorData(aPresContext, aElement, nsnull, aTreeMatchContext),
347 0 : mStateMask(aStateMask)
348 : {
349 0 : NS_PRECONDITION(aPresContext, "null pointer");
350 0 : NS_PRECONDITION(!aTreeMatchContext.mForStyling, "Not styling here!");
351 0 : }
352 : const nsEventStates mStateMask; // |HasStateDependentStyle| for which state(s)?
353 : // Constants defined in nsEventStates.h .
354 : };
355 :
356 : struct NS_STACK_CLASS AttributeRuleProcessorData : public RuleProcessorData {
357 0 : AttributeRuleProcessorData(nsPresContext* aPresContext,
358 : mozilla::dom::Element* aElement,
359 : nsIAtom* aAttribute,
360 : PRInt32 aModType,
361 : bool aAttrHasChanged,
362 : TreeMatchContext& aTreeMatchContext)
363 : : RuleProcessorData(aPresContext, aElement, nsnull, aTreeMatchContext),
364 : mAttribute(aAttribute),
365 : mModType(aModType),
366 0 : mAttrHasChanged(aAttrHasChanged)
367 : {
368 0 : NS_PRECONDITION(aPresContext, "null pointer");
369 0 : NS_PRECONDITION(!aTreeMatchContext.mForStyling, "Not styling here!");
370 0 : }
371 : nsIAtom* mAttribute; // |HasAttributeDependentStyle| for which attribute?
372 : PRInt32 mModType; // The type of modification (see nsIDOMMutationEvent).
373 : bool mAttrHasChanged; // Whether the attribute has already changed.
374 : };
375 :
376 : #endif /* !defined(nsRuleProcessorData_h_) */
|