Bug 1427292: [css-display] Update display: contents on Unusual Elements to the spec. r?mats draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Thu, 28 Dec 2017 19:48:14 +0100
changeset 716903 e8cbe09298edee00b60bff5c65c763d8ddc72a2f
parent 716902 6a80911cc3b5777546f4a8c9f683e591016757fa
child 745106 0090890f497a807ae664a44e5ba63405b929a3d7
push id94513
push userbmo:emilio@crisal.io
push dateSat, 06 Jan 2018 19:55:20 +0000
reviewersmats
bugs1427292
milestone59.0a1
Bug 1427292: [css-display] Update display: contents on Unusual Elements to the spec. r?mats This will pass[1] whenever the next WPT sync happens. See: https://drafts.csswg.org/css-display/#unbox-html [1]: https://github.com/w3c/web-platform-tests/blob/master/css/css-display/display-contents-unusual-html-elements-none.html MozReview-Commit-ID: 19dqDSxVm7A
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
layout/reftests/css-display/display-contents-acid-ref.html
layout/reftests/css-display/display-contents-acid.html
layout/reftests/css-display/display-contents-fieldset-ref.html
layout/svg/nsSVGUseFrame.cpp
testing/web-platform/meta/MANIFEST.json
testing/web-platform/tests/css/css-display/display-contents-fieldset-nested-legend-ref.html
testing/web-platform/tests/css/css-display/display-contents-fieldset-nested-legend.html
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -3618,23 +3618,30 @@ nsCSSFrameConstructor::FindDataByInt(int
 }
 
 /* static */
 const nsCSSFrameConstructor::FrameConstructionData*
 nsCSSFrameConstructor::FindDataByTag(nsAtom* aTag,
                                      Element* aElement,
                                      nsStyleContext* aStyleContext,
                                      const FrameConstructionDataByTag* aDataPtr,
-                                     uint32_t aDataLength)
-{
+                                     uint32_t aDataLength,
+                                     bool* aTagFound)
+{
+  if (aTagFound) {
+    *aTagFound = false;
+  }
   for (const FrameConstructionDataByTag *curData = aDataPtr,
          *endData = aDataPtr + aDataLength;
        curData != endData;
        ++curData) {
     if (*curData->mTag == aTag) {
+      if (aTagFound) {
+        *aTagFound = true;
+      }
       const FrameConstructionData* data = &curData->mData;
       if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
         return data->mFunc.mDataGetter(aElement, aStyleContext);
       }
 
       return data;
     }
   }
@@ -3728,18 +3735,39 @@ nsCSSFrameConstructor::FindHTMLData(Elem
     SIMPLE_TAG_CHAIN(canvas, nsCSSFrameConstructor::FindCanvasData),
     SIMPLE_TAG_CREATE(video, NS_NewHTMLVideoFrame),
     SIMPLE_TAG_CREATE(audio, NS_NewHTMLVideoFrame),
     SIMPLE_TAG_CREATE(progress, NS_NewProgressFrame),
     SIMPLE_TAG_CREATE(meter, NS_NewMeterFrame),
     COMPLEX_TAG_CREATE(details, &nsCSSFrameConstructor::ConstructDetailsFrame)
   };
 
-  return FindDataByTag(aTag, aElement, aStyleContext, sHTMLData,
-                       ArrayLength(sHTMLData));
+  bool tagFound;
+  const FrameConstructionData* data =
+    FindDataByTag(aTag, aElement, aStyleContext, sHTMLData,
+                  ArrayLength(sHTMLData), &tagFound);
+
+  // https://drafts.csswg.org/css-display/#unbox-html
+  if (tagFound &&
+      MOZ_UNLIKELY(aStyleContext->StyleDisplay()->mDisplay ==
+                   StyleDisplay::Contents)) {
+    // <button>, <legend>, <details> and <fieldset> don’t have any special
+    // behavior; display: contents simply removes their principal box, and their
+    // contents render as normal.
+    if (aTag != nsGkAtoms::button &&
+        aTag != nsGkAtoms::legend &&
+        aTag != nsGkAtoms::details &&
+        aTag != nsGkAtoms::fieldset) {
+      // On the rest of unusual HTML elements, display: contents creates no box.
+      static const FrameConstructionData sSuppressData = SUPPRESS_FCDATA();
+      return &sSuppressData;
+    }
+  }
+
+  return data;
 }
 
 /* static */
 const nsCSSFrameConstructor::FrameConstructionData*
 nsCSSFrameConstructor::FindImgData(Element* aElement,
                                    nsStyleContext* aStyleContext)
 {
   if (!nsImageFrame::ShouldCreateImageFrameFor(aElement, aStyleContext)) {
@@ -4492,18 +4520,32 @@ nsCSSFrameConstructor::FindXULTagData(El
                      nsCSSFrameConstructor::FindXULListBoxBodyData),
     SIMPLE_TAG_CHAIN(listitem, nsCSSFrameConstructor::FindXULListItemData),
 #endif /* MOZ_XUL */
     SIMPLE_XUL_CREATE(slider, NS_NewSliderFrame),
     SIMPLE_XUL_CREATE(scrollbar, NS_NewScrollbarFrame),
     SIMPLE_XUL_CREATE(scrollbarbutton, NS_NewScrollbarButtonFrame)
 };
 
-  return FindDataByTag(aTag, aElement, aStyleContext, sXULTagData,
-                       ArrayLength(sXULTagData));
+  bool tagFound;
+  const FrameConstructionData* data =
+    FindDataByTag(aTag, aElement, aStyleContext, sXULTagData,
+                  ArrayLength(sXULTagData), &tagFound);
+
+  // There's no spec that says what display: contents means for special XUL
+  // elements, but we do the same as for HTML "Unusual Elements", i.e. treat it
+  // as display:none.
+  if (tagFound &&
+      MOZ_UNLIKELY(aStyleContext->StyleDisplay()->mDisplay ==
+                   StyleDisplay::Contents)) {
+    static const FrameConstructionData sSuppressData = SUPPRESS_FCDATA();
+    return &sSuppressData;
+  }
+
+  return data;
 }
 
 #ifdef MOZ_XUL
 /* static */
 const nsCSSFrameConstructor::FrameConstructionData*
 nsCSSFrameConstructor::FindPopupGroupData(Element* aElement,
                                           nsStyleContext* /* unused */)
 {
@@ -4966,18 +5008,17 @@ nsCSSFrameConstructor::FindDisplayData(c
                   NS_NewRubyBaseContainerFrame)),
     FCDATA_FOR_DISPLAY(StyleDisplay::RubyText,
       FCDATA_DECL(FCDATA_IS_LINE_PARTICIPANT |
                   FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRubyTextContainer),
                   NS_NewRubyTextFrame)),
     FCDATA_FOR_DISPLAY(StyleDisplay::RubyTextContainer,
       FCDATA_DECL(FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRuby),
                   NS_NewRubyTextContainerFrame)),
-    FCDATA_FOR_DISPLAY(StyleDisplay::Contents,
-      FULL_CTOR_FCDATA(FCDATA_IS_CONTENTS, nullptr/*never called*/)),
+    FCDATA_FOR_DISPLAY(StyleDisplay::Contents, UNREACHABLE_FCDATA()),
     FCDATA_FOR_DISPLAY(StyleDisplay::WebkitBox,
       FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
     FCDATA_FOR_DISPLAY(StyleDisplay::WebkitInlineBox,
       FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
     FCDATA_FOR_DISPLAY(StyleDisplay::MozBox,
       FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
     FCDATA_FOR_DISPLAY(StyleDisplay::MozInlineBox,
       FCDATA_DECL(FCDATA_MAY_NEED_SCROLLFRAME, NS_NewFlexContainerFrame)),
@@ -5552,16 +5593,33 @@ nsCSSFrameConstructor::FindSVGData(Eleme
     return &sSuppressData;
   }
 
   // We don't need frames for animation elements
   if (aElement->IsNodeOfType(nsINode::eANIMATION)) {
     return &sSuppressData;
   }
 
+  // https://drafts.csswg.org/css-display/#unbox-svg
+  if (aStyleContext->StyleDisplay()->mDisplay == StyleDisplay::Contents) {
+    // For root <svg> elements, display: contents behaves as display: none.
+    if (aTag == nsGkAtoms::svg && !parentIsSVG) {
+      return &sSuppressData;
+    }
+
+    // For nested <svg>, <g>, <use> and <tspan> behave normally, but any other
+    // element behaves as display: none as well.
+    if (aTag != nsGkAtoms::g &&
+        aTag != nsGkAtoms::use &&
+        aTag != nsGkAtoms::svg &&
+        aTag != nsGkAtoms::tspan) {
+      return &sSuppressData;
+    }
+  }
+
   if (aTag == nsGkAtoms::svg && !parentIsSVG) {
     // We need outer <svg> elements to have an nsSVGOuterSVGFrame regardless
     // of whether they fail conditional processing attributes, since various
     // SVG frames assume that one exists.  We handle the non-rendering
     // of failing outer <svg> element contents like <switch> statements,
     // and do the PassesConditionalProcessingTests call in
     // nsSVGOuterSVGFrame::Init.
     static const FrameConstructionData sOuterSVGData =
@@ -6070,17 +6128,21 @@ nsCSSFrameConstructor::AddFrameConstruct
     !display->IsAbsolutelyPositionedStyle() &&
     !(aParentFrame && aParentFrame->IsGridContainerFrame()) &&
     !(bits & FCDATA_IS_TABLE_PART) && !(bits & FCDATA_IS_SVG_TEXT);
 
   if (canHavePageBreak && display->mBreakBefore) {
     AddPageBreakItem(aContent, aItems);
   }
 
-  if (MOZ_UNLIKELY(bits & FCDATA_IS_CONTENTS)) {
+  // FIXME(emilio, https://github.com/w3c/csswg-drafts/issues/2167):
+  //
+  // Figure out what should happen for display: contents in MathML.
+  if (display->mDisplay == StyleDisplay::Contents &&
+      !aContent->IsMathMLElement()) {
     if (!GetDisplayContentsStyleFor(aContent)) {
       MOZ_ASSERT(styleContext->GetPseudo() || !isGeneratedContent,
                  "Should have had pseudo type");
       aState.mFrameManager->RegisterDisplayContentsStyleFor(aContent,
                                                             styleContext);
     } else {
       aState.mFrameManager->ChangeRegisteredDisplayContentsStyleFor(aContent,
                                                                     styleContext);
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -730,20 +730,16 @@ private:
      block formatting context wrapper around the kids of this frame
      using the FrameConstructionData's mPseudoAtom for its anonymous
      box type. */
 #define FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS 0x40000
   /* If FCDATA_IS_SVG_TEXT is set, then this text frame is a descendant of
      an SVG text frame. */
 #define FCDATA_IS_SVG_TEXT 0x80000
   /**
-   * display:contents
-   */
-#define FCDATA_IS_CONTENTS 0x100000
-  /**
    * When FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS is set, this bit says
    * if we should create a grid/flex/columnset container instead of
    * a block wrapper when the styles says so.
    */
 #define FCDATA_ALLOW_GRID_FLEX_COLUMNSET 0x200000
   /**
    * Whether the kids of this FrameConstructionData should be flagged as having
    * a wrapper anon box parent.  This should only be set if
@@ -823,26 +819,31 @@ private:
      match or if the matching integer has a FrameConstructionDataGetter that
      returns null. */
   static const FrameConstructionData*
     FindDataByInt(int32_t aInt, Element* aElement,
                   nsStyleContext* aStyleContext,
                   const FrameConstructionDataByInt* aDataPtr,
                   uint32_t aDataLength);
 
-  /* A function that takes a tag, content, style context, and array of
-     FrameConstructionDataByTags and finds the appropriate frame construction
-     data to use and returns it.  This can return null if none of the tags
-     match or if the matching tag has a FrameConstructionDataGetter that
-     returns null. */
+  /**
+   * A function that takes a tag, content, style context, and array of
+   * FrameConstructionDataByTags and finds the appropriate frame construction
+   * data to use and returns it.
+   *
+   * This can return null if none of the tags match or if the matching tag has a
+   * FrameConstructionDataGetter that returns null. In the case that the tags
+   * actually match, aTagFound will be true, even if the return value is null.
+   */
   static const FrameConstructionData*
     FindDataByTag(nsAtom* aTag, Element* aElement,
                   nsStyleContext* aStyleContext,
                   const FrameConstructionDataByTag* aDataPtr,
-                  uint32_t aDataLength);
+                  uint32_t aDataLength,
+                  bool* aTagFound = nullptr);
 
   /* A class representing a list of FrameConstructionItems.  Instances of this
      class are only created as AutoFrameConstructionItemList, or as a member
      of FrameConstructionItem. */
   class FrameConstructionItemList
   {
   public:
     void Reset(nsCSSFrameConstructor* aFCtor)
--- a/layout/reftests/css-display/display-contents-acid-ref.html
+++ b/layout/reftests/css-display/display-contents-acid-ref.html
@@ -169,16 +169,12 @@ 0
 <div class="contents c3"><div>3</div></div>
 </div>
 
 <span class="c2 b"><legend class="inline c1">Legend</legend><legend class="inline c1">Legend</legend></span>
 <br clear="all">
 <span class="c3">x<div class="inline c1">float:left</div></span>
 <span class="c3">y<div class="inline c1">position:absolute</div></span>
 
-<!--  -->
-
-<fieldset class="c1" style="display:inline"><legend>Legend</legend>fieldset</fieldset>
-<button class="c1">but<span>ton</span></button>
-<select class="c1"><option>select</select>
+<span class="c1">Legendfieldset but<span>ton</span></span>
 
 </body>
 </html>
--- a/layout/reftests/css-display/display-contents-acid.html
+++ b/layout/reftests/css-display/display-contents-acid.html
@@ -176,16 +176,17 @@ 0
 <div class="contents c3"><!-- comment node --></div>
 <div class="contents c3"><?PI ?></div>
 
 <span class="c2"><legend class="contents c1">Legend</legend><legend class="contents c1">Legend</legend></span>
 <br clear="all">
 <span class="c3">x<div class="contents c1" style="float:left">float:left</div></span>
 <span class="c3">y<div class="contents c1" style="position:absolute">position:absolute</div></span>
 
-<!-- Stuff below should simply ignore having display:contents -->
+<fieldset class="contents c1"><legend class="contents">Legend</legend>fieldset</fieldset>
+<button class="contents c1" style="font: inherit;">but<span>ton</span></button>
 
-<fieldset class="contents c1"><legend class="contents">Legend</legend>fieldset</fieldset>
-<button class="contents c1">but<span>ton</span></button>
+<!-- Stuff below should simply behave as having display: none -->
+
 <select class="contents c1"><option>select</select>
 
 </body>
 </html>
--- a/layout/reftests/css-display/display-contents-fieldset-ref.html
+++ b/layout/reftests/css-display/display-contents-fieldset-ref.html
@@ -18,35 +18,43 @@ legend { border: 1px solid; }
 </style>
 </head>
 <body>
 <fieldset><div class="test contents"></div></fieldset>
 <fieldset><div class="test contents">x</div></fieldset>
 <fieldset><div class="test contents after"></div></fieldset>
 <fieldset><div class="test contents before"></div></fieldset>
 <fieldset><div class="test contents before after"></div></fieldset>
-<fieldset><legend class="test contents"></legend></fieldset>
-<fieldset><legend class="test contents" style="padding:0"></legend></fieldset>
-<fieldset><legend class="contents"><div class="test contents"></div></legend></fieldset>
+<fieldset><span></span></fieldset>
+<fieldset><span></span></fieldset>
+<fieldset><span></span></fieldset>
 <fieldset class="test2"></fieldset>
 <fieldset class="test2 after"></fieldset>
 <fieldset class="test2"><legend class="static"></legend></fieldset>
 <fieldset class="test2"><legend class="static contents"></legend></fieldset>
 <fieldset class="test2"><legend class="static" style="padding:0"></legend></fieldset>
 <fieldset class="test2 p0"></fieldset>
-<fieldset class="test2 p0"></fieldset>
+<fieldset class="test3 p0"></fieldset>
 <fieldset class="test2 p0"><legend class="static"></legend></fieldset>
-<fieldset class="test2 p0"><legend class="static"></legend></fieldset>
+<fieldset class="test3 p0"><legend class="static"></legend></fieldset>
 <script>
 document.body.offsetHeight;
 var tests = document.querySelectorAll('.test');
 for (i=0; i < tests.length; ++i) {
   test = tests[i];
   test.appendChild(document.createElement('span'));
 }
-var tests = document.querySelectorAll('.test2,.test3');
+var tests = document.querySelectorAll('.test2');
+for (i=0; i < tests.length; ++i) {
+  test = tests[i];
+  let span = document.createElement('dummy-inline');
+  span.innerHTML = "legend";
+  test.appendChild(span);
+}
+
+var tests = document.querySelectorAll('.test3');
 for (i=0; i < tests.length; ++i) {
   test = tests[i];
   test.appendChild(document.createElement('legend'));
 }
 </script>
 </body>
 </html>
--- a/layout/svg/nsSVGUseFrame.cpp
+++ b/layout/svg/nsSVGUseFrame.cpp
@@ -161,18 +161,20 @@ nsSVGUseFrame::NotifySVGChanged(uint32_t
 }
 
 //----------------------------------------------------------------------
 // nsIAnonymousContentCreator methods:
 
 nsresult
 nsSVGUseFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
 {
-  SVGUseElement *use = static_cast<SVGUseElement*>(GetContent());
-
+  // FIXME(emilio): This should not be done at frame construction time, but
+  // using Shadow DOM or something like that instead, to support properly
+  // display: contents in <svg:use>.
+  auto use = static_cast<SVGUseElement*>(GetContent());
   mContentClone = use->CreateAnonymousContent();
   nsLayoutUtils::PostRestyleEvent(
     use, nsRestyleHint(0), nsChangeHint_InvalidateRenderingObservers);
   if (!mContentClone)
     return NS_ERROR_FAILURE;
   aElements.AppendElement(mContentClone);
   return NS_OK;
 }
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -102532,16 +102532,28 @@
       [
        "/css/css-display/display-contents-table-002-ref.html",
        "=="
       ]
      ],
      {}
     ]
    ],
+   "css/css-display/display-contents-fieldset-nested-legend.html": [
+    [
+     "/css/css-display/display-contents-fieldset-nested-legend.html",
+     [
+      [
+       "/css/css-display/display-contents-fieldset-nested-legend-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-display/display-contents-first-letter-001.html": [
     [
      "/css/css-display/display-contents-first-letter-001.html",
      [
       [
        "/css/css-display/display-contents-pass-green-no-red-ref.html",
        "=="
       ]
@@ -229853,16 +229865,21 @@
      {}
     ]
    ],
    "css/css-display/display-contents-dynamic-pseudo-insertion-001-ref.html": [
     [
      {}
     ]
    ],
+   "css/css-display/display-contents-fieldset-nested-legend-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-display/display-contents-flex-001-ref.html": [
     [
      {}
     ]
    ],
    "css/css-display/display-contents-flex-002-ref.html": [
     [
      {}
@@ -469148,16 +469165,24 @@
   "css/css-display/display-contents-dynamic-table-002-inline.html": [
    "1c7f34107b3778f5d6f7d538ed05eb886dba08ed",
    "reftest"
   ],
   "css/css-display/display-contents-dynamic-table-002-none.html": [
    "c874f59947d37659e640d4e0abb8a0dc0f03927d",
    "reftest"
   ],
+  "css/css-display/display-contents-fieldset-nested-legend-ref.html": [
+   "89fbd146ffbd862ba3d0f058d8d8c9d8024da0fa",
+   "support"
+  ],
+  "css/css-display/display-contents-fieldset-nested-legend.html": [
+   "45be585ab1523c180b3ba159d25d0dadd80456ac",
+   "reftest"
+  ],
   "css/css-display/display-contents-first-letter-001.html": [
    "acfaf8f68595c7eb36585309b9d6b0bc5c0ffe41",
    "reftest"
   ],
   "css/css-display/display-contents-first-line-001.html": [
    "19f4bc895d895a6dd62b638960b4b7f2f26f5752",
    "reftest"
   ],
@@ -504565,21 +504590,21 @@
    "13056acc82d5e59310d10af30da8e46f73929e5f",
    "support"
   ],
   "css/css-ui/text-overflow-025.html": [
    "b4a2e0d1b86fd8893421de4335c9b6f36df1fc4d",
    "reftest"
   ],
   "css/css-ui/text-overflow-026-ref.html": [
-   "1a7d6d524a217d8fc2252e6434ac1b8fb3d5af2f",
+   "03c0337af58ba7bada64ab36721d9f1fe2f9a2f3",
    "support"
   ],
   "css/css-ui/text-overflow-026.html": [
-   "34cb2b690321f6f93763de2841ebdf5a9275f515",
+   "5087fe90cb3ef8e340be316f1534cb6dba3e0d17",
    "reftest"
   ],
   "css/css-ui/text-overflow-ref.html": [
    "db55b0b95a7406e9c4f00081b3e2cbe6b07363f7",
    "support"
   ],
   "css/css-ui/text-overflow.html": [
    "d3a6c835c23b82a85398e7981461a0cd3a75b861",
@@ -524409,17 +524434,17 @@
    "a53b3bd5909771c800c5d3e874fd83ae77f0efeb",
    "support"
   ],
   "dom/events/EventListener-incumbent-global-subsubframe.sub.html": [
    "35ffc948502021b3367ae759b5f5ac362fd7acaa",
    "support"
   ],
   "dom/events/EventListener-invoke-legacy.html": [
-   "e56b332acb454ab76964b78588536777946ddff8",
+   "13cb3802cb2722417b876ded17fddd222c69564a",
    "testharness"
   ],
   "dom/events/EventListenerOptions-capture.html": [
    "cebd60a18add5403d4f0bd68e88e05daacfd241a",
    "testharness"
   ],
   "dom/events/EventTarget-addEventListener.html": [
    "85dea0178b16b5c3e8ddbfa9a8b4bd8424bc0a3d",
@@ -545945,17 +545970,17 @@
    "f2a20180b6bf5f9c89f5b9541885d55dc8a8ade6",
    "support"
   ],
   "html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html": [
    "e2c860b1b348148fc6b9d77f918894b1bac42c94",
    "testharness"
   ],
   "html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html": [
-   "996d1aa45c5975e13ac0f1e9c9249b3d452ed2e2",
+   "3365d69d34e442962370a1f0ed22017876efe4fe",
    "testharness"
   ],
   "html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html": [
    "224fe5510f09c3dd6d58f9dcf61b4d6fca04c96c",
    "testharness"
   ],
   "html/semantics/scripting-1/the-script-element/module/instantiation-error-4a.js": [
    "051586d3af5158af29ee8f46157964252a47ef65",
@@ -546073,33 +546098,33 @@
    "a04ecfd484ada80c436c880c6fb39abba47eac1c",
    "testharness"
   ],
   "html/semantics/scripting-1/the-script-element/module/late-star-export-request.html": [
    "2fd8c4ee6fcc66a8ddc2100a0840ebcc324a7d58",
    "testharness"
   ],
   "html/semantics/scripting-1/the-script-element/module/load-error-events-inline.html": [
-   "9b35d8d7ba6bb4826274c9570056cc962660d715",
+   "bbdfd11cfc7e52748f07d09ebe7cf6782ad5e782",
    "testharness"
   ],
   "html/semantics/scripting-1/the-script-element/module/load-error-events.html": [
    "304dc3a7e9cd48699742b0a1431adda1d0f253c0",
    "testharness"
   ],
   "html/semantics/scripting-1/the-script-element/module/missing-export-nested.js": [
    "5c6c1dae178b88b42ce87964e372f7d7db99ba70",
    "support"
   ],
   "html/semantics/scripting-1/the-script-element/module/missing-export.js": [
    "27cd038ca24450b1aeb9fe52cb9dea85998d108c",
    "support"
   ],
   "html/semantics/scripting-1/the-script-element/module/module-in-xhtml.xhtml": [
-   "32a4a4db2a5325b909078c73f76ab51085e66c5a",
+   "4b41e3e07ff72b0f181b0dd3a6c1aab40a01da0c",
    "testharness"
   ],
   "html/semantics/scripting-1/the-script-element/module/module-vs-script-1.html": [
    "a7fd504c7bfeefb445de9f2a1212986f27e80465",
    "testharness"
   ],
   "html/semantics/scripting-1/the-script-element/module/module-vs-script-2.html": [
    "ca5ee235cc345d01e3d98cf3512dc26b9ad1896e",
@@ -569437,17 +569462,17 @@
    "881f51c7f9c64f6d69746e1e195c11cf6e29fb3e",
    "testharness"
   ],
   "service-workers/service-worker/unregister-controller.https.html": [
    "24cf65bf38dcdd90e24c20bd6be3823db1e9a601",
    "testharness"
   ],
   "service-workers/service-worker/unregister-then-register-new-script.https.html": [
-   "43964791edbb2b5cd3b3ed27b600e78412902240",
+   "ee8d7cd4e47cdb9bcf2b39c911593bc671df914d",
    "testharness"
   ],
   "service-workers/service-worker/unregister-then-register.https.html": [
    "b4a5e1933296cf96fa001822b5e269a5db60b188",
    "testharness"
   ],
   "service-workers/service-worker/unregister.https.html": [
    "672dbc9f930b829099b5788f995958f208cba3b7",
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-display/display-contents-fieldset-nested-legend-ref.html
@@ -0,0 +1,6 @@
+<!doctype html>
+<meta charset="utf-8">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<title>CSS Test Reference</title>
+<fieldset style="color: green">P<legend style="padding: 0">legend</legend>ASS</fieldset>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-display/display-contents-fieldset-nested-legend.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<meta charset="utf-8">
+<link rel="match" href="display-contents-fieldset-nested-legend-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css-display/#unbox">
+<link rel="help" href="https://drafts.csswg.org/css-display/#valdef-display-contents">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1427292">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<title>CSS Test: display: contents on legend</title>
+<style>
+fieldset {
+  color: red;
+}
+.contents {
+  display: contents;
+  color: green;
+  border: 10px solid red;
+}
+</style>
+<fieldset><legend class="contents">P<legend>legend</legend>ASS</legend></fieldset>