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 : * Daniel Glazman <glazman@netscape.com>
24 : * Brian Ryner <bryner@brianryner.com>
25 : * L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either of the GNU General Public License Version 2 or later (the "GPL"),
29 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : /*
42 : * the container for the style sheets that apply to a presentation, and
43 : * the internal API that the style system exposes for creating (and
44 : * potentially re-creating) style contexts
45 : */
46 :
47 : #ifndef nsStyleSet_h_
48 : #define nsStyleSet_h_
49 :
50 : #include "mozilla/Attributes.h"
51 :
52 : #include "nsIStyleRuleProcessor.h"
53 : #include "nsCSSStyleSheet.h"
54 : #include "nsBindingManager.h"
55 : #include "nsRuleNode.h"
56 : #include "nsTArray.h"
57 : #include "nsCOMArray.h"
58 : #include "nsAutoPtr.h"
59 : #include "nsIStyleRule.h"
60 : #include "nsCSSPseudoElements.h"
61 : #include "nsCSSAnonBoxes.h"
62 :
63 : class nsIURI;
64 : class nsCSSFontFaceRule;
65 : class nsCSSKeyframesRule;
66 : class nsRuleWalker;
67 : struct RuleProcessorData;
68 : struct TreeMatchContext;
69 :
70 : class nsEmptyStyleRule : public nsIStyleRule
71 : {
72 : NS_DECL_ISUPPORTS
73 : virtual void MapRuleInfoInto(nsRuleData* aRuleData);
74 : #ifdef DEBUG
75 : virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
76 : #endif
77 : };
78 :
79 : class nsInitialStyleRule : public nsIStyleRule
80 : {
81 : NS_DECL_ISUPPORTS
82 : virtual void MapRuleInfoInto(nsRuleData* aRuleData);
83 : #ifdef DEBUG
84 : virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
85 : #endif
86 : };
87 :
88 : // The style set object is created by the document viewer and ownership is
89 : // then handed off to the PresShell. Only the PresShell should delete a
90 : // style set.
91 :
92 : class nsStyleSet
93 0 : {
94 : public:
95 : nsStyleSet();
96 :
97 : size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
98 :
99 : // Initialize the object. You must check the return code and not use
100 : // the nsStyleSet if Init() fails.
101 :
102 : nsresult Init(nsPresContext *aPresContext);
103 :
104 : // For getting the cached default data in case we hit out-of-memory.
105 : // To be used only by nsRuleNode.
106 : nsCachedStyleData* DefaultStyleData() { return &mDefaultStyleData; }
107 :
108 : nsRuleNode* GetRuleTree() { return mRuleTree; }
109 :
110 : // enable / disable the Quirk style sheet
111 : void EnableQuirkStyleSheet(bool aEnable);
112 :
113 : // get a style context for a non-pseudo frame.
114 : already_AddRefed<nsStyleContext>
115 : ResolveStyleFor(mozilla::dom::Element* aElement,
116 : nsStyleContext* aParentContext);
117 :
118 : already_AddRefed<nsStyleContext>
119 : ResolveStyleFor(mozilla::dom::Element* aElement,
120 : nsStyleContext* aParentContext,
121 : TreeMatchContext& aTreeMatchContext);
122 :
123 : // Get a style context (with the given parent) for the
124 : // sequence of style rules in the |aRules| array.
125 : already_AddRefed<nsStyleContext>
126 : ResolveStyleForRules(nsStyleContext* aParentContext,
127 : const nsCOMArray<nsIStyleRule> &aRules);
128 :
129 : // Get a style context that represents aBaseContext, but as though
130 : // it additionally matched the rules in the aRules array (in that
131 : // order, as more specific than any other rules).
132 : already_AddRefed<nsStyleContext>
133 : ResolveStyleByAddingRules(nsStyleContext* aBaseContext,
134 : const nsCOMArray<nsIStyleRule> &aRules);
135 :
136 : // Get a style context for a non-element (which no rules will match),
137 : // such as text nodes, placeholder frames, and the nsFirstLetterFrame
138 : // for everything after the first letter.
139 : //
140 : // Perhaps this should go away and we shouldn't even create style
141 : // contexts for such content nodes. However, not doing any rule
142 : // matching for them is a first step.
143 : already_AddRefed<nsStyleContext>
144 : ResolveStyleForNonElement(nsStyleContext* aParentContext);
145 :
146 : // Get a style context for a pseudo-element. aParentElement must be
147 : // non-null. aPseudoID is the nsCSSPseudoElements::Type for the
148 : // pseudo-element.
149 : already_AddRefed<nsStyleContext>
150 : ResolvePseudoElementStyle(mozilla::dom::Element* aParentElement,
151 : nsCSSPseudoElements::Type aType,
152 : nsStyleContext* aParentContext);
153 :
154 : // This functions just like ResolvePseudoElementStyle except that it will
155 : // return nsnull if there are no explicit style rules for that
156 : // pseudo element.
157 : already_AddRefed<nsStyleContext>
158 : ProbePseudoElementStyle(mozilla::dom::Element* aParentElement,
159 : nsCSSPseudoElements::Type aType,
160 : nsStyleContext* aParentContext);
161 : already_AddRefed<nsStyleContext>
162 : ProbePseudoElementStyle(mozilla::dom::Element* aParentElement,
163 : nsCSSPseudoElements::Type aType,
164 : nsStyleContext* aParentContext,
165 : TreeMatchContext& aTreeMatchContext);
166 :
167 : // Get a style context for an anonymous box. aPseudoTag is the
168 : // pseudo-tag to use and must be non-null.
169 : already_AddRefed<nsStyleContext>
170 : ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag, nsStyleContext* aParentContext);
171 :
172 : #ifdef MOZ_XUL
173 : // Get a style context for a XUL tree pseudo. aPseudoTag is the
174 : // pseudo-tag to use and must be non-null. aParentContent must be
175 : // non-null. aComparator must be non-null.
176 : already_AddRefed<nsStyleContext>
177 : ResolveXULTreePseudoStyle(mozilla::dom::Element* aParentElement,
178 : nsIAtom* aPseudoTag,
179 : nsStyleContext* aParentContext,
180 : nsICSSPseudoComparator* aComparator);
181 : #endif
182 :
183 : // Append all the currently-active font face rules to aArray. Return
184 : // true for success and false for failure.
185 : bool AppendFontFaceRules(nsPresContext* aPresContext,
186 : nsTArray<nsFontFaceRuleContainer>& aArray);
187 :
188 : // Append all the currently-active keyframes rules to aArray. Return
189 : // true for success and false for failure.
190 : bool AppendKeyframesRules(nsPresContext* aPresContext,
191 : nsTArray<nsCSSKeyframesRule*>& aArray);
192 :
193 : // Begin ignoring style context destruction, to avoid lots of unnecessary
194 : // work on document teardown.
195 : void BeginShutdown(nsPresContext* aPresContext);
196 :
197 : // Free all of the data associated with this style set.
198 : void Shutdown(nsPresContext* aPresContext);
199 :
200 : // Notification that a style context is being destroyed.
201 : void NotifyStyleContextDestroyed(nsPresContext* aPresContext,
202 : nsStyleContext* aStyleContext);
203 :
204 : // Get a new style context that lives in a different parent
205 : // The new context will be the same as the old if the new parent is the
206 : // same as the old parent.
207 : // aElement should be non-null if this is a style context for an
208 : // element or pseudo-element; in the latter case it should be the
209 : // real element the pseudo-element is for.
210 : already_AddRefed<nsStyleContext>
211 : ReparentStyleContext(nsStyleContext* aStyleContext,
212 : nsStyleContext* aNewParentContext,
213 : mozilla::dom::Element* aElement);
214 :
215 : // Test if style is dependent on a document state.
216 : bool HasDocumentStateDependentStyle(nsPresContext* aPresContext,
217 : nsIContent* aContent,
218 : nsEventStates aStateMask);
219 :
220 : // Test if style is dependent on content state
221 : nsRestyleHint HasStateDependentStyle(nsPresContext* aPresContext,
222 : mozilla::dom::Element* aElement,
223 : nsEventStates aStateMask);
224 :
225 : // Test if style is dependent on the presence of an attribute.
226 : nsRestyleHint HasAttributeDependentStyle(nsPresContext* aPresContext,
227 : mozilla::dom::Element* aElement,
228 : nsIAtom* aAttribute,
229 : PRInt32 aModType,
230 : bool aAttrHasChanged);
231 :
232 : /*
233 : * Do any processing that needs to happen as a result of a change in
234 : * the characteristics of the medium, and return whether style rules
235 : * may have changed as a result.
236 : */
237 : bool MediumFeaturesChanged(nsPresContext* aPresContext);
238 :
239 : // APIs for registering objects that can supply additional
240 : // rules during processing.
241 : void SetBindingManager(nsBindingManager* aBindingManager)
242 : {
243 : mBindingManager = aBindingManager;
244 : }
245 :
246 : // The "origins" of the CSS cascade, from lowest precedence to
247 : // highest (for non-!important rules).
248 : enum sheetType {
249 : eAgentSheet, // CSS
250 : eUserSheet, // CSS
251 : ePresHintSheet,
252 : eDocSheet, // CSS
253 : eStyleAttrSheet,
254 : eOverrideSheet, // CSS
255 : eAnimationSheet,
256 : eTransitionSheet,
257 : eSheetTypeCount
258 : // be sure to keep the number of bits in |mDirty| below and in
259 : // NS_RULE_NODE_LEVEL_MASK updated when changing the number of sheet
260 : // types
261 : };
262 :
263 : // APIs to manipulate the style sheet lists. The sheets in each
264 : // list are stored with the most significant sheet last.
265 : nsresult AppendStyleSheet(sheetType aType, nsIStyleSheet *aSheet);
266 : nsresult PrependStyleSheet(sheetType aType, nsIStyleSheet *aSheet);
267 : nsresult RemoveStyleSheet(sheetType aType, nsIStyleSheet *aSheet);
268 : nsresult ReplaceSheets(sheetType aType,
269 : const nsCOMArray<nsIStyleSheet> &aNewSheets);
270 :
271 : // Enable/Disable entire author style level (Doc & PresHint levels)
272 : bool GetAuthorStyleDisabled();
273 : nsresult SetAuthorStyleDisabled(bool aStyleDisabled);
274 :
275 0 : PRInt32 SheetCount(sheetType aType) const {
276 0 : return mSheets[aType].Count();
277 : }
278 :
279 : nsIStyleSheet* StyleSheetAt(sheetType aType, PRInt32 aIndex) const {
280 : return mSheets[aType].ObjectAt(aIndex);
281 : }
282 :
283 : nsresult AddDocStyleSheet(nsIStyleSheet* aSheet, nsIDocument* aDocument);
284 :
285 : void BeginUpdate();
286 : nsresult EndUpdate();
287 :
288 : // Methods for reconstructing the tree; BeginReconstruct basically moves the
289 : // old rule tree root and style context roots out of the way,
290 : // and EndReconstruct destroys the old rule tree when we're done
291 : nsresult BeginReconstruct();
292 : // Note: EndReconstruct should not be called if BeginReconstruct fails
293 : void EndReconstruct();
294 :
295 : // Let the style set know that a particular sheet is the quirks sheet. This
296 : // sheet must already have been added to the UA sheets. The pointer must not
297 : // be null. This should only be called once for a given style set.
298 : void SetQuirkStyleSheet(nsIStyleSheet* aQuirkStyleSheet);
299 :
300 : // Return whether the rule tree has cached data such that we need to
301 : // do dynamic change handling for changes that change the results of
302 : // media queries or require rebuilding all style data.
303 : // We don't care whether we have cached rule processors or whether
304 : // they have cached rule cascades; getting the rule cascades again in
305 : // order to do rule matching will get the correct rule cascade.
306 : bool HasCachedStyleData() const {
307 : return (mRuleTree && mRuleTree->TreeHasCachedData()) || !mRoots.IsEmpty();
308 : }
309 :
310 : // Notify the style set that a rulenode is no longer in use, or was
311 : // just created and is not in use yet.
312 : void RuleNodeUnused() {
313 : ++mUnusedRuleNodeCount;
314 : }
315 :
316 : // Notify the style set that a rulenode that wasn't in use now is
317 : void RuleNodeInUse() {
318 : --mUnusedRuleNodeCount;
319 : }
320 :
321 : nsCSSStyleSheet::EnsureUniqueInnerResult EnsureUniqueInnerOnCSSSheets();
322 :
323 : nsIStyleRule* InitialStyleRule();
324 :
325 : private:
326 : nsStyleSet(const nsStyleSet& aCopy) MOZ_DELETE;
327 : nsStyleSet& operator=(const nsStyleSet& aCopy) MOZ_DELETE;
328 :
329 : // Returns false on out-of-memory.
330 : bool BuildDefaultStyleData(nsPresContext* aPresContext);
331 :
332 : // Run mark-and-sweep GC on mRuleTree and mOldRuleTrees, based on mRoots.
333 : void GCRuleTrees();
334 :
335 : // Update the rule processor list after a change to the style sheet list.
336 : nsresult GatherRuleProcessors(sheetType aType);
337 :
338 : void AddImportantRules(nsRuleNode* aCurrLevelNode,
339 : nsRuleNode* aLastPrevLevelNode,
340 : nsRuleWalker* aRuleWalker);
341 :
342 : // Move aRuleWalker forward by the appropriate rule if we need to add
343 : // a rule due to property restrictions on pseudo-elements.
344 : void WalkRestrictionRule(nsCSSPseudoElements::Type aPseudoType,
345 : nsRuleWalker* aRuleWalker);
346 :
347 : #ifdef DEBUG
348 : // Just like AddImportantRules except it doesn't actually add anything; it
349 : // just asserts that there are no important rules between aCurrLevelNode and
350 : // aLastPrevLevelNode.
351 : void AssertNoImportantRules(nsRuleNode* aCurrLevelNode,
352 : nsRuleNode* aLastPrevLevelNode);
353 :
354 : // Just like AddImportantRules except it doesn't actually add anything; it
355 : // just asserts that there are no CSS rules between aCurrLevelNode and
356 : // aLastPrevLevelNode. Mostly useful for the preshint level.
357 : void AssertNoCSSRules(nsRuleNode* aCurrLevelNode,
358 : nsRuleNode* aLastPrevLevelNode);
359 : #endif
360 :
361 : // Enumerate the rules in a way that cares about the order of the
362 : // rules.
363 : // aContent is the node the rules are for. It might be null. aData
364 : // is the closure to pass to aCollectorFunc. If aContent is not null,
365 : // aData must be a RuleProcessorData*
366 : void FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
367 : void* aData, nsIContent* aContent, nsRuleWalker* aRuleWalker);
368 :
369 : // Enumerate all the rules in a way that doesn't care about the order
370 : // of the rules and break out if the enumeration is halted.
371 : void WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc,
372 : RuleProcessorData* aData,
373 : bool aWalkAllXBLStylesheets);
374 :
375 : already_AddRefed<nsStyleContext>
376 : GetContext(nsStyleContext* aParentContext,
377 : nsRuleNode* aRuleNode,
378 : nsRuleNode* aVisitedRuleNode,
379 : bool aIsLink,
380 : bool aIsVisitedLink,
381 : nsIAtom* aPseudoTag,
382 : nsCSSPseudoElements::Type aPseudoType,
383 : bool aDoAnimation,
384 : mozilla::dom::Element* aElementForAnimation);
385 :
386 : nsPresContext* PresContext() { return mRuleTree->GetPresContext(); }
387 :
388 : // The sheets in each array in mSheets are stored with the most significant
389 : // sheet last.
390 : nsCOMArray<nsIStyleSheet> mSheets[eSheetTypeCount];
391 :
392 : nsCOMPtr<nsIStyleRuleProcessor> mRuleProcessors[eSheetTypeCount];
393 :
394 : // cached instance for enabling/disabling
395 : nsCOMPtr<nsIStyleSheet> mQuirkStyleSheet;
396 :
397 : nsRefPtr<nsBindingManager> mBindingManager;
398 :
399 : // To be used only in case of emergency, such as being out of memory
400 : // or operating on a deleted rule node. The latter should never
401 : // happen, of course.
402 : nsCachedStyleData mDefaultStyleData;
403 :
404 : nsRuleNode* mRuleTree; // This is the root of our rule tree. It is a
405 : // lexicographic tree of matched rules that style
406 : // contexts use to look up properties.
407 :
408 : PRUint32 mUnusedRuleNodeCount; // used to batch rule node GC
409 : nsTArray<nsStyleContext*> mRoots; // style contexts with no parent
410 :
411 : // Empty style rules to force things that restrict which properties
412 : // apply into different branches of the rule tree.
413 : nsRefPtr<nsEmptyStyleRule> mFirstLineRule, mFirstLetterRule;
414 :
415 : // Style rule which sets all properties to their initial values for
416 : // determining when context-sensitive values are in use.
417 : nsRefPtr<nsInitialStyleRule> mInitialStyleRule;
418 :
419 : PRUint16 mBatching;
420 :
421 : // Old rule trees, which should only be non-empty between
422 : // BeginReconstruct and EndReconstruct, but in case of bugs that cause
423 : // style contexts to exist too long, may last longer.
424 : nsTArray<nsRuleNode*> mOldRuleTrees;
425 :
426 : unsigned mInShutdown : 1;
427 : unsigned mAuthorStyleDisabled: 1;
428 : unsigned mInReconstruct : 1;
429 : unsigned mDirty : 8; // one dirty bit is used per sheet type
430 :
431 : };
432 :
433 : #ifdef _IMPL_NS_LAYOUT
434 : inline
435 : void nsRuleNode::AddRef()
436 : {
437 : if (mRefCnt++ == 0 && !IsRoot()) {
438 : mPresContext->StyleSet()->RuleNodeInUse();
439 : }
440 : }
441 :
442 : inline
443 : void nsRuleNode::Release()
444 : {
445 : if (--mRefCnt == 0 && !IsRoot()) {
446 : mPresContext->StyleSet()->RuleNodeUnused();
447 : }
448 : }
449 : #endif
450 :
451 : #endif
|