Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/style/StyleSheet.cpp
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
#include "mozilla/StyleSheet.h"
8
9
#include "mozilla/ComputedStyleInlines.h"
10
#include "mozilla/css/ErrorReporter.h"
11
#include "mozilla/css/GroupRule.h"
12
#include "mozilla/dom/CSSImportRule.h"
13
#include "mozilla/dom/CSSRuleList.h"
14
#include "mozilla/dom/Element.h"
15
#include "mozilla/dom/MediaList.h"
16
#include "mozilla/dom/ShadowRoot.h"
17
#include "mozilla/dom/ShadowRootBinding.h"
18
#include "mozilla/NullPrincipal.h"
19
#include "mozilla/ServoBindings.h"
20
#include "mozilla/ServoCSSRuleList.h"
21
#include "mozilla/ServoStyleSet.h"
22
#include "mozilla/StaticPrefs.h"
23
#include "mozilla/StyleSheetInlines.h"
24
25
#include "mozAutoDocUpdate.h"
26
27
namespace mozilla {
28
29
using namespace dom;
30
31
StyleSheet::StyleSheet(css::SheetParsingMode aParsingMode,
32
                       CORSMode aCORSMode,
33
                       net::ReferrerPolicy aReferrerPolicy,
34
                       const dom::SRIMetadata& aIntegrity)
35
  : mParent(nullptr)
36
  , mDocumentOrShadowRoot(nullptr)
37
  , mOwningNode(nullptr)
38
  , mOwnerRule(nullptr)
39
  , mParsingMode(aParsingMode)
40
  , mState(static_cast<State>(0))
41
  , mAssociationMode(NotOwnedByDocumentOrShadowRoot)
42
  , mInner(new StyleSheetInfo(aCORSMode, aReferrerPolicy, aIntegrity, aParsingMode))
43
0
{
44
0
  mInner->AddSheet(this);
45
0
}
46
47
StyleSheet::StyleSheet(const StyleSheet& aCopy,
48
                       StyleSheet* aParentToUse,
49
                       dom::CSSImportRule* aOwnerRuleToUse,
50
                       dom::DocumentOrShadowRoot* aDocumentOrShadowRoot,
51
                       nsINode* aOwningNodeToUse)
52
  : mParent(aParentToUse)
53
  , mTitle(aCopy.mTitle)
54
  , mDocumentOrShadowRoot(aDocumentOrShadowRoot)
55
  , mOwningNode(aOwningNodeToUse)
56
  , mOwnerRule(aOwnerRuleToUse)
57
  , mParsingMode(aCopy.mParsingMode)
58
  , mState(aCopy.mState)
59
  // We only use this constructor during cloning.  It's the cloner's
60
  // responsibility to notify us if we end up being owned by a document.
61
  , mAssociationMode(NotOwnedByDocumentOrShadowRoot)
62
  , mInner(aCopy.mInner) // Shallow copy, but concrete subclasses will fix up.
63
0
{
64
0
  MOZ_ASSERT(mInner, "Should only copy StyleSheets with an mInner.");
65
0
  mInner->AddSheet(this);
66
0
67
0
  if (HasForcedUniqueInner()) { // CSSOM's been there, force full copy now
68
0
    MOZ_ASSERT(IsComplete(),
69
0
               "Why have rules been accessed on an incomplete sheet?");
70
0
    // FIXME: handle failure?
71
0
    EnsureUniqueInner();
72
0
  }
73
0
74
0
  if (aCopy.mMedia) {
75
0
    // XXX This is wrong; we should be keeping @import rules and
76
0
    // sheets in sync!
77
0
    mMedia = aCopy.mMedia->Clone();
78
0
  }
79
0
}
80
81
StyleSheet::~StyleSheet()
82
0
{
83
0
  MOZ_ASSERT(!mInner, "Inner should have been dropped in LastRelease");
84
0
}
85
86
bool
87
StyleSheet::HasRules() const
88
0
{
89
0
  return Servo_StyleSheet_HasRules(Inner().mContents);
90
0
}
91
92
nsIDocument*
93
StyleSheet::GetAssociatedDocument() const
94
0
{
95
0
  return mDocumentOrShadowRoot
96
0
    ? mDocumentOrShadowRoot->AsNode().OwnerDoc()
97
0
    : nullptr;
98
0
}
99
100
nsIDocument*
101
StyleSheet::GetComposedDoc() const
102
0
{
103
0
  return mDocumentOrShadowRoot
104
0
    ? mDocumentOrShadowRoot->AsNode().GetComposedDoc()
105
0
    : nullptr;
106
0
}
107
108
bool
109
StyleSheet::IsKeptAliveByDocument() const
110
0
{
111
0
  if (mAssociationMode != OwnedByDocumentOrShadowRoot) {
112
0
    return false;
113
0
  }
114
0
115
0
  return !!GetComposedDoc();
116
0
}
117
118
void
119
StyleSheet::LastRelease()
120
0
{
121
0
  MOZ_ASSERT(mInner, "Should have an mInner at time of destruction.");
122
0
  MOZ_ASSERT(mInner->mSheets.Contains(this), "Our mInner should include us.");
123
0
124
0
  UnparentChildren();
125
0
126
0
  mInner->RemoveSheet(this);
127
0
  mInner = nullptr;
128
0
129
0
  DropMedia();
130
0
  DropRuleList();
131
0
}
132
133
void
134
StyleSheet::UnlinkInner()
135
0
{
136
0
  // We can only have a cycle through our inner if we have a unique inner,
137
0
  // because otherwise there are no JS wrappers for anything in the inner.
138
0
  if (mInner->mSheets.Length() != 1) {
139
0
    return;
140
0
  }
141
0
142
0
  // Have to be a bit careful with child sheets, because we want to
143
0
  // drop their mNext pointers and null out their mParent and
144
0
  // mDocument, but don't want to work with deleted objects.  And we
145
0
  // don't want to do any addrefing in the process, just to make sure
146
0
  // we don't confuse the cycle collector (though on the face of it,
147
0
  // addref/release pairs during unlink should probably be ok).
148
0
  RefPtr<StyleSheet> child;
149
0
  child.swap(Inner().mFirstChild);
150
0
  while (child) {
151
0
    MOZ_ASSERT(child->mParent == this, "We have a unique inner!");
152
0
    child->mParent = nullptr;
153
0
    // We (and child) might still think we're owned by a document, because
154
0
    // unlink order is non-deterministic, so the document's unlink, which would
155
0
    // tell us it does't own us anymore, may not have happened yet.  But if
156
0
    // we're being unlinked, clearly we're not owned by a document anymore
157
0
    // conceptually!
158
0
    child->ClearAssociatedDocumentOrShadowRoot();
159
0
160
0
    RefPtr<StyleSheet> next;
161
0
    // Null out child->mNext, but don't let it die yet
162
0
    next.swap(child->mNext);
163
0
    // Switch to looking at the old value of child->mNext next iteration
164
0
    child.swap(next);
165
0
    // "next" is now our previous value of child; it'll get released
166
0
    // as we loop around.
167
0
  }
168
0
}
169
170
void
171
StyleSheet::TraverseInner(nsCycleCollectionTraversalCallback &cb)
172
0
{
173
0
  // We can only have a cycle through our inner if we have a unique inner,
174
0
  // because otherwise there are no JS wrappers for anything in the inner.
175
0
  if (mInner->mSheets.Length() != 1) {
176
0
    return;
177
0
  }
178
0
179
0
  StyleSheet* childSheet = GetFirstChild();
180
0
  while (childSheet) {
181
0
    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "child sheet");
182
0
    cb.NoteXPCOMChild(childSheet);
183
0
    childSheet = childSheet->mNext;
184
0
  }
185
0
}
186
187
// QueryInterface implementation for StyleSheet
188
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StyleSheet)
189
0
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
190
0
  NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
191
0
  NS_INTERFACE_MAP_ENTRY(nsISupports)
192
0
NS_INTERFACE_MAP_END
193
194
NS_IMPL_CYCLE_COLLECTING_ADDREF(StyleSheet)
195
// We want to disconnect from our inner as soon as our refcount drops to zero,
196
// without waiting for async deletion by the cycle collector.  Otherwise we
197
// might end up cloning the inner if someone mutates another sheet that shares
198
// it with us, even though there is only one such sheet and we're about to go
199
// away.  This situation arises easily with sheet preloading.
200
NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(StyleSheet, LastRelease())
201
202
NS_IMPL_CYCLE_COLLECTION_CLASS(StyleSheet)
203
204
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(StyleSheet)
205
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMedia)
206
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRuleList)
207
0
  tmp->TraverseInner(cb);
208
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
209
210
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(StyleSheet)
211
0
  tmp->DropMedia();
212
0
  tmp->UnlinkInner();
213
0
  tmp->DropRuleList();
214
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
215
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
216
217
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(StyleSheet)
218
219
mozilla::dom::CSSStyleSheetParsingMode
220
StyleSheet::ParsingModeDOM()
221
0
{
222
0
#define CHECK(X, Y) \
223
0
  static_assert(static_cast<int>(X) == static_cast<int>(Y),             \
224
0
                "mozilla::dom::CSSStyleSheetParsingMode and mozilla::css::SheetParsingMode should have identical values");
225
0
226
0
  CHECK(mozilla::dom::CSSStyleSheetParsingMode::Agent, css::eAgentSheetFeatures);
227
0
  CHECK(mozilla::dom::CSSStyleSheetParsingMode::User, css::eUserSheetFeatures);
228
0
  CHECK(mozilla::dom::CSSStyleSheetParsingMode::Author, css::eAuthorSheetFeatures);
229
0
230
0
#undef CHECK
231
0
232
0
  return static_cast<mozilla::dom::CSSStyleSheetParsingMode>(mParsingMode);
233
0
}
234
235
void
236
StyleSheet::SetComplete()
237
0
{
238
0
  MOZ_ASSERT(!HasForcedUniqueInner(),
239
0
             "Can't complete a sheet that's already been forced unique.");
240
0
  MOZ_ASSERT(!IsComplete(), "Already complete?");
241
0
  mState |= State::Complete;
242
0
  if (!Disabled()) {
243
0
    ApplicableStateChanged(true);
244
0
  }
245
0
}
246
247
void
248
StyleSheet::ApplicableStateChanged(bool aApplicable)
249
0
{
250
0
  if (!mDocumentOrShadowRoot) {
251
0
    return;
252
0
  }
253
0
254
0
  nsINode& node = mDocumentOrShadowRoot->AsNode();
255
0
  if (auto* shadow = ShadowRoot::FromNode(node)) {
256
0
    shadow->StyleSheetApplicableStateChanged(*this, aApplicable);
257
0
  } else {
258
0
    node.AsDocument()->SetStyleSheetApplicableState(this, aApplicable);
259
0
  }
260
0
}
261
262
void
263
StyleSheet::SetDisabled(bool aDisabled)
264
0
{
265
0
  if (aDisabled == Disabled()) {
266
0
    return;
267
0
  }
268
0
269
0
  if (aDisabled) {
270
0
    mState |= State::Disabled;
271
0
  } else {
272
0
    mState &= ~State::Disabled;
273
0
  }
274
0
275
0
  if (IsComplete()) {
276
0
    ApplicableStateChanged(!aDisabled);
277
0
  }
278
0
}
279
280
already_AddRefed<URLExtraData>
281
StyleSheet::CreateURLExtraData() const
282
0
{
283
0
  RefPtr<URLExtraData> data = new URLExtraData(GetBaseURI(),
284
0
                                               GetSheetURI(),
285
0
                                               Principal(),
286
0
                                               GetReferrerPolicy());
287
0
  return data.forget();
288
0
}
289
StyleSheetInfo::StyleSheetInfo(CORSMode aCORSMode,
290
                               ReferrerPolicy aReferrerPolicy,
291
                               const SRIMetadata& aIntegrity,
292
                               css::SheetParsingMode aParsingMode)
293
  : mPrincipal(NullPrincipal::CreateWithoutOriginAttributes())
294
  , mCORSMode(aCORSMode)
295
  , mReferrerPolicy(aReferrerPolicy)
296
  , mIntegrity(aIntegrity)
297
  , mContents(Servo_StyleSheet_Empty(aParsingMode).Consume())
298
  , mURLData(URLExtraData::Dummy())
299
#ifdef DEBUG
300
  , mPrincipalSet(false)
301
#endif
302
0
{
303
0
  if (!mPrincipal) {
304
0
    MOZ_CRASH("NullPrincipal::Init failed");
305
0
  }
306
0
  MOZ_COUNT_CTOR(StyleSheetInfo);
307
0
}
308
309
StyleSheetInfo::StyleSheetInfo(StyleSheetInfo& aCopy, StyleSheet* aPrimarySheet)
310
  : mSheetURI(aCopy.mSheetURI)
311
  , mOriginalSheetURI(aCopy.mOriginalSheetURI)
312
  , mBaseURI(aCopy.mBaseURI)
313
  , mPrincipal(aCopy.mPrincipal)
314
  , mCORSMode(aCopy.mCORSMode)
315
  , mReferrerPolicy(aCopy.mReferrerPolicy)
316
  , mIntegrity(aCopy.mIntegrity)
317
  , mFirstChild()  // We don't rebuild the child because we're making a copy
318
                   // without children.
319
  , mSourceMapURL(aCopy.mSourceMapURL)
320
  , mSourceMapURLFromComment(aCopy.mSourceMapURLFromComment)
321
  , mSourceURL(aCopy.mSourceURL)
322
  , mContents(Servo_StyleSheet_Clone(aCopy.mContents.get(), aPrimarySheet).Consume())
323
  , mURLData(aCopy.mURLData)
324
#ifdef DEBUG
325
  , mPrincipalSet(aCopy.mPrincipalSet)
326
#endif
327
0
{
328
0
  AddSheet(aPrimarySheet);
329
0
330
0
  // Our child list is fixed up by our parent.
331
0
  MOZ_COUNT_CTOR(StyleSheetInfo);
332
0
}
333
334
StyleSheetInfo::~StyleSheetInfo()
335
0
{
336
0
  MOZ_COUNT_DTOR(StyleSheetInfo);
337
0
}
338
339
StyleSheetInfo*
340
StyleSheetInfo::CloneFor(StyleSheet* aPrimarySheet)
341
0
{
342
0
  return new StyleSheetInfo(*this, aPrimarySheet);
343
0
}
344
345
MOZ_DEFINE_MALLOC_SIZE_OF(ServoStyleSheetMallocSizeOf)
346
MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoStyleSheetMallocEnclosingSizeOf)
347
348
size_t
349
StyleSheetInfo::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
350
0
{
351
0
  size_t n = aMallocSizeOf(this);
352
0
  n += Servo_StyleSheet_SizeOfIncludingThis(
353
0
      ServoStyleSheetMallocSizeOf,
354
0
      ServoStyleSheetMallocEnclosingSizeOf,
355
0
      mContents);
356
0
  return n;
357
0
}
358
359
void
360
StyleSheetInfo::AddSheet(StyleSheet* aSheet)
361
0
{
362
0
  mSheets.AppendElement(aSheet);
363
0
}
364
365
void
366
StyleSheetInfo::RemoveSheet(StyleSheet* aSheet)
367
0
{
368
0
  if ((aSheet == mSheets.ElementAt(0)) && (mSheets.Length() > 1)) {
369
0
    StyleSheet::ChildSheetListBuilder::ReparentChildList(mSheets[1], mFirstChild);
370
0
  }
371
0
372
0
  if (1 == mSheets.Length()) {
373
0
    NS_ASSERTION(aSheet == mSheets.ElementAt(0), "bad parent");
374
0
    delete this;
375
0
    return;
376
0
  }
377
0
378
0
  mSheets.RemoveElement(aSheet);
379
0
}
380
381
void
382
StyleSheet::ChildSheetListBuilder::SetParentLinks(StyleSheet* aSheet)
383
0
{
384
0
  aSheet->mParent = parent;
385
0
  aSheet->SetAssociatedDocumentOrShadowRoot(parent->mDocumentOrShadowRoot,
386
0
                                            parent->mAssociationMode);
387
0
}
388
389
void
390
StyleSheet::ChildSheetListBuilder::ReparentChildList(StyleSheet* aPrimarySheet,
391
                                                     StyleSheet* aFirstChild)
392
0
{
393
0
  for (StyleSheet *child = aFirstChild; child; child = child->mNext) {
394
0
    child->mParent = aPrimarySheet;
395
0
    child->SetAssociatedDocumentOrShadowRoot(aPrimarySheet->mDocumentOrShadowRoot,
396
0
                                             aPrimarySheet->mAssociationMode);
397
0
  }
398
0
}
399
400
void
401
StyleSheet::GetType(nsAString& aType)
402
0
{
403
0
  aType.AssignLiteral("text/css");
404
0
}
405
406
void
407
StyleSheet::GetHref(nsAString& aHref, ErrorResult& aRv)
408
0
{
409
0
  if (nsIURI* sheetURI = Inner().mOriginalSheetURI) {
410
0
    nsAutoCString str;
411
0
    nsresult rv = sheetURI->GetSpec(str);
412
0
    if (NS_FAILED(rv)) {
413
0
      aRv.Throw(rv);
414
0
      return;
415
0
    }
416
0
    CopyUTF8toUTF16(str, aHref);
417
0
  } else {
418
0
    SetDOMStringToNull(aHref);
419
0
  }
420
0
}
421
422
void
423
StyleSheet::GetTitle(nsAString& aTitle)
424
0
{
425
0
  // From https://drafts.csswg.org/cssom/#dom-stylesheet-title:
426
0
  //
427
0
  //    The title attribute must return the title or null if title is the empty
428
0
  //    string.
429
0
  //
430
0
  if (!mTitle.IsEmpty()) {
431
0
    aTitle.Assign(mTitle);
432
0
  } else {
433
0
    SetDOMStringToNull(aTitle);
434
0
  }
435
0
}
436
437
void
438
StyleSheet::WillDirty()
439
0
{
440
0
  if (IsComplete()) {
441
0
    EnsureUniqueInner();
442
0
  }
443
0
}
444
445
void
446
StyleSheet::AddStyleSet(ServoStyleSet* aStyleSet)
447
0
{
448
0
  NS_ASSERTION(!mStyleSets.Contains(aStyleSet),
449
0
               "style set already registered");
450
0
  mStyleSets.AppendElement(aStyleSet);
451
0
}
452
453
void
454
StyleSheet::DropStyleSet(ServoStyleSet* aStyleSet)
455
0
{
456
0
  DebugOnly<bool> found = mStyleSets.RemoveElement(aStyleSet);
457
0
  NS_ASSERTION(found, "didn't find style set");
458
0
}
459
460
void
461
StyleSheet::EnsureUniqueInner()
462
0
{
463
0
  MOZ_ASSERT(mInner->mSheets.Length() != 0,
464
0
             "unexpected number of outers");
465
0
  mState |= State::ForcedUniqueInner;
466
0
467
0
  if (HasUniqueInner()) {
468
0
    // already unique
469
0
    return;
470
0
  }
471
0
472
0
  StyleSheetInfo* clone = mInner->CloneFor(this);
473
0
  MOZ_ASSERT(clone);
474
0
  mInner->RemoveSheet(this);
475
0
  mInner = clone;
476
0
477
0
  // Fixup the child lists and parent links in the Servo sheet. This is done
478
0
  // here instead of in StyleSheetInner::CloneFor, because it's just more
479
0
  // convenient to do so instead.
480
0
  BuildChildListAfterInnerClone();
481
0
482
0
  // let our containing style sets know that if we call
483
0
  // nsPresContext::EnsureSafeToHandOutCSSRules we will need to restyle the
484
0
  // document
485
0
  for (ServoStyleSet* setHandle : mStyleSets) {
486
0
    setHandle->SetNeedsRestyleAfterEnsureUniqueInner();
487
0
  }
488
0
}
489
490
void
491
StyleSheet::AppendAllChildSheets(nsTArray<StyleSheet*>& aArray)
492
0
{
493
0
  for (StyleSheet* child = GetFirstChild(); child; child = child->mNext) {
494
0
    aArray.AppendElement(child);
495
0
  }
496
0
}
497
498
// WebIDL CSSStyleSheet API
499
500
dom::CSSRuleList*
501
StyleSheet::GetCssRules(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv)
502
0
{
503
0
  if (!AreRulesAvailable(aSubjectPrincipal, aRv)) {
504
0
    return nullptr;
505
0
  }
506
0
  return GetCssRulesInternal();
507
0
}
508
509
void
510
StyleSheet::GetSourceMapURL(nsAString& aSourceMapURL)
511
0
{
512
0
  if (mInner->mSourceMapURL.IsEmpty()) {
513
0
    aSourceMapURL = mInner->mSourceMapURLFromComment;
514
0
  } else {
515
0
    aSourceMapURL = mInner->mSourceMapURL;
516
0
  }
517
0
}
518
519
void
520
StyleSheet::SetSourceMapURL(const nsAString& aSourceMapURL)
521
0
{
522
0
  mInner->mSourceMapURL = aSourceMapURL;
523
0
}
524
525
void
526
StyleSheet::SetSourceMapURLFromComment(const nsAString& aSourceMapURLFromComment)
527
0
{
528
0
  mInner->mSourceMapURLFromComment = aSourceMapURLFromComment;
529
0
}
530
531
void
532
StyleSheet::GetSourceURL(nsAString& aSourceURL)
533
0
{
534
0
  aSourceURL = mInner->mSourceURL;
535
0
}
536
537
void
538
StyleSheet::SetSourceURL(const nsAString& aSourceURL)
539
0
{
540
0
  mInner->mSourceURL = aSourceURL;
541
0
}
542
543
css::Rule*
544
StyleSheet::GetDOMOwnerRule() const
545
0
{
546
0
  return mOwnerRule;
547
0
}
548
549
uint32_t
550
StyleSheet::InsertRule(const nsAString& aRule, uint32_t aIndex,
551
                       nsIPrincipal& aSubjectPrincipal,
552
                       ErrorResult& aRv)
553
0
{
554
0
  if (!AreRulesAvailable(aSubjectPrincipal, aRv)) {
555
0
    return 0;
556
0
  }
557
0
  return InsertRuleInternal(aRule, aIndex, aRv);
558
0
}
559
560
void
561
StyleSheet::DeleteRule(uint32_t aIndex,
562
                       nsIPrincipal& aSubjectPrincipal,
563
                       ErrorResult& aRv)
564
0
{
565
0
  if (!AreRulesAvailable(aSubjectPrincipal, aRv)) {
566
0
    return;
567
0
  }
568
0
  return DeleteRuleInternal(aIndex, aRv);
569
0
}
570
571
nsresult
572
StyleSheet::DeleteRuleFromGroup(css::GroupRule* aGroup, uint32_t aIndex)
573
0
{
574
0
  NS_ENSURE_ARG_POINTER(aGroup);
575
0
  NS_ASSERTION(IsComplete(), "No deleting from an incomplete sheet!");
576
0
  RefPtr<css::Rule> rule = aGroup->GetStyleRuleAt(aIndex);
577
0
  NS_ENSURE_TRUE(rule, NS_ERROR_ILLEGAL_VALUE);
578
0
579
0
  // check that the rule actually belongs to this sheet!
580
0
  if (this != rule->GetStyleSheet()) {
581
0
    return NS_ERROR_INVALID_ARG;
582
0
  }
583
0
584
0
  WillDirty();
585
0
586
0
  nsresult result = aGroup->DeleteStyleRuleAt(aIndex);
587
0
  NS_ENSURE_SUCCESS(result, result);
588
0
589
0
  rule->DropReferences();
590
0
591
0
  RuleRemoved(*rule);
592
0
  return NS_OK;
593
0
}
594
595
dom::ShadowRoot*
596
StyleSheet::GetContainingShadow() const
597
0
{
598
0
  if (!mOwningNode || !mOwningNode->IsContent()) {
599
0
    return nullptr;
600
0
  }
601
0
602
0
  return mOwningNode->AsContent()->GetContainingShadow();
603
0
}
604
605
0
#define NOTIFY(function_, args_) do {                     \
606
0
  StyleSheet* current = this;                             \
607
0
  do {                                                    \
608
0
    for (ServoStyleSet* handle : current->mStyleSets) {   \
609
0
      handle->function_ args_;                            \
610
0
    }                                                     \
611
0
    if (auto* shadow = current->GetContainingShadow()) {  \
612
0
      shadow->function_ args_;                            \
613
0
    }                                                     \
614
0
    current = current->mParent;                           \
615
0
  } while (current);                                      \
616
0
} while (0)
617
618
void
619
StyleSheet::RuleAdded(css::Rule& aRule)
620
0
{
621
0
  mState |= State::ModifiedRules;
622
0
  NOTIFY(RuleAdded, (*this, aRule));
623
0
624
0
  if (nsIDocument* doc = GetComposedDoc()) {
625
0
    doc->StyleRuleAdded(this, &aRule);
626
0
  }
627
0
}
628
629
void
630
StyleSheet::RuleRemoved(css::Rule& aRule)
631
0
{
632
0
  mState |= State::ModifiedRules;
633
0
  NOTIFY(RuleRemoved, (*this, aRule));
634
0
635
0
  if (nsIDocument* doc = GetComposedDoc()) {
636
0
    doc->StyleRuleRemoved(this, &aRule);
637
0
  }
638
0
}
639
640
void
641
StyleSheet::RuleChanged(css::Rule* aRule)
642
0
{
643
0
  mState |= State::ModifiedRules;
644
0
  NOTIFY(RuleChanged, (*this, aRule));
645
0
646
0
  if (nsIDocument* doc = GetComposedDoc()) {
647
0
    doc->StyleRuleChanged(this, aRule);
648
0
  }
649
0
}
650
651
#undef NOTIFY
652
653
nsresult
654
StyleSheet::InsertRuleIntoGroup(const nsAString& aRule,
655
                                css::GroupRule* aGroup,
656
                                uint32_t aIndex)
657
0
{
658
0
  NS_ASSERTION(IsComplete(), "No inserting into an incomplete sheet!");
659
0
  // check that the group actually belongs to this sheet!
660
0
  if (this != aGroup->GetStyleSheet()) {
661
0
    return NS_ERROR_INVALID_ARG;
662
0
  }
663
0
664
0
  WillDirty();
665
0
666
0
  nsresult result = InsertRuleIntoGroupInternal(aRule, aGroup, aIndex);
667
0
  NS_ENSURE_SUCCESS(result, result);
668
0
  RuleAdded(*aGroup->GetStyleRuleAt(aIndex));
669
0
  return NS_OK;
670
0
}
671
672
uint64_t
673
StyleSheet::FindOwningWindowInnerID() const
674
0
{
675
0
  uint64_t windowID = 0;
676
0
  if (nsIDocument* doc = GetAssociatedDocument()) {
677
0
    windowID = doc->InnerWindowID();
678
0
  }
679
0
680
0
  if (windowID == 0 && mOwningNode) {
681
0
    windowID = mOwningNode->OwnerDoc()->InnerWindowID();
682
0
  }
683
0
684
0
  RefPtr<css::Rule> ownerRule;
685
0
  if (windowID == 0 && (ownerRule = GetDOMOwnerRule())) {
686
0
    RefPtr<StyleSheet> sheet = ownerRule->GetStyleSheet();
687
0
    if (sheet) {
688
0
      windowID = sheet->FindOwningWindowInnerID();
689
0
    }
690
0
  }
691
0
692
0
  if (windowID == 0 && mParent) {
693
0
    windowID = mParent->FindOwningWindowInnerID();
694
0
  }
695
0
696
0
  return windowID;
697
0
}
698
699
void
700
StyleSheet::UnparentChildren()
701
0
{
702
0
  // XXXbz this is a little bogus; see the XXX comment where we
703
0
  // declare mFirstChild in StyleSheetInfo.
704
0
  for (StyleSheet* child = GetFirstChild();
705
0
       child;
706
0
       child = child->mNext) {
707
0
    if (child->mParent == this) {
708
0
      child->mParent = nullptr;
709
0
      MOZ_ASSERT(child->mAssociationMode == NotOwnedByDocumentOrShadowRoot,
710
0
                 "How did we get to the destructor, exactly, if we're owned "
711
0
                 "by a document?");
712
0
      child->mDocumentOrShadowRoot = nullptr;
713
0
    }
714
0
  }
715
0
}
716
717
void
718
StyleSheet::SubjectSubsumesInnerPrincipal(nsIPrincipal& aSubjectPrincipal,
719
                                          ErrorResult& aRv)
720
0
{
721
0
  StyleSheetInfo& info = Inner();
722
0
723
0
  if (aSubjectPrincipal.Subsumes(info.mPrincipal)) {
724
0
    return;
725
0
  }
726
0
727
0
  // Allow access only if CORS mode is not NONE and the security flag
728
0
  // is not turned off.
729
0
  if (GetCORSMode() == CORS_NONE &&
730
0
      !nsContentUtils::BypassCSSOMOriginCheck()) {
731
0
    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
732
0
    return;
733
0
  }
734
0
735
0
  // Now make sure we set the principal of our inner to the subjectPrincipal.
736
0
  // We do this because we're in a situation where the caller would not normally
737
0
  // be able to access the sheet, but the sheet has opted in to being read.
738
0
  // Unfortunately, that means it's also opted in to being _edited_, and if the
739
0
  // caller now makes edits to the sheet we want the resulting resource loads,
740
0
  // if any, to look as if they are coming from the caller's principal, not the
741
0
  // original sheet principal.
742
0
  //
743
0
  // That means we need a unique inner, of course.  But we don't want to do that
744
0
  // if we're not complete yet.  Luckily, all the callers of this method throw
745
0
  // anyway if not complete, so we can just do that here too.
746
0
  if (!IsComplete()) {
747
0
    aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
748
0
    return;
749
0
  }
750
0
751
0
  WillDirty();
752
0
753
0
  info.mPrincipal = &aSubjectPrincipal;
754
0
}
755
756
bool
757
StyleSheet::AreRulesAvailable(nsIPrincipal& aSubjectPrincipal,
758
                              ErrorResult& aRv)
759
0
{
760
0
  // Rules are not available on incomplete sheets.
761
0
  if (!IsComplete()) {
762
0
    aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
763
0
    return false;
764
0
  }
765
0
  //-- Security check: Only scripts whose principal subsumes that of the
766
0
  //   style sheet can access rule collections.
767
0
  SubjectSubsumesInnerPrincipal(aSubjectPrincipal, aRv);
768
0
  if (NS_WARN_IF(aRv.Failed())) {
769
0
    return false;
770
0
  }
771
0
  return true;
772
0
}
773
774
StyleSheet*
775
StyleSheet::GetFirstChild() const
776
0
{
777
0
  return Inner().mFirstChild;
778
0
}
779
780
void
781
StyleSheet::SetAssociatedDocumentOrShadowRoot(DocumentOrShadowRoot* aDocOrShadowRoot,
782
                                              AssociationMode aAssociationMode)
783
0
{
784
0
  MOZ_ASSERT(aDocOrShadowRoot ||
785
0
             aAssociationMode == NotOwnedByDocumentOrShadowRoot);
786
0
787
0
  // not ref counted
788
0
  mDocumentOrShadowRoot = aDocOrShadowRoot;
789
0
  mAssociationMode = aAssociationMode;
790
0
791
0
  // Now set the same document on all our child sheets....
792
0
  // XXXbz this is a little bogus; see the XXX comment where we
793
0
  // declare mFirstChild.
794
0
  for (StyleSheet* child = GetFirstChild();
795
0
       child; child = child->mNext) {
796
0
    if (child->mParent == this) {
797
0
      child->SetAssociatedDocumentOrShadowRoot(aDocOrShadowRoot, aAssociationMode);
798
0
    }
799
0
  }
800
0
}
801
802
void
803
StyleSheet::PrependStyleSheet(StyleSheet* aSheet)
804
0
{
805
0
  WillDirty();
806
0
  PrependStyleSheetSilently(aSheet);
807
0
}
808
809
void
810
StyleSheet::PrependStyleSheetSilently(StyleSheet* aSheet)
811
0
{
812
0
  MOZ_ASSERT(aSheet);
813
0
814
0
  aSheet->mNext = Inner().mFirstChild;
815
0
  Inner().mFirstChild = aSheet;
816
0
817
0
  // This is not reference counted. Our parent tells us when
818
0
  // it's going away.
819
0
  aSheet->mParent = this;
820
0
  aSheet->SetAssociatedDocumentOrShadowRoot(mDocumentOrShadowRoot, mAssociationMode);
821
0
}
822
823
size_t
824
StyleSheet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
825
0
{
826
0
  size_t n = 0;
827
0
  const StyleSheet* s = this;
828
0
  while (s) {
829
0
    n += aMallocSizeOf(s);
830
0
831
0
    // See the comment in CSSStyleSheet::SizeOfIncludingThis() for an
832
0
    // explanation of this.
833
0
    //
834
0
    // FIXME(emilio): This comment is gone, someone should go find it.
835
0
    if (s->Inner().mSheets.LastElement() == s) {
836
0
      n += s->Inner().SizeOfIncludingThis(aMallocSizeOf);
837
0
    }
838
0
839
0
    // Measurement of the following members may be added later if DMD finds it
840
0
    // is worthwhile:
841
0
    // - s->mTitle
842
0
    // - s->mMedia
843
0
    // - s->mStyleSets
844
0
    // - s->mRuleList
845
0
846
0
    s = s->mNext;
847
0
  }
848
0
  return n;
849
0
}
850
851
#ifdef DEBUG
852
void
853
StyleSheet::List(FILE* out, int32_t aIndent) const
854
{
855
  int32_t index;
856
857
  // Indent
858
  nsAutoCString str;
859
  for (index = aIndent; --index >= 0; ) {
860
    str.AppendLiteral("  ");
861
  }
862
863
  str.AppendLiteral("CSS Style Sheet: ");
864
  nsAutoCString urlSpec;
865
  nsresult rv = GetSheetURI()->GetSpec(urlSpec);
866
  if (NS_SUCCEEDED(rv) && !urlSpec.IsEmpty()) {
867
    str.Append(urlSpec);
868
  }
869
870
  if (mMedia) {
871
    str.AppendLiteral(" media: ");
872
    nsAutoString  buffer;
873
    mMedia->GetText(buffer);
874
    AppendUTF16toUTF8(buffer, str);
875
  }
876
  str.Append('\n');
877
  fprintf_stderr(out, "%s", str.get());
878
879
  for (const StyleSheet* child = GetFirstChild();
880
       child;
881
       child = child->mNext) {
882
    child->List(out, aIndent + 1);
883
  }
884
}
885
#endif
886
887
void
888
StyleSheet::SetMedia(dom::MediaList* aMedia)
889
0
{
890
0
  if (aMedia) {
891
0
    aMedia->SetStyleSheet(this);
892
0
  }
893
0
  mMedia = aMedia;
894
0
}
895
896
void
897
StyleSheet::SetReferrerPolicy(net::ReferrerPolicy aReferrerPolicy)
898
0
{
899
0
  Inner().mReferrerPolicy = aReferrerPolicy;
900
0
}
901
902
void
903
StyleSheet::DropMedia()
904
0
{
905
0
  if (mMedia) {
906
0
    mMedia->SetStyleSheet(nullptr);
907
0
    mMedia = nullptr;
908
0
  }
909
0
}
910
911
dom::MediaList*
912
StyleSheet::Media()
913
0
{
914
0
  if (!mMedia) {
915
0
    mMedia = dom::MediaList::Create(nsString());
916
0
    mMedia->SetStyleSheet(this);
917
0
  }
918
0
919
0
  return mMedia;
920
0
}
921
922
// nsWrapperCache
923
924
JSObject*
925
StyleSheet::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
926
0
{
927
0
  return dom::CSSStyleSheet_Binding::Wrap(aCx, this, aGivenProto);
928
0
}
929
930
/* static */ bool
931
StyleSheet::RuleHasPendingChildSheet(css::Rule* aRule)
932
0
{
933
0
  MOZ_ASSERT(aRule->Type() == dom::CSSRule_Binding::IMPORT_RULE);
934
0
  auto rule = static_cast<dom::CSSImportRule*>(aRule);
935
0
  if (StyleSheet* childSheet = rule->GetStyleSheet()) {
936
0
    return !childSheet->IsComplete();
937
0
  }
938
0
  return false;
939
0
}
940
941
void
942
StyleSheet::BuildChildListAfterInnerClone()
943
0
{
944
0
  MOZ_ASSERT(Inner().mSheets.Length() == 1, "Should've just cloned");
945
0
  MOZ_ASSERT(Inner().mSheets[0] == this);
946
0
  MOZ_ASSERT(!Inner().mFirstChild);
947
0
948
0
  auto* contents = Inner().mContents.get();
949
0
  RefPtr<ServoCssRules> rules =
950
0
    Servo_StyleSheet_GetRules(contents).Consume();
951
0
952
0
  uint32_t index = 0;
953
0
  while (true) {
954
0
    uint32_t line, column; // Actually unused.
955
0
    RefPtr<RawServoImportRule> import =
956
0
      Servo_CssRules_GetImportRuleAt(rules, index, &line, &column).Consume();
957
0
    if (!import) {
958
0
      // Note that only @charset rules come before @import rules, and @charset
959
0
      // rules are parsed but skipped, so we can stop iterating as soon as we
960
0
      // find something that isn't an @import rule.
961
0
      break;
962
0
    }
963
0
    auto* sheet =
964
0
      const_cast<StyleSheet*>(Servo_ImportRule_GetSheet(import));
965
0
    MOZ_ASSERT(sheet);
966
0
    PrependStyleSheetSilently(sheet);
967
0
    index++;
968
0
  }
969
0
}
970
971
already_AddRefed<StyleSheet>
972
StyleSheet::CreateEmptyChildSheet(
973
    already_AddRefed<dom::MediaList> aMediaList) const
974
0
{
975
0
  RefPtr<StyleSheet> child =
976
0
    new StyleSheet(ParsingMode(),
977
0
                   CORSMode::CORS_NONE,
978
0
                   GetReferrerPolicy(),
979
0
                   SRIMetadata());
980
0
981
0
  child->mMedia = aMediaList;
982
0
  return child.forget();
983
0
}
984
985
// We disable parallel stylesheet parsing if any of the following three
986
// conditions hold:
987
//
988
// (1) The pref is off.
989
// (2) The browser is recording CSS errors (which parallel parsing can't handle).
990
// (3) The stylesheet is a chrome stylesheet, since those can use -moz-bool-pref,
991
//     which needs to access the pref service, which is not threadsafe.
992
static bool
993
AllowParallelParse(css::Loader* aLoader, nsIURI* aSheetURI)
994
0
{
995
0
  // Check the pref.
996
0
  if (!StaticPrefs::layout_css_parsing_parallel()) {
997
0
    return false;
998
0
  }
999
0
1000
0
  // If the browser is recording CSS errors, we need to use the sequential path
1001
0
  // because the parallel path doesn't support that.
1002
0
  nsIDocument* doc = aLoader->GetDocument();
1003
0
  if (doc && css::ErrorReporter::ShouldReportErrors(*doc)) {
1004
0
    return false;
1005
0
  }
1006
0
1007
0
  // If this is a chrome stylesheet, it might use -moz-bool-pref, which needs to
1008
0
  // access the pref service, which is not thread-safe. We could probably expose
1009
0
  // the relevant booleans as thread-safe var caches if we needed to, but
1010
0
  // parsing chrome stylesheets in parallel is unlikely to be a win anyway.
1011
0
  //
1012
0
  // Note that UA stylesheets can also use -moz-bool-pref, but those are always
1013
0
  // parsed sync.
1014
0
  if (dom::IsChromeURI(aSheetURI)) {
1015
0
    return false;
1016
0
  }
1017
0
1018
0
  return true;
1019
0
}
1020
1021
RefPtr<StyleSheetParsePromise>
1022
StyleSheet::ParseSheet(css::Loader* aLoader,
1023
                       const nsACString& aBytes,
1024
                       css::SheetLoadData* aLoadData)
1025
0
{
1026
0
  MOZ_ASSERT(aLoader);
1027
0
  MOZ_ASSERT(aLoadData);
1028
0
  MOZ_ASSERT(mParsePromise.IsEmpty());
1029
0
  RefPtr<StyleSheetParsePromise> p = mParsePromise.Ensure(__func__);
1030
0
  Inner().mURLData = CreateURLExtraData(); // RefPtr
1031
0
1032
0
  const StyleUseCounters* useCounters = aLoader->GetDocument()
1033
0
    ? aLoader->GetDocument()->GetStyleUseCounters()
1034
0
    : nullptr;
1035
0
1036
0
  if (!AllowParallelParse(aLoader, GetSheetURI())) {
1037
0
    RefPtr<RawServoStyleSheetContents> contents =
1038
0
      Servo_StyleSheet_FromUTF8Bytes(aLoader,
1039
0
                                     this,
1040
0
                                     aLoadData,
1041
0
                                     &aBytes,
1042
0
                                     mParsingMode,
1043
0
                                     Inner().mURLData,
1044
0
                                     aLoadData->mLineNumber,
1045
0
                                     aLoader->GetCompatibilityMode(),
1046
0
                                     /* reusable_sheets = */ nullptr,
1047
0
                                     useCounters)
1048
0
      .Consume();
1049
0
    FinishAsyncParse(contents.forget());
1050
0
  } else {
1051
0
    RefPtr<css::SheetLoadDataHolder> loadDataHolder =
1052
0
      new css::SheetLoadDataHolder(__func__, aLoadData);
1053
0
    Servo_StyleSheet_FromUTF8BytesAsync(loadDataHolder,
1054
0
                                        Inner().mURLData,
1055
0
                                        &aBytes,
1056
0
                                        mParsingMode,
1057
0
                                        aLoadData->mLineNumber,
1058
0
                                        aLoader->GetCompatibilityMode(),
1059
0
                                        /* should_record_counters = */ !!useCounters);
1060
0
  }
1061
0
1062
0
  return p;
1063
0
}
1064
1065
void
1066
StyleSheet::FinishAsyncParse(already_AddRefed<RawServoStyleSheetContents> aSheetContents)
1067
0
{
1068
0
  MOZ_ASSERT(NS_IsMainThread());
1069
0
  MOZ_ASSERT(!mParsePromise.IsEmpty());
1070
0
  Inner().mContents = aSheetContents;
1071
0
  FinishParse();
1072
0
  mParsePromise.Resolve(true, __func__);
1073
0
}
1074
1075
1076
void
1077
StyleSheet::ParseSheetSync(css::Loader* aLoader,
1078
                           const nsACString& aBytes,
1079
                           css::SheetLoadData* aLoadData,
1080
                           uint32_t aLineNumber,
1081
                           css::LoaderReusableStyleSheets* aReusableSheets)
1082
0
{
1083
0
  nsCompatibility compatMode =
1084
0
    aLoader ? aLoader->GetCompatibilityMode() : eCompatibility_FullStandards;
1085
0
1086
0
  const StyleUseCounters* useCounters = aLoader && aLoader->GetDocument()
1087
0
    ? aLoader->GetDocument()->GetStyleUseCounters()
1088
0
    : nullptr;
1089
0
1090
0
  Inner().mURLData = CreateURLExtraData(); // RefPtr
1091
0
  Inner().mContents = Servo_StyleSheet_FromUTF8Bytes(aLoader,
1092
0
                                                     this,
1093
0
                                                     aLoadData,
1094
0
                                                     &aBytes,
1095
0
                                                     mParsingMode,
1096
0
                                                     Inner().mURLData,
1097
0
                                                     aLineNumber,
1098
0
                                                     compatMode,
1099
0
                                                     aReusableSheets,
1100
0
                                                     useCounters)
1101
0
                         .Consume();
1102
0
1103
0
  FinishParse();
1104
0
}
1105
1106
void
1107
StyleSheet::FinishParse()
1108
0
{
1109
0
  nsString sourceMapURL;
1110
0
  Servo_StyleSheet_GetSourceMapURL(Inner().mContents, &sourceMapURL);
1111
0
  SetSourceMapURLFromComment(sourceMapURL);
1112
0
1113
0
  nsString sourceURL;
1114
0
  Servo_StyleSheet_GetSourceURL(Inner().mContents, &sourceURL);
1115
0
  SetSourceURL(sourceURL);
1116
0
}
1117
1118
nsresult
1119
StyleSheet::ReparseSheet(const nsAString& aInput)
1120
0
{
1121
0
  if (!IsComplete()) {
1122
0
    return NS_ERROR_DOM_INVALID_ACCESS_ERR;
1123
0
  }
1124
0
1125
0
  // Hold strong ref to the CSSLoader in case the document update
1126
0
  // kills the document
1127
0
  RefPtr<css::Loader> loader;
1128
0
  if (nsIDocument* doc = GetAssociatedDocument()) {
1129
0
    loader = doc->CSSLoader();
1130
0
    NS_ASSERTION(loader, "Document with no CSS loader!");
1131
0
  } else {
1132
0
    loader = new css::Loader;
1133
0
  }
1134
0
1135
0
  WillDirty();
1136
0
1137
0
  // cache child sheets to reuse
1138
0
  css::LoaderReusableStyleSheets reusableSheets;
1139
0
  for (StyleSheet* child = GetFirstChild(); child; child = child->mNext) {
1140
0
    if (child->GetOriginalURI()) {
1141
0
      reusableSheets.AddReusableSheet(child);
1142
0
    }
1143
0
  }
1144
0
1145
0
  // clean up child sheets list
1146
0
  for (StyleSheet* child = GetFirstChild(); child; ) {
1147
0
    StyleSheet* next = child->mNext;
1148
0
    child->mParent = nullptr;
1149
0
    child->ClearAssociatedDocumentOrShadowRoot();
1150
0
    child->mNext = nullptr;
1151
0
    child = next;
1152
0
  }
1153
0
  Inner().mFirstChild = nullptr;
1154
0
1155
0
  uint32_t lineNumber = 1;
1156
0
  if (mOwningNode) {
1157
0
    nsCOMPtr<nsIStyleSheetLinkingElement> link = do_QueryInterface(mOwningNode);
1158
0
    if (link) {
1159
0
      lineNumber = link->GetLineNumber();
1160
0
    }
1161
0
  }
1162
0
1163
0
  // Notify to the stylesets about the old rules going away.
1164
0
  {
1165
0
    ServoCSSRuleList* ruleList = GetCssRulesInternal();
1166
0
    MOZ_ASSERT(ruleList);
1167
0
1168
0
    uint32_t ruleCount = ruleList->Length();
1169
0
    for (uint32_t i = 0; i < ruleCount; ++i) {
1170
0
      css::Rule* rule = ruleList->GetRule(i);
1171
0
      MOZ_ASSERT(rule);
1172
0
      if (rule->Type() == dom::CSSRule_Binding::IMPORT_RULE &&
1173
0
          RuleHasPendingChildSheet(rule)) {
1174
0
        continue; // notify when loaded (see StyleSheetLoaded)
1175
0
      }
1176
0
      RuleRemoved(*rule);
1177
0
    }
1178
0
  }
1179
0
1180
0
  DropRuleList();
1181
0
1182
0
  ParseSheetSync(loader,
1183
0
                 NS_ConvertUTF16toUTF8(aInput),
1184
0
                 /* aLoadData = */ nullptr,
1185
0
                 lineNumber,
1186
0
                 &reusableSheets);
1187
0
1188
0
  // Notify the stylesets about the new rules.
1189
0
  {
1190
0
    // Get the rule list (which will need to be regenerated after ParseSheet).
1191
0
    ServoCSSRuleList* ruleList = GetCssRulesInternal();
1192
0
    MOZ_ASSERT(ruleList);
1193
0
1194
0
    uint32_t ruleCount = ruleList->Length();
1195
0
    for (uint32_t i = 0; i < ruleCount; ++i) {
1196
0
      css::Rule* rule = ruleList->GetRule(i);
1197
0
      MOZ_ASSERT(rule);
1198
0
      if (rule->Type() == CSSRule_Binding::IMPORT_RULE &&
1199
0
          RuleHasPendingChildSheet(rule)) {
1200
0
        continue; // notify when loaded (see StyleSheetLoaded)
1201
0
      }
1202
0
1203
0
      RuleAdded(*rule);
1204
0
    }
1205
0
  }
1206
0
1207
0
  // Our rules are no longer considered modified.
1208
0
  ClearModifiedRules();
1209
0
1210
0
  return NS_OK;
1211
0
}
1212
1213
// nsICSSLoaderObserver implementation
1214
NS_IMETHODIMP
1215
StyleSheet::StyleSheetLoaded(StyleSheet* aSheet,
1216
                             bool aWasAlternate,
1217
                             nsresult aStatus)
1218
0
{
1219
0
  if (!aSheet->GetParentSheet()) {
1220
0
    return NS_OK; // ignore if sheet has been detached already
1221
0
  }
1222
0
  NS_ASSERTION(this == aSheet->GetParentSheet(),
1223
0
               "We are being notified of a sheet load for a sheet that is not our child!");
1224
0
1225
0
  if (NS_SUCCEEDED(aStatus)) {
1226
0
    RuleAdded(*aSheet->GetOwnerRule());
1227
0
  }
1228
0
1229
0
  return NS_OK;
1230
0
}
1231
1232
void
1233
StyleSheet::DropRuleList()
1234
0
{
1235
0
  if (mRuleList) {
1236
0
    mRuleList->DropReferences();
1237
0
    mRuleList = nullptr;
1238
0
  }
1239
0
}
1240
1241
already_AddRefed<StyleSheet>
1242
StyleSheet::Clone(StyleSheet* aCloneParent,
1243
                  dom::CSSImportRule* aCloneOwnerRule,
1244
                  dom::DocumentOrShadowRoot* aCloneDocumentOrShadowRoot,
1245
                  nsINode* aCloneOwningNode) const
1246
0
{
1247
0
  RefPtr<StyleSheet> clone =
1248
0
    new StyleSheet(*this,
1249
0
                   aCloneParent,
1250
0
                   aCloneOwnerRule,
1251
0
                   aCloneDocumentOrShadowRoot,
1252
0
                   aCloneOwningNode);
1253
0
  return clone.forget();
1254
0
}
1255
1256
ServoCSSRuleList*
1257
StyleSheet::GetCssRulesInternal()
1258
0
{
1259
0
  if (!mRuleList) {
1260
0
    EnsureUniqueInner();
1261
0
1262
0
    RefPtr<ServoCssRules> rawRules =
1263
0
      Servo_StyleSheet_GetRules(Inner().mContents).Consume();
1264
0
    MOZ_ASSERT(rawRules);
1265
0
    mRuleList = new ServoCSSRuleList(rawRules.forget(), this, nullptr);
1266
0
  }
1267
0
  return mRuleList;
1268
0
}
1269
1270
uint32_t
1271
StyleSheet::InsertRuleInternal(const nsAString& aRule,
1272
                               uint32_t aIndex,
1273
                               ErrorResult& aRv)
1274
0
{
1275
0
  // Ensure mRuleList is constructed.
1276
0
  GetCssRulesInternal();
1277
0
1278
0
  aRv = mRuleList->InsertRule(aRule, aIndex);
1279
0
  if (aRv.Failed()) {
1280
0
    return 0;
1281
0
  }
1282
0
1283
0
  // XXX We may not want to get the rule when stylesheet change event
1284
0
  // is not enabled.
1285
0
  css::Rule* rule = mRuleList->GetRule(aIndex);
1286
0
  if (rule->Type() != CSSRule_Binding::IMPORT_RULE ||
1287
0
      !RuleHasPendingChildSheet(rule)) {
1288
0
    RuleAdded(*rule);
1289
0
  }
1290
0
1291
0
  return aIndex;
1292
0
}
1293
1294
void
1295
StyleSheet::DeleteRuleInternal(uint32_t aIndex, ErrorResult& aRv)
1296
0
{
1297
0
  // Ensure mRuleList is constructed.
1298
0
  GetCssRulesInternal();
1299
0
  if (aIndex >= mRuleList->Length()) {
1300
0
    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
1301
0
    return;
1302
0
  }
1303
0
1304
0
  // Hold a strong ref to the rule so it doesn't die when we remove it
1305
0
  // from the list. XXX We may not want to hold it if stylesheet change
1306
0
  // event is not enabled.
1307
0
  RefPtr<css::Rule> rule = mRuleList->GetRule(aIndex);
1308
0
  aRv = mRuleList->DeleteRule(aIndex);
1309
0
  MOZ_ASSERT(!aRv.ErrorCodeIs(NS_ERROR_DOM_INDEX_SIZE_ERR),
1310
0
             "IndexSizeError should have been handled earlier");
1311
0
  if (!aRv.Failed()) {
1312
0
    RuleRemoved(*rule);
1313
0
  }
1314
0
}
1315
1316
nsresult
1317
StyleSheet::InsertRuleIntoGroupInternal(const nsAString& aRule,
1318
                                             css::GroupRule* aGroup,
1319
                                             uint32_t aIndex)
1320
0
{
1321
0
  auto rules = static_cast<ServoCSSRuleList*>(aGroup->CssRules());
1322
0
  MOZ_ASSERT(rules->GetParentRule() == aGroup);
1323
0
  return rules->InsertRule(aRule, aIndex);
1324
0
}
1325
1326
OriginFlags
1327
StyleSheet::GetOrigin()
1328
0
{
1329
0
  return static_cast<OriginFlags>(
1330
0
    Servo_StyleSheet_GetOrigin(Inner().mContents));
1331
0
}
1332
1333
} // namespace mozilla