|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 // vim:cindent:tabstop=2:expandtab:shiftwidth=2: |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 /* representation of a CSS style sheet */ |
|
8 |
|
9 #ifndef nsCSSStyleSheet_h_ |
|
10 #define nsCSSStyleSheet_h_ |
|
11 |
|
12 #include "mozilla/Attributes.h" |
|
13 #include "mozilla/MemoryReporting.h" |
|
14 #include "mozilla/dom/Element.h" |
|
15 |
|
16 #include "nscore.h" |
|
17 #include "nsCOMPtr.h" |
|
18 #include "nsAutoPtr.h" |
|
19 #include "nsIStyleSheet.h" |
|
20 #include "nsIDOMCSSStyleSheet.h" |
|
21 #include "nsICSSLoaderObserver.h" |
|
22 #include "nsCOMArray.h" |
|
23 #include "nsTArray.h" |
|
24 #include "nsString.h" |
|
25 #include "mozilla/CORSMode.h" |
|
26 #include "nsCycleCollectionParticipant.h" |
|
27 #include "nsWrapperCache.h" |
|
28 |
|
29 class nsXMLNameSpaceMap; |
|
30 class nsCSSRuleProcessor; |
|
31 class nsIPrincipal; |
|
32 class nsIURI; |
|
33 class nsMediaList; |
|
34 class nsMediaQueryResultCacheKey; |
|
35 class nsCSSStyleSheet; |
|
36 class nsPresContext; |
|
37 |
|
38 namespace mozilla { |
|
39 namespace css { |
|
40 class Rule; |
|
41 class GroupRule; |
|
42 class ImportRule; |
|
43 } |
|
44 } |
|
45 |
|
46 // ------------------------------- |
|
47 // CSS Style Sheet Inner Data Container |
|
48 // |
|
49 |
|
50 class nsCSSStyleSheetInner { |
|
51 public: |
|
52 friend class nsCSSStyleSheet; |
|
53 friend class nsCSSRuleProcessor; |
|
54 private: |
|
55 nsCSSStyleSheetInner(nsCSSStyleSheet* aPrimarySheet, |
|
56 mozilla::CORSMode aCORSMode); |
|
57 nsCSSStyleSheetInner(nsCSSStyleSheetInner& aCopy, |
|
58 nsCSSStyleSheet* aPrimarySheet); |
|
59 ~nsCSSStyleSheetInner(); |
|
60 |
|
61 nsCSSStyleSheetInner* CloneFor(nsCSSStyleSheet* aPrimarySheet); |
|
62 void AddSheet(nsCSSStyleSheet* aSheet); |
|
63 void RemoveSheet(nsCSSStyleSheet* aSheet); |
|
64 |
|
65 void RebuildNameSpaces(); |
|
66 |
|
67 // Create a new namespace map |
|
68 nsresult CreateNamespaceMap(); |
|
69 |
|
70 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; |
|
71 |
|
72 nsAutoTArray<nsCSSStyleSheet*, 8> mSheets; |
|
73 nsCOMPtr<nsIURI> mSheetURI; // for error reports, etc. |
|
74 nsCOMPtr<nsIURI> mOriginalSheetURI; // for GetHref. Can be null. |
|
75 nsCOMPtr<nsIURI> mBaseURI; // for resolving relative URIs |
|
76 nsCOMPtr<nsIPrincipal> mPrincipal; |
|
77 nsCOMArray<mozilla::css::Rule> mOrderedRules; |
|
78 nsAutoPtr<nsXMLNameSpaceMap> mNameSpaceMap; |
|
79 // Linked list of child sheets. This is al fundamentally broken, because |
|
80 // each of the child sheets has a unique parent... We can only hope (and |
|
81 // currently this is the case) that any time page JS can get ts hands on a |
|
82 // child sheet that means we've already ensured unique inners throughout its |
|
83 // parent chain and things are good. |
|
84 nsRefPtr<nsCSSStyleSheet> mFirstChild; |
|
85 mozilla::CORSMode mCORSMode; |
|
86 bool mComplete; |
|
87 |
|
88 #ifdef DEBUG |
|
89 bool mPrincipalSet; |
|
90 #endif |
|
91 }; |
|
92 |
|
93 |
|
94 // ------------------------------- |
|
95 // CSS Style Sheet |
|
96 // |
|
97 |
|
98 class CSSRuleListImpl; |
|
99 |
|
100 // CID for the nsCSSStyleSheet class |
|
101 // ca926f30-2a7e-477e-8467-803fb32af20a |
|
102 #define NS_CSS_STYLE_SHEET_IMPL_CID \ |
|
103 { 0xca926f30, 0x2a7e, 0x477e, \ |
|
104 { 0x84, 0x67, 0x80, 0x3f, 0xb3, 0x2a, 0xf2, 0x0a } } |
|
105 |
|
106 |
|
107 class nsCSSStyleSheet MOZ_FINAL : public nsIStyleSheet, |
|
108 public nsIDOMCSSStyleSheet, |
|
109 public nsICSSLoaderObserver, |
|
110 public nsWrapperCache |
|
111 { |
|
112 public: |
|
113 nsCSSStyleSheet(mozilla::CORSMode aCORSMode); |
|
114 |
|
115 NS_DECL_CYCLE_COLLECTING_ISUPPORTS |
|
116 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsCSSStyleSheet, |
|
117 nsIStyleSheet) |
|
118 |
|
119 NS_DECLARE_STATIC_IID_ACCESSOR(NS_CSS_STYLE_SHEET_IMPL_CID) |
|
120 |
|
121 // nsIStyleSheet interface |
|
122 virtual nsIURI* GetSheetURI() const MOZ_OVERRIDE; |
|
123 virtual nsIURI* GetBaseURI() const MOZ_OVERRIDE; |
|
124 virtual void GetTitle(nsString& aTitle) const MOZ_OVERRIDE; |
|
125 virtual void GetType(nsString& aType) const MOZ_OVERRIDE; |
|
126 virtual bool HasRules() const MOZ_OVERRIDE; |
|
127 virtual bool IsApplicable() const MOZ_OVERRIDE; |
|
128 virtual void SetEnabled(bool aEnabled) MOZ_OVERRIDE; |
|
129 virtual bool IsComplete() const MOZ_OVERRIDE; |
|
130 virtual void SetComplete() MOZ_OVERRIDE; |
|
131 virtual nsIStyleSheet* GetParentSheet() const MOZ_OVERRIDE; // may be null |
|
132 virtual nsIDocument* GetOwningDocument() const MOZ_OVERRIDE; // may be null |
|
133 virtual void SetOwningDocument(nsIDocument* aDocument) MOZ_OVERRIDE; |
|
134 |
|
135 // Find the ID of the owner inner window. |
|
136 uint64_t FindOwningWindowInnerID() const; |
|
137 #ifdef DEBUG |
|
138 virtual void List(FILE* out = stdout, int32_t aIndent = 0) const MOZ_OVERRIDE; |
|
139 #endif |
|
140 |
|
141 void AppendStyleSheet(nsCSSStyleSheet* aSheet); |
|
142 void InsertStyleSheetAt(nsCSSStyleSheet* aSheet, int32_t aIndex); |
|
143 |
|
144 // XXX do these belong here or are they generic? |
|
145 void PrependStyleRule(mozilla::css::Rule* aRule); |
|
146 void AppendStyleRule(mozilla::css::Rule* aRule); |
|
147 void ReplaceStyleRule(mozilla::css::Rule* aOld, mozilla::css::Rule* aNew); |
|
148 |
|
149 int32_t StyleRuleCount() const; |
|
150 mozilla::css::Rule* GetStyleRuleAt(int32_t aIndex) const; |
|
151 |
|
152 nsresult DeleteRuleFromGroup(mozilla::css::GroupRule* aGroup, uint32_t aIndex); |
|
153 nsresult InsertRuleIntoGroup(const nsAString& aRule, mozilla::css::GroupRule* aGroup, uint32_t aIndex, uint32_t* _retval); |
|
154 nsresult ReplaceRuleInGroup(mozilla::css::GroupRule* aGroup, mozilla::css::Rule* aOld, mozilla::css::Rule* aNew); |
|
155 |
|
156 int32_t StyleSheetCount() const; |
|
157 |
|
158 /** |
|
159 * SetURIs must be called on all sheets before parsing into them. |
|
160 * SetURIs may only be called while the sheet is 1) incomplete and 2) |
|
161 * has no rules in it |
|
162 */ |
|
163 void SetURIs(nsIURI* aSheetURI, nsIURI* aOriginalSheetURI, nsIURI* aBaseURI); |
|
164 |
|
165 /** |
|
166 * SetPrincipal should be called on all sheets before parsing into them. |
|
167 * This can only be called once with a non-null principal. Calling this with |
|
168 * a null pointer is allowed and is treated as a no-op. |
|
169 */ |
|
170 void SetPrincipal(nsIPrincipal* aPrincipal); |
|
171 |
|
172 // Principal() never returns a null pointer. |
|
173 nsIPrincipal* Principal() const { return mInner->mPrincipal; } |
|
174 |
|
175 // The document this style sheet is associated with. May be null |
|
176 nsIDocument* GetDocument() const { return mDocument; } |
|
177 |
|
178 void SetTitle(const nsAString& aTitle) { mTitle = aTitle; } |
|
179 void SetMedia(nsMediaList* aMedia); |
|
180 void SetOwningNode(nsINode* aOwningNode) { mOwningNode = aOwningNode; /* Not ref counted */ } |
|
181 |
|
182 void SetOwnerRule(mozilla::css::ImportRule* aOwnerRule) { mOwnerRule = aOwnerRule; /* Not ref counted */ } |
|
183 mozilla::css::ImportRule* GetOwnerRule() const { return mOwnerRule; } |
|
184 |
|
185 nsXMLNameSpaceMap* GetNameSpaceMap() const { return mInner->mNameSpaceMap; } |
|
186 |
|
187 already_AddRefed<nsCSSStyleSheet> Clone(nsCSSStyleSheet* aCloneParent, |
|
188 mozilla::css::ImportRule* aCloneOwnerRule, |
|
189 nsIDocument* aCloneDocument, |
|
190 nsINode* aCloneOwningNode) const; |
|
191 |
|
192 bool IsModified() const { return mDirty; } |
|
193 |
|
194 void SetModifiedByChildRule() { |
|
195 NS_ASSERTION(mDirty, |
|
196 "sheet must be marked dirty before handing out child rules"); |
|
197 DidDirty(); |
|
198 } |
|
199 |
|
200 nsresult AddRuleProcessor(nsCSSRuleProcessor* aProcessor); |
|
201 nsresult DropRuleProcessor(nsCSSRuleProcessor* aProcessor); |
|
202 |
|
203 /** |
|
204 * Like the DOM insertRule() method, but doesn't do any security checks |
|
205 */ |
|
206 nsresult InsertRuleInternal(const nsAString& aRule, |
|
207 uint32_t aIndex, uint32_t* aReturn); |
|
208 |
|
209 /* Get the URI this sheet was originally loaded from, if any. Can |
|
210 return null */ |
|
211 virtual nsIURI* GetOriginalURI() const; |
|
212 |
|
213 // nsICSSLoaderObserver interface |
|
214 NS_IMETHOD StyleSheetLoaded(nsCSSStyleSheet* aSheet, bool aWasAlternate, |
|
215 nsresult aStatus) MOZ_OVERRIDE; |
|
216 |
|
217 enum EnsureUniqueInnerResult { |
|
218 // No work was needed to ensure a unique inner. |
|
219 eUniqueInner_AlreadyUnique, |
|
220 // A clone was done to ensure a unique inner (which means the style |
|
221 // rules in this sheet have changed). |
|
222 eUniqueInner_ClonedInner |
|
223 }; |
|
224 EnsureUniqueInnerResult EnsureUniqueInner(); |
|
225 |
|
226 // Append all of this sheet's child sheets to aArray. |
|
227 void AppendAllChildSheets(nsTArray<nsCSSStyleSheet*>& aArray); |
|
228 |
|
229 bool UseForPresentation(nsPresContext* aPresContext, |
|
230 nsMediaQueryResultCacheKey& aKey) const; |
|
231 |
|
232 nsresult ParseSheet(const nsAString& aInput); |
|
233 |
|
234 // nsIDOMStyleSheet interface |
|
235 NS_DECL_NSIDOMSTYLESHEET |
|
236 |
|
237 // nsIDOMCSSStyleSheet interface |
|
238 NS_DECL_NSIDOMCSSSTYLESHEET |
|
239 |
|
240 // Function used as a callback to rebuild our inner's child sheet |
|
241 // list after we clone a unique inner for ourselves. |
|
242 static bool RebuildChildList(mozilla::css::Rule* aRule, void* aBuilder); |
|
243 |
|
244 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE; |
|
245 |
|
246 // Get this style sheet's CORS mode |
|
247 mozilla::CORSMode GetCORSMode() const { return mInner->mCORSMode; } |
|
248 |
|
249 mozilla::dom::Element* GetScopeElement() const { return mScopeElement; } |
|
250 void SetScopeElement(mozilla::dom::Element* aScopeElement) |
|
251 { |
|
252 mScopeElement = aScopeElement; |
|
253 } |
|
254 |
|
255 // WebIDL StyleSheet API |
|
256 // Our nsIStyleSheet::GetType is a const method, so it ends up |
|
257 // ambiguous with with the XPCOM version. Just disambiguate. |
|
258 void GetType(nsString& aType) { |
|
259 const_cast<const nsCSSStyleSheet*>(this)->GetType(aType); |
|
260 } |
|
261 // Our XPCOM GetHref is fine for WebIDL |
|
262 nsINode* GetOwnerNode() const { return mOwningNode; } |
|
263 nsCSSStyleSheet* GetParentStyleSheet() const { return mParent; } |
|
264 // Our nsIStyleSheet::GetTitle is a const method, so it ends up |
|
265 // ambiguous with with the XPCOM version. Just disambiguate. |
|
266 void GetTitle(nsString& aTitle) { |
|
267 const_cast<const nsCSSStyleSheet*>(this)->GetTitle(aTitle); |
|
268 } |
|
269 nsMediaList* Media(); |
|
270 bool Disabled() const { return mDisabled; } |
|
271 // The XPCOM SetDisabled is fine for WebIDL |
|
272 |
|
273 // WebIDL CSSStyleSheet API |
|
274 // Can't be inline because we can't include ImportRule here. And can't be |
|
275 // called GetOwnerRule because that would be ambiguous with the ImportRule |
|
276 // version. |
|
277 nsIDOMCSSRule* GetDOMOwnerRule() const; |
|
278 nsIDOMCSSRuleList* GetCssRules(mozilla::ErrorResult& aRv); |
|
279 uint32_t InsertRule(const nsAString& aRule, uint32_t aIndex, |
|
280 mozilla::ErrorResult& aRv) { |
|
281 uint32_t retval; |
|
282 aRv = InsertRule(aRule, aIndex, &retval); |
|
283 return retval; |
|
284 } |
|
285 void DeleteRule(uint32_t aIndex, mozilla::ErrorResult& aRv) { |
|
286 aRv = DeleteRule(aIndex); |
|
287 } |
|
288 |
|
289 // WebIDL miscellaneous bits |
|
290 mozilla::dom::ParentObject GetParentObject() const { |
|
291 if (mOwningNode) { |
|
292 return mozilla::dom::ParentObject(mOwningNode); |
|
293 } |
|
294 |
|
295 return mozilla::dom::ParentObject(static_cast<nsIStyleSheet*>(mParent), |
|
296 mParent); |
|
297 } |
|
298 virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; |
|
299 |
|
300 private: |
|
301 nsCSSStyleSheet(const nsCSSStyleSheet& aCopy, |
|
302 nsCSSStyleSheet* aParentToUse, |
|
303 mozilla::css::ImportRule* aOwnerRuleToUse, |
|
304 nsIDocument* aDocumentToUse, |
|
305 nsINode* aOwningNodeToUse); |
|
306 |
|
307 nsCSSStyleSheet(const nsCSSStyleSheet& aCopy) MOZ_DELETE; |
|
308 nsCSSStyleSheet& operator=(const nsCSSStyleSheet& aCopy) MOZ_DELETE; |
|
309 |
|
310 protected: |
|
311 virtual ~nsCSSStyleSheet(); |
|
312 |
|
313 void ClearRuleCascades(); |
|
314 |
|
315 void WillDirty(); |
|
316 void DidDirty(); |
|
317 |
|
318 // Return success if the subject principal subsumes the principal of our |
|
319 // inner, error otherwise. This will also succeed if the subject has |
|
320 // UniversalXPConnect or if access is allowed by CORS. In the latter case, |
|
321 // it will set the principal of the inner to the subject principal. |
|
322 nsresult SubjectSubsumesInnerPrincipal(); |
|
323 |
|
324 // Add the namespace mapping from this @namespace rule to our namespace map |
|
325 nsresult RegisterNamespaceRule(mozilla::css::Rule* aRule); |
|
326 |
|
327 // Drop our reference to mRuleCollection |
|
328 void DropRuleCollection(); |
|
329 |
|
330 // Drop our reference to mMedia |
|
331 void DropMedia(); |
|
332 |
|
333 // Unlink our inner, if needed, for cycle collection |
|
334 void UnlinkInner(); |
|
335 // Traverse our inner, if needed, for cycle collection |
|
336 void TraverseInner(nsCycleCollectionTraversalCallback &); |
|
337 |
|
338 protected: |
|
339 nsString mTitle; |
|
340 nsRefPtr<nsMediaList> mMedia; |
|
341 nsRefPtr<nsCSSStyleSheet> mNext; |
|
342 nsCSSStyleSheet* mParent; // weak ref |
|
343 mozilla::css::ImportRule* mOwnerRule; // weak ref |
|
344 |
|
345 nsRefPtr<CSSRuleListImpl> mRuleCollection; |
|
346 nsIDocument* mDocument; // weak ref; parents maintain this for their children |
|
347 nsINode* mOwningNode; // weak ref |
|
348 bool mDisabled; |
|
349 bool mDirty; // has been modified |
|
350 nsRefPtr<mozilla::dom::Element> mScopeElement; |
|
351 |
|
352 nsCSSStyleSheetInner* mInner; |
|
353 |
|
354 nsAutoTArray<nsCSSRuleProcessor*, 8>* mRuleProcessors; |
|
355 |
|
356 friend class nsMediaList; |
|
357 friend class nsCSSRuleProcessor; |
|
358 friend struct ChildSheetListBuilder; |
|
359 }; |
|
360 |
|
361 NS_DEFINE_STATIC_IID_ACCESSOR(nsCSSStyleSheet, NS_CSS_STYLE_SHEET_IMPL_CID) |
|
362 |
|
363 #endif /* !defined(nsCSSStyleSheet_h_) */ |