Bug 1531715 - Implement the CSS line-break property, with values "auto | anywhere". r=emilio
authorJonathan Kew <jkew@mozilla.com>
Mon, 20 May 2019 20:46:07 +0000
changeset 474594 7c7e340a7886dc8fff517b29149527dc2dc6a0ea
parent 474593 95918413069f5ff80feb050f8ef8d45dd8e08b6e
child 474595 e7b525e15531245d12672fa3c08eef5703f93b70
push id36042
push userdvarga@mozilla.com
push dateTue, 21 May 2019 04:19:40 +0000
treeherdermozilla-central@ca560ff55451 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
bugs1531715
milestone69.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 1531715 - Implement the CSS line-break property, with values "auto | anywhere". r=emilio Note that the "loose | normal | strict" values are not yet parsed/implemented. Differential Revision: https://phabricator.services.mozilla.com/D29817
devtools/server/actors/animation-type-longhand.js
devtools/shared/css/generated/properties-db.js
dom/base/nsLineBreaker.cpp
intl/lwbrk/LineBreaker.h
layout/generic/nsTextFrame.cpp
layout/style/ServoBindings.toml
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/test/property_database.js
servo/components/style/properties/data.py
servo/components/style/properties/longhands/inherited_text.mako.rs
servo/components/style/values/computed/mod.rs
servo/components/style/values/computed/text.rs
servo/components/style/values/specified/mod.rs
servo/components/style/values/specified/text.rs
servo/ports/geckolib/cbindgen.toml
testing/web-platform/meta/css/css-text/line-break/line-break-anywhere-001.html.ini
testing/web-platform/meta/css/css-text/line-break/line-break-anywhere-002.html.ini
testing/web-platform/meta/css/css-text/parsing/line-break-valid.html.ini
--- a/devtools/server/actors/animation-type-longhand.js
+++ b/devtools/server/actors/animation-type-longhand.js
@@ -85,16 +85,17 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
     "image-orientation",
     "image-rendering",
     "ime-mode",
     "initial-letter",
     "isolation",
     "justify-content",
     "justify-items",
     "justify-self",
+    "line-break",
     "list-style-image",
     "list-style-position",
     "list-style-type",
     "-moz-list-reversed",
     "marker-end",
     "marker-mid",
     "marker-start",
     "mask-clip",
--- a/devtools/shared/css/generated/properties-db.js
+++ b/devtools/shared/css/generated/properties-db.js
@@ -3178,16 +3178,17 @@ exports.CSS_PROPERTIES = {
       "letter-spacing",
       "word-spacing",
       "white-space",
       "text-shadow",
       "text-emphasis-style",
       "text-emphasis-position",
       "text-emphasis-color",
       "-moz-tab-size",
+      "line-break",
       "-webkit-text-fill-color",
       "-webkit-text-stroke-color",
       "-webkit-text-stroke-width",
       "ruby-align",
       "ruby-position",
       "text-combine-upright",
       "text-rendering",
       "-moz-control-character-visibility",
@@ -7318,16 +7319,31 @@ exports.CSS_PROPERTIES = {
       "initial",
       "revert",
       "rgb",
       "rgba",
       "transparent",
       "unset"
     ]
   },
+  "line-break": {
+    "isInherited": true,
+    "subproperties": [
+      "line-break"
+    ],
+    "supports": [],
+    "values": [
+      "anywhere",
+      "auto",
+      "inherit",
+      "initial",
+      "revert",
+      "unset"
+    ]
+  },
   "line-height": {
     "isInherited": true,
     "subproperties": [
       "line-height"
     ],
     "supports": [],
     "values": [
       "-moz-block-height",
--- a/dom/base/nsLineBreaker.cpp
+++ b/dom/base/nsLineBreaker.cpp
@@ -56,21 +56,22 @@ static void SetupCapitalization(const ch
 
 nsresult nsLineBreaker::FlushCurrentWord() {
   uint32_t length = mCurrentWord.Length();
   AutoTArray<uint8_t, 4000> breakState;
   if (!breakState.AppendElements(length)) return NS_ERROR_OUT_OF_MEMORY;
 
   nsTArray<bool> capitalizationState;
 
-  if (!mCurrentWordContainsComplexChar) {
+  if (!mCurrentWordContainsComplexChar ||
+      mWordBreak == LineBreaker::kWordBreak_Anywhere) {
     // For break-strict set everything internal to "break", otherwise
     // to "no break"!
     memset(breakState.Elements(),
-           mWordBreak == LineBreaker::kWordBreak_BreakAll
+           mWordBreak >= LineBreaker::kWordBreak_BreakAll
                ? gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL
                : gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE,
            length * sizeof(uint8_t));
   } else {
     nsContentUtils::LineBreaker()->GetJISx4051Breaks(
         mCurrentWord.Elements(), length, mWordBreak, breakState.Elements());
   }
 
@@ -220,17 +221,17 @@ nsresult nsLineBreaker::AppendText(nsAto
   for (;;) {
     char16_t ch = aText[offset];
     bool isSpace = IsSpace(ch);
     bool isBreakableSpace = isSpace && !(aFlags & BREAK_SUPPRESS_INSIDE);
 
     if (aSink && !noBreaksNeeded) {
       breakState[offset] =
           mBreakHere || (mAfterBreakableSpace && !isBreakableSpace) ||
-                  (mWordBreak == LineBreaker::kWordBreak_BreakAll)
+                  (mWordBreak >= LineBreaker::kWordBreak_BreakAll)
               ? gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL
               : gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE;
     }
     mBreakHere = false;
     mAfterBreakableSpace = isBreakableSpace;
 
     if (isSpace || ch == '\n') {
       if (offset > wordStart && aSink) {
@@ -378,17 +379,17 @@ nsresult nsLineBreaker::AppendText(nsAto
     bool isSpace = IsSpace(ch);
     bool isBreakableSpace = isSpace && !(aFlags & BREAK_SUPPRESS_INSIDE);
 
     if (aSink) {
       // Consider word-break style.  Since the break position of CJK scripts
       // will be set by nsILineBreaker, we don't consider CJK at this point.
       breakState[offset] =
           mBreakHere || (mAfterBreakableSpace && !isBreakableSpace) ||
-                  (mWordBreak == LineBreaker::kWordBreak_BreakAll)
+                  (mWordBreak >= LineBreaker::kWordBreak_BreakAll)
               ? gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL
               : gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE;
     }
     mBreakHere = false;
     mAfterBreakableSpace = isBreakableSpace;
 
     if (isSpace) {
       if (offset > wordStart && wordHasComplexChar) {
--- a/intl/lwbrk/LineBreaker.h
+++ b/intl/lwbrk/LineBreaker.h
@@ -13,19 +13,21 @@
 namespace mozilla {
 namespace intl {
 
 class LineBreaker {
  public:
   NS_INLINE_DECL_REFCOUNTING(LineBreaker)
 
   enum {
+    // Order is important here, because of tests for value >= BreakAll
     kWordBreak_Normal = 0,    // default
-    kWordBreak_BreakAll = 1,  // break all
-    kWordBreak_KeepAll = 2    // always keep
+    kWordBreak_KeepAll = 1,   // always keep
+    kWordBreak_BreakAll = 2,  // break all
+    kWordBreak_Anywhere = 3   // line-break:anywhere
   };
 
   static already_AddRefed<LineBreaker> Create();
 
   int32_t Next(const char16_t* aText, uint32_t aLen, uint32_t aPos);
 
   int32_t Prev(const char16_t* aText, uint32_t aLen, uint32_t aPos);
 
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -1900,17 +1900,18 @@ bool BuildTextRunsScanner::ContinueTextR
   }
 
   if (sc1 == sc2) {
     return true;
   }
 
   const nsStyleText* textStyle2 = sc2->StyleText();
   if (textStyle1->mTextTransform != textStyle2->mTextTransform ||
-      textStyle1->EffectiveWordBreak() != textStyle2->EffectiveWordBreak()) {
+      textStyle1->EffectiveWordBreak() != textStyle2->EffectiveWordBreak() ||
+      textStyle1->mLineBreak != textStyle2->mLineBreak) {
     return false;
   }
 
   nsPresContext* pc = aFrame1->PresContext();
   MOZ_ASSERT(pc == aFrame2->PresContext());
 
   const nsStyleFont* fontStyle1 = sc1->StyleFont();
   const nsStyleFont* fontStyle2 = sc2->StyleFont();
@@ -2582,29 +2583,34 @@ void BuildTextRunsScanner::SetupBreakSin
   // whitespace...
   gfxSkipCharsIterator iter(aTextRun->GetSkipChars());
 
   for (uint32_t i = 0; i < mMappedFlows.Length(); ++i) {
     MappedFlow* mappedFlow = &mMappedFlows[i];
     // The CSS word-break value may change within a word, so we reset it for
     // each MappedFlow. The line-breaker will flush its text if the property
     // actually changes.
-    auto wordBreak = mappedFlow->mStartFrame->StyleText()->EffectiveWordBreak();
-    switch (wordBreak) {
-      case StyleWordBreak::BreakAll:
-        mLineBreaker.SetWordBreak(LineBreaker::kWordBreak_BreakAll);
-        break;
-      case StyleWordBreak::KeepAll:
-        mLineBreaker.SetWordBreak(LineBreaker::kWordBreak_KeepAll);
-        break;
-      case StyleWordBreak::Normal:
-      default:
-        MOZ_ASSERT(wordBreak == StyleWordBreak::Normal);
-        mLineBreaker.SetWordBreak(LineBreaker::kWordBreak_Normal);
-        break;
+    const auto* styleText = mappedFlow->mStartFrame->StyleText();
+    if (styleText->mLineBreak == StyleLineBreak::Anywhere) {
+        mLineBreaker.SetWordBreak(LineBreaker::kWordBreak_Anywhere);
+    } else {
+      auto wordBreak = styleText->EffectiveWordBreak();
+      switch (wordBreak) {
+        case StyleWordBreak::BreakAll:
+          mLineBreaker.SetWordBreak(LineBreaker::kWordBreak_BreakAll);
+          break;
+        case StyleWordBreak::KeepAll:
+          mLineBreaker.SetWordBreak(LineBreaker::kWordBreak_KeepAll);
+          break;
+        case StyleWordBreak::Normal:
+        default:
+          MOZ_ASSERT(wordBreak == StyleWordBreak::Normal);
+          mLineBreaker.SetWordBreak(LineBreaker::kWordBreak_Normal);
+          break;
+      }
     }
 
     uint32_t offset = iter.GetSkippedOffset();
     gfxSkipCharsIterator iterNext = iter;
     iterNext.AdvanceOriginal(mappedFlow->GetContentEnd() -
                              mappedFlow->mStartFrame->GetContentOffset());
 
     UniquePtr<BreakSink>* breakSink = mBreakSinks.AppendElement(
@@ -2628,17 +2634,18 @@ void BuildTextRunsScanner::SetupBreakSin
       flags |= nsLineBreaker::BREAK_SUPPRESS_INSIDE;
     }
     if (aTextRun->GetFlags2() & nsTextFrameUtils::Flags::NoBreaks) {
       flags |= nsLineBreaker::BREAK_SKIP_SETTING_NO_BREAKS;
     }
     if (textStyle->mTextTransform.case_ == StyleTextTransformCase::Capitalize) {
       flags |= nsLineBreaker::BREAK_NEED_CAPITALIZATION;
     }
-    if (textStyle->mHyphens == StyleHyphens::Auto) {
+    if (textStyle->mHyphens == StyleHyphens::Auto &&
+        textStyle->mLineBreak != StyleLineBreak::Anywhere) {
       flags |= nsLineBreaker::BREAK_USE_AUTO_HYPHENATION;
     }
 
     if (HasCompressedLeadingWhitespace(startFrame, textStyle,
                                        mappedFlow->GetContentEnd(), iter)) {
       mLineBreaker.AppendInvisibleWhitespace(flags);
     }
 
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -407,16 +407,17 @@ cbindgen-types = [
     { gecko = "StyleFillRule", servo = "values::generics::basic_shape::FillRule" },
     { gecko = "StyleFontDisplay", servo = "font_face::FontDisplay" },
     { gecko = "StyleFontFaceSourceListComponent", servo = "font_face::FontFaceSourceListComponent" },
     { gecko = "StyleFontLanguageOverride", servo = "values::computed::font::FontLanguageOverride" },
     { gecko = "StylePathCommand", servo = "values::specified::svg_path::PathCommand" },
     { gecko = "StyleUnicodeRange", servo = "cssparser::UnicodeRange" },
     { gecko = "StyleOverflowWrap", servo = "values::computed::OverflowWrap" },
     { gecko = "StyleWordBreak", servo = "values::computed::WordBreak" },
+    { gecko = "StyleLineBreak", servo = "values::computed::LineBreak" },
     { gecko = "StyleUserSelect", servo = "values::computed::UserSelect" },
     { gecko = "StyleBreakBetween", servo = "values::computed::BreakBetween" },
     { gecko = "StyleBreakWithin", servo = "values::computed::BreakWithin" },
     { gecko = "StyleBorderStyle", servo = "values::computed::BorderStyle" },
     { gecko = "StyleOutlineStyle", servo = "values::computed::OutlineStyle" },
     { gecko = "StyleScrollSnapAlign", servo = "values::computed::ScrollSnapAlign" },
     { gecko = "StyleScrollSnapStrictness", servo = "values::computed::ScrollSnapStrictness" },
     { gecko = "StyleScrollSnapType", servo = "values::computed::ScrollSnapType" },
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -3656,16 +3656,17 @@ nsStyleText::nsStyleText(const Document&
 }
 
 nsStyleText::nsStyleText(const nsStyleText& aSource)
     : mTextTransform(aSource.mTextTransform),
       mTextAlign(aSource.mTextAlign),
       mTextAlignLast(aSource.mTextAlignLast),
       mTextJustify(aSource.mTextJustify),
       mWhiteSpace(aSource.mWhiteSpace),
+      mLineBreak(aSource.mLineBreak),
       mWordBreak(aSource.mWordBreak),
       mOverflowWrap(aSource.mOverflowWrap),
       mHyphens(aSource.mHyphens),
       mRubyAlign(aSource.mRubyAlign),
       mRubyPosition(aSource.mRubyPosition),
       mTextSizeAdjust(aSource.mTextSizeAdjust),
       mTextCombineUpright(aSource.mTextCombineUpright),
       mControlCharacterVisibility(aSource.mControlCharacterVisibility),
@@ -3699,16 +3700,17 @@ nsChangeHint nsStyleText::CalcDifference
       mControlCharacterVisibility != aNewData.mControlCharacterVisibility) {
     return nsChangeHint_ReconstructFrame;
   }
 
   if ((mTextAlign != aNewData.mTextAlign) ||
       (mTextAlignLast != aNewData.mTextAlignLast) ||
       (mTextTransform != aNewData.mTextTransform) ||
       (mWhiteSpace != aNewData.mWhiteSpace) ||
+      (mLineBreak != aNewData.mLineBreak) ||
       (mWordBreak != aNewData.mWordBreak) ||
       (mOverflowWrap != aNewData.mOverflowWrap) ||
       (mHyphens != aNewData.mHyphens) || (mRubyAlign != aNewData.mRubyAlign) ||
       (mRubyPosition != aNewData.mRubyPosition) ||
       (mTextSizeAdjust != aNewData.mTextSizeAdjust) ||
       (mLetterSpacing != aNewData.mLetterSpacing) ||
       (mLineHeight != aNewData.mLineHeight) ||
       (mTextIndent != aNewData.mTextIndent) ||
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1351,16 +1351,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
 
   nsChangeHint CalcDifference(const nsStyleText& aNewData) const;
 
   mozilla::StyleTextTransform mTextTransform;
   uint8_t mTextAlign;      // NS_STYLE_TEXT_ALIGN_*
   uint8_t mTextAlignLast;  // NS_STYLE_TEXT_ALIGN_*
   mozilla::StyleTextJustify mTextJustify;
   mozilla::StyleWhiteSpace mWhiteSpace;
+  mozilla::StyleLineBreak mLineBreak = mozilla::StyleLineBreak::Auto;
 
  private:
   mozilla::StyleWordBreak mWordBreak = mozilla::StyleWordBreak::Normal;
   mozilla::StyleOverflowWrap mOverflowWrap = mozilla::StyleOverflowWrap::Normal;
 
  public:
   mozilla::StyleHyphens mHyphens;
   uint8_t mRubyAlign;           // NS_STYLE_RUBY_ALIGN_*
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -3991,16 +3991,25 @@ var gCSSProperties = {
     applies_to_first_line: true,
     applies_to_placeholder: true,
     initial_values: [ "normal", "0", "0px", "calc(0px)" ],
     other_values: [ "1em", "2px", "-3px", "calc(1em)", "calc(1em + 3px)",
       "calc(15px / 2)", "calc(15px/2)", "calc(-3px)" ],
     invalid_values: [],
     quirks_values: { "5": "5px" },
   },
+  "line-break": {
+    domProp: "lineBreak",
+    inherited: true,
+    type: CSS_TYPE_LONGHAND,
+    initial_values: [ "auto" ],
+    other_values: [ "anywhere" ],
+    /* these values should be valid but are not yet implemented in gecko */
+    invalid_values: [ "loose", "normal", "strict" ]
+  },
   "line-height": {
     domProp: "lineHeight",
     inherited: true,
     type: CSS_TYPE_LONGHAND,
     applies_to_first_letter: true,
     applies_to_first_line: true,
     applies_to_placeholder: true,
     /*
--- a/servo/components/style/properties/data.py
+++ b/servo/components/style/properties/data.py
@@ -320,16 +320,17 @@ class Longhand(object):
                 "FontWeight",
                 "GreaterThanOrEqualToOneNumber",
                 "GridAutoFlow",
                 "InitialLetter",
                 "Integer",
                 "JustifyContent",
                 "JustifyItems",
                 "JustifySelf",
+                "LineBreak",
                 "MozForceBrokenImageIcon",
                 "MozListReversed",
                 "MozScriptLevel",
                 "MozScriptMinSize",
                 "MozScriptSizeMultiplier",
                 "NonNegativeNumber",
                 "Opacity",
                 "OutlineStyle",
--- a/servo/components/style/properties/longhands/inherited_text.mako.rs
+++ b/servo/components/style/properties/longhands/inherited_text.mako.rs
@@ -259,16 +259,26 @@
     "-moz-tab-size",
     "NonNegativeLengthOrNumber",
     "generics::length::LengthOrNumber::Number(From::from(8.0))",
     products="gecko",
     animation_value_type="LengthOrNumber",
     spec="https://drafts.csswg.org/css-text-3/#tab-size-property",
 )}
 
+${helpers.predefined_type(
+    "line-break",
+    "LineBreak",
+    "computed::LineBreak::Auto",
+    products="gecko",
+    animation_value_type="discrete",
+    spec="https://drafts.csswg.org/css-text-3/#line-break-property",
+    needs_context=False,
+)}
+
 // CSS Compatibility
 // https://compat.spec.whatwg.org
 ${helpers.predefined_type(
     "-webkit-text-fill-color",
     "Color",
     "computed_value::T::currentcolor()",
     products="gecko",
     gecko_pref="layout.css.prefixes.webkit",
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -72,17 +72,17 @@ pub use self::outline::OutlineStyle;
 pub use self::percentage::{NonNegativePercentage, Percentage};
 pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, ZIndex};
 pub use self::rect::NonNegativeLengthOrNumberRect;
 pub use self::resolution::Resolution;
 pub use self::svg::MozContextProperties;
 pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
 pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
 pub use self::table::XSpan;
-pub use self::text::{InitialLetter, LetterSpacing, LineHeight};
+pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight};
 pub use self::text::{OverflowWrap, TextOverflow, WordBreak, WordSpacing};
 pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle};
 pub use self::time::Time;
 pub use self::transform::{Rotate, Scale, Transform, TransformOperation};
 pub use self::transform::{TransformOrigin, TransformStyle, Translate};
 #[cfg(feature = "gecko")]
 pub use self::ui::CursorImage;
 pub use self::ui::{Cursor, MozForceBrokenImageIcon, UserSelect};
--- a/servo/components/style/values/computed/text.rs
+++ b/servo/components/style/values/computed/text.rs
@@ -15,17 +15,17 @@ use crate::values::specified::text::{sel
 use crate::values::specified::text::{TextEmphasisFillMode, TextEmphasisShapeKeyword};
 use crate::values::{CSSFloat, CSSInteger};
 use crate::Zero;
 use std::fmt::{self, Write};
 use style_traits::{CssWriter, ToCss};
 
 pub use crate::values::specified::TextAlignKeyword as TextAlign;
 pub use crate::values::specified::TextTransform;
-pub use crate::values::specified::{OverflowWrap, WordBreak};
+pub use crate::values::specified::{LineBreak, OverflowWrap, WordBreak};
 pub use crate::values::specified::{TextDecorationLine, TextEmphasisPosition};
 
 /// A computed value for the `initial-letter` property.
 pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;
 
 /// A computed value for the `letter-spacing` property.
 #[repr(transparent)]
 #[derive(
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -76,17 +76,17 @@ pub use self::position::{PositionCompone
 pub use self::rect::NonNegativeLengthOrNumberRect;
 pub use self::resolution::Resolution;
 pub use self::svg::MozContextProperties;
 pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
 pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
 pub use self::svg_path::SVGPathData;
 pub use self::table::XSpan;
 pub use self::text::TextTransform;
-pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextAlign};
+pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight, TextAlign};
 pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle, WordBreak};
 pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing};
 pub use self::time::Time;
 pub use self::transform::{Rotate, Scale, Transform};
 pub use self::transform::{TransformOrigin, TransformStyle, Translate};
 #[cfg(feature = "gecko")]
 pub use self::ui::CursorImage;
 pub use self::ui::{Cursor, MozForceBrokenImageIcon, UserSelect};
--- a/servo/components/style/values/specified/text.rs
+++ b/servo/components/style/values/specified/text.rs
@@ -1000,16 +1000,42 @@ pub enum WordBreak {
     /// The break-word value, needed for compat.
     ///
     /// Specifying `word-break: break-word` makes `overflow-wrap` behave as
     /// `anywhere`, and `word-break` behave like `normal`.
     #[cfg(feature = "gecko")]
     BreakWord,
 }
 
+/// Values for the `line-break` property.
+#[repr(u8)]
+#[derive(
+    Clone,
+    Copy,
+    Debug,
+    Eq,
+    MallocSizeOf,
+    Parse,
+    PartialEq,
+    SpecifiedValueInfo,
+    ToComputedValue,
+    ToCss,
+    ToResolvedValue,
+    ToShmem,
+)]
+#[allow(missing_docs)]
+pub enum LineBreak {
+    Auto,
+    /// TODO: additional values not yet implemented
+    /// Loose,
+    /// Normal,
+    /// Strict,
+    Anywhere,
+}
+
 /// Values for the `overflow-wrap` property.
 #[repr(u8)]
 #[derive(
     Clone,
     Copy,
     Debug,
     Eq,
     MallocSizeOf,
--- a/servo/ports/geckolib/cbindgen.toml
+++ b/servo/ports/geckolib/cbindgen.toml
@@ -100,16 +100,17 @@ include = [
   "BackgroundSize",
   "BorderImageSlice",
   "BorderSpacing",
   "BorderRadius",
   "NonNegativeLengthOrNumberRect",
   "Perspective",
   "ZIndex",
   "TransformOrigin",
+  "LineBreak",
   "WordBreak",
   "Contain",
   "Origin",
   "RestyleHint",
   "TouchAction",
   "WillChange",
   "TextDecorationLine",
   "TextTransform",
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-text/line-break/line-break-anywhere-001.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[line-break-anywhere-001.html]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-text/line-break/line-break-anywhere-002.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[line-break-anywhere-002.html]
-  expected: FAIL
--- a/testing/web-platform/meta/css/css-text/parsing/line-break-valid.html.ini
+++ b/testing/web-platform/meta/css/css-text/parsing/line-break-valid.html.ini
@@ -1,16 +1,10 @@
 [line-break-valid.html]
   [e.style['line-break'\] = "loose" should set the property value]
     expected: FAIL
 
   [e.style['line-break'\] = "normal" should set the property value]
     expected: FAIL
 
-  [e.style['line-break'\] = "anywhere" should set the property value]
-    expected: FAIL
-
-  [e.style['line-break'\] = "auto" should set the property value]
-    expected: FAIL
-
   [e.style['line-break'\] = "strict" should set the property value]
     expected: FAIL