Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 : #ifndef mozilla_StyleSheet_h
8 : #define mozilla_StyleSheet_h
9 :
10 : #include "mozilla/css/SheetParsingMode.h"
11 : #include "mozilla/dom/CSSStyleSheetBinding.h"
12 : #include "mozilla/net/ReferrerPolicy.h"
13 : #include "mozilla/StyleBackendType.h"
14 : #include "mozilla/CORSMode.h"
15 : #include "mozilla/ServoUtils.h"
16 :
17 : #include "nsICSSLoaderObserver.h"
18 : #include "nsIDOMCSSStyleSheet.h"
19 : #include "nsWrapperCache.h"
20 :
21 : class nsIDocument;
22 : class nsINode;
23 : class nsIPrincipal;
24 : class nsCSSRuleProcessor;
25 :
26 : namespace mozilla {
27 :
28 : class CSSStyleSheet;
29 : class ServoStyleSheet;
30 : class StyleSetHandle;
31 : struct StyleSheetInfo;
32 : struct CSSStyleSheetInner;
33 :
34 : namespace dom {
35 : class CSSImportRule;
36 : class CSSRuleList;
37 : class MediaList;
38 : class SRIMetadata;
39 : } // namespace dom
40 :
41 : namespace css {
42 : class GroupRule;
43 : class Rule;
44 : }
45 :
46 : /**
47 : * Superclass for data common to CSSStyleSheet and ServoStyleSheet.
48 : */
49 : class StyleSheet : public nsIDOMCSSStyleSheet
50 : , public nsICSSLoaderObserver
51 : , public nsWrapperCache
52 : {
53 : protected:
54 : StyleSheet(StyleBackendType aType, css::SheetParsingMode aParsingMode);
55 : StyleSheet(const StyleSheet& aCopy,
56 : StyleSheet* aParentToUse,
57 : dom::CSSImportRule* aOwnerRuleToUse,
58 : nsIDocument* aDocumentToUse,
59 : nsINode* aOwningNodeToUse);
60 : virtual ~StyleSheet();
61 :
62 : public:
63 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
64 1186 : NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(StyleSheet,
65 : nsIDOMCSSStyleSheet)
66 :
67 : /**
68 : * The different changes that a stylesheet may go through.
69 : *
70 : * Used by the StyleSets in order to handle more efficiently some kinds of
71 : * changes.
72 : */
73 : enum class ChangeType {
74 : Added,
75 : Removed,
76 : ApplicableStateChanged,
77 : RuleAdded,
78 : RuleRemoved,
79 : RuleChanged,
80 : };
81 :
82 11 : void SetOwningNode(nsINode* aOwningNode)
83 : {
84 11 : mOwningNode = aOwningNode;
85 11 : }
86 :
87 63 : css::SheetParsingMode ParsingMode() const { return mParsingMode; }
88 : mozilla::dom::CSSStyleSheetParsingMode ParsingModeDOM();
89 :
90 : /**
91 : * Whether the sheet is complete.
92 : */
93 : bool IsComplete() const;
94 : void SetComplete();
95 :
96 : /**
97 : * Set the stylesheet to be enabled. This may or may not make it
98 : * applicable. Note that this WILL inform the sheet's document of
99 : * its new applicable state if the state changes but WILL NOT call
100 : * BeginUpdate() or EndUpdate() on the document -- calling those is
101 : * the caller's responsibility. This allows use of SetEnabled when
102 : * batched updates are desired. If you want updates handled for
103 : * you, see nsIDOMStyleSheet::SetDisabled().
104 : */
105 : void SetEnabled(bool aEnabled);
106 :
107 988 : MOZ_DECL_STYLO_METHODS(CSSStyleSheet, ServoStyleSheet)
108 :
109 : // Whether the sheet is for an inline <style> element.
110 : inline bool IsInline() const;
111 :
112 : inline nsIURI* GetSheetURI() const;
113 : /* Get the URI this sheet was originally loaded from, if any. Can
114 : return null */
115 : inline nsIURI* GetOriginalURI() const;
116 : inline nsIURI* GetBaseURI() const;
117 : /**
118 : * SetURIs must be called on all sheets before parsing into them.
119 : * SetURIs may only be called while the sheet is 1) incomplete and 2)
120 : * has no rules in it
121 : */
122 : inline void SetURIs(nsIURI* aSheetURI, nsIURI* aOriginalSheetURI,
123 : nsIURI* aBaseURI);
124 :
125 : /**
126 : * Whether the sheet is applicable. A sheet that is not applicable
127 : * should never be inserted into a style set. A sheet may not be
128 : * applicable for a variety of reasons including being disabled and
129 : * being incomplete.
130 : */
131 : inline bool IsApplicable() const;
132 : inline bool HasRules() const;
133 :
134 : virtual already_AddRefed<StyleSheet> Clone(StyleSheet* aCloneParent,
135 : dom::CSSImportRule* aCloneOwnerRule,
136 : nsIDocument* aCloneDocument,
137 : nsINode* aCloneOwningNode) const = 0;
138 :
139 88 : bool IsModified() const { return mDirty; }
140 :
141 : void EnsureUniqueInner();
142 :
143 : // Append all of this sheet's child sheets to aArray.
144 : void AppendAllChildSheets(nsTArray<StyleSheet*>& aArray);
145 :
146 : // style sheet owner info
147 : enum DocumentAssociationMode : uint8_t {
148 : // OwnedByDocument means mDocument owns us (possibly via a chain of other
149 : // stylesheets).
150 : OwnedByDocument,
151 : // NotOwnedByDocument means we're owned by something that might have a
152 : // different lifetime than mDocument.
153 : NotOwnedByDocument
154 : };
155 6469 : nsIDocument* GetAssociatedDocument() const { return mDocument; }
156 0 : bool IsOwnedByDocument() const {
157 0 : return mDocumentAssociationMode == OwnedByDocument;
158 : }
159 : // aDocument must not be null.
160 : void SetAssociatedDocument(nsIDocument* aDocument,
161 : DocumentAssociationMode aMode);
162 : void ClearAssociatedDocument();
163 57 : nsINode* GetOwnerNode() const { return mOwningNode; }
164 56 : inline StyleSheet* GetParentSheet() const { return mParent; }
165 :
166 3 : void SetOwnerRule(dom::CSSImportRule* aOwnerRule) {
167 3 : mOwnerRule = aOwnerRule; /* Not ref counted */
168 3 : }
169 0 : dom::CSSImportRule* GetOwnerRule() const { return mOwnerRule; }
170 :
171 : void PrependStyleSheet(StyleSheet* aSheet);
172 :
173 : // Prepend a stylesheet to the child list without calling Will/DidDirty.
174 : void PrependStyleSheetSilently(StyleSheet* aSheet);
175 :
176 : StyleSheet* GetFirstChild() const;
177 : StyleSheet* GetMostRecentlyAddedChildSheet() const {
178 : // New child sheet can only be prepended into the linked list of
179 : // child sheets, so the most recently added one is always the first.
180 : return GetFirstChild();
181 : }
182 :
183 : // Principal() never returns a null pointer.
184 : inline nsIPrincipal* Principal() const;
185 : /**
186 : * SetPrincipal should be called on all sheets before parsing into them.
187 : * This can only be called once with a non-null principal. Calling this with
188 : * a null pointer is allowed and is treated as a no-op.
189 : */
190 : inline void SetPrincipal(nsIPrincipal* aPrincipal);
191 :
192 73 : void SetTitle(const nsAString& aTitle) { mTitle = aTitle; }
193 : void SetMedia(dom::MediaList* aMedia);
194 :
195 : // Get this style sheet's CORS mode
196 : inline CORSMode GetCORSMode() const;
197 : // Get this style sheet's Referrer Policy
198 : inline net::ReferrerPolicy GetReferrerPolicy() const;
199 : // Get this style sheet's integrity metadata
200 : inline void GetIntegrity(dom::SRIMetadata& aResult) const;
201 :
202 : virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
203 : #ifdef DEBUG
204 : virtual void List(FILE* aOut = stdout, int32_t aIndex = 0) const;
205 : #endif
206 :
207 : // WebIDL StyleSheet API
208 : // The XPCOM GetType is fine for WebIDL.
209 : // The XPCOM GetHref is fine for WebIDL
210 : // GetOwnerNode is defined above.
211 : inline StyleSheet* GetParentStyleSheet() const;
212 : // The XPCOM GetTitle is fine for WebIDL.
213 : dom::MediaList* Media();
214 0 : bool Disabled() const { return mDisabled; }
215 : // The XPCOM SetDisabled is fine for WebIDL.
216 : void GetSourceMapURL(nsAString& aTitle);
217 : void SetSourceMapURL(const nsAString& aSourceMapURL);
218 :
219 : // WebIDL CSSStyleSheet API
220 : // Can't be inline because we can't include ImportRule here. And can't be
221 : // called GetOwnerRule because that would be ambiguous with the ImportRule
222 : // version.
223 : css::Rule* GetDOMOwnerRule() const;
224 : dom::CSSRuleList* GetCssRules(nsIPrincipal& aSubjectPrincipal,
225 : ErrorResult& aRv);
226 : uint32_t InsertRule(const nsAString& aRule, uint32_t aIndex,
227 : nsIPrincipal& aSubjectPrincipal,
228 : ErrorResult& aRv);
229 : void DeleteRule(uint32_t aIndex,
230 : nsIPrincipal& aSubjectPrincipal,
231 : ErrorResult& aRv);
232 :
233 : // WebIDL miscellaneous bits
234 : inline dom::ParentObject GetParentObject() const;
235 : JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) final;
236 :
237 : // nsIDOMStyleSheet interface
238 : NS_IMETHOD GetType(nsAString& aType) final;
239 : NS_IMETHOD GetDisabled(bool* aDisabled) final;
240 : NS_IMETHOD SetDisabled(bool aDisabled) final;
241 : NS_IMETHOD GetOwnerNode(nsIDOMNode** aOwnerNode) final;
242 : NS_IMETHOD GetParentStyleSheet(nsIDOMStyleSheet** aParentStyleSheet) final;
243 : NS_IMETHOD GetHref(nsAString& aHref) final;
244 : NS_IMETHOD GetTitle(nsAString& aTitle) final;
245 : NS_IMETHOD GetMedia(nsIDOMMediaList** aMedia) final;
246 :
247 : // nsIDOMCSSStyleSheet
248 : NS_IMETHOD GetOwnerRule(nsIDOMCSSRule** aOwnerRule) final;
249 : NS_IMETHOD GetCssRules(nsIDOMCSSRuleList** aCssRules) final;
250 : NS_IMETHOD InsertRule(const nsAString& aRule, uint32_t aIndex,
251 : uint32_t* aReturn) final;
252 : NS_IMETHOD DeleteRule(uint32_t aIndex) final;
253 :
254 : // Changes to sheets should be inside of a WillDirty-DidDirty pair.
255 : // However, the calls do not need to be matched; it's ok to call
256 : // WillDirty and then make no change and skip the DidDirty call.
257 : void WillDirty();
258 0 : virtual void DidDirty() {}
259 :
260 : void AddStyleSet(const StyleSetHandle& aStyleSet);
261 : void DropStyleSet(const StyleSetHandle& aStyleSet);
262 :
263 : nsresult DeleteRuleFromGroup(css::GroupRule* aGroup, uint32_t aIndex);
264 : nsresult InsertRuleIntoGroup(const nsAString& aRule,
265 : css::GroupRule* aGroup, uint32_t aIndex);
266 :
267 : // Find the ID of the owner inner window.
268 : uint64_t FindOwningWindowInnerID() const;
269 :
270 : template<typename Func>
271 : void EnumerateChildSheets(Func aCallback) {
272 : for (StyleSheet* child = GetFirstChild(); child; child = child->mNext) {
273 : aCallback(child);
274 : }
275 : }
276 :
277 : private:
278 : // Get a handle to the various stylesheet bits which live on the 'inner' for
279 : // gecko stylesheets and live on the StyleSheet for Servo stylesheets.
280 : inline StyleSheetInfo& SheetInfo();
281 : inline const StyleSheetInfo& SheetInfo() const;
282 :
283 : // Check if the rules are available for read and write.
284 : // It does the security check as well as whether the rules have been
285 : // completely loaded. aRv will have an exception set if this function
286 : // returns false.
287 : bool AreRulesAvailable(nsIPrincipal& aSubjectPrincipal,
288 : ErrorResult& aRv);
289 :
290 : protected:
291 : struct ChildSheetListBuilder {
292 : RefPtr<StyleSheet>* sheetSlot;
293 : StyleSheet* parent;
294 :
295 : void SetParentLinks(StyleSheet* aSheet);
296 :
297 : static void ReparentChildList(StyleSheet* aPrimarySheet,
298 : StyleSheet* aFirstChild);
299 : };
300 :
301 : void UnparentChildren();
302 :
303 : void LastRelease();
304 :
305 : // Return success if the subject principal subsumes the principal of our
306 : // inner, error otherwise. This will also succeed if the subject has
307 : // UniversalXPConnect or if access is allowed by CORS. In the latter case,
308 : // it will set the principal of the inner to the subject principal.
309 : void SubjectSubsumesInnerPrincipal(nsIPrincipal& aSubjectPrincipal,
310 : ErrorResult& aRv);
311 :
312 : // Drop our reference to mMedia
313 : void DropMedia();
314 :
315 : // Called from SetEnabled when the enabled state changed.
316 : void EnabledStateChanged();
317 :
318 : // Unlink our inner, if needed, for cycle collection
319 : virtual void UnlinkInner();
320 : // Traverse our inner, if needed, for cycle collection
321 : virtual void TraverseInner(nsCycleCollectionTraversalCallback &);
322 :
323 : // Return whether the given @import rule has pending child sheet.
324 : static bool RuleHasPendingChildSheet(css::Rule* aRule);
325 :
326 : StyleSheet* mParent; // weak ref
327 :
328 : nsString mTitle;
329 : nsIDocument* mDocument; // weak ref; parents maintain this for their children
330 : nsINode* mOwningNode; // weak ref
331 : dom::CSSImportRule* mOwnerRule; // weak ref
332 :
333 : RefPtr<dom::MediaList> mMedia;
334 :
335 : RefPtr<StyleSheet> mNext;
336 :
337 : // mParsingMode controls access to nonstandard style constructs that
338 : // are not safe for use on the public Web but necessary in UA sheets
339 : // and/or useful in user sheets.
340 : css::SheetParsingMode mParsingMode;
341 :
342 : const StyleBackendType mType;
343 : bool mDisabled;
344 :
345 : bool mDirty; // has been modified
346 :
347 : // mDocumentAssociationMode determines whether mDocument directly owns us (in
348 : // the sense that if it's known-live then we're known-live). Always
349 : // NotOwnedByDocument when mDocument is null.
350 : DocumentAssociationMode mDocumentAssociationMode;
351 :
352 : // Core information we get from parsed sheets, which are shared amongst
353 : // StyleSheet clones.
354 : StyleSheetInfo* mInner;
355 :
356 : nsTArray<StyleSetHandle> mStyleSets;
357 :
358 : friend class ::nsCSSRuleProcessor;
359 :
360 : // Make CSSStyleSheet and ServoStyleSheet friends so they can access
361 : // protected members of other StyleSheet objects (useful for iterating
362 : // through children).
363 : friend class mozilla::CSSStyleSheet;
364 : friend class mozilla::ServoStyleSheet;
365 :
366 : // Make StyleSheetInfo and subclasses into friends so they can use
367 : // ChildSheetListBuilder.
368 : friend struct mozilla::StyleSheetInfo;
369 : friend struct mozilla::CSSStyleSheetInner;
370 : };
371 :
372 : } // namespace mozilla
373 :
374 : #endif // mozilla_StyleSheet_h
|