From f0be219b008bd0cb396a0cb2c3117461facc22c0 Mon Sep 17 00:00:00 2001 From: Cristian Tuns Date: Thu, 25 Jan 2024 18:29:39 -0500 Subject: [PATCH] Backed out 4 changesets (bug 1758391, bug 1852478) for causing build bustages in UseCounterMetrics.cpp CLOSED TREE Backed out changeset fe673f87d86a (bug 1852478) Backed out changeset d466ccbd1aad (bug 1852478) Backed out changeset c0fa98fec39a (bug 1758391) Backed out changeset 04d322f23fd0 (bug 1852478) --- .../server/actors/animation-type-longhand.js | 5 +- .../tests/chrome/test_styles-computed.html | 10 +- dom/base/use_counter_metrics.yaml | 1 - dom/html/HTMLPreElement.cpp | 7 +- dom/html/HTMLTableCellElement.cpp | 6 +- dom/html/HTMLTextAreaElement.cpp | 14 +- editor/libeditor/EditorUtils.cpp | 11 +- editor/libeditor/EditorUtils.h | 8 +- editor/libeditor/HTMLEditorDeleteHandler.cpp | 91 ++++------ editor/libeditor/WSRunObject.cpp | 4 +- layout/generic/nsBlockFrame.cpp | 5 +- layout/generic/nsIFrame.cpp | 4 +- layout/generic/nsTextFrame.cpp | 34 ++-- layout/style/ServoBindings.toml | 5 +- layout/style/nsStyleConsts.h | 21 +-- layout/style/nsStyleStruct.cpp | 11 +- layout/style/nsStyleStruct.h | 41 +++-- layout/style/test/property_database.js | 51 +----- servo/components/style/properties/data.py | 19 +- .../longhands/inherited_text.mako.rs | 72 +++++--- .../shorthands/inherited_text.mako.rs | 163 ------------------ servo/ports/geckolib/glue.rs | 3 +- .../meta/css/css-text/inheritance.html.ini | 24 +++ .../parsing/text-wrap-computed.html.ini | 45 +++++ .../parsing/text-wrap-mode-computed.html.ini | 6 + .../parsing/text-wrap-mode-valid.html.ini | 21 +++ .../parsing/text-wrap-style-computed.html.ini | 9 + .../parsing/text-wrap-style-valid.html.ini | 24 +++ .../css-text/parsing/text-wrap-valid.html.ini | 45 +++++ .../white-space-collapse-computed.html.ini | 12 ++ .../white-space-collapse-valid.html.ini | 27 +++ .../white-space-shorthand-text-wrap.html.ini | 6 + .../parsing/white-space-shorthand.html.ini | 108 ++++++++++++ .../accumulation-per-property-002.html.ini | 6 + .../addition-per-property-002.html.ini | 6 + .../interpolation-per-property-002.html.ini | 9 + 36 files changed, 534 insertions(+), 400 deletions(-) create mode 100644 testing/web-platform/meta/css/css-text/parsing/text-wrap-mode-computed.html.ini create mode 100644 testing/web-platform/meta/css/css-text/parsing/text-wrap-mode-valid.html.ini create mode 100644 testing/web-platform/meta/css/css-text/parsing/white-space-collapse-computed.html.ini create mode 100644 testing/web-platform/meta/css/css-text/parsing/white-space-collapse-valid.html.ini create mode 100644 testing/web-platform/meta/css/css-text/parsing/white-space-shorthand-text-wrap.html.ini create mode 100644 testing/web-platform/meta/css/css-text/parsing/white-space-shorthand.html.ini create mode 100644 testing/web-platform/meta/web-animations/animation-model/animation-types/accumulation-per-property-002.html.ini create mode 100644 testing/web-platform/meta/web-animations/animation-model/animation-types/addition-per-property-002.html.ini create mode 100644 testing/web-platform/meta/web-animations/animation-model/animation-types/interpolation-per-property-002.html.ini diff --git a/devtools/server/actors/animation-type-longhand.js b/devtools/server/actors/animation-type-longhand.js index febf8457adb8..39ab8d2dab6e 100644 --- a/devtools/server/actors/animation-type-longhand.js +++ b/devtools/server/actors/animation-type-longhand.js @@ -174,8 +174,7 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [ "-webkit-text-stroke-width", "text-transform", "text-underline-position", - "text-wrap-mode", - "text-wrap-style", + "text-wrap", "touch-action", "transform-box", "transform-style", @@ -186,7 +185,7 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [ "user-select", "vector-effect", "visibility", - "white-space-collapse", + "white-space", "will-change", "-moz-window-dragging", "word-break", diff --git a/devtools/server/tests/chrome/test_styles-computed.html b/devtools/server/tests/chrome/test_styles-computed.html index 9aa962108af4..af96869ed803 100644 --- a/devtools/server/tests/chrome/test_styles-computed.html +++ b/devtools/server/tests/chrome/test_styles-computed.html @@ -38,7 +38,7 @@ addTest(function testComputed() { // Test a smattering of properties that include some system-defined // props, some props that were defined in this node's stylesheet, // and some default props. - is(computed["white-space-collapse"].value, "collapse", "Default value should appear"); + is(computed["white-space"].value, "normal", "Default value should appear"); is(computed.display.value, "block", "System stylesheet item should appear"); is(computed.cursor.value, "crosshair", "Included stylesheet rule should appear"); is(computed.color.value, "rgb(255, 0, 0)", @@ -58,7 +58,7 @@ addTest(function testComputedUserMatched() { gWalker.querySelector(gWalker.rootNode, "#computed-test-node").then(node => { return gStyles.getComputed(node, { filter: "user", markMatched: true }); }).then(computed => { - ok(!computed["white-space-collapse"].matched, "Default style shouldn't match"); + ok(!computed["white-space"].matched, "Default style shouldn't match"); ok(!computed.display.matched, "Only user styles should match"); ok(computed.cursor.matched, "Asked for matched, should get it"); ok(computed.color.matched, "Asked for matched, should get it"); @@ -72,7 +72,7 @@ addTest(function testComputedSystemMatched() { gWalker.querySelector(gWalker.rootNode, "#computed-test-node").then(node => { return gStyles.getComputed(node, { filter: "ua", markMatched: true }); }).then(computed => { - ok(!computed["white-space-collapse"].matched, "Default style shouldn't match"); + ok(!computed["white-space"].matched, "Default style shouldn't match"); ok(computed.display.matched, "System stylesheets should match"); ok(computed.cursor.matched, "Asked for matched, should get it"); ok(computed.color.matched, "Asked for matched, should get it"); @@ -86,7 +86,7 @@ addTest(function testComputedUserOnlyMatched() { gWalker.querySelector(gWalker.rootNode, "#computed-test-node").then(node => { return gStyles.getComputed(node, { filter: "user", onlyMatched: true }); }).then(computed => { - ok(!("white-space-collapse" in computed), "Default style shouldn't exist"); + ok(!("white-space" in computed), "Default style shouldn't exist"); ok(!("display" in computed), "System stylesheets shouldn't exist"); ok(("cursor" in computed), "User items should exist."); ok(("color" in computed), "User items should exist."); @@ -100,7 +100,7 @@ addTest(function testComputedSystemOnlyMatched() { gWalker.querySelector(gWalker.rootNode, "#computed-test-node").then(node => { return gStyles.getComputed(node, { filter: "ua", onlyMatched: true }); }).then(computed => { - ok(!("white-space-collapse" in computed), "Default style shouldn't exist"); + ok(!("white-space" in computed), "Default style shouldn't exist"); ok(("display" in computed), "System stylesheets should exist"); ok(("cursor" in computed), "User items should exist."); ok(("color" in computed), "User items should exist."); diff --git a/dom/base/use_counter_metrics.yaml b/dom/base/use_counter_metrics.yaml index 5b33223610c4..5bb2ea43db19 100644 --- a/dom/base/use_counter_metrics.yaml +++ b/dom/base/use_counter_metrics.yaml @@ -39267,7 +39267,6 @@ use.counter.css.doc: send_in_pings: - use-counters - webkit_column_rule_color: type: counter description: > diff --git a/dom/html/HTMLPreElement.cpp b/dom/html/HTMLPreElement.cpp index 13628400d041..feaa764bd594 100644 --- a/dom/html/HTMLPreElement.cpp +++ b/dom/html/HTMLPreElement.cpp @@ -38,11 +38,8 @@ void HTMLPreElement::MapAttributesIntoRule( MappedDeclarationsBuilder& aBuilder) { // wrap: empty if (aBuilder.GetAttr(nsGkAtoms::wrap)) { - // Equivalent to expanding `white-space: pre-wrap` - aBuilder.SetKeywordValue(eCSSProperty_white_space_collapse, - StyleWhiteSpaceCollapse::Preserve); - aBuilder.SetKeywordValue(eCSSProperty_text_wrap_mode, - StyleTextWrapMode::Wrap); + aBuilder.SetKeywordValue(eCSSProperty_white_space, + StyleWhiteSpace::PreWrap); } nsGenericHTMLElement::MapCommonAttributesInto(aBuilder); diff --git a/dom/html/HTMLTableCellElement.cpp b/dom/html/HTMLTableCellElement.cpp index c260323a8bd8..4c2e33cb3ac3 100644 --- a/dom/html/HTMLTableCellElement.cpp +++ b/dom/html/HTMLTableCellElement.cpp @@ -163,7 +163,7 @@ void HTMLTableCellElement::MapAttributesIntoRule( MappedDeclarationsBuilder& aBuilder) { MapImageSizeAttributesInto(aBuilder); - if (!aBuilder.PropertyIsSet(eCSSProperty_text_wrap_mode)) { + if (!aBuilder.PropertyIsSet(eCSSProperty_white_space)) { // nowrap: enum if (aBuilder.GetAttr(nsGkAtoms::nowrap)) { // See if our width is not a nonzero integer width. @@ -171,8 +171,8 @@ void HTMLTableCellElement::MapAttributesIntoRule( nsCompatibility mode = aBuilder.Document().GetCompatibilityMode(); if (!value || value->Type() != nsAttrValue::eInteger || value->GetIntegerValue() == 0 || eCompatibility_NavQuirks != mode) { - aBuilder.SetKeywordValue(eCSSProperty_text_wrap_mode, - StyleTextWrapMode::Nowrap); + aBuilder.SetKeywordValue(eCSSProperty_white_space, + StyleWhiteSpace::Nowrap); } } } diff --git a/dom/html/HTMLTextAreaElement.cpp b/dom/html/HTMLTextAreaElement.cpp index afcb1f75d08b..046655453859 100644 --- a/dom/html/HTMLTextAreaElement.cpp +++ b/dom/html/HTMLTextAreaElement.cpp @@ -365,14 +365,12 @@ bool HTMLTextAreaElement::ParseAttribute(int32_t aNamespaceID, void HTMLTextAreaElement::MapAttributesIntoRule( MappedDeclarationsBuilder& aBuilder) { // wrap=off - const nsAttrValue* value = aBuilder.GetAttr(nsGkAtoms::wrap); - if (value && value->Type() == nsAttrValue::eString && - value->Equals(nsGkAtoms::OFF, eIgnoreCase)) { - // Equivalent to expanding `white-space; pre` - aBuilder.SetKeywordValue(eCSSProperty_white_space_collapse, - StyleWhiteSpaceCollapse::Preserve); - aBuilder.SetKeywordValue(eCSSProperty_text_wrap_mode, - StyleTextWrapMode::Nowrap); + if (!aBuilder.PropertyIsSet(eCSSProperty_white_space)) { + const nsAttrValue* value = aBuilder.GetAttr(nsGkAtoms::wrap); + if (value && value->Type() == nsAttrValue::eString && + value->Equals(nsGkAtoms::OFF, eIgnoreCase)) { + aBuilder.SetKeywordValue(eCSSProperty_white_space, StyleWhiteSpace::Pre); + } } nsGenericHTMLFormControlElementWithState::MapDivAlignAttributeInto(aBuilder); diff --git a/editor/libeditor/EditorUtils.cpp b/editor/libeditor/EditorUtils.cpp index d9df9338e075..c37f75047085 100644 --- a/editor/libeditor/EditorUtils.cpp +++ b/editor/libeditor/EditorUtils.cpp @@ -89,8 +89,8 @@ bool EditorUtils::IsDescendantOf(const nsINode& aNode, const nsINode& aParent, } // static -Maybe> -EditorUtils::GetComputedWhiteSpaceStyles(const nsIContent& aContent) { +Maybe EditorUtils::GetComputedWhiteSpaceStyle( + const nsIContent& aContent) { if (MOZ_UNLIKELY(!aContent.IsElement() && !aContent.GetParentElement())) { return Nothing(); } @@ -101,9 +101,7 @@ EditorUtils::GetComputedWhiteSpaceStyles(const nsIContent& aContent) { if (NS_WARN_IF(!elementStyle)) { return Nothing(); } - const auto* styleText = elementStyle->StyleText(); - return Some( - std::pair(styleText->mWhiteSpaceCollapse, styleText->mTextWrapMode)); + return Some(elementStyle->StyleText()->mWhiteSpace); } // static @@ -166,8 +164,7 @@ bool EditorUtils::IsOnlyNewLinePreformatted(const nsIContent& aContent) { return false; } - return elementStyle->StyleText()->mWhiteSpaceCollapse == - StyleWhiteSpaceCollapse::PreserveBreaks; + return elementStyle->StyleText()->mWhiteSpace == StyleWhiteSpace::PreLine; } // static diff --git a/editor/libeditor/EditorUtils.h b/editor/libeditor/EditorUtils.h index c6b08952dd4f..80de25b53274 100644 --- a/editor/libeditor/EditorUtils.h +++ b/editor/libeditor/EditorUtils.h @@ -401,10 +401,10 @@ class EditorUtils final { } /** - * Get the two longhands that make up computed white-space style of aContent. + * Get computed white-space style of aContent. */ - static Maybe> - GetComputedWhiteSpaceStyles(const nsIContent& aContent); + static Maybe GetComputedWhiteSpaceStyle( + const nsIContent& aContent); /** * IsWhiteSpacePreformatted() checks the style info for the node for the @@ -421,7 +421,7 @@ class EditorUtils final { /** * IsOnlyNewLinePreformatted() checks whether the linefeed characters are * preformated but white-spaces are collapsed, or otherwise. I.e., this - * returns true only when `white-space-collapse:pre-line`. + * returns true only when `white-space:pre-line`. */ static bool IsOnlyNewLinePreformatted(const nsIContent& aContent); diff --git a/editor/libeditor/HTMLEditorDeleteHandler.cpp b/editor/libeditor/HTMLEditorDeleteHandler.cpp index 18f9eda88e25..07738de6ee12 100644 --- a/editor/libeditor/HTMLEditorDeleteHandler.cpp +++ b/editor/libeditor/HTMLEditorDeleteHandler.cpp @@ -5353,10 +5353,8 @@ HTMLEditor::AutoMoveOneLineHandler::ConsiderWhetherPreserveWhiteSpaceStyle( // If the content has different `white-space` style from
, we
     // shouldn't treat it as a descendant of 
 because web apps or
     // the user intent to treat the white-spaces in aContent not as `pre`.
-    if (EditorUtils::GetComputedWhiteSpaceStyles(aContent).valueOr(std::pair(
-            StyleWhiteSpaceCollapse::Collapse, StyleTextWrapMode::Wrap)) !=
-        std::pair(StyleWhiteSpaceCollapse::Preserve,
-                  StyleTextWrapMode::Nowrap)) {
+    if (EditorUtils::GetComputedWhiteSpaceStyle(aContent).valueOr(
+            StyleWhiteSpace::Normal) != StyleWhiteSpace::Pre) {
       return false;
     }
     for (const Element* element :
@@ -5803,67 +5801,52 @@ Result HTMLEditor::MoveNodeOrChildrenWithTransaction(
   MOZ_ASSERT(IsEditActionDataAvailable());
   MOZ_ASSERT(aPointToInsert.IsInContentNode());
 
-  const auto destWhiteSpaceStyles =
-      [&]() -> Maybe> {
+  const auto destWhiteSpaceStyle = [&]() -> Maybe {
     if (aPreserveWhiteSpaceStyle == PreserveWhiteSpaceStyle::No ||
         !aPointToInsert.IsInContentNode()) {
       return Nothing();
     }
-    auto styles = EditorUtils::GetComputedWhiteSpaceStyles(
+    auto style = EditorUtils::GetComputedWhiteSpaceStyle(
         *aPointToInsert.ContainerAs());
-    if (NS_WARN_IF(styles.isSome() &&
-                   styles.value().first ==
-                       StyleWhiteSpaceCollapse::PreserveSpaces)) {
+    if (NS_WARN_IF(style.isSome() &&
+                   style.value() == StyleWhiteSpace::PreSpace)) {
       return Nothing();
     }
-    return styles;
+    return style;
   }();
-  const auto srcWhiteSpaceStyles =
-      [&]() -> Maybe> {
+  const auto srcWhiteSpaceStyle = [&]() -> Maybe {
     if (aPreserveWhiteSpaceStyle == PreserveWhiteSpaceStyle::No) {
       return Nothing();
     }
-    auto styles = EditorUtils::GetComputedWhiteSpaceStyles(aContentToMove);
-    if (NS_WARN_IF(styles.isSome() &&
-                   styles.value().first ==
-                       StyleWhiteSpaceCollapse::PreserveSpaces)) {
+    auto style = EditorUtils::GetComputedWhiteSpaceStyle(aContentToMove);
+    if (NS_WARN_IF(style.isSome() &&
+                   style.value() == StyleWhiteSpace::PreSpace)) {
       return Nothing();
     }
-    return styles;
+    return style;
   }();
-  // Get the `white-space` shorthand form for the given collapse + mode pair.
-  const auto GetWhiteSpaceStyleValue =
-      [](std::pair aStyles) {
-        if (aStyles.second == StyleTextWrapMode::Wrap) {
-          switch (aStyles.first) {
-            case StyleWhiteSpaceCollapse::Collapse:
-              return u"normal"_ns;
-            case StyleWhiteSpaceCollapse::Preserve:
-              return u"pre-wrap"_ns;
-            case StyleWhiteSpaceCollapse::PreserveBreaks:
-              return u"pre-line"_ns;
-            case StyleWhiteSpaceCollapse::PreserveSpaces:
-              return u"preserve-spaces"_ns;
-            case StyleWhiteSpaceCollapse::BreakSpaces:
-              return u"break-spaces"_ns;
-          }
-        } else {
-          switch (aStyles.first) {
-            case StyleWhiteSpaceCollapse::Collapse:
-              return u"nowrap"_ns;
-            case StyleWhiteSpaceCollapse::Preserve:
-              return u"pre"_ns;
-            case StyleWhiteSpaceCollapse::PreserveBreaks:
-              return u"nowrap preserve-breaks"_ns;
-            case StyleWhiteSpaceCollapse::PreserveSpaces:
-              return u"nowrap preserve-spaces"_ns;
-            case StyleWhiteSpaceCollapse::BreakSpaces:
-              return u"nowrap break-spaces"_ns;
-          }
-        }
-        MOZ_ASSERT_UNREACHABLE("all values should be handled above!");
+  const auto GetWhiteSpaceStyleValue = [](StyleWhiteSpace aStyleWhiteSpace) {
+    switch (aStyleWhiteSpace) {
+      case StyleWhiteSpace::Normal:
         return u"normal"_ns;
-      };
+      case StyleWhiteSpace::Pre:
+        return u"pre"_ns;
+      case StyleWhiteSpace::Nowrap:
+        return u"nowrap"_ns;
+      case StyleWhiteSpace::PreWrap:
+        return u"pre-wrap"_ns;
+      case StyleWhiteSpace::PreLine:
+        return u"pre-line"_ns;
+      case StyleWhiteSpace::BreakSpaces:
+        return u"break-spaces"_ns;
+      case StyleWhiteSpace::PreSpace:
+        MOZ_ASSERT_UNREACHABLE("Don't handle -moz-pre-space");
+        return u""_ns;
+      default:
+        MOZ_ASSERT_UNREACHABLE("Handle the new white-space value");
+        return u""_ns;
+    }
+  };
 
   if (aRemoveIfCommentNode == RemoveIfCommentNode::Yes &&
       aContentToMove.IsComment()) {
@@ -5889,15 +5872,15 @@ Result HTMLEditor::MoveNodeOrChildrenWithTransaction(
     // Preserve white-space in the new position with using `style` attribute.
     // This is additional path from point of view of our traditional behavior.
     // Therefore, ignore errors especially if we got unexpected DOM tree.
-    if (destWhiteSpaceStyles.isSome() && srcWhiteSpaceStyles.isSome() &&
-        destWhiteSpaceStyles.value() != srcWhiteSpaceStyles.value()) {
+    if (destWhiteSpaceStyle.isSome() && srcWhiteSpaceStyle.isSome() &&
+        destWhiteSpaceStyle.value() != srcWhiteSpaceStyle.value()) {
       // Set `white-space` with `style` attribute if it's nsStyledElement.
       if (nsStyledElement* styledElement =
               nsStyledElement::FromNode(&aContentToMove)) {
         DebugOnly rvIgnored =
             CSSEditUtils::SetCSSPropertyWithTransaction(
                 *this, MOZ_KnownLive(*styledElement), *nsGkAtoms::white_space,
-                GetWhiteSpaceStyleValue(srcWhiteSpaceStyles.value()));
+                GetWhiteSpaceStyleValue(srcWhiteSpaceStyle.value()));
         if (NS_WARN_IF(Destroyed())) {
           return Err(NS_ERROR_EDITOR_DESTROYED);
         }
@@ -5917,7 +5900,7 @@ Result HTMLEditor::MoveNodeOrChildrenWithTransaction(
         }
         nsAutoString styleAttrValue(u"white-space: "_ns);
         styleAttrValue.Append(
-            GetWhiteSpaceStyleValue(srcWhiteSpaceStyles.value()));
+            GetWhiteSpaceStyleValue(srcWhiteSpaceStyle.value()));
         IgnoredErrorResult error;
         newSpanElement->SetAttr(nsGkAtoms::style, styleAttrValue, error);
         NS_WARNING_ASSERTION(!error.Failed(),
diff --git a/editor/libeditor/WSRunObject.cpp b/editor/libeditor/WSRunObject.cpp
index 7149578be113..3136c468dec2 100644
--- a/editor/libeditor/WSRunObject.cpp
+++ b/editor/libeditor/WSRunObject.cpp
@@ -724,8 +724,8 @@ Result WhiteSpaceVisibilityKeeper::
       // a bug to manage only the change.
       (aLeftBlockElement.NodeInfo()->NameAtom() ==
            aRightBlockElement.NodeInfo()->NameAtom() &&
-       EditorUtils::GetComputedWhiteSpaceStyles(aLeftBlockElement) ==
-           EditorUtils::GetComputedWhiteSpaceStyles(aRightBlockElement))) {
+       EditorUtils::GetComputedWhiteSpaceStyle(aLeftBlockElement) ==
+           EditorUtils::GetComputedWhiteSpaceStyle(aRightBlockElement))) {
     // Nodes are same type.  merge them.
     EditorDOMPoint atFirstChildOfRightNode;
     nsresult rv = aHTMLEditor.JoinNearestEditableNodesWithTransaction(
diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp
index 3e68bb96d46d..7c13b3fc5aca 100644
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -1470,9 +1470,8 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
   }
 
   // Whether to apply text-wrap: balance behavior.
-  bool tryBalance =
-      StyleText()->mTextWrapStyle == StyleTextWrapStyle::Balance &&
-      !GetPrevContinuation();
+  bool tryBalance = StyleText()->mTextWrap == StyleTextWrap::Balance &&
+                    !GetPrevContinuation();
 
   // Struct used to hold the "target" number of lines or clamp position to
   // maintain when doing text-wrap: balance.
diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp
index 60389e7eb6b0..8e44561e186e 100644
--- a/layout/generic/nsIFrame.cpp
+++ b/layout/generic/nsIFrame.cpp
@@ -9128,8 +9128,8 @@ nsresult nsIFrame::PeekOffsetForWord(PeekOffsetStruct* aPos, int32_t aOffset) {
       // significant.
       if (next.mJumpedLine && wordSelectEatSpace &&
           current.mFrame->HasSignificantTerminalNewline() &&
-          current.mFrame->StyleText()->mWhiteSpaceCollapse !=
-              StyleWhiteSpaceCollapse::PreserveBreaks) {
+          current.mFrame->StyleText()->mWhiteSpace !=
+              StyleWhiteSpace::PreLine) {
         current.mOffset -= 1;
       }
       break;
diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp
index 9046cb22cfa5..b63781e0e99c 100644
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -781,8 +781,7 @@ static bool IsTrimmableSpace(const nsTextFragment* aFrag, uint32_t aPos,
              !IsSpaceCombiningSequenceTail(aFrag, aPos + 1);
     case '\n':
       return !aStyleText->NewlineIsSignificantStyle() &&
-             aStyleText->mWhiteSpaceCollapse !=
-                 StyleWhiteSpaceCollapse::PreserveSpaces;
+             aStyleText->mWhiteSpace != mozilla::StyleWhiteSpace::PreSpace;
     case '\t':
     case '\r':
     case '\f':
@@ -1172,23 +1171,27 @@ static bool TextContainsLineBreakerWhiteSpace(const void* aText,
 
 static nsTextFrameUtils::CompressionMode GetCSSWhitespaceToCompressionMode(
     nsTextFrame* aFrame, const nsStyleText* aStyleText) {
-  switch (aStyleText->mWhiteSpaceCollapse) {
-    case StyleWhiteSpaceCollapse::Collapse:
+  switch (aStyleText->mWhiteSpace) {
+    case StyleWhiteSpace::Normal:
+    case StyleWhiteSpace::Nowrap:
       return nsTextFrameUtils::COMPRESS_WHITESPACE_NEWLINE;
-    case StyleWhiteSpaceCollapse::PreserveBreaks:
-      return nsTextFrameUtils::COMPRESS_WHITESPACE;
-    case StyleWhiteSpaceCollapse::Preserve:
-    case StyleWhiteSpaceCollapse::PreserveSpaces:
-    case StyleWhiteSpaceCollapse::BreakSpaces:
+    case StyleWhiteSpace::Pre:
+    case StyleWhiteSpace::PreWrap:
+    case StyleWhiteSpace::BreakSpaces:
       if (!aStyleText->NewlineIsSignificant(aFrame)) {
         // If newline is set to be preserved, but then suppressed,
         // transform newline to space.
         return nsTextFrameUtils::COMPRESS_NONE_TRANSFORM_TO_SPACE;
       }
       return nsTextFrameUtils::COMPRESS_NONE;
+    case StyleWhiteSpace::PreSpace:
+      return nsTextFrameUtils::COMPRESS_NONE_TRANSFORM_TO_SPACE;
+    case StyleWhiteSpace::PreLine:
+      return nsTextFrameUtils::COMPRESS_WHITESPACE;
+    default:
+      MOZ_ASSERT_UNREACHABLE("Unknown white-space value");
+      return nsTextFrameUtils::COMPRESS_WHITESPACE_NEWLINE;
   }
-  MOZ_ASSERT_UNREACHABLE("Unknown white-space-collapse value");
-  return nsTextFrameUtils::COMPRESS_WHITESPACE_NEWLINE;
 }
 
 struct FrameTextTraversal {
@@ -9536,8 +9539,7 @@ void nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
   }
   bool canTrimTrailingWhitespace = !textStyle->WhiteSpaceIsSignificant() ||
                                    HasAnyStateBits(TEXT_IS_IN_TOKEN_MATHML);
-  bool isBreakSpaces =
-      textStyle->mWhiteSpaceCollapse == StyleWhiteSpaceCollapse::BreakSpaces;
+  bool isBreakSpaces = textStyle->mWhiteSpace == StyleWhiteSpace::BreakSpaces;
   // allow whitespace to overflow the container
   bool whitespaceCanHang = textStyle->WhiteSpaceCanHangOrVisuallyCollapse();
   gfxBreakPriority breakPriority = aLineLayout.LastOptionalBreakPriority();
@@ -10305,9 +10307,9 @@ bool nsTextFrame::IsEmpty() {
     return true;
   }
 
-  bool isEmpty = IsAllWhitespace(TextFragment(),
-                                 textStyle->mWhiteSpaceCollapse !=
-                                     StyleWhiteSpaceCollapse::PreserveBreaks);
+  bool isEmpty =
+      IsAllWhitespace(TextFragment(), textStyle->mWhiteSpace !=
+                                          mozilla::StyleWhiteSpace::PreLine);
   AddStateBits(isEmpty ? TEXT_IS_ONLY_WHITESPACE : TEXT_ISNOT_ONLY_WHITESPACE);
   return isEmpty;
 }
diff --git a/layout/style/ServoBindings.toml b/layout/style/ServoBindings.toml
index 9e16c418b89f..2deafbfb14b6 100644
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -137,8 +137,7 @@ rusty-enums = [
     "mozilla::StyleListStylePosition",
     "mozilla::StylePointerEvents",
     "mozilla::StyleScrollbarWidth",
-    "mozilla::StyleWhiteSpaceCollapse",
-    "mozilla::StyleTextWrapMode",
+    "mozilla::StyleWhiteSpace",
     "mozilla::StyleTextRendering",
     "mozilla::StyleFlexDirection",
     "mozilla::StyleStrokeLinecap",
@@ -177,7 +176,7 @@ rusty-enums = [
     "mozilla::StyleBlend",
     "mozilla::StyleMaskComposite",
     "mozilla::StyleWritingModeProperty",
-    "mozilla::StyleTextWrapStyle",
+    "mozilla::StyleTextWrap",
     "StyleFontVariantEmoji",
 ]
 allowlist-vars = [
diff --git a/layout/style/nsStyleConsts.h b/layout/style/nsStyleConsts.h
index 99433c902730..8152dfc9dea8 100644
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -389,19 +389,14 @@ enum class StyleVisibility : uint8_t {
 };
 
 // See nsStyleText
-enum class StyleWhiteSpaceCollapse : uint8_t {
-  Collapse = 0,
-  // TODO: Discard not yet supported
-  Preserve,
-  PreserveBreaks,
-  PreserveSpaces,
-  BreakSpaces,
-};
-
-// See nsStyleText
-enum class StyleTextWrapMode : uint8_t {
-  Wrap = 0,
+enum class StyleWhiteSpace : uint8_t {
+  Normal = 0,
+  Pre,
   Nowrap,
+  PreWrap,
+  PreLine,
+  PreSpace,
+  BreakSpaces,
 };
 
 // See nsStyleText
@@ -409,7 +404,7 @@ enum class StyleTextWrapMode : uint8_t {
 // (see https://bugzilla.mozilla.org/show_bug.cgi?id=1758391) and
 // white-space (https://bugzilla.mozilla.org/show_bug.cgi?id=1852478)
 // into shorthands.
-enum class StyleTextWrapStyle : uint8_t {
+enum class StyleTextWrap : uint8_t {
   Auto = 0,
   Stable,
   Balance,
diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp
index 123a1b3304cc..f8f538559558 100644
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2791,6 +2791,7 @@ nsStyleText::nsStyleText(const Document& aDocument)
       mTextAlign(StyleTextAlign::Start),
       mTextAlignLast(StyleTextAlignLast::Auto),
       mTextJustify(StyleTextJustify::Auto),
+      mWhiteSpace(StyleWhiteSpace::Normal),
       mHyphens(StyleHyphens::Manual),
       mRubyAlign(StyleRubyAlign::SpaceAround),
       mRubyPosition(StyleRubyPosition::AlternateOver),
@@ -2827,8 +2828,7 @@ nsStyleText::nsStyleText(const nsStyleText& aSource)
       mTextAlign(aSource.mTextAlign),
       mTextAlignLast(aSource.mTextAlignLast),
       mTextJustify(aSource.mTextJustify),
-      mWhiteSpaceCollapse(aSource.mWhiteSpaceCollapse),
-      mTextWrapMode(aSource.mTextWrapMode),
+      mWhiteSpace(aSource.mWhiteSpace),
       mLineBreak(aSource.mLineBreak),
       mWordBreak(aSource.mWordBreak),
       mOverflowWrap(aSource.mOverflowWrap),
@@ -2855,7 +2855,7 @@ nsStyleText::nsStyleText(const nsStyleText& aSource)
       mTextEmphasisStyle(aSource.mTextEmphasisStyle),
       mHyphenateCharacter(aSource.mHyphenateCharacter),
       mWebkitTextSecurity(aSource.mWebkitTextSecurity),
-      mTextWrapStyle(aSource.mTextWrapStyle) {
+      mTextWrap(aSource.mTextWrap) {
   MOZ_COUNT_CTOR(nsStyleText);
 }
 
@@ -2875,8 +2875,7 @@ nsChangeHint nsStyleText::CalcDifference(const nsStyleText& aNewData) const {
   if ((mTextAlign != aNewData.mTextAlign) ||
       (mTextAlignLast != aNewData.mTextAlignLast) ||
       (mTextTransform != aNewData.mTextTransform) ||
-      (mWhiteSpaceCollapse != aNewData.mWhiteSpaceCollapse) ||
-      (mTextWrapMode != aNewData.mTextWrapMode) ||
+      (mWhiteSpace != aNewData.mWhiteSpace) ||
       (mLineBreak != aNewData.mLineBreak) ||
       (mWordBreak != aNewData.mWordBreak) ||
       (mOverflowWrap != aNewData.mOverflowWrap) ||
@@ -2890,7 +2889,7 @@ nsChangeHint nsStyleText::CalcDifference(const nsStyleText& aNewData) const {
       (mTabSize != aNewData.mTabSize) ||
       (mHyphenateCharacter != aNewData.mHyphenateCharacter) ||
       (mWebkitTextSecurity != aNewData.mWebkitTextSecurity) ||
-      (mTextWrapStyle != aNewData.mTextWrapStyle)) {
+      (mTextWrap != aNewData.mTextWrap)) {
     return NS_STYLE_HINT_REFLOW;
   }
 
diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h
index c2354290ab86..6bd14e505c9a 100644
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -845,9 +845,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText {
   mozilla::StyleTextAlign mTextAlign;
   mozilla::StyleTextAlignLast mTextAlignLast;
   mozilla::StyleTextJustify mTextJustify;
-  mozilla::StyleWhiteSpaceCollapse mWhiteSpaceCollapse =
-      mozilla::StyleWhiteSpaceCollapse::Collapse;
-  mozilla::StyleTextWrapMode mTextWrapMode = mozilla::StyleTextWrapMode::Wrap;
+  mozilla::StyleWhiteSpace mWhiteSpace;
   mozilla::StyleLineBreak mLineBreak = mozilla::StyleLineBreak::Auto;
 
  private:
@@ -887,8 +885,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText {
   mozilla::StyleTextSecurity mWebkitTextSecurity =
       mozilla::StyleTextSecurity::None;
 
-  mozilla::StyleTextWrapStyle mTextWrapStyle =
-      mozilla::StyleTextWrapStyle::Auto;
+  mozilla::StyleTextWrap mTextWrap = mozilla::StyleTextWrap::Auto;
 
   char16_t TextSecurityMaskChar() const {
     switch (mWebkitTextSecurity) {
@@ -921,9 +918,10 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText {
   }
 
   bool WhiteSpaceIsSignificant() const {
-    return mWhiteSpaceCollapse != mozilla::StyleWhiteSpaceCollapse::Collapse &&
-           mWhiteSpaceCollapse !=
-               mozilla::StyleWhiteSpaceCollapse::PreserveBreaks;
+    return mWhiteSpace == mozilla::StyleWhiteSpace::Pre ||
+           mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap ||
+           mWhiteSpace == mozilla::StyleWhiteSpace::BreakSpaces ||
+           mWhiteSpace == mozilla::StyleWhiteSpace::PreSpace;
   }
 
   bool WhiteSpaceCanHangOrVisuallyCollapse() const {
@@ -932,28 +930,35 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText {
     //       WhiteSpaceCanWrapStyle() &&
     //       WhiteSpaceIsSignificant()
     // which simplifies to:
-    return mTextWrapMode == mozilla::StyleTextWrapMode::Wrap &&
-           mWhiteSpaceCollapse != mozilla::StyleWhiteSpaceCollapse::BreakSpaces;
+    return mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap;
   }
 
   bool NewlineIsSignificantStyle() const {
-    return mWhiteSpaceCollapse == mozilla::StyleWhiteSpaceCollapse::Preserve ||
-           mWhiteSpaceCollapse ==
-               mozilla::StyleWhiteSpaceCollapse::PreserveBreaks ||
-           mWhiteSpaceCollapse == mozilla::StyleWhiteSpaceCollapse::BreakSpaces;
+    return mWhiteSpace == mozilla::StyleWhiteSpace::Pre ||
+           mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap ||
+           mWhiteSpace == mozilla::StyleWhiteSpace::BreakSpaces ||
+           mWhiteSpace == mozilla::StyleWhiteSpace::PreLine;
   }
 
   bool WhiteSpaceOrNewlineIsSignificant() const {
-    return NewlineIsSignificantStyle() || WhiteSpaceIsSignificant();
+    return mWhiteSpace == mozilla::StyleWhiteSpace::Pre ||
+           mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap ||
+           mWhiteSpace == mozilla::StyleWhiteSpace::BreakSpaces ||
+           mWhiteSpace == mozilla::StyleWhiteSpace::PreLine ||
+           mWhiteSpace == mozilla::StyleWhiteSpace::PreSpace;
   }
 
   bool TabIsSignificant() const {
-    return mWhiteSpaceCollapse == mozilla::StyleWhiteSpaceCollapse::Preserve ||
-           mWhiteSpaceCollapse == mozilla::StyleWhiteSpaceCollapse::BreakSpaces;
+    return mWhiteSpace == mozilla::StyleWhiteSpace::Pre ||
+           mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap ||
+           mWhiteSpace == mozilla::StyleWhiteSpace::BreakSpaces;
   }
 
   bool WhiteSpaceCanWrapStyle() const {
-    return mTextWrapMode == mozilla::StyleTextWrapMode::Wrap;
+    return mWhiteSpace == mozilla::StyleWhiteSpace::Normal ||
+           mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap ||
+           mWhiteSpace == mozilla::StyleWhiteSpace::BreakSpaces ||
+           mWhiteSpace == mozilla::StyleWhiteSpace::PreLine;
   }
 
   bool WordCanWrapStyle() const {
diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js
index 913d6906971e..d137a8cae57c 100644
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -8255,29 +8255,6 @@ var gCSSProperties = {
       "uppercase full-width lowercase",
     ],
   },
-  "text-wrap": {
-    domProp: "textWrap",
-    inherited: true,
-    type: CSS_TYPE_TRUE_SHORTHAND,
-    subproperties: ["text-wrap-mode"],
-    applies_to_placeholder: true,
-    applies_to_cue: true,
-    applies_to_marker: true,
-    initial_values: ["wrap"],
-    other_values: ["nowrap"],
-    invalid_values: [],
-  },
-  "text-wrap-mode": {
-    domProp: "textWrapMode",
-    inherited: true,
-    type: CSS_TYPE_LONGHAND,
-    applies_to_cue: true,
-    applies_to_placeholder: true,
-    applies_to_marker: true,
-    initial_values: ["wrap"],
-    other_values: ["nowrap"],
-    invalid_values: ["none", "normal", "on", "off", "wrap nowrap"],
-  },
   top: {
     domProp: "top",
     inherited: false,
@@ -8565,8 +8542,7 @@ var gCSSProperties = {
   "white-space": {
     domProp: "whiteSpace",
     inherited: true,
-    type: CSS_TYPE_TRUE_SHORTHAND,
-    subproperties: ["white-space-collapse", "text-wrap-mode"],
+    type: CSS_TYPE_LONGHAND,
     applies_to_placeholder: true,
     applies_to_cue: true,
     applies_to_marker: true,
@@ -8581,22 +8557,6 @@ var gCSSProperties = {
     ],
     invalid_values: [],
   },
-  "white-space-collapse": {
-    domProp: "whiteSpaceCollapse",
-    inherited: true,
-    type: CSS_TYPE_LONGHAND,
-    applies_to_placeholder: true,
-    applies_to_cue: true,
-    applies_to_marker: true,
-    initial_values: ["collapse"],
-    other_values: [
-      "preserve",
-      "preserve-breaks",
-      "preserve-spaces",
-      "break-spaces",
-    ],
-    invalid_values: ["normal", "auto"],
-  },
   width: {
     domProp: "width",
     inherited: false,
@@ -13938,8 +13898,8 @@ gCSSProperties["scrollbar-gutter"] = {
 };
 
 if (IsCSSPropertyPrefEnabled("layout.css.text-wrap-balance.enabled")) {
-  gCSSProperties["text-wrap-style"] = {
-    domProp: "textWrapStyle",
+  gCSSProperties["text-wrap"] = {
+    domProp: "textWrap",
     inherited: true,
     type: CSS_TYPE_LONGHAND,
     applies_to_placeholder: true,
@@ -13949,11 +13909,6 @@ if (IsCSSPropertyPrefEnabled("layout.css.text-wrap-balance.enabled")) {
     other_values: ["stable", "balance"],
     invalid_values: ["wrap", "nowrap", "normal"],
   };
-  gCSSProperties["text-wrap"].subproperties.push("text-wrap-style");
-  gCSSProperties["text-wrap"].other_values.push("stable");
-  gCSSProperties["text-wrap"].other_values.push("balance");
-  gCSSProperties["text-wrap"].other_values.push("wrap stable");
-  gCSSProperties["text-wrap"].other_values.push("nowrap balance");
 }
 
 if (IsCSSPropertyPrefEnabled("layout.css.prefixes.transforms")) {
diff --git a/servo/components/style/properties/data.py b/servo/components/style/properties/data.py
index ea8363d323dc..5950ddf92d21 100644
--- a/servo/components/style/properties/data.py
+++ b/servo/components/style/properties/data.py
@@ -880,9 +880,8 @@ def _remove_common_first_line_and_first_letter_properties(props, engine):
     props.remove("overflow-wrap")
     props.remove("text-align")
     props.remove("text-justify")
-    props.remove("white-space-collapse")
-    props.remove("text-wrap-mode")
-    props.remove("text-wrap-style")
+    props.remove("white-space")
+    props.remove("text-wrap")
     props.remove("word-break")
     props.remove("text-indent")
 
@@ -984,13 +983,11 @@ class PropertyRestrictions:
     def placeholder(data):
         props = PropertyRestrictions.first_line(data)
         props.add("opacity")
+        props.add("white-space")
+        props.add("text-wrap")
         props.add("text-overflow")
         props.add("text-align")
         props.add("text-justify")
-        for p in PropertyRestrictions.shorthand(data, "text-wrap"):
-            props.add(p)
-        for p in PropertyRestrictions.shorthand(data, "white-space"):
-            props.add(p)
         return props
 
     # https://drafts.csswg.org/css-pseudo/#marker-pseudo
@@ -998,6 +995,8 @@ class PropertyRestrictions:
     def marker(data):
         return set(
             [
+                "white-space",
+                "text-wrap",
                 "color",
                 "text-combine-upright",
                 "text-transform",
@@ -1007,8 +1006,6 @@ class PropertyRestrictions:
                 "line-height",
                 "-moz-osx-font-smoothing",
             ]
-            + PropertyRestrictions.shorthand(data, "text-wrap")
-            + PropertyRestrictions.shorthand(data, "white-space")
             + PropertyRestrictions.spec(data, "css-fonts")
             + PropertyRestrictions.spec(data, "css-animations")
             + PropertyRestrictions.spec(data, "css-transitions")
@@ -1023,6 +1020,8 @@ class PropertyRestrictions:
                 "opacity",
                 "visibility",
                 "text-shadow",
+                "white-space",
+                "text-wrap",
                 "text-combine-upright",
                 "ruby-position",
                 # XXX Should these really apply to cue?
@@ -1033,8 +1032,6 @@ class PropertyRestrictions:
                 "background-blend-mode",
             ]
             + PropertyRestrictions.shorthand(data, "text-decoration")
-            + PropertyRestrictions.shorthand(data, "text-wrap")
-            + PropertyRestrictions.shorthand(data, "white-space")
             + PropertyRestrictions.shorthand(data, "background")
             + PropertyRestrictions.shorthand(data, "outline")
             + PropertyRestrictions.shorthand(data, "font")
diff --git a/servo/components/style/properties/longhands/inherited_text.mako.rs b/servo/components/style/properties/longhands/inherited_text.mako.rs
index fb7fdd2d03a7..00543e0c849e 100644
--- a/servo/components/style/properties/longhands/inherited_text.mako.rs
+++ b/servo/components/style/properties/longhands/inherited_text.mako.rs
@@ -149,16 +149,52 @@ ${helpers.predefined_type(
     affects="layout",
 )}
 
-// TODO: `white-space-collapse: discard` not yet supported
-${helpers.single_keyword(
-    name="white-space-collapse",
-    values="collapse preserve preserve-breaks preserve-spaces break-spaces",
-    engines="gecko",
-    gecko_enum_prefix="StyleWhiteSpaceCollapse",
-    animation_value_type="discrete",
-    spec="https://drafts.csswg.org/css-text-4/#propdef-white-space-collapse",
-    affects="layout",
-)}
+<%helpers:single_keyword
+    name="white-space"
+    values="normal pre nowrap pre-wrap pre-line"
+    engines="gecko servo-2013 servo-2020",
+    extra_gecko_values="break-spaces -moz-pre-space"
+    gecko_enum_prefix="StyleWhiteSpace"
+    needs_conversion="True"
+    animation_value_type="discrete"
+    spec="https://drafts.csswg.org/css-text/#propdef-white-space"
+    servo_restyle_damage="rebuild_and_reflow"
+    affects="layout"
+>
+    % if engine in ["servo-2013", "servo-2020"]:
+    impl SpecifiedValue {
+        pub fn allow_wrap(&self) -> bool {
+            match *self {
+                SpecifiedValue::Nowrap |
+                SpecifiedValue::Pre => false,
+                SpecifiedValue::Normal |
+                SpecifiedValue::PreWrap |
+                SpecifiedValue::PreLine => true,
+            }
+        }
+
+        pub fn preserve_newlines(&self) -> bool {
+            match *self {
+                SpecifiedValue::Normal |
+                SpecifiedValue::Nowrap => false,
+                SpecifiedValue::Pre |
+                SpecifiedValue::PreWrap |
+                SpecifiedValue::PreLine => true,
+            }
+        }
+
+        pub fn preserve_spaces(&self) -> bool {
+            match *self {
+                SpecifiedValue::Normal |
+                SpecifiedValue::Nowrap |
+                SpecifiedValue::PreLine => false,
+                SpecifiedValue::Pre |
+                SpecifiedValue::PreWrap => true,
+            }
+        }
+    }
+    % endif
+
 
 ${helpers.predefined_type(
     "text-shadow",
@@ -392,23 +428,13 @@ ${helpers.single_keyword(
 )}
 
 ${helpers.single_keyword(
-    "text-wrap-mode",
-    "wrap nowrap",
-    engines="gecko",
-    gecko_enum_prefix="StyleTextWrapMode",
-    animation_value_type="discrete",
-    spec="https://drafts.csswg.org/css-text-4/#propdef-text-wrap-mode",
-    affects="layout",
-)}
-
-${helpers.single_keyword(
-    "text-wrap-style",
+    "text-wrap",
     "auto stable balance",
     engines="gecko",
     gecko_pref="layout.css.text-wrap-balance.enabled",
     has_effect_on_gecko_scrollbars=False,
-    gecko_enum_prefix="StyleTextWrapStyle",
+    gecko_enum_prefix="StyleTextWrap",
     animation_value_type="discrete",
-    spec="https://drafts.csswg.org/css-text-4/#text-wrap-style",
+    spec="https://drafts.csswg.org/css-text-4/#text-wrap",
     affects="layout",
 )}
diff --git a/servo/components/style/properties/shorthands/inherited_text.mako.rs b/servo/components/style/properties/shorthands/inherited_text.mako.rs
index d470553e4258..9eb278da05ca 100644
--- a/servo/components/style/properties/shorthands/inherited_text.mako.rs
+++ b/servo/components/style/properties/shorthands/inherited_text.mako.rs
@@ -46,169 +46,6 @@
     }
 
 
-<%helpers:shorthand
-    name="text-wrap"
-    engines="gecko"
-    sub_properties="text-wrap-mode text-wrap-style"
-    spec="https://www.w3.org/TR/css-text-4/#text-wrap"
->
-    use crate::properties::longhands::{text_wrap_mode, text_wrap_style};
-
-    pub fn parse_value<'i, 't>(
-        context: &ParserContext,
-        input: &mut Parser<'i, 't>,
-    ) -> Result> {
-        let mut mode = None;
-        let mut style = None;
-
-        loop {
-            if mode.is_none() {
-                if let Ok(value) = input.try_parse(|input| text_wrap_mode::parse(context, input)) {
-                    mode = Some(value);
-                    continue
-                }
-            }
-            if style.is_none() {
-                if let Ok(value) = input.try_parse(|input| text_wrap_style::parse(context, input)) {
-                    style = Some(value);
-                    continue
-                }
-            }
-            break
-        }
-        if mode.is_some() || style.is_some() {
-            Ok(expanded! {
-                text_wrap_mode: unwrap_or_initial!(text_wrap_mode, mode),
-                text_wrap_style: unwrap_or_initial!(text_wrap_style, style),
-            })
-        } else {
-            Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
-        }
-    }
-
-    impl<'a> ToCss for LonghandsToSerialize<'a>  {
-        fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where W: fmt::Write {
-            use text_wrap_mode::computed_value::T as Mode;
-            use text_wrap_style::computed_value::T as Style;
-
-            if matches!(self.text_wrap_style, None | Some(&Style::Auto)) {
-                return self.text_wrap_mode.to_css(dest);
-            }
-
-            if *self.text_wrap_mode != Mode::Wrap {
-                self.text_wrap_mode.to_css(dest)?;
-                dest.write_char(' ')?;
-            }
-
-            self.text_wrap_style.to_css(dest)
-        }
-    }
-
-
-<%helpers:shorthand
-    name="white-space"
-    engines="gecko"
-    sub_properties="text-wrap-mode white-space-collapse"
-    spec="https://www.w3.org/TR/css-text-4/#white-space-property"
->
-    use crate::properties::longhands::{text_wrap_mode, white_space_collapse};
-
-    pub fn parse_value<'i, 't>(
-        context: &ParserContext,
-        input: &mut Parser<'i, 't>,
-    ) -> Result> {
-        use white_space_collapse::computed_value::T as Collapse;
-        use text_wrap_mode::computed_value::T as Wrap;
-
-        fn parse_special_shorthands<'i, 't>(input: &mut Parser<'i, 't>) -> Result> {
-            let (mode, collapse) = try_match_ident_ignore_ascii_case! { input,
-                "normal" => (Wrap::Wrap, Collapse::Collapse),
-                "pre" => (Wrap::Nowrap, Collapse::Preserve),
-                "pre-wrap" => (Wrap::Wrap, Collapse::Preserve),
-                "pre-line" => (Wrap::Wrap, Collapse::PreserveBreaks),
-                // TODO: deprecate/remove -moz-pre-space; the white-space-collapse: preserve-spaces value
-                // should serve this purpose?
-                "-moz-pre-space" => (Wrap::Wrap, Collapse::PreserveSpaces),
-            };
-            Ok(expanded! {
-                text_wrap_mode: mode,
-                white_space_collapse: collapse,
-            })
-        }
-
-        if let Ok(result) = input.try_parse(parse_special_shorthands) {
-            return Ok(result);
-        }
-
-        let mut wrap = None;
-        let mut collapse = None;
-
-        loop {
-            if wrap.is_none() {
-                if let Ok(value) = input.try_parse(|input| text_wrap_mode::parse(context, input)) {
-                    wrap = Some(value);
-                    continue
-                }
-            }
-            if collapse.is_none() {
-                if let Ok(value) = input.try_parse(|input| white_space_collapse::parse(context, input)) {
-                    collapse = Some(value);
-                    continue
-                }
-            }
-            break
-        }
-
-        if wrap.is_some() || collapse.is_some() {
-            Ok(expanded! {
-                text_wrap_mode: unwrap_or_initial!(text_wrap_mode, wrap),
-                white_space_collapse: unwrap_or_initial!(white_space_collapse, collapse),
-            })
-        } else {
-            Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
-        }
-    }
-
-    impl<'a> ToCss for LonghandsToSerialize<'a>  {
-        fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where W: fmt::Write {
-            use white_space_collapse::computed_value::T as Collapse;
-            use text_wrap_mode::computed_value::T as Wrap;
-
-            match *self.text_wrap_mode {
-                Wrap::Wrap => {
-                    match *self.white_space_collapse {
-                        Collapse::Collapse => return dest.write_str("normal"),
-                        Collapse::Preserve => return dest.write_str("pre-wrap"),
-                        Collapse::PreserveBreaks => return dest.write_str("pre-line"),
-                        Collapse::PreserveSpaces => return dest.write_str("-moz-pre-space"),
-                        _ => (),
-                    }
-                },
-                Wrap::Nowrap => {
-                    if let Collapse::Preserve = *self.white_space_collapse {
-                        return dest.write_str("pre");
-                    }
-                },
-            }
-
-            let mut has_value = false;
-            if *self.white_space_collapse != Collapse::Collapse {
-                self.white_space_collapse.to_css(dest)?;
-                has_value = true;
-            }
-
-            if *self.text_wrap_mode != Wrap::Wrap {
-                if has_value {
-                    dest.write_char(' ')?;
-                }
-                self.text_wrap_mode.to_css(dest)?;
-            }
-
-            Ok(())
-        }
-    }
-
-
 // CSS Compatibility
 // https://compat.spec.whatwg.org/
 <%helpers:shorthand name="-webkit-text-stroke"
diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs
index 43eced662482..0c3ae85e742a 100644
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -5311,8 +5311,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(
         ListStyleType => Box::new(longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value)),
         MathStyle => longhands::math_style::SpecifiedValue::from_gecko_keyword(value),
         MozMathVariant => longhands::_moz_math_variant::SpecifiedValue::from_gecko_keyword(value),
-        WhiteSpaceCollapse => get_from_computed::(value),
-        TextWrapMode => get_from_computed::(value),
+        WhiteSpace => longhands::white_space::SpecifiedValue::from_gecko_keyword(value),
         CaptionSide => get_from_computed::(value),
         BorderTopStyle => get_from_computed::(value),
         BorderRightStyle => get_from_computed::(value),
diff --git a/testing/web-platform/meta/css/css-text/inheritance.html.ini b/testing/web-platform/meta/css/css-text/inheritance.html.ini
index c7679d53bfdd..e751981d75c4 100644
--- a/testing/web-platform/meta/css/css-text/inheritance.html.ini
+++ b/testing/web-platform/meta/css/css-text/inheritance.html.ini
@@ -10,3 +10,27 @@
 
   [Property text-align-all inherits]
     expected: FAIL
+
+  [Property text-wrap has initial value wrap]
+    expected: FAIL
+
+  [Property text-wrap inherits]
+    expected: FAIL
+
+  [Property white-space-collapse has initial value collapse]
+    expected: FAIL
+
+  [Property white-space-collapse inherits]
+    expected: FAIL
+
+  [Property text-wrap-mode has initial value wrap]
+    expected: FAIL
+
+  [Property text-wrap-mode inherits]
+    expected: FAIL
+
+  [Property text-wrap-style has initial value auto]
+    expected: FAIL
+
+  [Property text-wrap-style inherits]
+    expected: FAIL
diff --git a/testing/web-platform/meta/css/css-text/parsing/text-wrap-computed.html.ini b/testing/web-platform/meta/css/css-text/parsing/text-wrap-computed.html.ini
index 971bd2ba0dba..07e2c1d37272 100644
--- a/testing/web-platform/meta/css/css-text/parsing/text-wrap-computed.html.ini
+++ b/testing/web-platform/meta/css/css-text/parsing/text-wrap-computed.html.ini
@@ -1,15 +1,60 @@
 [text-wrap-computed.html]
+  [Property text-wrap value 'wrap']
+    expected: FAIL
+
+  [Property text-wrap value 'nowrap']
+    expected: FAIL
+
+  [Property text-wrap value 'auto']
+    expected: FAIL
+
   [Property text-wrap value 'pretty']
     expected: FAIL
 
+  [Property text-wrap value 'wrap auto']
+    expected: FAIL
+
+  [Property text-wrap value 'wrap balance']
+    expected: FAIL
+
   [Property text-wrap value 'wrap pretty']
     expected: FAIL
 
+  [Property text-wrap value 'wrap stable']
+    expected: FAIL
+
+  [Property text-wrap value 'auto wrap']
+    expected: FAIL
+
+  [Property text-wrap value 'balance wrap']
+    expected: FAIL
+
   [Property text-wrap value 'pretty wrap']
     expected: FAIL
 
+  [Property text-wrap value 'stable wrap']
+    expected: FAIL
+
+  [Property text-wrap value 'nowrap auto']
+    expected: FAIL
+
+  [Property text-wrap value 'nowrap balance']
+    expected: FAIL
+
   [Property text-wrap value 'nowrap pretty']
     expected: FAIL
 
+  [Property text-wrap value 'nowrap stable']
+    expected: FAIL
+
+  [Property text-wrap value 'auto nowrap']
+    expected: FAIL
+
+  [Property text-wrap value 'balance nowrap']
+    expected: FAIL
+
   [Property text-wrap value 'pretty nowrap']
     expected: FAIL
+
+  [Property text-wrap value 'stable nowrap']
+    expected: FAIL
diff --git a/testing/web-platform/meta/css/css-text/parsing/text-wrap-mode-computed.html.ini b/testing/web-platform/meta/css/css-text/parsing/text-wrap-mode-computed.html.ini
new file mode 100644
index 000000000000..f9739ca0b286
--- /dev/null
+++ b/testing/web-platform/meta/css/css-text/parsing/text-wrap-mode-computed.html.ini
@@ -0,0 +1,6 @@
+[text-wrap-mode-computed.html]
+  [Property text-wrap-mode value 'wrap']
+    expected: FAIL
+
+  [Property text-wrap-mode value 'nowrap']
+    expected: FAIL
diff --git a/testing/web-platform/meta/css/css-text/parsing/text-wrap-mode-valid.html.ini b/testing/web-platform/meta/css/css-text/parsing/text-wrap-mode-valid.html.ini
new file mode 100644
index 000000000000..76dc7a87b4e0
--- /dev/null
+++ b/testing/web-platform/meta/css/css-text/parsing/text-wrap-mode-valid.html.ini
@@ -0,0 +1,21 @@
+[text-wrap-mode-valid.html]
+  [e.style['text-wrap-mode'\] = "wrap" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap-mode'\] = "nowrap" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap-mode'\] = "initial" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap-mode'\] = "inherit" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap-mode'\] = "unset" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap-mode'\] = "revert" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap-mode'\] = "revert-layer" should set the property value]
+    expected: FAIL
diff --git a/testing/web-platform/meta/css/css-text/parsing/text-wrap-style-computed.html.ini b/testing/web-platform/meta/css/css-text/parsing/text-wrap-style-computed.html.ini
index 740685dcc377..8be1df9f7ff9 100644
--- a/testing/web-platform/meta/css/css-text/parsing/text-wrap-style-computed.html.ini
+++ b/testing/web-platform/meta/css/css-text/parsing/text-wrap-style-computed.html.ini
@@ -1,3 +1,12 @@
 [text-wrap-style-computed.html]
+  [Property text-wrap-style value 'auto']
+    expected: FAIL
+
+  [Property text-wrap-style value 'balance']
+    expected: FAIL
+
   [Property text-wrap-style value 'pretty']
     expected: FAIL
+
+  [Property text-wrap-style value 'stable']
+    expected: FAIL
diff --git a/testing/web-platform/meta/css/css-text/parsing/text-wrap-style-valid.html.ini b/testing/web-platform/meta/css/css-text/parsing/text-wrap-style-valid.html.ini
index 266a88afcf7d..fd637df85dbf 100644
--- a/testing/web-platform/meta/css/css-text/parsing/text-wrap-style-valid.html.ini
+++ b/testing/web-platform/meta/css/css-text/parsing/text-wrap-style-valid.html.ini
@@ -1,3 +1,27 @@
 [text-wrap-style-valid.html]
+  [e.style['text-wrap-style'\] = "auto" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap-style'\] = "balance" should set the property value]
+    expected: FAIL
+
   [e.style['text-wrap-style'\] = "pretty" should set the property value]
     expected: FAIL
+
+  [e.style['text-wrap-style'\] = "stable" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap-style'\] = "initial" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap-style'\] = "inherit" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap-style'\] = "unset" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap-style'\] = "revert" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap-style'\] = "revert-layer" should set the property value]
+    expected: FAIL
diff --git a/testing/web-platform/meta/css/css-text/parsing/text-wrap-valid.html.ini b/testing/web-platform/meta/css/css-text/parsing/text-wrap-valid.html.ini
index 98a212dc2351..8bf2212897bc 100644
--- a/testing/web-platform/meta/css/css-text/parsing/text-wrap-valid.html.ini
+++ b/testing/web-platform/meta/css/css-text/parsing/text-wrap-valid.html.ini
@@ -1,15 +1,60 @@
 [text-wrap-valid.html]
+  [e.style['text-wrap'\] = "wrap" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap'\] = "nowrap" should set the property value]
+    expected: FAIL
+
   [e.style['text-wrap'\] = "pretty" should set the property value]
     expected: FAIL
 
+  [e.style['text-wrap'\] = "wrap auto" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap'\] = "wrap balance" should set the property value]
+    expected: FAIL
+
   [e.style['text-wrap'\] = "wrap pretty" should set the property value]
     expected: FAIL
 
+  [e.style['text-wrap'\] = "wrap stable" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap'\] = "auto wrap" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap'\] = "balance wrap" should set the property value]
+    expected: FAIL
+
   [e.style['text-wrap'\] = "pretty wrap" should set the property value]
     expected: FAIL
 
+  [e.style['text-wrap'\] = "stable wrap" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap'\] = "nowrap auto" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap'\] = "nowrap balance" should set the property value]
+    expected: FAIL
+
   [e.style['text-wrap'\] = "nowrap pretty" should set the property value]
     expected: FAIL
 
+  [e.style['text-wrap'\] = "nowrap stable" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap'\] = "auto nowrap" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap'\] = "balance nowrap" should set the property value]
+    expected: FAIL
+
   [e.style['text-wrap'\] = "pretty nowrap" should set the property value]
     expected: FAIL
+
+  [e.style['text-wrap'\] = "stable nowrap" should set the property value]
+    expected: FAIL
+
+  [e.style['text-wrap'\] = "auto" should set the property value]
+    expected: FAIL
diff --git a/testing/web-platform/meta/css/css-text/parsing/white-space-collapse-computed.html.ini b/testing/web-platform/meta/css/css-text/parsing/white-space-collapse-computed.html.ini
new file mode 100644
index 000000000000..0a98b5c27158
--- /dev/null
+++ b/testing/web-platform/meta/css/css-text/parsing/white-space-collapse-computed.html.ini
@@ -0,0 +1,12 @@
+[white-space-collapse-computed.html]
+  [Property white-space-collapse value 'collapse']
+    expected: FAIL
+
+  [Property white-space-collapse value 'preserve']
+    expected: FAIL
+
+  [Property white-space-collapse value 'preserve-breaks']
+    expected: FAIL
+
+  [Property white-space-collapse value 'break-spaces']
+    expected: FAIL
diff --git a/testing/web-platform/meta/css/css-text/parsing/white-space-collapse-valid.html.ini b/testing/web-platform/meta/css/css-text/parsing/white-space-collapse-valid.html.ini
new file mode 100644
index 000000000000..9c9ea49d3e07
--- /dev/null
+++ b/testing/web-platform/meta/css/css-text/parsing/white-space-collapse-valid.html.ini
@@ -0,0 +1,27 @@
+[white-space-collapse-valid.html]
+  [e.style['white-space-collapse'\] = "collapse" should set the property value]
+    expected: FAIL
+
+  [e.style['white-space-collapse'\] = "preserve" should set the property value]
+    expected: FAIL
+
+  [e.style['white-space-collapse'\] = "preserve-breaks" should set the property value]
+    expected: FAIL
+
+  [e.style['white-space-collapse'\] = "break-spaces" should set the property value]
+    expected: FAIL
+
+  [e.style['white-space-collapse'\] = "initial" should set the property value]
+    expected: FAIL
+
+  [e.style['white-space-collapse'\] = "inherit" should set the property value]
+    expected: FAIL
+
+  [e.style['white-space-collapse'\] = "unset" should set the property value]
+    expected: FAIL
+
+  [e.style['white-space-collapse'\] = "revert" should set the property value]
+    expected: FAIL
+
+  [e.style['white-space-collapse'\] = "revert-layer" should set the property value]
+    expected: FAIL
diff --git a/testing/web-platform/meta/css/css-text/parsing/white-space-shorthand-text-wrap.html.ini b/testing/web-platform/meta/css/css-text/parsing/white-space-shorthand-text-wrap.html.ini
new file mode 100644
index 000000000000..bae84b4d2c4d
--- /dev/null
+++ b/testing/web-platform/meta/css/css-text/parsing/white-space-shorthand-text-wrap.html.ini
@@ -0,0 +1,6 @@
+[white-space-shorthand-text-wrap.html]
+  [`white-space` should overwrite previous `text-wrap-mode: nowrap`]
+    expected: FAIL
+
+  [`white-space` should overwrite `text-wrap-mode` on the parent]
+    expected: FAIL
diff --git a/testing/web-platform/meta/css/css-text/parsing/white-space-shorthand.html.ini b/testing/web-platform/meta/css/css-text/parsing/white-space-shorthand.html.ini
new file mode 100644
index 000000000000..3cc42abde803
--- /dev/null
+++ b/testing/web-platform/meta/css/css-text/parsing/white-space-shorthand.html.ini
@@ -0,0 +1,108 @@
+[white-space-shorthand.html]
+  [e.style['white-space'\] = "collapse" should set the property value]
+    expected: FAIL
+
+  [Property white-space value 'collapse']
+    expected: FAIL
+
+  [e.style['white-space'\] = "wrap" should set the property value]
+    expected: FAIL
+
+  [Property white-space value 'wrap']
+    expected: FAIL
+
+  [e.style['white-space'\] = "collapse wrap" should set the property value]
+    expected: FAIL
+
+  [Property white-space value 'collapse wrap']
+    expected: FAIL
+
+  [e.style['white-space'\] = "wrap collapse" should set the property value]
+    expected: FAIL
+
+  [Property white-space value 'wrap collapse']
+    expected: FAIL
+
+  [e.style['white-space'\] = "preserve nowrap" should set the property value]
+    expected: FAIL
+
+  [Property white-space value 'preserve nowrap']
+    expected: FAIL
+
+  [e.style['white-space'\] = "nowrap preserve" should set the property value]
+    expected: FAIL
+
+  [Property white-space value 'nowrap preserve']
+    expected: FAIL
+
+  [e.style['white-space'\] = "collapse nowrap" should set the property value]
+    expected: FAIL
+
+  [Property white-space value 'collapse nowrap']
+    expected: FAIL
+
+  [e.style['white-space'\] = "nowrap collapse" should set the property value]
+    expected: FAIL
+
+  [Property white-space value 'nowrap collapse']
+    expected: FAIL
+
+  [e.style['white-space'\] = "preserve" should set the property value]
+    expected: FAIL
+
+  [Property white-space value 'preserve']
+    expected: FAIL
+
+  [e.style['white-space'\] = "preserve wrap" should set the property value]
+    expected: FAIL
+
+  [Property white-space value 'preserve wrap']
+    expected: FAIL
+
+  [e.style['white-space'\] = "wrap preserve" should set the property value]
+    expected: FAIL
+
+  [Property white-space value 'wrap preserve']
+    expected: FAIL
+
+  [e.style['white-space'\] = "break-spaces wrap" should set the property value]
+    expected: FAIL
+
+  [Property white-space value 'break-spaces wrap']
+    expected: FAIL
+
+  [e.style['white-space'\] = "wrap break-spaces" should set the property value]
+    expected: FAIL
+
+  [Property white-space value 'wrap break-spaces']
+    expected: FAIL
+
+  [e.style['white-space'\] = "preserve-breaks" should set the property value]
+    expected: FAIL
+
+  [Property white-space value 'preserve-breaks']
+    expected: FAIL
+
+  [e.style['white-space'\] = "preserve-breaks wrap" should set the property value]
+    expected: FAIL
+
+  [Property white-space value 'preserve-breaks wrap']
+    expected: FAIL
+
+  [e.style['white-space'\] = "wrap preserve-breaks" should set the property value]
+    expected: FAIL
+
+  [Property white-space value 'wrap preserve-breaks']
+    expected: FAIL
+
+  [e.style['white-space'\] = "preserve-breaks nowrap" should set the property value]
+    expected: FAIL
+
+  [Property white-space value 'preserve-breaks nowrap']
+    expected: FAIL
+
+  [e.style['white-space'\] = "nowrap preserve-breaks" should set the property value]
+    expected: FAIL
+
+  [Property white-space value 'nowrap preserve-breaks']
+    expected: FAIL
diff --git a/testing/web-platform/meta/web-animations/animation-model/animation-types/accumulation-per-property-002.html.ini b/testing/web-platform/meta/web-animations/animation-model/animation-types/accumulation-per-property-002.html.ini
new file mode 100644
index 000000000000..cf6f920c2262
--- /dev/null
+++ b/testing/web-platform/meta/web-animations/animation-model/animation-types/accumulation-per-property-002.html.ini
@@ -0,0 +1,6 @@
+[accumulation-per-property-002.html]
+  [text-wrap: "nowrap" onto "wrap"]
+    expected: FAIL
+
+  [text-wrap: "wrap" onto "nowrap"]
+    expected: FAIL
diff --git a/testing/web-platform/meta/web-animations/animation-model/animation-types/addition-per-property-002.html.ini b/testing/web-platform/meta/web-animations/animation-model/animation-types/addition-per-property-002.html.ini
new file mode 100644
index 000000000000..dc2e0cb53dd8
--- /dev/null
+++ b/testing/web-platform/meta/web-animations/animation-model/animation-types/addition-per-property-002.html.ini
@@ -0,0 +1,6 @@
+[addition-per-property-002.html]
+  [text-wrap: "nowrap" onto "wrap"]
+    expected: FAIL
+
+  [text-wrap: "wrap" onto "nowrap"]
+    expected: FAIL
diff --git a/testing/web-platform/meta/web-animations/animation-model/animation-types/interpolation-per-property-002.html.ini b/testing/web-platform/meta/web-animations/animation-model/animation-types/interpolation-per-property-002.html.ini
new file mode 100644
index 000000000000..837f1bd83738
--- /dev/null
+++ b/testing/web-platform/meta/web-animations/animation-model/animation-types/interpolation-per-property-002.html.ini
@@ -0,0 +1,9 @@
+[interpolation-per-property-002.html]
+  [text-wrap uses discrete animation when animating between "wrap" and "nowrap" with linear easing]
+    expected: FAIL
+
+  [text-wrap uses discrete animation when animating between "wrap" and "nowrap" with effect easing]
+    expected: FAIL
+
+  [text-wrap uses discrete animation when animating between "wrap" and "nowrap" with keyframe easing]
+    expected: FAIL