Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/StyleSheet.h
Line
Count
Source (jump to first uncovered line)
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/dom/SRIMetadata.h"
13
#include "mozilla/net/ReferrerPolicy.h"
14
#include "mozilla/CORSMode.h"
15
#include "mozilla/MozPromise.h"
16
#include "mozilla/RefPtr.h"
17
#include "mozilla/ServoBindingTypes.h"
18
#include "mozilla/ServoUtils.h"
19
#include "mozilla/StyleSheetInfo.h"
20
#include "mozilla/URLExtraData.h"
21
#include "nsICSSLoaderObserver.h"
22
#include "nsWrapperCache.h"
23
#include "nsCompatibility.h"
24
#include "nsStringFwd.h"
25
26
class nsIDocument;
27
class nsINode;
28
class nsIPrincipal;
29
30
namespace mozilla {
31
32
class ServoCSSRuleList;
33
class ServoStyleSet;
34
35
typedef MozPromise</* Dummy */ bool,
36
                   /* Dummy */ bool,
37
                   /* IsExclusive = */ true> StyleSheetParsePromise;
38
39
namespace css {
40
class GroupRule;
41
class Loader;
42
class LoaderReusableStyleSheets;
43
class Rule;
44
class SheetLoadData;
45
}
46
47
namespace dom {
48
class CSSImportRule;
49
class CSSRuleList;
50
class DocumentOrShadowRoot;
51
class MediaList;
52
class ShadowRoot;
53
class SRIMetadata;
54
} // namespace dom
55
56
enum class StyleSheetState : uint8_t
57
{
58
  // Whether the sheet is disabled. Sheets can be made disabled via CSSOM, or
59
  // via alternate links and such.
60
  Disabled = 1 << 0,
61
  // Whether the sheet is complete. The sheet is complete if it's finished
62
  // loading. See StyleSheet::SetComplete.
63
  Complete = 1 << 1,
64
  // Whether we've forced a unique inner. StyleSheet objects share an 'inner'
65
  // StyleSheetInfo object if they share URL, CORS mode, etc.
66
  //
67
  // See the Loader's `mCompleteSheets` and `mLoadingSheets`.
68
  ForcedUniqueInner = 1 << 2,
69
  // Whether this stylesheet has suffered any modification to the rules via
70
  // CSSOM.
71
  //
72
  // FIXME(emilio): I think as of right now we also set this flag for normal
73
  // @import rules, which looks very fishy.
74
  ModifiedRules = 1 << 3,
75
};
76
77
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(StyleSheetState)
78
79
class StyleSheet final : public nsICSSLoaderObserver
80
                       , public nsWrapperCache
81
{
82
  StyleSheet(const StyleSheet& aCopy,
83
             StyleSheet* aParentToUse,
84
             dom::CSSImportRule* aOwnerRuleToUse,
85
             dom::DocumentOrShadowRoot* aDocOrShadowRootToUse,
86
             nsINode* aOwningNodeToUse);
87
88
  virtual ~StyleSheet();
89
90
  using State = StyleSheetState;
91
92
public:
93
  StyleSheet(css::SheetParsingMode aParsingMode,
94
             CORSMode aCORSMode,
95
             net::ReferrerPolicy aReferrerPolicy,
96
             const dom::SRIMetadata& aIntegrity);
97
98
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
99
  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StyleSheet)
100
101
  already_AddRefed<StyleSheet> CreateEmptyChildSheet(
102
      already_AddRefed<dom::MediaList> aMediaList) const;
103
104
  bool HasRules() const;
105
106
  // Parses a stylesheet. The aLoadData argument corresponds to the
107
  // SheetLoadData for this stylesheet. It may be null in some cases.
108
  RefPtr<StyleSheetParsePromise>
109
  ParseSheet(css::Loader* aLoader,
110
             const nsACString& aBytes,
111
             css::SheetLoadData* aLoadData);
112
113
  // Common code that needs to be called after servo finishes parsing. This is
114
  // shared between the parallel and sequential paths.
115
  void FinishAsyncParse(already_AddRefed<RawServoStyleSheetContents> aSheetContents);
116
117
  // Similar to the above, but guarantees that parsing will be performed
118
  // synchronously.
119
  void
120
  ParseSheetSync(css::Loader* aLoader,
121
                 const nsACString& aBytes,
122
                 css::SheetLoadData* aLoadData,
123
                 uint32_t aLineNumber,
124
                 css::LoaderReusableStyleSheets* aReusableSheets = nullptr);
125
126
  nsresult ReparseSheet(const nsAString& aInput);
127
128
  const RawServoStyleSheetContents* RawContents() const
129
0
  {
130
0
    return Inner().mContents;
131
0
  }
132
133
0
  void SetContentsForImport(const RawServoStyleSheetContents* aContents) {
134
0
    MOZ_ASSERT(!Inner().mContents);
135
0
    Inner().mContents = aContents;
136
0
  }
137
138
0
  URLExtraData* URLData() const { return Inner().mURLData; }
139
140
  // nsICSSLoaderObserver interface
141
  NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet, bool aWasAlternate,
142
                              nsresult aStatus) final;
143
144
  // Internal GetCssRules methods which do not have security check and
145
  // completeness check.
146
  ServoCSSRuleList* GetCssRulesInternal();
147
148
  // Returns the stylesheet's Servo origin as an OriginFlags value.
149
  OriginFlags GetOrigin();
150
151
  /**
152
   * The different changes that a stylesheet may go through.
153
   *
154
   * Used by the StyleSets in order to handle more efficiently some kinds of
155
   * changes.
156
   */
157
  enum class ChangeType {
158
    Added,
159
    Removed,
160
    ApplicableStateChanged,
161
    RuleAdded,
162
    RuleRemoved,
163
    RuleChanged,
164
  };
165
166
  void SetOwningNode(nsINode* aOwningNode)
167
0
  {
168
0
    mOwningNode = aOwningNode;
169
0
  }
170
171
0
  css::SheetParsingMode ParsingMode() const { return mParsingMode; }
172
  mozilla::dom::CSSStyleSheetParsingMode ParsingModeDOM();
173
174
  /**
175
   * Whether the sheet is complete.
176
   */
177
  bool IsComplete() const
178
0
  {
179
0
    return bool(mState & State::Complete);
180
0
  }
181
182
  void SetComplete();
183
184
  void SetEnabled(bool aEnabled)
185
0
  {
186
0
    SetDisabled(!aEnabled);
187
0
  }
188
189
  // Whether the sheet is for an inline <style> element.
190
  bool IsInline() const
191
0
  {
192
0
    return !GetOriginalURI();
193
0
  }
194
195
  nsIURI* GetSheetURI() const
196
0
  {
197
0
    return Inner().mSheetURI;
198
0
  }
199
200
  /**
201
   * Get the URI this sheet was originally loaded from, if any. Can return null.
202
   */
203
  nsIURI* GetOriginalURI() const
204
0
  {
205
0
    return Inner().mOriginalSheetURI;
206
0
  }
207
208
  nsIURI* GetBaseURI() const
209
0
  {
210
0
    return Inner().mBaseURI;
211
0
  }
212
213
  /**
214
   * SetURIs must be called on all sheets before parsing into them.
215
   * SetURIs may only be called while the sheet is 1) incomplete and 2)
216
   * has no rules in it.
217
   *
218
   * FIXME(emilio): Can we pass this down when constructing the sheet instead?
219
   */
220
  inline void SetURIs(nsIURI* aSheetURI,
221
                      nsIURI* aOriginalSheetURI,
222
                      nsIURI* aBaseURI);
223
224
  /**
225
   * Whether the sheet is applicable.  A sheet that is not applicable
226
   * should never be inserted into a style set.  A sheet may not be
227
   * applicable for a variety of reasons including being disabled and
228
   * being incomplete.
229
   */
230
  bool IsApplicable() const
231
0
  {
232
0
    return !Disabled() && IsComplete();
233
0
  }
234
235
  already_AddRefed<StyleSheet> Clone(StyleSheet* aCloneParent,
236
                                     dom::CSSImportRule* aCloneOwnerRule,
237
                                     dom::DocumentOrShadowRoot* aCloneDocumentOrShadowRoot,
238
                                     nsINode* aCloneOwningNode) const;
239
240
  bool HasForcedUniqueInner() const
241
0
  {
242
0
    return bool(mState & State::ForcedUniqueInner);
243
0
  }
244
245
  bool HasModifiedRules() const
246
0
  {
247
0
    return bool(mState & State::ModifiedRules);
248
0
  }
249
250
  void ClearModifiedRules()
251
0
  {
252
0
    mState &= ~State::ModifiedRules;
253
0
  }
254
255
  bool HasUniqueInner() const
256
0
  {
257
0
    return Inner().mSheets.Length() == 1;
258
0
  }
259
260
  void AssertHasUniqueInner() const
261
0
  {
262
0
    MOZ_ASSERT(HasUniqueInner());
263
0
  }
264
265
  void EnsureUniqueInner();
266
267
  // Append all of this sheet's child sheets to aArray.
268
  void AppendAllChildSheets(nsTArray<StyleSheet*>& aArray);
269
270
  // style sheet owner info
271
  enum AssociationMode : uint8_t {
272
    // OwnedByDocumentOrShadowRoot means mDocumentOrShadowRoot owns us (possibly
273
    // via a chain of other stylesheets).
274
    OwnedByDocumentOrShadowRoot,
275
    // NotOwnedByDocument means we're owned by something that might have a
276
    // different lifetime than mDocument.
277
    NotOwnedByDocumentOrShadowRoot
278
  };
279
  dom::DocumentOrShadowRoot* GetAssociatedDocumentOrShadowRoot() const
280
0
  {
281
0
    return mDocumentOrShadowRoot;
282
0
  }
283
284
  // Whether this stylesheet is kept alive by the associated document or
285
  // associated shadow root's document somehow, and thus at least has the same
286
  // lifetime as GetAssociatedDocument().
287
  bool IsKeptAliveByDocument() const;
288
289
  // Returns the document whose styles this sheet is affecting.
290
  nsIDocument* GetComposedDoc() const;
291
292
  // Returns the document we're associated to, via mDocumentOrShadowRoot.
293
  //
294
  // Non-null iff GetAssociatedDocumentOrShadowRoot is non-null.
295
  nsIDocument* GetAssociatedDocument() const;
296
297
  void SetAssociatedDocumentOrShadowRoot(dom::DocumentOrShadowRoot*,
298
                                         AssociationMode);
299
  void ClearAssociatedDocumentOrShadowRoot()
300
0
  {
301
0
    SetAssociatedDocumentOrShadowRoot(nullptr, NotOwnedByDocumentOrShadowRoot);
302
0
  }
303
304
  nsINode* GetOwnerNode() const
305
0
  {
306
0
    return mOwningNode;
307
0
  }
308
309
  StyleSheet* GetParentSheet() const
310
0
  {
311
0
    return mParent;
312
0
  }
313
314
0
  void SetOwnerRule(dom::CSSImportRule* aOwnerRule) {
315
0
    mOwnerRule = aOwnerRule; /* Not ref counted */
316
0
  }
317
0
  dom::CSSImportRule* GetOwnerRule() const { return mOwnerRule; }
318
319
  void PrependStyleSheet(StyleSheet* aSheet);
320
321
  // Prepend a stylesheet to the child list without calling WillDirty.
322
  void PrependStyleSheetSilently(StyleSheet* aSheet);
323
324
  StyleSheet* GetFirstChild() const;
325
0
  StyleSheet* GetMostRecentlyAddedChildSheet() const {
326
0
    // New child sheet can only be prepended into the linked list of
327
0
    // child sheets, so the most recently added one is always the first.
328
0
    return GetFirstChild();
329
0
  }
330
331
  // Principal() never returns a null pointer.
332
  nsIPrincipal* Principal() const
333
0
  {
334
0
    return Inner().mPrincipal;
335
0
  }
336
337
  /**
338
   * SetPrincipal should be called on all sheets before parsing into them.
339
   * This can only be called once with a non-null principal.
340
   *
341
   * Calling this with a null pointer is allowed and is treated as a no-op.
342
   *
343
   * FIXME(emilio): Can we get this at construction time instead?
344
   */
345
  void SetPrincipal(nsIPrincipal* aPrincipal)
346
0
  {
347
0
    StyleSheetInfo& info = Inner();
348
0
    MOZ_ASSERT(!info.mPrincipalSet, "Should only set principal once");
349
0
    if (aPrincipal) {
350
0
      info.mPrincipal = aPrincipal;
351
#ifdef DEBUG
352
      info.mPrincipalSet = true;
353
#endif
354
    }
355
0
  }
356
357
0
  void SetTitle(const nsAString& aTitle) { mTitle = aTitle; }
358
  void SetMedia(dom::MediaList* aMedia);
359
360
  // Get this style sheet's CORS mode
361
  CORSMode GetCORSMode() const
362
0
  {
363
0
    return Inner().mCORSMode;
364
0
  }
365
366
  // Set style sheet's Referrer Policy
367
  void SetReferrerPolicy(net::ReferrerPolicy aReferrerPolicy);
368
369
  // Get this style sheet's Referrer Policy
370
  net::ReferrerPolicy GetReferrerPolicy() const
371
0
  {
372
0
    return Inner().mReferrerPolicy;
373
0
  }
374
  // Get this style sheet's integrity metadata
375
  void GetIntegrity(dom::SRIMetadata& aResult) const
376
0
  {
377
0
    aResult = Inner().mIntegrity;
378
0
  }
379
380
  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
381
#ifdef DEBUG
382
  void List(FILE* aOut = stdout, int32_t aIndex = 0) const;
383
#endif
384
385
  // WebIDL StyleSheet API
386
  void GetType(nsAString& aType);
387
  void GetHref(nsAString& aHref, ErrorResult& aRv);
388
  // GetOwnerNode is defined above.
389
  StyleSheet* GetParentStyleSheet() const
390
0
  {
391
0
    return GetParentSheet();
392
0
  }
393
  void GetTitle(nsAString& aTitle);
394
  dom::MediaList* Media();
395
  bool Disabled() const
396
0
  {
397
0
    return bool(mState & State::Disabled);
398
0
  }
399
  void SetDisabled(bool aDisabled);
400
  void GetSourceMapURL(nsAString& aTitle);
401
  void SetSourceMapURL(const nsAString& aSourceMapURL);
402
  void SetSourceMapURLFromComment(const nsAString& aSourceMapURLFromComment);
403
  void GetSourceURL(nsAString& aSourceURL);
404
  void SetSourceURL(const nsAString& aSourceURL);
405
406
  // WebIDL CSSStyleSheet API
407
  // Can't be inline because we can't include ImportRule here.  And can't be
408
  // called GetOwnerRule because that would be ambiguous with the ImportRule
409
  // version.
410
  css::Rule* GetDOMOwnerRule() const;
411
  dom::CSSRuleList* GetCssRules(nsIPrincipal& aSubjectPrincipal, ErrorResult&);
412
  uint32_t InsertRule(const nsAString& aRule, uint32_t aIndex,
413
                      nsIPrincipal& aSubjectPrincipal,
414
                      ErrorResult& aRv);
415
  void DeleteRule(uint32_t aIndex,
416
                  nsIPrincipal& aSubjectPrincipal,
417
                  ErrorResult& aRv);
418
419
  // WebIDL miscellaneous bits
420
  inline dom::ParentObject GetParentObject() const;
421
  JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) final;
422
423
  // Changes to sheets should be after a WillDirty call.
424
  void WillDirty();
425
426
  // Called when a rule changes from CSSOM.
427
  //
428
  // FIXME(emilio): This shouldn't allow null, but MediaList doesn't know about
429
  // it's owning media rule, plus it's used for the stylesheet media itself.
430
  void RuleChanged(css::Rule*);
431
432
  void AddStyleSet(ServoStyleSet* aStyleSet);
433
  void DropStyleSet(ServoStyleSet* aStyleSet);
434
435
  nsresult DeleteRuleFromGroup(css::GroupRule* aGroup, uint32_t aIndex);
436
  nsresult InsertRuleIntoGroup(const nsAString& aRule,
437
                               css::GroupRule* aGroup, uint32_t aIndex);
438
439
  // Find the ID of the owner inner window.
440
  uint64_t FindOwningWindowInnerID() const;
441
442
  template<typename Func>
443
  void EnumerateChildSheets(Func aCallback) {
444
    for (StyleSheet* child = GetFirstChild(); child; child = child->mNext) {
445
      aCallback(child);
446
    }
447
  }
448
449
private:
450
  dom::ShadowRoot* GetContainingShadow() const;
451
452
  StyleSheetInfo& Inner()
453
0
  {
454
0
    MOZ_ASSERT(mInner);
455
0
    return *mInner;
456
0
  }
457
458
  const StyleSheetInfo& Inner() const
459
0
  {
460
0
    MOZ_ASSERT(mInner);
461
0
    return *mInner;
462
0
  }
463
464
  // Check if the rules are available for read and write.
465
  // It does the security check as well as whether the rules have been
466
  // completely loaded. aRv will have an exception set if this function
467
  // returns false.
468
  bool AreRulesAvailable(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv);
469
470
  already_AddRefed<URLExtraData> CreateURLExtraData() const;
471
472
protected:
473
  // Internal methods which do not have security check and completeness check.
474
  uint32_t InsertRuleInternal(const nsAString& aRule,
475
                              uint32_t aIndex,
476
                              ErrorResult&);
477
  void DeleteRuleInternal(uint32_t aIndex, ErrorResult&);
478
  nsresult InsertRuleIntoGroupInternal(const nsAString& aRule,
479
                                       css::GroupRule* aGroup,
480
                                       uint32_t aIndex);
481
482
  // Common tail routine for the synchronous and asynchronous parsing paths.
483
  void FinishParse();
484
485
  // Take the recently cloned sheets from the `@import` rules, and reparent them
486
  // correctly to `aPrimarySheet`.
487
  void BuildChildListAfterInnerClone();
488
489
  void DropRuleList();
490
491
  // Called when a rule is removed from the sheet from CSSOM.
492
  void RuleAdded(css::Rule&);
493
494
  // Called when a rule is added to the sheet from CSSOM.
495
  void RuleRemoved(css::Rule&);
496
497
  void ApplicableStateChanged(bool aApplicable);
498
499
  struct ChildSheetListBuilder {
500
    RefPtr<StyleSheet>* sheetSlot;
501
    StyleSheet* parent;
502
503
    void SetParentLinks(StyleSheet* aSheet);
504
505
    static void ReparentChildList(StyleSheet* aPrimarySheet,
506
                                  StyleSheet* aFirstChild);
507
  };
508
509
  void UnparentChildren();
510
511
  void LastRelease();
512
513
  // Return success if the subject principal subsumes the principal of our
514
  // inner, error otherwise.  This will also succeed if the subject has
515
  // UniversalXPConnect or if access is allowed by CORS.  In the latter case,
516
  // it will set the principal of the inner to the subject principal.
517
  void SubjectSubsumesInnerPrincipal(nsIPrincipal& aSubjectPrincipal,
518
                                     ErrorResult& aRv);
519
520
  // Drop our reference to mMedia
521
  void DropMedia();
522
523
  // Unlink our inner, if needed, for cycle collection.
524
  void UnlinkInner();
525
  // Traverse our inner, if needed, for cycle collection
526
  void TraverseInner(nsCycleCollectionTraversalCallback &);
527
528
  // Return whether the given @import rule has pending child sheet.
529
  static bool RuleHasPendingChildSheet(css::Rule* aRule);
530
531
  StyleSheet* mParent;    // weak ref
532
533
  nsString mTitle;
534
  dom::DocumentOrShadowRoot* mDocumentOrShadowRoot; // weak ref; parents maintain this for their children
535
  nsINode* mOwningNode; // weak ref
536
  dom::CSSImportRule* mOwnerRule; // weak ref
537
538
  RefPtr<dom::MediaList> mMedia;
539
540
  RefPtr<StyleSheet> mNext;
541
542
  // mParsingMode controls access to nonstandard style constructs that
543
  // are not safe for use on the public Web but necessary in UA sheets
544
  // and/or useful in user sheets.
545
  //
546
  // FIXME(emilio): Given we store the parsed contents in the Inner, this should
547
  // probably also move there.
548
  css::SheetParsingMode mParsingMode;
549
550
  State mState;
551
552
  // mAssociationMode determines whether mDocumentOrShadowRoot directly owns us
553
  // (in the sense that if it's known-live then we're known-live).
554
  //
555
  // Always NotOwnedByDocumentOrShadowRoot when mDocumentOrShadowRoot is null.
556
  AssociationMode mAssociationMode;
557
558
  // Core information we get from parsed sheets, which are shared amongst
559
  // StyleSheet clones.
560
  //
561
  // Always nonnull until LastRelease().
562
  StyleSheetInfo* mInner;
563
564
  nsTArray<ServoStyleSet*> mStyleSets;
565
566
  RefPtr<ServoCSSRuleList> mRuleList;
567
568
  MozPromiseHolder<StyleSheetParsePromise> mParsePromise;
569
570
  // Make StyleSheetInfo and subclasses into friends so they can use
571
  // ChildSheetListBuilder.
572
  friend struct mozilla::StyleSheetInfo;
573
};
574
575
} // namespace mozilla
576
577
#endif // mozilla_StyleSheet_h