Bug 1484690 - Move the enabled state to the sheet instead of sharing it. r=heycam
authorEmilio Cobos Álvarez <emilio@crisal.io>
Tue, 21 Aug 2018 08:55:10 +0000
changeset 432505 8abcae4371215a3e85217b64b40e9c4e6b36d3ff
parent 432504 1598dc35d16af3bcb77e855190b47df1992dc6e3
child 432506 9bbc18da7365730bfa3d88400149e80a64296a9e
push id68034
push useremilio@crisal.io
push dateTue, 21 Aug 2018 08:56:00 +0000
treeherderautoland@8abcae437121 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1484690
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1484690 - Move the enabled state to the sheet instead of sharing it. r=heycam We share the inner object across sheets from the same URL, so what happens here is that, once the sheet parses and loads, we call SetEnabled() on the first sheet, which sets the inner bit, then calls ApplicableStateChanged. That set actually turned the second sheet complete, so when inserting the sheet, we think that the second sheet is already enabled, and thus in the author data, and try to insert before it. Of course there's nothing there, so we panic. We rely on calling SetEnabled() on all the sheets already to insert them in the styleset / author data, so this makes it clearer and fixes the bug by moving the state to each individual sheet. Differential Revision: https://phabricator.services.mozilla.com/D3798
layout/style/StyleSheet.cpp
layout/style/StyleSheet.h
layout/style/StyleSheetInfo.h
layout/style/StyleSheetInlines.h
testing/web-platform/meta/MANIFEST.json
testing/web-platform/tests/css/css-scoping/shadow-multiple-links.html
--- a/layout/style/StyleSheet.cpp
+++ b/layout/style/StyleSheet.cpp
@@ -32,18 +32,17 @@ StyleSheet::StyleSheet(css::SheetParsing
                        CORSMode aCORSMode,
                        net::ReferrerPolicy aReferrerPolicy,
                        const dom::SRIMetadata& aIntegrity)
   : mParent(nullptr)
   , mDocumentOrShadowRoot(nullptr)
   , mOwningNode(nullptr)
   , mOwnerRule(nullptr)
   , mParsingMode(aParsingMode)
-  , mDisabled(false)
-  , mDirtyFlags(0)
+  , mState(static_cast<State>(0))
   , mAssociationMode(NotOwnedByDocumentOrShadowRoot)
   , mInner(new StyleSheetInfo(aCORSMode, aReferrerPolicy, aIntegrity, aParsingMode))
 {
   mInner->AddSheet(this);
 }
 
 StyleSheet::StyleSheet(const StyleSheet& aCopy,
                        StyleSheet* aParentToUse,
@@ -51,29 +50,28 @@ StyleSheet::StyleSheet(const StyleSheet&
                        dom::DocumentOrShadowRoot* aDocumentOrShadowRoot,
                        nsINode* aOwningNodeToUse)
   : mParent(aParentToUse)
   , mTitle(aCopy.mTitle)
   , mDocumentOrShadowRoot(aDocumentOrShadowRoot)
   , mOwningNode(aOwningNodeToUse)
   , mOwnerRule(aOwnerRuleToUse)
   , mParsingMode(aCopy.mParsingMode)
-  , mDisabled(aCopy.mDisabled)
-  , mDirtyFlags(aCopy.mDirtyFlags)
+  , mState(aCopy.mState)
   // We only use this constructor during cloning.  It's the cloner's
   // responsibility to notify us if we end up being owned by a document.
   , mAssociationMode(NotOwnedByDocumentOrShadowRoot)
   , mInner(aCopy.mInner) // Shallow copy, but concrete subclasses will fix up.
 {
   MOZ_ASSERT(mInner, "Should only copy StyleSheets with an mInner.");
   mInner->AddSheet(this);
 
   if (HasForcedUniqueInner()) { // CSSOM's been there, force full copy now
-    NS_ASSERTION(mInner->mComplete,
-                 "Why have rules been accessed on an incomplete sheet?");
+    MOZ_ASSERT(IsComplete(),
+               "Why have rules been accessed on an incomplete sheet?");
     // FIXME: handle failure?
     EnsureUniqueInner();
   }
 
   if (aCopy.mMedia) {
     // XXX This is wrong; we should be keeping @import rules and
     // sheets in sync!
     mMedia = aCopy.mMedia->Clone();
@@ -229,30 +227,24 @@ StyleSheet::ParsingModeDOM()
   CHECK(mozilla::dom::CSSStyleSheetParsingMode::User, css::eUserSheetFeatures);
   CHECK(mozilla::dom::CSSStyleSheetParsingMode::Author, css::eAuthorSheetFeatures);
 
 #undef CHECK
 
   return static_cast<mozilla::dom::CSSStyleSheetParsingMode>(mParsingMode);
 }
 
-bool
-StyleSheet::IsComplete() const
-{
-  return Inner().mComplete;
-}
-
 void
 StyleSheet::SetComplete()
 {
-  NS_ASSERTION(!HasForcedUniqueInner(),
-               "Can't complete a sheet that's already been forced "
-               "unique.");
-  Inner().mComplete = true;
-  if (!mDisabled) {
+  MOZ_ASSERT(!HasForcedUniqueInner(),
+             "Can't complete a sheet that's already been forced unique.");
+  MOZ_ASSERT(!IsComplete(), "Already complete?");
+  mState |= State::Complete;
+  if (!Disabled()) {
     ApplicableStateChanged(true);
   }
 }
 
 void
 StyleSheet::ApplicableStateChanged(bool aApplicable)
 {
   if (!mDocumentOrShadowRoot) {
@@ -263,36 +255,41 @@ StyleSheet::ApplicableStateChanged(bool 
   if (auto* shadow = ShadowRoot::FromNode(node)) {
     shadow->StyleSheetApplicableStateChanged(*this, aApplicable);
   } else {
     node.AsDocument()->SetStyleSheetApplicableState(this, aApplicable);
   }
 }
 
 void
-StyleSheet::SetEnabled(bool aEnabled)
+StyleSheet::SetDisabled(bool aDisabled)
 {
-  // Internal method, so callers must handle BeginUpdate/EndUpdate
-  bool oldDisabled = mDisabled;
-  mDisabled = !aEnabled;
+  if (aDisabled == Disabled()) {
+    return;
+  }
 
-  if (IsComplete() && oldDisabled != mDisabled) {
-    ApplicableStateChanged(!mDisabled);
+  if (aDisabled) {
+    mState |= State::Disabled;
+  } else {
+    mState &= ~State::Disabled;
+  }
+
+  if (IsComplete()) {
+    ApplicableStateChanged(!aDisabled);
   }
 }
 
 StyleSheetInfo::StyleSheetInfo(CORSMode aCORSMode,
                                ReferrerPolicy aReferrerPolicy,
                                const SRIMetadata& aIntegrity,
                                css::SheetParsingMode aParsingMode)
   : mPrincipal(NullPrincipal::CreateWithoutOriginAttributes())
   , mCORSMode(aCORSMode)
   , mReferrerPolicy(aReferrerPolicy)
   , mIntegrity(aIntegrity)
-  , mComplete(false)
   , mContents(Servo_StyleSheet_Empty(aParsingMode).Consume())
   , mURLData(URLExtraData::Dummy())
 #ifdef DEBUG
   , mPrincipalSet(false)
 #endif
 {
   if (!mPrincipal) {
     MOZ_CRASH("NullPrincipal::Init failed");
@@ -303,17 +300,16 @@ StyleSheetInfo::StyleSheetInfo(CORSMode 
 StyleSheetInfo::StyleSheetInfo(StyleSheetInfo& aCopy, StyleSheet* aPrimarySheet)
   : mSheetURI(aCopy.mSheetURI)
   , mOriginalSheetURI(aCopy.mOriginalSheetURI)
   , mBaseURI(aCopy.mBaseURI)
   , mPrincipal(aCopy.mPrincipal)
   , mCORSMode(aCopy.mCORSMode)
   , mReferrerPolicy(aCopy.mReferrerPolicy)
   , mIntegrity(aCopy.mIntegrity)
-  , mComplete(aCopy.mComplete)
   , mFirstChild()  // We don't rebuild the child because we're making a copy
                    // without children.
   , mSourceMapURL(aCopy.mSourceMapURL)
   , mSourceMapURLFromComment(aCopy.mSourceMapURLFromComment)
   , mSourceURL(aCopy.mSourceURL)
   , mContents(Servo_StyleSheet_Clone(aCopy.mContents.get(), aPrimarySheet).Consume())
   , mURLData(aCopy.mURLData)
 #ifdef DEBUG
@@ -394,22 +390,16 @@ StyleSheet::ChildSheetListBuilder::Repar
 
 void
 StyleSheet::GetType(nsAString& aType)
 {
   aType.AssignLiteral("text/css");
 }
 
 void
-StyleSheet::SetDisabled(bool aDisabled)
-{
-  SetEnabled(!aDisabled);
-}
-
-void
 StyleSheet::GetHref(nsAString& aHref, ErrorResult& aRv)
 {
   if (nsIURI* sheetURI = Inner().mOriginalSheetURI) {
     nsAutoCString str;
     nsresult rv = sheetURI->GetSpec(str);
     if (NS_FAILED(rv)) {
       aRv.Throw(rv);
       return;
@@ -433,17 +423,17 @@ StyleSheet::GetTitle(nsAString& aTitle)
   } else {
     SetDOMStringToNull(aTitle);
   }
 }
 
 void
 StyleSheet::WillDirty()
 {
-  if (mInner->mComplete) {
+  if (IsComplete()) {
     EnsureUniqueInner();
   }
 }
 
 void
 StyleSheet::AddStyleSet(ServoStyleSet* aStyleSet)
 {
   NS_ASSERTION(!mStyleSets.Contains(aStyleSet),
@@ -458,17 +448,17 @@ StyleSheet::DropStyleSet(ServoStyleSet* 
   NS_ASSERTION(found, "didn't find style set");
 }
 
 void
 StyleSheet::EnsureUniqueInner()
 {
   MOZ_ASSERT(mInner->mSheets.Length() != 0,
              "unexpected number of outers");
-  mDirtyFlags |= FORCED_UNIQUE_INNER;
+  mState |= State::ForcedUniqueInner;
 
   if (HasUniqueInner()) {
     // already unique
     return;
   }
 
   StyleSheetInfo* clone = mInner->CloneFor(this);
   MOZ_ASSERT(clone);
@@ -494,18 +484,17 @@ StyleSheet::AppendAllChildSheets(nsTArra
   for (StyleSheet* child = GetFirstChild(); child; child = child->mNext) {
     aArray.AppendElement(child);
   }
 }
 
 // WebIDL CSSStyleSheet API
 
 dom::CSSRuleList*
-StyleSheet::GetCssRules(nsIPrincipal& aSubjectPrincipal,
-                        ErrorResult& aRv)
+StyleSheet::GetCssRules(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv)
 {
   if (!AreRulesAvailable(aSubjectPrincipal, aRv)) {
     return nullptr;
   }
   return GetCssRulesInternal();
 }
 
 void
@@ -615,39 +604,39 @@ StyleSheet::GetContainingShadow() const
     }                                                     \
     current = current->mParent;                           \
   } while (current);                                      \
 } while (0)
 
 void
 StyleSheet::RuleAdded(css::Rule& aRule)
 {
-  mDirtyFlags |= MODIFIED_RULES;
+  mState |= State::ModifiedRules;
   NOTIFY(RuleAdded, (*this, aRule));
 
   if (nsIDocument* doc = GetComposedDoc()) {
     doc->StyleRuleAdded(this, &aRule);
   }
 }
 
 void
 StyleSheet::RuleRemoved(css::Rule& aRule)
 {
-  mDirtyFlags |= MODIFIED_RULES;
+  mState |= State::ModifiedRules;
   NOTIFY(RuleRemoved, (*this, aRule));
 
   if (nsIDocument* doc = GetComposedDoc()) {
     doc->StyleRuleRemoved(this, &aRule);
   }
 }
 
 void
 StyleSheet::RuleChanged(css::Rule* aRule)
 {
-  mDirtyFlags |= MODIFIED_RULES;
+  mState |= State::ModifiedRules;
   NOTIFY(RuleChanged, (*this, aRule));
 
   if (nsIDocument* doc = GetComposedDoc()) {
     doc->StyleRuleChanged(this, aRule);
   }
 }
 
 #undef NOTIFY
@@ -740,32 +729,32 @@ StyleSheet::SubjectSubsumesInnerPrincipa
   // Unfortunately, that means it's also opted in to being _edited_, and if the
   // caller now makes edits to the sheet we want the resulting resource loads,
   // if any, to look as if they are coming from the caller's principal, not the
   // original sheet principal.
   //
   // That means we need a unique inner, of course.  But we don't want to do that
   // if we're not complete yet.  Luckily, all the callers of this method throw
   // anyway if not complete, so we can just do that here too.
-  if (!info.mComplete) {
+  if (!IsComplete()) {
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return;
   }
 
   WillDirty();
 
   info.mPrincipal = &aSubjectPrincipal;
 }
 
 bool
 StyleSheet::AreRulesAvailable(nsIPrincipal& aSubjectPrincipal,
                               ErrorResult& aRv)
 {
   // Rules are not available on incomplete sheets.
-  if (!Inner().mComplete) {
+  if (!IsComplete()) {
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return false;
   }
   //-- Security check: Only scripts whose principal subsumes that of the
   //   style sheet can access rule collections.
   SubjectSubsumesInnerPrincipal(aSubjectPrincipal, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return false;
@@ -1099,17 +1088,17 @@ StyleSheet::FinishParse()
   nsString sourceURL;
   Servo_StyleSheet_GetSourceURL(Inner().mContents, &sourceURL);
   SetSourceURL(sourceURL);
 }
 
 nsresult
 StyleSheet::ReparseSheet(const nsAString& aInput)
 {
-  if (!mInner->mComplete) {
+  if (!IsComplete()) {
     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
   }
 
   // Hold strong ref to the CSSLoader in case the document update
   // kills the document
   RefPtr<css::Loader> loader;
   if (nsIDocument* doc = GetAssociatedDocument()) {
     loader = doc->CSSLoader();
--- a/layout/style/StyleSheet.h
+++ b/layout/style/StyleSheet.h
@@ -48,27 +48,52 @@ namespace dom {
 class CSSImportRule;
 class CSSRuleList;
 class DocumentOrShadowRoot;
 class MediaList;
 class ShadowRoot;
 class SRIMetadata;
 } // namespace dom
 
+enum class StyleSheetState : uint8_t
+{
+  // Whether the sheet is disabled. Sheets can be made disabled via CSSOM, or
+  // via alternate links and such.
+  Disabled = 1 << 0,
+  // Whether the sheet is complete. The sheet is complete if it's finished
+  // loading. See StyleSheet::SetComplete.
+  Complete = 1 << 1,
+  // Whether we've forced a unique inner. StyleSheet objects share an 'inner'
+  // StyleSheetInfo object if they share URL, CORS mode, etc.
+  //
+  // See the Loader's `mCompleteSheets` and `mLoadingSheets`.
+  ForcedUniqueInner = 1 << 2,
+  // Whether this stylesheet has suffered any modification to the rules via
+  // CSSOM.
+  //
+  // FIXME(emilio): I think as of right now we also set this flag for normal
+  // @import rules, which looks very fishy.
+  ModifiedRules = 1 << 3,
+};
+
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(StyleSheetState)
+
 class StyleSheet final : public nsICSSLoaderObserver
                        , public nsWrapperCache
 {
   StyleSheet(const StyleSheet& aCopy,
              StyleSheet* aParentToUse,
              dom::CSSImportRule* aOwnerRuleToUse,
              dom::DocumentOrShadowRoot* aDocOrShadowRootToUse,
              nsINode* aOwningNodeToUse);
 
   virtual ~StyleSheet();
 
+  using State = StyleSheetState;
+
 public:
   StyleSheet(css::SheetParsingMode aParsingMode,
              CORSMode aCORSMode,
              net::ReferrerPolicy aReferrerPolicy,
              const dom::SRIMetadata& aIntegrity);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StyleSheet)
@@ -144,29 +169,27 @@ public:
   }
 
   css::SheetParsingMode ParsingMode() const { return mParsingMode; }
   mozilla::dom::CSSStyleSheetParsingMode ParsingModeDOM();
 
   /**
    * Whether the sheet is complete.
    */
-  bool IsComplete() const;
+  bool IsComplete() const
+  {
+    return bool(mState & State::Complete);
+  }
+
   void SetComplete();
 
-  /**
-   * Set the stylesheet to be enabled.  This may or may not make it
-   * applicable.  Note that this WILL inform the sheet's document of
-   * its new applicable state if the state changes but WILL NOT call
-   * BeginUpdate() or EndUpdate() on the document -- calling those is
-   * the caller's responsibility.  This allows use of SetEnabled when
-   * batched updates are desired.  If you want updates handled for
-   * you, see SetDisabled().
-   */
-  void SetEnabled(bool aEnabled);
+  void SetEnabled(bool aEnabled)
+  {
+    SetDisabled(!aEnabled);
+  }
 
   // Whether the sheet is for an inline <style> element.
   bool IsInline() const
   {
     return !GetOriginalURI();
   }
 
   nsIURI* GetSheetURI() const
@@ -201,37 +224,37 @@ public:
   /**
    * Whether the sheet is applicable.  A sheet that is not applicable
    * should never be inserted into a style set.  A sheet may not be
    * applicable for a variety of reasons including being disabled and
    * being incomplete.
    */
   bool IsApplicable() const
   {
-    return !mDisabled && Inner().mComplete;
+    return !Disabled() && IsComplete();
   }
 
   already_AddRefed<StyleSheet> Clone(StyleSheet* aCloneParent,
                                      dom::CSSImportRule* aCloneOwnerRule,
                                      dom::DocumentOrShadowRoot* aCloneDocumentOrShadowRoot,
                                      nsINode* aCloneOwningNode) const;
 
   bool HasForcedUniqueInner() const
   {
-    return mDirtyFlags & FORCED_UNIQUE_INNER;
+    return bool(mState & State::ForcedUniqueInner);
   }
 
   bool HasModifiedRules() const
   {
-    return mDirtyFlags & MODIFIED_RULES;
+    return bool(mState & State::ModifiedRules);
   }
 
   void ClearModifiedRules()
   {
-    mDirtyFlags &= ~MODIFIED_RULES;
+    mState &= ~State::ModifiedRules;
   }
 
   bool HasUniqueInner() const
   {
     return Inner().mSheets.Length() == 1;
   }
 
   void AssertHasUniqueInner() const
@@ -361,17 +384,20 @@ public:
   void GetHref(nsAString& aHref, ErrorResult& aRv);
   // GetOwnerNode is defined above.
   StyleSheet* GetParentStyleSheet() const
   {
     return GetParentSheet();
   }
   void GetTitle(nsAString& aTitle);
   dom::MediaList* Media();
-  bool Disabled() const { return mDisabled; }
+  bool Disabled() const
+  {
+    return bool(mState & State::Disabled);
+  }
   void SetDisabled(bool aDisabled);
   void GetSourceMapURL(nsAString& aTitle);
   void SetSourceMapURL(const nsAString& aSourceMapURL);
   void SetSourceMapURLFromComment(const nsAString& aSourceMapURLFromComment);
   void GetSourceURL(nsAString& aSourceURL);
   void SetSourceURL(const nsAString& aSourceURL);
 
   // WebIDL CSSStyleSheet API
@@ -506,36 +532,33 @@ protected:
 
   RefPtr<dom::MediaList> mMedia;
 
   RefPtr<StyleSheet> mNext;
 
   // mParsingMode controls access to nonstandard style constructs that
   // are not safe for use on the public Web but necessary in UA sheets
   // and/or useful in user sheets.
+  //
+  // FIXME(emilio): Given we store the parsed contents in the Inner, this should
+  // probably also move there.
   css::SheetParsingMode mParsingMode;
 
-  bool mDisabled;
-
-  enum dirtyFlagAttributes {
-    FORCED_UNIQUE_INNER = 0x1,
-    MODIFIED_RULES = 0x2,
-  };
-  uint8_t mDirtyFlags; // has been modified
+  State mState;
 
   // mAssociationMode determines whether mDocumentOrShadowRoot directly owns us
   // (in the sense that if it's known-live then we're known-live).
   //
   // Always NotOwnedByDocumentOrShadowRoot when mDocumentOrShadowRoot is null.
   AssociationMode mAssociationMode;
 
   // Core information we get from parsed sheets, which are shared amongst
   // StyleSheet clones.
   //
-  // FIXME(emilio): Should be NonNull.
+  // Always nonnull until LastRelease().
   StyleSheetInfo* mInner;
 
   nsTArray<ServoStyleSet*> mStyleSets;
 
   RefPtr<ServoCSSRuleList> mRuleList;
 
   MozPromiseHolder<StyleSheetParsePromise> mParsePromise;
 
--- a/layout/style/StyleSheetInfo.h
+++ b/layout/style/StyleSheetInfo.h
@@ -51,24 +51,23 @@ struct StyleSheetInfo final
   nsCOMPtr<nsIURI>       mOriginalSheetURI;  // for GetHref.  Can be null.
   nsCOMPtr<nsIURI>       mBaseURI; // for resolving relative URIs
   nsCOMPtr<nsIPrincipal> mPrincipal;
   CORSMode               mCORSMode;
   // The Referrer Policy of a stylesheet is used for its child sheets, so it is
   // stored here.
   ReferrerPolicy         mReferrerPolicy;
   dom::SRIMetadata       mIntegrity;
-  bool                   mComplete;
 
   // Pointer to start of linked list of child sheets. This is all fundamentally
   // broken, because each of the child sheets has a unique parent... We can
   // only hope (and currently this is the case) that any time page JS can get
   // its hands on a child sheet that means we've already ensured unique infos
   // throughout its parent chain and things are good.
-  RefPtr<StyleSheet>     mFirstChild;
+  RefPtr<StyleSheet> mFirstChild;
   AutoTArray<StyleSheet*, 8> mSheets;
 
   // If a SourceMap or X-SourceMap response header is seen, this is
   // the value.  If both are seen, SourceMap is preferred.  If neither
   // is seen, this will be an empty string.
   nsString mSourceMapURL;
   // This stores any source map URL that might have been seen in a
   // comment in the style sheet.  This is separate from mSourceMapURL
--- a/layout/style/StyleSheetInlines.h
+++ b/layout/style/StyleSheetInlines.h
@@ -13,19 +13,19 @@
 namespace mozilla {
 
 void
 StyleSheet::SetURIs(nsIURI* aSheetURI,
                     nsIURI* aOriginalSheetURI,
                     nsIURI* aBaseURI)
 {
   MOZ_ASSERT(aSheetURI && aBaseURI, "null ptr");
+  MOZ_ASSERT(!HasRules() && !IsComplete(),
+             "Can't call SetURIs on sheets that are complete or have rules");
   StyleSheetInfo& info = Inner();
-  MOZ_ASSERT(!HasRules() && !info.mComplete,
-             "Can't call SetURIs on sheets that are complete or have rules");
   info.mSheetURI = aSheetURI;
   info.mOriginalSheetURI = aOriginalSheetURI;
   info.mBaseURI = aBaseURI;
 }
 
 dom::ParentObject
 StyleSheet::GetParentObject() const
 {
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -277082,26 +277082,16 @@
      {}
     ]
    ],
    "fetch/README.md": [
     [
      {}
     ]
    ],
-   "fetch/api/cors/resources/corspreflight.js": [
-    [
-     {}
-    ]
-   ],
-   "fetch/api/cors/resources/not-cors-safelisted.json": [
-    [
-     {}
-    ]
-   ],
    "fetch/api/policies/csp-blocked.html.headers": [
     [
      {}
     ]
    ],
    "fetch/api/policies/csp-blocked.js": [
     [
      {}
@@ -277752,26 +277742,16 @@
      {}
     ]
    ],
    "fetch/sec-metadata/README.md": [
     [
      {}
     ]
    ],
-   "fetch/sec-metadata/report.tentative.https.sub.html.sub.headers": [
-    [
-     {}
-    ]
-   ],
-   "fetch/sec-metadata/resources/dedicatedWorker.js": [
-    [
-     {}
-    ]
-   ],
    "fetch/sec-metadata/resources/echo-as-json.py": [
     [
      {}
     ]
    ],
    "fetch/sec-metadata/resources/echo-as-script.py": [
     [
      {}
@@ -277782,31 +277762,16 @@
      {}
     ]
    ],
    "fetch/sec-metadata/resources/post-to-owner.py": [
     [
      {}
     ]
    ],
-   "fetch/sec-metadata/resources/record-header.py": [
-    [
-     {}
-    ]
-   ],
-   "fetch/sec-metadata/resources/sharedWorker.js": [
-    [
-     {}
-    ]
-   ],
-   "fetch/sec-metadata/resources/xslt-test.sub.xml": [
-    [
-     {}
-    ]
-   ],
    "fetch/security/support/embedded-credential-window.sub.html": [
     [
      {}
     ]
    ],
    "fonts/AD.woff": [
     [
      {}
@@ -295072,16 +295037,26 @@
      {}
     ]
    ],
    "resources/chromium/README.md": [
     [
      {}
     ]
    ],
+   "resources/chromium/chooser_service.mojom.js": [
+    [
+     {}
+    ]
+   ],
+   "resources/chromium/chooser_service.mojom.js.headers": [
+    [
+     {}
+    ]
+   ],
    "resources/chromium/device.mojom.js": [
     [
      {}
     ]
    ],
    "resources/chromium/device.mojom.js.headers": [
     [
      {}
@@ -331634,16 +331609,22 @@
     ]
    ],
    "css/css-scoping/shadow-cascade-order-001.html": [
     [
      "/css/css-scoping/shadow-cascade-order-001.html",
      {}
     ]
    ],
+   "css/css-scoping/shadow-multiple-links.html": [
+    [
+     "/css/css-scoping/shadow-multiple-links.html",
+     {}
+    ]
+   ],
    "css/css-scoping/slot-non-html-display-value.html": [
     [
      "/css/css-scoping/slot-non-html-display-value.html",
      {}
     ]
    ],
    "css/css-scoping/slotted-invalidation.html": [
     [
@@ -350860,26 +350841,16 @@
      "/fetch/api/cors/cors-preflight-cache.any.html",
      {}
     ],
     [
      "/fetch/api/cors/cors-preflight-cache.any.worker.html",
      {}
     ]
    ],
-   "fetch/api/cors/cors-preflight-not-cors-safelisted.any.js": [
-    [
-     "/fetch/api/cors/cors-preflight-not-cors-safelisted.any.html",
-     {}
-    ],
-    [
-     "/fetch/api/cors/cors-preflight-not-cors-safelisted.any.worker.html",
-     {}
-    ]
-   ],
    "fetch/api/cors/cors-preflight-redirect.any.js": [
     [
      "/fetch/api/cors/cors-preflight-redirect.any.html",
      {}
     ],
     [
      "/fetch/api/cors/cors-preflight-redirect.any.worker.html",
      {}
@@ -351016,22 +350987,16 @@
     ]
    ],
    "fetch/api/headers/headers-errors.html": [
     [
      "/fetch/api/headers/headers-errors.html",
      {}
     ]
    ],
-   "fetch/api/headers/headers-no-cors.window.js": [
-    [
-     "/fetch/api/headers/headers-no-cors.window.html",
-     {}
-    ]
-   ],
    "fetch/api/headers/headers-normalize.html": [
     [
      "/fetch/api/headers/headers-normalize.html",
      {}
     ]
    ],
    "fetch/api/headers/headers-record.html": [
     [
@@ -351856,162 +351821,48 @@
     ]
    ],
    "fetch/range/sw.https.window.js": [
     [
      "/fetch/range/sw.https.window.html",
      {}
     ]
    ],
-   "fetch/sec-metadata/embed.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/embed.tentative.https.sub.html",
-     {}
-    ]
-   ],
    "fetch/sec-metadata/fetch.tentative.https.sub.html": [
     [
      "/fetch/sec-metadata/fetch.tentative.https.sub.html",
      {}
     ]
    ],
-   "fetch/sec-metadata/font.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/font.tentative.https.sub.html",
-     {}
-    ]
-   ],
    "fetch/sec-metadata/iframe.tentative.https.sub.html": [
     [
      "/fetch/sec-metadata/iframe.tentative.https.sub.html",
      {}
     ]
    ],
    "fetch/sec-metadata/img.tentative.https.sub.html": [
     [
      "/fetch/sec-metadata/img.tentative.https.sub.html",
      {}
     ]
    ],
-   "fetch/sec-metadata/object.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/object.tentative.https.sub.html",
-     {}
-    ]
-   ],
-   "fetch/sec-metadata/redirect/cross-site/cross-site.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/redirect/cross-site/cross-site.tentative.https.sub.html",
-     {}
-    ]
-   ],
-   "fetch/sec-metadata/redirect/cross-site/same-origin.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/redirect/cross-site/same-origin.tentative.https.sub.html",
-     {}
-    ]
-   ],
-   "fetch/sec-metadata/redirect/cross-site/same-site.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/redirect/cross-site/same-site.tentative.https.sub.html",
-     {}
-    ]
-   ],
-   "fetch/sec-metadata/redirect/same-origin/cross-site.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/redirect/same-origin/cross-site.tentative.https.sub.html",
-     {}
-    ]
-   ],
-   "fetch/sec-metadata/redirect/same-origin/same-origin.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/redirect/same-origin/same-origin.tentative.https.sub.html",
-     {}
-    ]
-   ],
-   "fetch/sec-metadata/redirect/same-origin/same-site.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/redirect/same-origin/same-site.tentative.https.sub.html",
-     {}
-    ]
-   ],
-   "fetch/sec-metadata/redirect/same-site/cross-site.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/redirect/same-site/cross-site.tentative.https.sub.html",
-     {}
-    ]
-   ],
-   "fetch/sec-metadata/redirect/same-site/same-origin.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/redirect/same-site/same-origin.tentative.https.sub.html",
-     {}
-    ]
-   ],
-   "fetch/sec-metadata/redirect/same-site/same-site.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/redirect/same-site/same-site.tentative.https.sub.html",
-     {}
-    ]
-   ],
-   "fetch/sec-metadata/report.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/report.tentative.https.sub.html",
-     {}
-    ]
-   ],
    "fetch/sec-metadata/script.tentative.https.sub.html": [
     [
      "/fetch/sec-metadata/script.tentative.https.sub.html",
      {}
     ]
    ],
-   "fetch/sec-metadata/serviceworker.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/serviceworker.tentative.https.sub.html",
-     {}
-    ]
-   ],
-   "fetch/sec-metadata/sharedworker.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/sharedworker.tentative.https.sub.html",
-     {}
-    ]
-   ],
-   "fetch/sec-metadata/style.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/style.tentative.https.sub.html",
-     {}
-    ]
-   ],
-   "fetch/sec-metadata/track.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/track.tentative.https.sub.html",
-     {}
-    ]
-   ],
    "fetch/sec-metadata/window-open.tentative.https.sub.html": [
     [
      "/fetch/sec-metadata/window-open.tentative.https.sub.html",
      {
       "testdriver": true
      }
     ]
    ],
-   "fetch/sec-metadata/worker.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/worker.tentative.https.sub.html",
-     {}
-    ]
-   ],
-   "fetch/sec-metadata/xslt.tentative.https.sub.html": [
-    [
-     "/fetch/sec-metadata/xslt.tentative.https.sub.html",
-     {}
-    ]
-   ],
    "fetch/security/dangling-markup-mitigation-data-url.tentative.sub.html": [
     [
      "/fetch/security/dangling-markup-mitigation-data-url.tentative.sub.html",
      {}
     ]
    ],
    "fetch/security/dangling-markup-mitigation.tentative.html": [
     [
@@ -365478,24 +365329,16 @@
     ]
    ],
    "infrastructure/server/wpt-server-websocket.sub.html": [
     [
      "/infrastructure/server/wpt-server-websocket.sub.html",
      {}
     ]
    ],
-   "infrastructure/testdriver/bless.html": [
-    [
-     "/infrastructure/testdriver/bless.html",
-     {
-      "testdriver": true
-     }
-    ]
-   ],
    "infrastructure/testdriver/click.html": [
     [
      "/infrastructure/testdriver/click.html",
      {
       "testdriver": true
      }
     ]
    ],
@@ -368278,22 +368121,16 @@
     ]
    ],
    "mixed-content/xhr-request/no-opt-in/same-host-https/top-level/no-redirect/allowed/allowed.https.html": [
     [
      "/mixed-content/xhr-request/no-opt-in/same-host-https/top-level/no-redirect/allowed/allowed.https.html",
      {}
     ]
    ],
-   "mst-content-hint/MediaStreamTrack-contentHint.html": [
-    [
-     "/mst-content-hint/MediaStreamTrack-contentHint.html",
-     {}
-    ]
-   ],
    "mst-content-hint/idlharness.window.js": [
     [
      "/mst-content-hint/idlharness.window.html",
      {}
     ]
    ],
    "navigation-timing/idlharness.window.js": [
     [
@@ -542381,16 +542218,20 @@
   "css/css-scoping/shadow-link-rel-stylesheet-no-style-leak.html": [
    "8ca69ccd1b287ad36283405c8ca95742ad08299e",
    "reftest"
   ],
   "css/css-scoping/shadow-link-rel-stylesheet.html": [
    "d67929a1adbd42b807500685c6a36a9e61e22fed",
    "reftest"
   ],
+  "css/css-scoping/shadow-multiple-links.html": [
+   "d1c4fd9eb7ed7595d5f30b01777b4f1c15f242ba",
+   "testharness"
+  ],
   "css/css-scoping/shadow-reassign-dynamic-001.html": [
    "e8fe49ac96ff1694565bd82213c07f7204f0bb1c",
    "reftest"
   ],
   "css/css-scoping/shadow-reassign-dynamic-002.html": [
    "7874e2e13987246c1160c419967aba9db32bbf63",
    "reftest"
   ],
@@ -543622,17 +543463,17 @@
    "d76345df01f14927f96f79834113e09cc10af813",
    "testharness"
   ],
   "css/css-shapes/shape-outside/values/shape-outside-shape-notation-000.html": [
    "c84f934bcf381a27bab055d214da7e69d38679d4",
    "testharness"
   ],
   "css/css-shapes/shape-outside/values/support/parsing-utils.js": [
-   "68b0c1b1f7c4641cc8e28eb0dca52163b71eb1f7",
+   "06007f50939e251851be58a896208d03bb58d0dd",
    "support"
   ],
   "css/css-shapes/spec-examples/reference/shape-outside-001-ref.html": [
    "b175d5503835ec135027ea2df690134d971201de",
    "support"
   ],
   "css/css-shapes/spec-examples/reference/shape-outside-004-ref.html": [
    "0a62f3b8c88c4643c81b7667cc3d8852c6cdd0b0",
@@ -580034,17 +579875,17 @@
    "27abf74f602148ebb53d967bc4873a337ef45d35",
    "support"
   ],
   "docs/_writing-tests/testdriver-tutorial.md": [
    "7bf9e9aa9e6c6c7a8c057c9dbe4151194ca3edd0",
    "support"
   ],
   "docs/_writing-tests/testdriver.md": [
-   "a934e3278f1e2ea3b105b392cdac0e6a895e1b86",
+   "5cbe0bc377b4dafde60bec06c77aba83baebe9db",
    "support"
   ],
   "docs/_writing-tests/testharness-api.md": [
    "bb5524532915a58e4fab3c3bb89a41bbe2a46b4a",
    "support"
   ],
   "docs/_writing-tests/testharness.md": [
    "e91302f1d214fb7fd05a9dce2676569321fc2206",
@@ -580346,17 +580187,17 @@
    "da2d7db3c4ddb53512cbf2d876d0212116b4a3e5",
    "testharness"
   ],
   "dom/events/event-disabled-dynamic.html": [
    "3f995b02f1b421f376dc6037d42c442307503fb2",
    "testharness"
   ],
   "dom/events/event-global-extra.window.js": [
-   "0f14961c40a650a911a1d451e216e27d12195eb5",
+   "f26876966800121622b2d32ef86c955797c0141d",
    "testharness"
   ],
   "dom/events/event-global.html": [
    "5cb1b1416aa35eb75a69be57b0bc8108d0fc7c93",
    "testharness"
   ],
   "dom/events/event-global.worker.js": [
    "116cf32932bd8dd0efba8b56a573028a9770d07b",
@@ -585217,20 +585058,16 @@
   "fetch/api/cors/cors-origin.any.js": [
    "0903147e400deedde62e639ba6f8afc249aabcde",
    "testharness"
   ],
   "fetch/api/cors/cors-preflight-cache.any.js": [
    "ce6a169d8146750b183c9210d1b2041fac879248",
    "testharness"
   ],
-  "fetch/api/cors/cors-preflight-not-cors-safelisted.any.js": [
-   "b2747ccd5bc09e4174aa4c59244e386c80527b51",
-   "testharness"
-  ],
   "fetch/api/cors/cors-preflight-redirect.any.js": [
    "5d4de7ebaad1d45775cdb00bf0233aca1a34f612",
    "testharness"
   ],
   "fetch/api/cors/cors-preflight-referrer.any.js": [
    "6d69b328644a8aa2155b25a153b094fec2bf18de",
    "testharness"
   ],
@@ -585238,39 +585075,31 @@
    "44255d806e8cbb1cb429bcd1dffb4b99a4c094a2",
    "testharness"
   ],
   "fetch/api/cors/cors-preflight-status.any.js": [
    "037526e618ce9b46d08aad0f59cb18e53b1adf12",
    "testharness"
   ],
   "fetch/api/cors/cors-preflight.any.js": [
-   "7455b9774031c8ead6ebaf65165ee920eb9f4218",
+   "4765c5684cf84ddfad2dadace08e99d609bed6e6",
    "testharness"
   ],
   "fetch/api/cors/cors-redirect-credentials.any.js": [
    "17dc4fc853a89f18c0cd2cfefd05f14089343b1d",
    "testharness"
   ],
   "fetch/api/cors/cors-redirect-preflight.any.js": [
    "d44057b254c54625117661e756bcf957e859b7b4",
    "testharness"
   ],
   "fetch/api/cors/cors-redirect.any.js": [
    "cdf4097d5669241373dc7a03ad52c1cb974b5258",
    "testharness"
   ],
-  "fetch/api/cors/resources/corspreflight.js": [
-   "f85d90d9edd6a345564e2b8144123472fde58e4d",
-   "support"
-  ],
-  "fetch/api/cors/resources/not-cors-safelisted.json": [
-   "20a162f92c13b3d7fa8bcefab49c98cdd4b42a4c",
-   "support"
-  ],
   "fetch/api/cors/sandboxed-iframe.html": [
    "feb9f1f2e5bd3e2a1d1937103ea13c2fdb32aea6",
    "testharness"
   ],
   "fetch/api/credentials/authentication-basic.any.js": [
    "4969b3042e8dcde56b0adb708fb2c5f64d18a9eb",
    "testharness"
   ],
@@ -585297,20 +585126,16 @@
   "fetch/api/headers/headers-combine.html": [
    "7341b77e86b7ed7befa0398d3f68f51624dc1bce",
    "testharness"
   ],
   "fetch/api/headers/headers-errors.html": [
    "194ff32f1559f2dd9b5903eb3738c17c061c7172",
    "testharness"
   ],
-  "fetch/api/headers/headers-no-cors.window.js": [
-   "aa6562b7d377f4ad74456a87d7e37bf0bd18cb2b",
-   "testharness"
-  ],
   "fetch/api/headers/headers-normalize.html": [
    "6dfcf9d8194776479d500a6f6c6a5851424d9efc",
    "testharness"
   ],
   "fetch/api/headers/headers-record.html": [
    "85dfadd269d2c7460865dc5d1b16ae1b9834a5a8",
    "testharness"
   ],
@@ -586321,146 +586146,50 @@
   "fetch/range/sw.https.window.js": [
    "faaee86734e93bb514095e34671a57e00bcbcd98",
    "testharness"
   ],
   "fetch/sec-metadata/README.md": [
    "c460aa1ecb941118b6999209ba4601eb145a61b9",
    "support"
   ],
-  "fetch/sec-metadata/embed.tentative.https.sub.html": [
-   "745ef42d484f5258f46ffc6ee9447fe5d8d3c142",
-   "testharness"
-  ],
   "fetch/sec-metadata/fetch.tentative.https.sub.html": [
-   "12072476bebb693233a4cbffcb71019b1d1d5a91",
-   "testharness"
-  ],
-  "fetch/sec-metadata/font.tentative.https.sub.html": [
-   "65432b5bacf3bddf8d5cbaad74bdbaf5e63fb44e",
+   "7a2c223d07112b38dd8053b07f44e7c4ac720161",
    "testharness"
   ],
   "fetch/sec-metadata/iframe.tentative.https.sub.html": [
-   "8d89cda8936cc33a22e0899a2c8b3560b7ef20bd",
+   "5b56c62ad71316c6c820d2cdfe2023c91c5a9da7",
    "testharness"
   ],
   "fetch/sec-metadata/img.tentative.https.sub.html": [
-   "20701a6514653f86e33b3cdf700ecd0628097d6c",
-   "testharness"
-  ],
-  "fetch/sec-metadata/object.tentative.https.sub.html": [
-   "e1ac53157e023a9c6bc4806feda2e782ef4eefa5",
-   "testharness"
-  ],
-  "fetch/sec-metadata/redirect/cross-site/cross-site.tentative.https.sub.html": [
-   "e25fd3f61d5487de6026a0204f107201f491afad",
-   "testharness"
-  ],
-  "fetch/sec-metadata/redirect/cross-site/same-origin.tentative.https.sub.html": [
-   "ac5982d8956c96cd638c2464ec9f8cce3f7e3a34",
-   "testharness"
-  ],
-  "fetch/sec-metadata/redirect/cross-site/same-site.tentative.https.sub.html": [
-   "5b3b965f5e96d75f93796e55e77cfac94de18a52",
-   "testharness"
-  ],
-  "fetch/sec-metadata/redirect/same-origin/cross-site.tentative.https.sub.html": [
-   "ea6b167673f5e64396db4690abde56253e8af914",
-   "testharness"
-  ],
-  "fetch/sec-metadata/redirect/same-origin/same-origin.tentative.https.sub.html": [
-   "430990a57c48b858fdc509653c0b689abcedcc6d",
-   "testharness"
-  ],
-  "fetch/sec-metadata/redirect/same-origin/same-site.tentative.https.sub.html": [
-   "591cf67d18111592a5e696e346371a88770bdb32",
-   "testharness"
-  ],
-  "fetch/sec-metadata/redirect/same-site/cross-site.tentative.https.sub.html": [
-   "8592d02c269b6afc4193f4323238b68d8fc26979",
-   "testharness"
-  ],
-  "fetch/sec-metadata/redirect/same-site/same-origin.tentative.https.sub.html": [
-   "191dbaa7f77a3ac569b37e95e2db9f2ac4985a3e",
-   "testharness"
-  ],
-  "fetch/sec-metadata/redirect/same-site/same-site.tentative.https.sub.html": [
-   "11d60473981cf056ebc56b15905f27c070dad9c8",
-   "testharness"
-  ],
-  "fetch/sec-metadata/report.tentative.https.sub.html": [
-   "279836457ebe72354ec68525bd92bc533b11b0dd",
-   "testharness"
-  ],
-  "fetch/sec-metadata/report.tentative.https.sub.html.sub.headers": [
-   "5c8bc58ad472ed9de841491df4e3e9e26e2e1c70",
-   "support"
-  ],
-  "fetch/sec-metadata/resources/dedicatedWorker.js": [
-   "18626d3d8458b967829b724fabebc10e939b62a9",
-   "support"
+   "7c5cbc34bfd5af975b534e75f3fa2383d6b594aa",
+   "testharness"
   ],
   "fetch/sec-metadata/resources/echo-as-json.py": [
-   "16cc67774f76347e5c71220f590a82a37302cff0",
+   "a45bb68654618fa95f0fa3266be6412612750b57",
    "support"
   ],
   "fetch/sec-metadata/resources/echo-as-script.py": [
-   "c1c6a4673acfbda17e2a7045a304a30082288d1d",
+   "c503822d5c605de0141e7e5316182519b6adc740",
    "support"
   ],
   "fetch/sec-metadata/resources/helper.js": [
-   "cbd96d06863427f34d75d0621839bcfe76c7ad96",
+   "03d2d2d2ebaa8d04d348230a9f751b611ae0dfec",
    "support"
   ],
   "fetch/sec-metadata/resources/post-to-owner.py": [
    "fe08cd1cbcaa4585fb3be0ce0ee33e7d75759129",
    "support"
   ],
-  "fetch/sec-metadata/resources/record-header.py": [
-   "06157e4cd8bd35e54b99c04f09a995185ba5686c",
-   "support"
-  ],
-  "fetch/sec-metadata/resources/sharedWorker.js": [
-   "5eb89cb4f68a098154cf3605f53318af2f5e56f1",
-   "support"
-  ],
-  "fetch/sec-metadata/resources/xslt-test.sub.xml": [
-   "4beb9af8d282f2672ab08c4c369d1fe0b061e80f",
-   "support"
-  ],
   "fetch/sec-metadata/script.tentative.https.sub.html": [
-   "643e11827f565ad11416589ae601d18cd8008239",
-   "testharness"
-  ],
-  "fetch/sec-metadata/serviceworker.tentative.https.sub.html": [
-   "9d1fe2a3449da49b3b4e167f74e63e815ef5cf6c",
-   "testharness"
-  ],
-  "fetch/sec-metadata/sharedworker.tentative.https.sub.html": [
-   "aa118e04239691f5488c4d62f3f1cf0ae59e8f1d",
-   "testharness"
-  ],
-  "fetch/sec-metadata/style.tentative.https.sub.html": [
-   "78fac567b43f3c48c81897b44237d820a6209d8a",
-   "testharness"
-  ],
-  "fetch/sec-metadata/track.tentative.https.sub.html": [
-   "e89d4745ff2db234e3e49ee28dd8af15acbc9731",
+   "6f86e87c5388bc8962feec80a67f9ab4413b4ff8",
    "testharness"
   ],
   "fetch/sec-metadata/window-open.tentative.https.sub.html": [
-   "3cd6190f944816258b29546ef89ec5947faa035d",
-   "testharness"
-  ],
-  "fetch/sec-metadata/worker.tentative.https.sub.html": [
-   "eff66fcc7811d9aacced799d6707f8f9edcafa9b",
-   "testharness"
-  ],
-  "fetch/sec-metadata/xslt.tentative.https.sub.html": [
-   "dff996679ff900cf3e3fe82381ef29ea5f5889b5",
+   "1f9df663f1da911a6683ed54649efba0e8df7c85",
    "testharness"
   ],
   "fetch/security/dangling-markup-mitigation-data-url.tentative.sub.html": [
    "f27735daa1dd650726525d72a48b91d58d62535b",
    "testharness"
   ],
   "fetch/security/dangling-markup-mitigation.tentative.html": [
    "61a931608ba5f3dc7f53f3f7a14ef5111737b07d",
@@ -600294,17 +600023,17 @@
    "d9aee12b5f3519836c1fee380b77d1d3f30d3646",
    "testharness"
   ],
   "html/semantics/forms/form-control-infrastructure/form_owner_and_table_3.html": [
    "db70b34b1adb81f197013175dc131a8aa361ac52",
    "testharness"
   ],
   "html/semantics/forms/form-submission-0/constructing-form-data-set.html": [
-   "afd75d87e95a6344bb3cb004c5af9973b63d645e",
+   "0fe917138693fe2bdd0a2b4d83b5f4c797b61244",
    "testharness"
   ],
   "html/semantics/forms/form-submission-0/contains.json": [
    "f9d0d63bf684d4ad0c4f0e77b0bce2502d0c4e52",
    "support"
   ],
   "html/semantics/forms/form-submission-0/form-data-set-empty-file.window.js": [
    "693bcf9a2af5287e3b3fbca7090980a53cbef5b0",
@@ -606173,20 +605902,16 @@
   "infrastructure/server/wpt-server-http.sub.html": [
    "8099b9d9c68023f1855118b39b25155d2c9bbd74",
    "testharness"
   ],
   "infrastructure/server/wpt-server-websocket.sub.html": [
    "ea7973a62e0ee9cdc874879fd844b2309e944e61",
    "testharness"
   ],
-  "infrastructure/testdriver/bless.html": [
-   "feb444f89d91088b51e04b610dd642c00814c3b4",
-   "testharness"
-  ],
   "infrastructure/testdriver/click.html": [
    "37721ad9ef3df10f8cdc1da74c27a2259d4601f6",
    "testharness"
   ],
   "infrastructure/testdriver/send_keys.html": [
    "2170347c9729564f7e492009b3d20b3267422c1d",
    "testharness"
   ],
@@ -609981,20 +609706,16 @@
   "mixed-content/xhr-request/no-opt-in/same-host-https/top-level/no-redirect/allowed/allowed.https.html": [
    "b0fff36eb94609ac24a76121bf9e201234885db1",
    "testharness"
   ],
   "mst-content-hint/META.yml": [
    "7f79eccbaa6b9950233ee8968c6b358dd89b5d03",
    "support"
   ],
-  "mst-content-hint/MediaStreamTrack-contentHint.html": [
-   "98c88e66ea1ec137cdcf794c63a14d9af4b964b1",
-   "testharness"
-  ],
   "mst-content-hint/idlharness.window.js": [
    "0d9137dc6fb91b1499d922e01d6ad96049f5757b",
    "testharness"
   ],
   "navigation-timing/META.yml": [
    "c09a6e03fd19f5a405b391c2c4671df6ff04edf1",
    "support"
   ],
@@ -626901,16 +626622,24 @@
   "resources/check-layout-th.js": [
    "928b0cf2a1041ecb831fadb44943e8907a29b872",
    "support"
   ],
   "resources/chromium/README.md": [
    "b53c6a8c4232dbe9c787b0ea17f0ed1a49f1e386",
    "support"
   ],
+  "resources/chromium/chooser_service.mojom.js": [
+   "fd344e71faf7806a8ee687bd2049537b26e89ae2",
+   "support"
+  ],
+  "resources/chromium/chooser_service.mojom.js.headers": [
+   "6805c323df5a975231648b830e33ce183c3cbbd3",
+   "support"
+  ],
   "resources/chromium/device.mojom.js": [
    "435fc1fc7addabfddb093e003795512c28360357",
    "support"
   ],
   "resources/chromium/device.mojom.js.headers": [
    "6805c323df5a975231648b830e33ce183c3cbbd3",
    "support"
   ],
@@ -626990,25 +626719,25 @@
    "f0eba0f0c6c3b6ec1b2b4ace33b957f4e23e1be2",
    "support"
   ],
   "resources/chromium/web-bluetooth-test.js.headers": [
    "6805c323df5a975231648b830e33ce183c3cbbd3",
    "support"
   ],
   "resources/chromium/web_usb_service.mojom.js": [
-   "d0b93a168bf06fe6b1dac3dd58c9e7d6f2a66d13",
+   "c283f0e9aea4bee4202352ef91f7d95b6f291f2e",
    "support"
   ],
   "resources/chromium/web_usb_service.mojom.js.headers": [
    "6805c323df5a975231648b830e33ce183c3cbbd3",
    "support"
   ],
   "resources/chromium/webusb-test.js": [
-   "9037a109c91610957091f73752074faa031e497b",
+   "94db93d31e389aa2aa525d82feb57ff414d0426b",
    "support"
   ],
   "resources/chromium/webusb-test.js.headers": [
    "6805c323df5a975231648b830e33ce183c3cbbd3",
    "support"
   ],
   "resources/chromium/webxr-test.js": [
    "10ed703e01b7efe434333a9c69ac27be1aa0cc08",
@@ -642658,25 +642387,25 @@
    "46c4b13a3bf3b045fc477272f9b555ef90971e73",
    "support"
   ],
   "tools/wpt/run.py": [
    "1252f47f15270acf466951ec209d5d587f87c8ba",
    "support"
   ],
   "tools/wpt/testfiles.py": [
-   "35a4b97d7ffaa24f630d70c6877c719d155c2ec7",
+   "c4e714c2640925bda1343b3575f77823144a8b1d",
    "support"
   ],
   "tools/wpt/tests/latest_mozilla_central.txt": [
    "7078a36b0c5bd5b4fe6f55f2ecf5fcbc2c535b4f",
    "support"
   ],
   "tools/wpt/tests/test_wpt.py": [
-   "16d286d382c7179ad36807b47638d82b4b46f286",
+   "ada7cc7c164d835edcdf081d421bfe2a4daff0bf",
    "support"
   ],
   "tools/wpt/tox.ini": [
    "e486bb221d72900b103fa56fbf18175afc5560c8",
    "support"
   ],
   "tools/wpt/update.py": [
    "a4a7b62b86083fd05be0be6ca74dd354920871e7",
@@ -643246,17 +642975,17 @@
    "f63869636da79cdcdc961e137d4f044055d74de4",
    "support"
   ],
   "tools/wptrunner/wptrunner/wptmanifest/tests/test_tokenizer.py": [
    "a64ce0c7bb7d8d089a8cb1365c0477a08652eacc",
    "support"
   ],
   "tools/wptrunner/wptrunner/wptrunner.py": [
-   "aab5996afd94e78686a027fd8546ca83e77766f4",
+   "74f7a7b9e733f1b73b9937705c6472b66e117c04",
    "support"
   ],
   "tools/wptrunner/wptrunner/wpttest.py": [
    "c29ba974a99786f687f2aead1ba14045c12fb643",
    "support"
   ],
   "tools/wptserve/.gitignore": [
    "8e87d388488bbc21c664209fecd2f3e030411b0e",
@@ -643462,17 +643191,17 @@
    "014386e172fbb79de4554284e4c51dcaabaf70b4",
    "support"
   ],
   "tools/wptserve/tests/functional/test_pipes.py": [
    "ebdbc3ee57ddfa50338938aa2e226028d7bb6555",
    "support"
   ],
   "tools/wptserve/tests/functional/test_request.py": [
-   "97d75eb71289adf643ab073ddc740f1f24cffc76",
+   "de29638f6c11dae97cbb5d26d60d3fd530403e5b",
    "support"
   ],
   "tools/wptserve/tests/functional/test_response.py": [
    "daf8e6ed0028502f0876159cbda37e9ac6b6c99c",
    "support"
   ],
   "tools/wptserve/tests/functional/test_server.py": [
    "511c86f32c54ab704e9dca2ba11452f24161e05f",
@@ -650318,17 +650047,17 @@
    "99ac97e28b0ba8dff1af22096589ba18201129c0",
    "support"
   ],
   "webusb/resources/usb-disabled-by-feature-policy-worker.js": [
    "59349560ad197538e569c4dca7c46504ff2567bf",
    "support"
   ],
   "webusb/resources/usb-helpers.js": [
-   "93740920dee8f259fc266cd4927b5972985df77e",
+   "881ea8b95619393a35e1df05864c3cad2ff0eb60",
    "support"
   ],
   "webusb/usb-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html": [
    "e0757feeb2da84da7e391053dd03a9b3458a2900",
    "testharness"
   ],
   "webusb/usb-allowed-by-feature-policy-attribute.https.sub.html": [
    "078db141ad319d83079a7c8f7a6b7b9ebd813286",
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-scoping/shadow-multiple-links.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>CSS Test: ShadowRoot with multiple sheet links with the same href shouldn't crash</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="help" href="https://drafts.csswg.org/css-scoping/#selectors-data-model">
+<div id="host"></div>
+<script>
+test(function() {
+  host.attachShadow({ mode: "open" }).innerHTML = `
+    <link rel="stylesheet" href="data:text/css,">
+    <link rel="stylesheet" href="data:text/css,">
+  `;
+}, "Multiple stylesheets with the same href in a ShadowRoot should not assert or crash");
+</script>