diff --git a/Libraries/LibWeb/CSS/CSSStyleProperties.cpp b/Libraries/LibWeb/CSS/CSSStyleProperties.cpp index 8060b737fd4..7c2a298faaa 100644 --- a/Libraries/LibWeb/CSS/CSSStyleProperties.cpp +++ b/Libraries/LibWeb/CSS/CSSStyleProperties.cpp @@ -553,6 +553,42 @@ Optional CSSStyleProperties::get_property_internal(PropertyID pro auto left = get_property_internal(PropertyID::PaddingLeft); return style_property_for_sided_shorthand(property_id, top, right, bottom, left); } + case PropertyID::WhiteSpace: { + auto white_space_collapse_property = get_property_internal(PropertyID::WhiteSpaceCollapse); + auto text_wrap_mode_property = get_property_internal(PropertyID::TextWrapMode); + auto white_space_trim_property = get_property_internal(PropertyID::WhiteSpaceTrim); + + if (!white_space_collapse_property.has_value() || !text_wrap_mode_property.has_value() || !white_space_trim_property.has_value()) + break; + + RefPtr value; + + if (white_space_trim_property->value->is_keyword() && white_space_trim_property->value->as_keyword().keyword() == Keyword::None) { + auto white_space_collapse_keyword = white_space_collapse_property->value->as_keyword().keyword(); + auto text_wrap_mode_keyword = text_wrap_mode_property->value->as_keyword().keyword(); + + if (white_space_collapse_keyword == Keyword::Collapse && text_wrap_mode_keyword == Keyword::Wrap) + value = CSSKeywordValue::create(Keyword::Normal); + + if (white_space_collapse_keyword == Keyword::Preserve && text_wrap_mode_keyword == Keyword::Nowrap) + value = CSSKeywordValue::create(Keyword::Pre); + + if (white_space_collapse_keyword == Keyword::Preserve && text_wrap_mode_keyword == Keyword::Wrap) + value = CSSKeywordValue::create(Keyword::PreWrap); + + if (white_space_collapse_keyword == Keyword::PreserveBreaks && text_wrap_mode_keyword == Keyword::Wrap) + value = CSSKeywordValue::create(Keyword::PreLine); + } + + if (!value) + break; + + return StyleProperty { + .important = white_space_collapse_property->important, + .property_id = property_id, + .value = value.release_nonnull(), + }; + } default: break; } diff --git a/Libraries/LibWeb/CSS/ComputedProperties.cpp b/Libraries/LibWeb/CSS/ComputedProperties.cpp index cc8b2bf7af6..29f68241f39 100644 --- a/Libraries/LibWeb/CSS/ComputedProperties.cpp +++ b/Libraries/LibWeb/CSS/ComputedProperties.cpp @@ -824,12 +824,6 @@ Optional ComputedProperties::word_spacing() const return {}; } -WhiteSpace ComputedProperties::white_space() const -{ - auto const& value = property(PropertyID::WhiteSpace); - return keyword_to_white_space(value.to_keyword()).release_value(); -} - WhiteSpaceCollapse ComputedProperties::white_space_collapse() const { auto const& value = property(PropertyID::WhiteSpaceCollapse); diff --git a/Libraries/LibWeb/CSS/ComputedProperties.h b/Libraries/LibWeb/CSS/ComputedProperties.h index fb31ed867d8..934776046cc 100644 --- a/Libraries/LibWeb/CSS/ComputedProperties.h +++ b/Libraries/LibWeb/CSS/ComputedProperties.h @@ -100,7 +100,6 @@ public: ContentVisibility content_visibility() const; Vector cursor() const; Variant tab_size() const; - WhiteSpace white_space() const; WhiteSpaceCollapse white_space_collapse() const; WhiteSpaceTrimData white_space_trim() const; WordBreak word_break() const; diff --git a/Libraries/LibWeb/CSS/ComputedValues.h b/Libraries/LibWeb/CSS/ComputedValues.h index ec146adf401..5b6b0c89d55 100644 --- a/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Libraries/LibWeb/CSS/ComputedValues.h @@ -100,7 +100,6 @@ public: static CSS::PreferredColorScheme color_scheme() { return CSS::PreferredColorScheme::Auto; } static CSS::ContentVisibility content_visibility() { return CSS::ContentVisibility::Visible; } static CursorData cursor() { return { CSS::Cursor::Auto }; } - static CSS::WhiteSpace white_space() { return CSS::WhiteSpace::Normal; } static CSS::WhiteSpaceCollapse white_space_collapse() { return CSS::WhiteSpaceCollapse::Collapse; } static CSS::WordBreak word_break() { return CSS::WordBreak::Normal; } static CSS::LengthOrCalculated word_spacing() { return CSS::Length::make_px(0); } @@ -431,7 +430,6 @@ public: CSS::TextOverflow text_overflow() const { return m_noninherited.text_overflow; } Vector const& text_shadow() const { return m_inherited.text_shadow; } CSS::Positioning position() const { return m_noninherited.position; } - CSS::WhiteSpace white_space() const { return m_inherited.white_space; } CSS::WhiteSpaceCollapse white_space_collapse() const { return m_inherited.white_space_collapse; } WhiteSpaceTrimData white_space_trim() const { return m_noninherited.white_space_trim; } CSS::LengthOrCalculated word_spacing() const { return m_inherited.word_spacing; } @@ -627,7 +625,6 @@ protected: CSS::TextTransform text_transform { InitialValues::text_transform() }; CSS::LengthPercentage text_indent { InitialValues::text_indent() }; CSS::TextWrapMode text_wrap_mode { InitialValues::text_wrap_mode() }; - CSS::WhiteSpace white_space { InitialValues::white_space() }; CSS::WhiteSpaceCollapse white_space_collapse { InitialValues::white_space_collapse() }; CSS::WordBreak word_break { InitialValues::word_break() }; CSS::LengthOrCalculated word_spacing { InitialValues::word_spacing() }; @@ -833,7 +830,6 @@ public: void set_text_overflow(CSS::TextOverflow value) { m_noninherited.text_overflow = value; } void set_webkit_text_fill_color(Color value) { m_inherited.webkit_text_fill_color = value; } void set_position(CSS::Positioning position) { m_noninherited.position = position; } - void set_white_space(CSS::WhiteSpace value) { m_inherited.white_space = value; } void set_white_space_collapse(CSS::WhiteSpaceCollapse value) { m_inherited.white_space_collapse = value; } void set_white_space_trim(WhiteSpaceTrimData value) { m_noninherited.white_space_trim = value; } void set_word_spacing(CSS::LengthOrCalculated value) { m_inherited.word_spacing = move(value); } diff --git a/Libraries/LibWeb/CSS/Enums.json b/Libraries/LibWeb/CSS/Enums.json index 30acba7bd5a..e9b2aaab987 100644 --- a/Libraries/LibWeb/CSS/Enums.json +++ b/Libraries/LibWeb/CSS/Enums.json @@ -675,7 +675,6 @@ ], "white-space": [ "normal", - "nowrap", "pre", "pre-line", "pre-wrap" diff --git a/Libraries/LibWeb/CSS/Parser/Parser.h b/Libraries/LibWeb/CSS/Parser/Parser.h index 08ccbf26804..6ddf6bc27f6 100644 --- a/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Libraries/LibWeb/CSS/Parser/Parser.h @@ -445,6 +445,7 @@ private: RefPtr parse_grid_area_shorthand_value(TokenStream&); RefPtr parse_grid_shorthand_value(TokenStream&); RefPtr parse_touch_action_value(TokenStream&); + RefPtr parse_white_space_shorthand(TokenStream&); RefPtr parse_white_space_trim_value(TokenStream&); RefPtr parse_list_of_time_values(PropertyID, TokenStream&); diff --git a/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp b/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp index ba2097ba406..5964206ce20 100644 --- a/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp +++ b/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp @@ -708,6 +708,10 @@ Parser::ParseErrorOr> Parser::parse_css_value if (auto parsed_value = parse_contain_value(tokens); parsed_value && !tokens.has_next_token()) return parsed_value.release_nonnull(); return ParseError::SyntaxError; + case PropertyID::WhiteSpace: + if (auto parsed_value = parse_white_space_shorthand(tokens); parsed_value && !tokens.has_next_token()) + return parsed_value.release_nonnull(); + return ParseError::SyntaxError; case PropertyID::WhiteSpaceTrim: if (auto parsed_value = parse_white_space_trim_value(tokens); parsed_value && !tokens.has_next_token()) return parsed_value.release_nonnull(); @@ -4819,4 +4823,97 @@ RefPtr Parser::parse_white_space_trim_value(TokenStream Parser::parse_white_space_shorthand(TokenStream& tokens) +{ + // normal | pre | pre-wrap | pre-line | <'white-space-collapse'> || <'text-wrap-mode'> || <'white-space-trim'> + + auto transaction = tokens.begin_transaction(); + + auto make_whitespace_shorthand = [&](RefPtr white_space_collapse, RefPtr text_wrap_mode, RefPtr white_space_trim) { + transaction.commit(); + + if (!white_space_collapse) + white_space_collapse = property_initial_value(PropertyID::WhiteSpaceCollapse); + + if (!text_wrap_mode) + text_wrap_mode = property_initial_value(PropertyID::TextWrapMode); + + if (!white_space_trim) + white_space_trim = property_initial_value(PropertyID::WhiteSpaceTrim); + + return ShorthandStyleValue::create( + PropertyID::WhiteSpace, + { PropertyID::WhiteSpaceCollapse, PropertyID::TextWrapMode, PropertyID::WhiteSpaceTrim }, + { white_space_collapse.release_nonnull(), text_wrap_mode.release_nonnull(), white_space_trim.release_nonnull() }); + }; + + // normal | pre | pre-wrap | pre-line + if (parse_all_as_single_keyword_value(tokens, Keyword::Normal)) + return make_whitespace_shorthand(CSSKeywordValue::create(Keyword::Collapse), CSSKeywordValue::create(Keyword::Wrap), CSSKeywordValue::create(Keyword::None)); + + if (parse_all_as_single_keyword_value(tokens, Keyword::Pre)) + return make_whitespace_shorthand(CSSKeywordValue::create(Keyword::Preserve), CSSKeywordValue::create(Keyword::Nowrap), CSSKeywordValue::create(Keyword::None)); + + if (parse_all_as_single_keyword_value(tokens, Keyword::PreWrap)) + return make_whitespace_shorthand(CSSKeywordValue::create(Keyword::Preserve), CSSKeywordValue::create(Keyword::Wrap), CSSKeywordValue::create(Keyword::None)); + + if (parse_all_as_single_keyword_value(tokens, Keyword::PreLine)) + return make_whitespace_shorthand(CSSKeywordValue::create(Keyword::PreserveBreaks), CSSKeywordValue::create(Keyword::Wrap), CSSKeywordValue::create(Keyword::None)); + + // <'white-space-collapse'> || <'text-wrap-mode'> || <'white-space-trim'> + RefPtr white_space_collapse; + RefPtr text_wrap_mode; + RefPtr white_space_trim; + + while (tokens.has_next_token()) { + if (auto value = parse_css_value_for_property(PropertyID::WhiteSpaceCollapse, tokens)) { + if (white_space_collapse) + return {}; + white_space_collapse = value; + continue; + } + + if (auto value = parse_css_value_for_property(PropertyID::TextWrapMode, tokens)) { + if (text_wrap_mode) + return {}; + text_wrap_mode = value; + continue; + } + + Vector white_space_trim_component_values; + + while (true) { + auto peek_token = tokens.next_token(); + + if (!peek_token.is(Token::Type::Ident)) { + break; + } + + auto keyword = keyword_from_string(peek_token.token().ident()); + + if (!keyword.has_value() || !property_accepts_keyword(PropertyID::WhiteSpaceTrim, keyword.value())) { + break; + } + + white_space_trim_component_values.append(tokens.consume_a_token()); + } + + if (!white_space_trim_component_values.is_empty()) { + auto white_space_trim_token_stream = TokenStream { white_space_trim_component_values }; + + if (auto value = parse_white_space_trim_value(white_space_trim_token_stream)) { + if (white_space_trim) + return {}; + white_space_trim = value; + continue; + } + } + + return {}; + } + + return make_whitespace_shorthand(white_space_collapse, text_wrap_mode, white_space_trim); +} + } diff --git a/Libraries/LibWeb/CSS/Properties.json b/Libraries/LibWeb/CSS/Properties.json index 3f151d3a8bc..3cedb16c9f8 100644 --- a/Libraries/LibWeb/CSS/Properties.json +++ b/Libraries/LibWeb/CSS/Properties.json @@ -3127,11 +3127,15 @@ ] }, "white-space": { - "animation-type": "discrete", - "inherited": true, + "inherited": false, "initial": "normal", "valid-types": [ "white-space" + ], + "longhands": [ + "white-space-collapse", + "text-wrap-mode", + "white-space-trim" ] }, "white-space-collapse": { diff --git a/Libraries/LibWeb/CSS/StyleValues/ShorthandStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/ShorthandStyleValue.cpp index 0dd1b93c3e9..9dbbf997c09 100644 --- a/Libraries/LibWeb/CSS/StyleValues/ShorthandStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/ShorthandStyleValue.cpp @@ -61,6 +61,38 @@ String ShorthandStyleValue::to_string(SerializationMode mode) const if (all_same_keyword && built_in_keyword.has_value()) return m_properties.values.first()->to_string(mode); + auto default_to_string = [&]() { + auto all_properties_same_value = true; + auto first_property_value = m_properties.values.first(); + for (auto i = 1u; i < m_properties.values.size(); ++i) { + if (m_properties.values[i] != first_property_value) { + all_properties_same_value = false; + break; + } + } + if (all_properties_same_value) + return first_property_value->to_string(mode); + + StringBuilder builder; + auto first = true; + for (size_t i = 0; i < m_properties.values.size(); ++i) { + auto value = m_properties.values[i]; + auto value_string = value->to_string(mode); + auto initial_value_string = property_initial_value(m_properties.sub_properties[i])->to_string(mode); + if (value_string == initial_value_string) + continue; + if (first) + first = false; + else + builder.append(' '); + builder.append(value->to_string(mode)); + } + if (builder.is_empty()) + return m_properties.values.first()->to_string(mode); + + return MUST(builder.to_string()); + }; + // Then special cases switch (m_properties.shorthand_property) { case PropertyID::Background: { @@ -402,36 +434,34 @@ String ShorthandStyleValue::to_string(SerializationMode mode) const return builder.to_string_without_validation(); } + case PropertyID::WhiteSpace: { + auto white_space_collapse_property = longhand(PropertyID::WhiteSpaceCollapse); + auto text_wrap_mode_property = longhand(PropertyID::TextWrapMode); + auto white_space_trim_property = longhand(PropertyID::WhiteSpaceTrim); + + RefPtr value; + + if (white_space_trim_property->is_keyword() && white_space_trim_property->as_keyword().keyword() == Keyword::None) { + auto white_space_collapse_keyword = white_space_collapse_property->as_keyword().keyword(); + auto text_wrap_mode_keyword = text_wrap_mode_property->as_keyword().keyword(); + + if (white_space_collapse_keyword == Keyword::Collapse && text_wrap_mode_keyword == Keyword::Wrap) + return "normal"_string; + + if (white_space_collapse_keyword == Keyword::Preserve && text_wrap_mode_keyword == Keyword::Nowrap) + return "pre"_string; + + if (white_space_collapse_keyword == Keyword::Preserve && text_wrap_mode_keyword == Keyword::Wrap) + return "pre-wrap"_string; + + if (white_space_collapse_keyword == Keyword::PreserveBreaks && text_wrap_mode_keyword == Keyword::Wrap) + return "pre-line"_string; + } + + return default_to_string(); + } default: - auto all_properties_same_value = true; - auto first_property_value = m_properties.values.first(); - for (auto i = 1u; i < m_properties.values.size(); ++i) { - if (m_properties.values[i] != first_property_value) { - all_properties_same_value = false; - break; - } - } - if (all_properties_same_value) - return first_property_value->to_string(mode); - - StringBuilder builder; - auto first = true; - for (size_t i = 0; i < m_properties.values.size(); ++i) { - auto value = m_properties.values[i]; - auto value_string = value->to_string(mode); - auto initial_value_string = property_initial_value(m_properties.sub_properties[i])->to_string(mode); - if (value_string == initial_value_string) - continue; - if (first) - first = false; - else - builder.append(' '); - builder.append(value->to_string(mode)); - } - if (builder.is_empty()) - return m_properties.values.first()->to_string(mode); - - return MUST(builder.to_string()); + return default_to_string(); } } diff --git a/Libraries/LibWeb/Editing/Commands.cpp b/Libraries/LibWeb/Editing/Commands.cpp index 300b26bdb9f..bbf7afc17ce 100644 --- a/Libraries/LibWeb/Editing/Commands.cpp +++ b/Libraries/LibWeb/Editing/Commands.cpp @@ -1355,8 +1355,8 @@ bool command_insert_linebreak_action(DOM::Document& document, String const&) if (is(*start_node) && active_range.start_offset() == start_node->length()) MUST(selection.collapse(start_node->parent(), start_node->index() + 1)); - // AD-HOC: If the active range's start node is a Text node and its resolved value for "white-space" is one of "pre", - // "pre-line" or "pre-wrap": + // AD-HOC: If the active range's start node is a Text node and its resolved value for "white-space-collapse" is one of + // "preserve" or "preserve-breaks": // * Insert a newline (\n) character at the active range's start offset; // * Collapse the selection with active range's start node as the first argument and one plus active range's // start offset as the second argument @@ -1364,9 +1364,8 @@ bool command_insert_linebreak_action(DOM::Document& document, String const&) // active range's start node. // * Return true. if (auto* text_node = as_if(*start_node); text_node) { - auto resolved_white_space = resolved_keyword(*start_node, CSS::PropertyID::WhiteSpace); - if (resolved_white_space.has_value() - && first_is_one_of(resolved_white_space.value(), CSS::Keyword::Pre, CSS::Keyword::PreLine, CSS::Keyword::PreWrap)) { + auto resolved_white_space_collapse = resolved_keyword(*start_node, CSS::PropertyID::WhiteSpaceCollapse); + if (resolved_white_space_collapse.has_value() && first_is_one_of(resolved_white_space_collapse.value(), CSS::Keyword::Preserve, CSS::Keyword::PreserveBreaks)) { MUST(text_node->insert_data(active_range.start_offset(), "\n"_string)); MUST(selection.collapse(start_node, active_range.start_offset() + 1)); if (selection.range()->start_offset() == start_node->length()) diff --git a/Libraries/LibWeb/Editing/Internal/Algorithms.cpp b/Libraries/LibWeb/Editing/Internal/Algorithms.cpp index 2e15a125ff9..da87a090e87 100644 --- a/Libraries/LibWeb/Editing/Internal/Algorithms.cpp +++ b/Libraries/LibWeb/Editing/Internal/Algorithms.cpp @@ -379,15 +379,15 @@ void canonicalize_whitespace(DOM::BoundaryPoint boundary, bool fix_collapsed_spa // "white-space" is neither "pre" nor "pre-wrap" and start offset is not zero and the // (start offset − 1)st code unit of start node's data is a space (0x0020) or // non-breaking space (0x00A0), subtract one from start offset. + // AD-HOC: Use the white-space-collapse longhand instead of "white-space" shorthand: https://github.com/w3c/editing/issues/486. if (is(*start_node) && start_offset != 0) { - auto parent_white_space = resolved_keyword(*start_node->parent(), CSS::PropertyID::WhiteSpace); + auto parent_white_space_collapse = resolved_keyword(*start_node->parent(), CSS::PropertyID::WhiteSpaceCollapse); // FIXME: Find a way to get code points directly from the UTF-8 string auto start_node_data = *start_node->text_content(); auto utf16_code_units = MUST(AK::utf8_to_utf16(start_node_data)); auto offset_minus_one_code_point = Utf16View { utf16_code_units }.code_point_at(start_offset - 1); - if (parent_white_space != CSS::Keyword::Pre && parent_white_space != CSS::Keyword::PreWrap - && (offset_minus_one_code_point == 0x20 || offset_minus_one_code_point == 0xA0)) { + if (parent_white_space_collapse != CSS::Keyword::Preserve && (offset_minus_one_code_point == 0x20 || offset_minus_one_code_point == 0xA0)) { --start_offset; continue; } @@ -432,15 +432,15 @@ void canonicalize_whitespace(DOM::BoundaryPoint boundary, bool fix_collapsed_spa // "white-space" is neither "pre" nor "pre-wrap" and end offset is not end node's length // and the end offsetth code unit of end node's data is a space (0x0020) or non-breaking // space (0x00A0): + // AD-HOC: Use the white-space-collapse longhand instead of "white-space" shorthand: https://github.com/w3c/editing/issues/486. if (is(*end_node) && end_offset != end_node->length()) { - auto parent_white_space = resolved_keyword(*end_node->parent(), CSS::PropertyID::WhiteSpace); + auto parent_white_space_collapse = resolved_keyword(*end_node->parent(), CSS::PropertyID::WhiteSpaceCollapse); // FIXME: Find a way to get code points directly from the UTF-8 string auto end_node_data = *end_node->text_content(); auto utf16_code_units = MUST(AK::utf8_to_utf16(end_node_data)); auto offset_code_point = Utf16View { utf16_code_units }.code_point_at(end_offset); - if (parent_white_space != CSS::Keyword::Pre && parent_white_space != CSS::Keyword::PreWrap - && (offset_code_point == 0x20 || offset_code_point == 0xA0)) { + if (parent_white_space_collapse != CSS::Keyword::Preserve && (offset_code_point == 0x20 || offset_code_point == 0xA0)) { // 1. If fix collapsed space is true, and collapse spaces is true, and the end offsetth // code unit of end node's data is a space (0x0020): call deleteData(end offset, 1) // on end node, then continue this loop from the beginning. @@ -497,10 +497,10 @@ void canonicalize_whitespace(DOM::BoundaryPoint boundary, bool fix_collapsed_spa // "white-space" is neither "pre" nor "pre-wrap" and end offset is end node's length and // the last code unit of end node's data is a space (0x0020) and end node precedes a line // break: + // AD-HOC: Use the white-space-collapse longhand instead of "white-space" shorthand: https://github.com/w3c/editing/issues/486. if (is(*end_node) && end_offset == end_node->length() && precedes_a_line_break(end_node)) { - auto parent_white_space = resolved_keyword(*end_node->parent(), CSS::PropertyID::WhiteSpace); - if (parent_white_space != CSS::Keyword::Pre && parent_white_space != CSS::Keyword::PreWrap - && end_node->text_content().value().ends_with_bytes(" "sv)) { + auto parent_white_space_collapse = resolved_keyword(*end_node->parent(), CSS::PropertyID::WhiteSpaceCollapse); + if (parent_white_space_collapse != CSS::Keyword::Preserve && end_node->text_content().value().ends_with_bytes(" "sv)) { // 1. Subtract one from end offset. --end_offset; @@ -2597,32 +2597,34 @@ bool is_whitespace_node(GC::Ref node) if (character_data.data().is_empty()) return true; - // NOTE: All constraints below require a parent Element with a resolved value for "white-space" + // NOTE: All constraints below require a parent Element with a resolved value for "white-space-collapse" GC::Ptr parent = node->parent(); if (!is(parent.ptr())) return false; - auto resolved_white_space = resolved_keyword(*parent, CSS::PropertyID::WhiteSpace); - if (!resolved_white_space.has_value()) + auto resolved_white_space_collapse = resolved_keyword(*parent, CSS::PropertyID::WhiteSpaceCollapse); + if (!resolved_white_space_collapse.has_value()) return false; - auto white_space = resolved_white_space.value(); + auto white_space_collapse = resolved_white_space_collapse.value(); // or a Text node whose data consists only of one or more tabs (0x0009), line feeds (0x000A), // carriage returns (0x000D), and/or spaces (0x0020), and whose parent is an Element whose // resolved value for "white-space" is "normal" or "nowrap"; + // AD-HOC: We use the equivalent "white-space-collapse" longhand property instead of "white-space" shorthand auto is_tab_lf_cr_or_space = [](u32 codepoint) { return codepoint == '\t' || codepoint == '\n' || codepoint == '\r' || codepoint == ' '; }; auto code_points = character_data.data().code_points(); - if (all_of(code_points, is_tab_lf_cr_or_space) && (white_space == CSS::Keyword::Normal || white_space == CSS::Keyword::Nowrap)) + if (all_of(code_points, is_tab_lf_cr_or_space) && (white_space_collapse == CSS::Keyword::Collapse)) return true; // or a Text node whose data consists only of one or more tabs (0x0009), carriage returns // (0x000D), and/or spaces (0x0020), and whose parent is an Element whose resolved value for // "white-space" is "pre-line". + // AD-HOC: We use the equivalent "white-space-collapse" longhand property instead of "white-space" shorthand auto is_tab_cr_or_space = [](u32 codepoint) { return codepoint == '\t' || codepoint == '\r' || codepoint == ' '; }; - if (all_of(code_points, is_tab_cr_or_space) && white_space == CSS::Keyword::PreLine) + if (all_of(code_points, is_tab_cr_or_space) && white_space_collapse == CSS::Keyword::PreserveBreaks) return true; return false; @@ -3910,6 +3912,7 @@ Optional specified_command_value(GC::Ref element, FlyStrin // 10. If element has a style attribute set, and that attribute has the effect of setting property, return the value // that it sets property to. + // FIXME: Use property_in_style_attribute once it supports shorthands. if (auto inline_style = element->inline_style()) { auto value = inline_style->get_property_value(string_from_property_id(property.value())); if (!value.is_empty()) @@ -4704,6 +4707,7 @@ Optional> property_in_style_attribute(GC if (!inline_style) return {}; + // FIXME: This doesn't support shorthand properties. auto style_property = inline_style->property(property_id); if (!style_property.has_value()) return {}; diff --git a/Libraries/LibWeb/HTML/HTMLPreElement.cpp b/Libraries/LibWeb/HTML/HTMLPreElement.cpp index d60eb2a0a13..bb068afd819 100644 --- a/Libraries/LibWeb/HTML/HTMLPreElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLPreElement.cpp @@ -41,8 +41,9 @@ void HTMLPreElement::apply_presentational_hints(GC::Ref HTMLElement::apply_presentational_hints(cascaded_properties); for_each_attribute([&](auto const& name, auto const&) { - if (name.equals_ignoring_ascii_case(HTML::AttributeNames::wrap)) - cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::WhiteSpace, CSS::CSSKeywordValue::create(CSS::Keyword::PreWrap)); + if (name.equals_ignoring_ascii_case(HTML::AttributeNames::wrap)) { + cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::TextWrapMode, CSS::CSSKeywordValue::create(CSS::Keyword::Wrap)); + } }); } diff --git a/Libraries/LibWeb/HTML/HTMLTableCellElement.cpp b/Libraries/LibWeb/HTML/HTMLTableCellElement.cpp index add8cd106b7..c4786a65043 100644 --- a/Libraries/LibWeb/HTML/HTMLTableCellElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLTableCellElement.cpp @@ -94,7 +94,7 @@ void HTMLTableCellElement::apply_presentational_hints(GC::Refset_property_from_presentational_hint(CSS::PropertyID::BackgroundImage, CSS::ImageStyleValue::create(*parsed_value)); return; } else if (name == HTML::AttributeNames::nowrap) { - cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::WhiteSpace, CSS::CSSKeywordValue::create(CSS::Keyword::Nowrap)); + cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::TextWrapMode, CSS::CSSKeywordValue::create(CSS::Keyword::Nowrap)); return; } }); diff --git a/Libraries/LibWeb/Layout/InlineFormattingContext.cpp b/Libraries/LibWeb/Layout/InlineFormattingContext.cpp index c906e57c9e4..9c2f92fddad 100644 --- a/Libraries/LibWeb/Layout/InlineFormattingContext.cpp +++ b/Libraries/LibWeb/Layout/InlineFormattingContext.cpp @@ -264,7 +264,7 @@ void InlineFormattingContext::generate_line_boxes() // Ignore collapsible whitespace chunks at the start of line, and if the last fragment already ends in whitespace. if (item.is_collapsible_whitespace && (line_boxes.is_empty() || line_boxes.last().is_empty_or_ends_in_whitespace())) { - if (item.node->computed_values().white_space() != CSS::WhiteSpace::Nowrap) { + if (item.node->computed_values().text_wrap_mode() == CSS::TextWrapMode::Wrap) { auto next_width = iterator.next_non_whitespace_sequence_width(); if (next_width > 0) line_builder.break_if_needed(next_width); @@ -291,7 +291,7 @@ void InlineFormattingContext::generate_line_boxes() case InlineLevelIterator::Item::Type::Element: { auto& box = as(*item.node); compute_inset(box, content_box_rect(m_containing_block_used_values).size()); - if (containing_block().computed_values().white_space() != CSS::WhiteSpace::Nowrap) { + if (containing_block().computed_values().text_wrap_mode() == CSS::TextWrapMode::Wrap) { auto minimum_space_needed_on_line = item.border_box_width(); if (item.margin_start < 0) minimum_space_needed_on_line += item.margin_start; @@ -322,7 +322,7 @@ void InlineFormattingContext::generate_line_boxes() case InlineLevelIterator::Item::Type::Text: { auto& text_node = as(*item.node); - if (text_node.computed_values().white_space() != CSS::WhiteSpace::Nowrap) { + if (text_node.computed_values().text_wrap_mode() == CSS::TextWrapMode::Wrap) { bool is_whitespace = false; CSSPixels next_width = 0; // If we're in a whitespace-collapsing context, we can simply check the flag. diff --git a/Libraries/LibWeb/Layout/InlineLevelIterator.cpp b/Libraries/LibWeb/Layout/InlineLevelIterator.cpp index 8d4d52f6b85..5b0bc0334b2 100644 --- a/Libraries/LibWeb/Layout/InlineLevelIterator.cpp +++ b/Libraries/LibWeb/Layout/InlineLevelIterator.cpp @@ -155,7 +155,7 @@ CSSPixels InlineLevelIterator::next_non_whitespace_sequence_width() auto& next_item = m_lookahead_items.tail(); if (next_item.type == InlineLevelIterator::Item::Type::ForcedBreak) break; - if (next_item.node->computed_values().white_space() != CSS::WhiteSpace::Nowrap) { + if (next_item.node->computed_values().text_wrap_mode() == CSS::TextWrapMode::Wrap) { if (next_item.type != InlineLevelIterator::Item::Type::Text) break; if (next_item.is_collapsible_whitespace) @@ -640,27 +640,12 @@ Optional InlineLevelIterator::next_without_lookahead( void InlineLevelIterator::enter_text_node(Layout::TextNode const& text_node) { - bool do_collapse = true; - bool do_wrap_lines = true; - bool do_respect_linebreaks = false; + auto white_space_collapse = text_node.computed_values().white_space_collapse(); + auto text_wrap_mode = text_node.computed_values().text_wrap_mode(); - if (text_node.computed_values().white_space() == CSS::WhiteSpace::Nowrap) { - do_collapse = true; - do_wrap_lines = false; - do_respect_linebreaks = false; - } else if (text_node.computed_values().white_space() == CSS::WhiteSpace::Pre) { - do_collapse = false; - do_wrap_lines = false; - do_respect_linebreaks = true; - } else if (text_node.computed_values().white_space() == CSS::WhiteSpace::PreLine) { - do_collapse = true; - do_wrap_lines = true; - do_respect_linebreaks = true; - } else if (text_node.computed_values().white_space() == CSS::WhiteSpace::PreWrap) { - do_collapse = false; - do_wrap_lines = true; - do_respect_linebreaks = true; - } + bool do_collapse = white_space_collapse == CSS::WhiteSpaceCollapse::Collapse || white_space_collapse == CSS::WhiteSpaceCollapse::PreserveBreaks; + bool do_wrap_lines = text_wrap_mode == CSS::TextWrapMode::Wrap; + bool do_respect_linebreaks = white_space_collapse == CSS::WhiteSpaceCollapse::Preserve || white_space_collapse == CSS::WhiteSpaceCollapse::PreserveBreaks || white_space_collapse == CSS::WhiteSpaceCollapse::BreakSpaces; if (text_node.dom_node().is_editable() && !text_node.dom_node().is_uninteresting_whitespace_node()) do_collapse = false; diff --git a/Libraries/LibWeb/Layout/LineBox.cpp b/Libraries/LibWeb/Layout/LineBox.cpp index b7062b5d71e..2f749c48c6c 100644 --- a/Libraries/LibWeb/Layout/LineBox.cpp +++ b/Libraries/LibWeb/Layout/LineBox.cpp @@ -55,8 +55,9 @@ void LineBox::add_fragment(Node const& layout_node, int start, int length, CSSPi CSSPixels LineBox::calculate_or_trim_trailing_whitespace(RemoveTrailingWhitespace should_remove) { auto should_trim = [](LineBoxFragment* fragment) { - auto ws = fragment->layout_node().computed_values().white_space(); - return ws == CSS::WhiteSpace::Normal || ws == CSS::WhiteSpace::Nowrap || ws == CSS::WhiteSpace::PreLine; + auto white_space_collapse = fragment->layout_node().computed_values().white_space_collapse(); + + return white_space_collapse == CSS::WhiteSpaceCollapse::Collapse || white_space_collapse == CSS::WhiteSpaceCollapse::PreserveBreaks; }; CSSPixels whitespace_width = 0; diff --git a/Libraries/LibWeb/Layout/Node.cpp b/Libraries/LibWeb/Layout/Node.cpp index 2c4b4c6074f..1e4f9e5a3e2 100644 --- a/Libraries/LibWeb/Layout/Node.cpp +++ b/Libraries/LibWeb/Layout/Node.cpp @@ -643,7 +643,6 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style) computed_values.set_text_wrap_mode(computed_style.text_wrap_mode()); computed_values.set_tab_size(computed_style.tab_size()); - computed_values.set_white_space(computed_style.white_space()); computed_values.set_white_space_collapse(computed_style.white_space_collapse()); computed_values.set_word_break(computed_style.word_break()); if (auto word_spacing = computed_style.word_spacing(); word_spacing.has_value()) diff --git a/Libraries/LibWeb/Layout/TextNode.cpp b/Libraries/LibWeb/Layout/TextNode.cpp index fedb503c94f..6d8c769f149 100644 --- a/Libraries/LibWeb/Layout/TextNode.cpp +++ b/Libraries/LibWeb/Layout/TextNode.cpp @@ -326,18 +326,7 @@ void TextNode::compute_text_for_rendering() return; } - bool collapse = [](CSS::WhiteSpace white_space) { - switch (white_space) { - case CSS::WhiteSpace::Normal: - case CSS::WhiteSpace::Nowrap: - case CSS::WhiteSpace::PreLine: - return true; - case CSS::WhiteSpace::Pre: - case CSS::WhiteSpace::PreWrap: - return false; - } - VERIFY_NOT_REACHED(); - }(computed_values().white_space()); + bool collapse = first_is_one_of(computed_values().white_space_collapse(), CSS::WhiteSpaceCollapse::Collapse, CSS::WhiteSpaceCollapse::PreserveBreaks); auto parent_element = dom_node().parent_element(); auto const maybe_lang = parent_element ? parent_element->lang() : Optional {}; diff --git a/Tests/LibWeb/Layout/expected/tab-size-text-wrap.txt b/Tests/LibWeb/Layout/expected/tab-size-text-wrap.txt index 903fab5d5fa..4af804029e9 100644 --- a/Tests/LibWeb/Layout/expected/tab-size-text-wrap.txt +++ b/Tests/LibWeb/Layout/expected/tab-size-text-wrap.txt @@ -1,33 +1,33 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline - BlockContainer at (0,0) content-size 800x61 [BFC] children: not-inline - BlockContainer at (8,8) content-size 784x45 children: not-inline - BlockContainer
at (8,8) content-size 100x45 children: inline + BlockContainer at (0,0) content-size 800x31 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x15 children: not-inline + BlockContainer
at (8,8) content-size 100x15 children: inline frag 0 from BlockContainer start: 0, length: 0, rect: [8,8 111.59375x15] baseline: 11.390625 - frag 1 from BlockContainer start: 0, length: 0, rect: [8,23 119.1875x15] baseline: 11.390625 - frag 2 from BlockContainer start: 0, length: 0, rect: [8,38 127.5625x15] baseline: 11.390625 + frag 1 from BlockContainer start: 0, length: 0, rect: [119.59375,8 119.1875x15] baseline: 11.390625 + frag 2 from BlockContainer start: 0, length: 0, rect: [238.78125,8 127.5625x15] baseline: 11.390625 BlockContainer at (8,8) content-size 111.59375x15 inline-block [BFC] children: inline frag 0 from TextNode start: 0, length: 2, rect: [8,8 111.59375x15] baseline: 11.390625 " A" TextNode <#text> - BlockContainer at (8,23) content-size 119.1875x15 inline-block [BFC] children: inline - frag 0 from TextNode start: 0, length: 3, rect: [8,23 119.1875x15] baseline: 11.390625 + BlockContainer at (119.59375,8) content-size 119.1875x15 inline-block [BFC] children: inline + frag 0 from TextNode start: 0, length: 3, rect: [119.59375,8 119.1875x15] baseline: 11.390625 " AB" TextNode <#text> - BlockContainer at (8,38) content-size 127.5625x15 inline-block [BFC] children: inline - frag 0 from TextNode start: 0, length: 4, rect: [8,38 127.5625x15] baseline: 11.390625 + BlockContainer at (238.78125,8) content-size 127.5625x15 inline-block [BFC] children: inline + frag 0 from TextNode start: 0, length: 4, rect: [238.78125,8 127.5625x15] baseline: 11.390625 " ABC" TextNode <#text> - BlockContainer <(anonymous)> at (8,53) content-size 784x0 children: inline + BlockContainer <(anonymous)> at (8,23) content-size 784x0 children: inline TextNode <#text> ViewportPaintable (Viewport<#document>) [0,0 800x600] - PaintableWithLines (BlockContainer) [0,0 800x61] - PaintableWithLines (BlockContainer) [8,8 784x45] - PaintableWithLines (BlockContainer
) [8,8 100x45] overflow: [8,8 127.5625x45] + PaintableWithLines (BlockContainer) [0,0 800x31] + PaintableWithLines (BlockContainer) [8,8 784x15] + PaintableWithLines (BlockContainer
) [8,8 100x15] overflow: [8,8 358.34375x15] PaintableWithLines (BlockContainer) [8,8 111.59375x15] TextPaintable (TextNode<#text>) - PaintableWithLines (BlockContainer) [8,23 119.1875x15] + PaintableWithLines (BlockContainer) [119.59375,8 119.1875x15] TextPaintable (TextNode<#text>) - PaintableWithLines (BlockContainer) [8,38 127.5625x15] + PaintableWithLines (BlockContainer) [238.78125,8 127.5625x15] TextPaintable (TextNode<#text>) - PaintableWithLines (BlockContainer(anonymous)) [8,53 784x0] + PaintableWithLines (BlockContainer(anonymous)) [8,23 784x0] diff --git a/Tests/LibWeb/Layout/input/tab-size-text-wrap.html b/Tests/LibWeb/Layout/input/tab-size-text-wrap.html index 80867babb7e..2341a4a2d89 100644 --- a/Tests/LibWeb/Layout/input/tab-size-text-wrap.html +++ b/Tests/LibWeb/Layout/input/tab-size-text-wrap.html @@ -5,6 +5,7 @@ font-family: monospace; tab-size: 100px; width: 100px; + /* FIXME: The layout here is incorrect until the text-wrap property is implemented. */ text-wrap: wrap; background-color: khaki; } diff --git a/Tests/LibWeb/Text/expected/Editing/execCommand-preserveWhitespace.txt b/Tests/LibWeb/Text/expected/Editing/execCommand-preserveWhitespace.txt index b6db7c81e10..eb8dac2b8bb 100644 --- a/Tests/LibWeb/Text/expected/Editing/execCommand-preserveWhitespace.txt +++ b/Tests/LibWeb/Text/expected/Editing/execCommand-preserveWhitespace.txt @@ -1,2 +1,2 @@ Before: foo
bar
-After: foobar +After: foobar diff --git a/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-has-indexed-property-getter.txt b/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-has-indexed-property-getter.txt index 00a52882ba8..9092c4a638b 100644 --- a/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-has-indexed-property-getter.txt +++ b/Tests/LibWeb/Text/expected/css/CSSStyleDeclaration-has-indexed-property-getter.txt @@ -58,186 +58,185 @@ All properties associated with getComputedStyle(document.body): "55": "text-transform", "56": "text-wrap-mode", "57": "visibility", - "58": "white-space", - "59": "white-space-collapse", - "60": "word-break", - "61": "word-spacing", - "62": "word-wrap", - "63": "writing-mode", - "64": "align-content", - "65": "align-items", - "66": "align-self", - "67": "animation-delay", - "68": "animation-direction", - "69": "animation-duration", - "70": "animation-fill-mode", - "71": "animation-iteration-count", - "72": "animation-name", - "73": "animation-play-state", - "74": "animation-timing-function", - "75": "appearance", - "76": "aspect-ratio", - "77": "backdrop-filter", - "78": "background-attachment", - "79": "background-blend-mode", - "80": "background-clip", - "81": "background-color", - "82": "background-image", - "83": "background-origin", - "84": "background-position-x", - "85": "background-position-y", - "86": "background-repeat", - "87": "background-size", - "88": "block-size", - "89": "border-block-end-color", - "90": "border-block-end-style", - "91": "border-block-end-width", - "92": "border-block-start-color", - "93": "border-block-start-style", - "94": "border-block-start-width", - "95": "border-bottom-color", - "96": "border-bottom-left-radius", - "97": "border-bottom-right-radius", - "98": "border-bottom-style", - "99": "border-bottom-width", - "100": "border-inline-end-color", - "101": "border-inline-end-style", - "102": "border-inline-end-width", - "103": "border-inline-start-color", - "104": "border-inline-start-style", - "105": "border-inline-start-width", - "106": "border-left-color", - "107": "border-left-style", - "108": "border-left-width", - "109": "border-right-color", - "110": "border-right-style", - "111": "border-right-width", - "112": "border-top-color", - "113": "border-top-left-radius", - "114": "border-top-right-radius", - "115": "border-top-style", - "116": "border-top-width", - "117": "bottom", - "118": "box-shadow", - "119": "box-sizing", - "120": "clear", - "121": "clip", - "122": "clip-path", - "123": "column-count", - "124": "column-gap", - "125": "column-span", - "126": "column-width", - "127": "contain", - "128": "content", - "129": "content-visibility", - "130": "counter-increment", - "131": "counter-reset", - "132": "counter-set", - "133": "cx", - "134": "cy", - "135": "display", - "136": "filter", - "137": "flex-basis", - "138": "flex-direction", - "139": "flex-grow", - "140": "flex-shrink", - "141": "flex-wrap", - "142": "float", - "143": "grid-auto-columns", - "144": "grid-auto-flow", - "145": "grid-auto-rows", - "146": "grid-column-end", - "147": "grid-column-start", - "148": "grid-row-end", - "149": "grid-row-start", - "150": "grid-template-areas", - "151": "grid-template-columns", - "152": "grid-template-rows", - "153": "height", - "154": "inline-size", - "155": "inset-block-end", - "156": "inset-block-start", - "157": "inset-inline-end", - "158": "inset-inline-start", - "159": "isolation", - "160": "justify-content", - "161": "justify-items", - "162": "justify-self", - "163": "left", - "164": "margin-block-end", - "165": "margin-block-start", - "166": "margin-bottom", - "167": "margin-inline-end", - "168": "margin-inline-start", - "169": "margin-left", - "170": "margin-right", - "171": "margin-top", - "172": "mask-image", - "173": "mask-type", - "174": "max-block-size", - "175": "max-height", - "176": "max-inline-size", - "177": "max-width", - "178": "min-block-size", - "179": "min-height", - "180": "min-inline-size", - "181": "min-width", - "182": "mix-blend-mode", - "183": "object-fit", - "184": "object-position", - "185": "opacity", - "186": "order", - "187": "outline-color", - "188": "outline-offset", - "189": "outline-style", - "190": "outline-width", - "191": "overflow-x", - "192": "overflow-y", - "193": "padding-block-end", - "194": "padding-block-start", - "195": "padding-bottom", - "196": "padding-inline-end", - "197": "padding-inline-start", - "198": "padding-left", - "199": "padding-right", - "200": "padding-top", - "201": "position", - "202": "r", - "203": "right", - "204": "rotate", - "205": "row-gap", - "206": "rx", - "207": "ry", - "208": "scale", - "209": "scrollbar-gutter", - "210": "scrollbar-width", - "211": "stop-color", - "212": "stop-opacity", - "213": "table-layout", - "214": "text-decoration-color", - "215": "text-decoration-style", - "216": "text-decoration-thickness", - "217": "text-overflow", - "218": "top", - "219": "touch-action", - "220": "transform", - "221": "transform-box", - "222": "transform-origin", - "223": "transition-behavior", - "224": "transition-delay", - "225": "transition-duration", - "226": "transition-property", - "227": "transition-timing-function", - "228": "translate", - "229": "unicode-bidi", - "230": "user-select", - "231": "vertical-align", - "232": "view-transition-name", - "233": "white-space-trim", - "234": "width", - "235": "x", - "236": "y", - "237": "z-index" + "58": "white-space-collapse", + "59": "word-break", + "60": "word-spacing", + "61": "word-wrap", + "62": "writing-mode", + "63": "align-content", + "64": "align-items", + "65": "align-self", + "66": "animation-delay", + "67": "animation-direction", + "68": "animation-duration", + "69": "animation-fill-mode", + "70": "animation-iteration-count", + "71": "animation-name", + "72": "animation-play-state", + "73": "animation-timing-function", + "74": "appearance", + "75": "aspect-ratio", + "76": "backdrop-filter", + "77": "background-attachment", + "78": "background-blend-mode", + "79": "background-clip", + "80": "background-color", + "81": "background-image", + "82": "background-origin", + "83": "background-position-x", + "84": "background-position-y", + "85": "background-repeat", + "86": "background-size", + "87": "block-size", + "88": "border-block-end-color", + "89": "border-block-end-style", + "90": "border-block-end-width", + "91": "border-block-start-color", + "92": "border-block-start-style", + "93": "border-block-start-width", + "94": "border-bottom-color", + "95": "border-bottom-left-radius", + "96": "border-bottom-right-radius", + "97": "border-bottom-style", + "98": "border-bottom-width", + "99": "border-inline-end-color", + "100": "border-inline-end-style", + "101": "border-inline-end-width", + "102": "border-inline-start-color", + "103": "border-inline-start-style", + "104": "border-inline-start-width", + "105": "border-left-color", + "106": "border-left-style", + "107": "border-left-width", + "108": "border-right-color", + "109": "border-right-style", + "110": "border-right-width", + "111": "border-top-color", + "112": "border-top-left-radius", + "113": "border-top-right-radius", + "114": "border-top-style", + "115": "border-top-width", + "116": "bottom", + "117": "box-shadow", + "118": "box-sizing", + "119": "clear", + "120": "clip", + "121": "clip-path", + "122": "column-count", + "123": "column-gap", + "124": "column-span", + "125": "column-width", + "126": "contain", + "127": "content", + "128": "content-visibility", + "129": "counter-increment", + "130": "counter-reset", + "131": "counter-set", + "132": "cx", + "133": "cy", + "134": "display", + "135": "filter", + "136": "flex-basis", + "137": "flex-direction", + "138": "flex-grow", + "139": "flex-shrink", + "140": "flex-wrap", + "141": "float", + "142": "grid-auto-columns", + "143": "grid-auto-flow", + "144": "grid-auto-rows", + "145": "grid-column-end", + "146": "grid-column-start", + "147": "grid-row-end", + "148": "grid-row-start", + "149": "grid-template-areas", + "150": "grid-template-columns", + "151": "grid-template-rows", + "152": "height", + "153": "inline-size", + "154": "inset-block-end", + "155": "inset-block-start", + "156": "inset-inline-end", + "157": "inset-inline-start", + "158": "isolation", + "159": "justify-content", + "160": "justify-items", + "161": "justify-self", + "162": "left", + "163": "margin-block-end", + "164": "margin-block-start", + "165": "margin-bottom", + "166": "margin-inline-end", + "167": "margin-inline-start", + "168": "margin-left", + "169": "margin-right", + "170": "margin-top", + "171": "mask-image", + "172": "mask-type", + "173": "max-block-size", + "174": "max-height", + "175": "max-inline-size", + "176": "max-width", + "177": "min-block-size", + "178": "min-height", + "179": "min-inline-size", + "180": "min-width", + "181": "mix-blend-mode", + "182": "object-fit", + "183": "object-position", + "184": "opacity", + "185": "order", + "186": "outline-color", + "187": "outline-offset", + "188": "outline-style", + "189": "outline-width", + "190": "overflow-x", + "191": "overflow-y", + "192": "padding-block-end", + "193": "padding-block-start", + "194": "padding-bottom", + "195": "padding-inline-end", + "196": "padding-inline-start", + "197": "padding-left", + "198": "padding-right", + "199": "padding-top", + "200": "position", + "201": "r", + "202": "right", + "203": "rotate", + "204": "row-gap", + "205": "rx", + "206": "ry", + "207": "scale", + "208": "scrollbar-gutter", + "209": "scrollbar-width", + "210": "stop-color", + "211": "stop-opacity", + "212": "table-layout", + "213": "text-decoration-color", + "214": "text-decoration-style", + "215": "text-decoration-thickness", + "216": "text-overflow", + "217": "top", + "218": "touch-action", + "219": "transform", + "220": "transform-box", + "221": "transform-origin", + "222": "transition-behavior", + "223": "transition-delay", + "224": "transition-duration", + "225": "transition-property", + "226": "transition-timing-function", + "227": "translate", + "228": "unicode-bidi", + "229": "user-select", + "230": "vertical-align", + "231": "view-transition-name", + "232": "white-space-trim", + "233": "width", + "234": "x", + "235": "y", + "236": "z-index" } All properties associated with document.body.style by default: {} diff --git a/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt b/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt index ed893c1de07..7901825f878 100644 --- a/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt +++ b/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt @@ -56,7 +56,6 @@ text-shadow: none text-transform: none text-wrap-mode: wrap visibility: visible -white-space: normal white-space-collapse: collapse word-break: normal word-spacing: normal @@ -86,7 +85,7 @@ background-position-x: 0% background-position-y: 0% background-repeat: repeat background-size: auto auto -block-size: 1320px +block-size: 1305px border-block-end-color: rgb(0, 0, 0) border-block-end-style: none border-block-end-width: medium @@ -151,7 +150,7 @@ grid-row-start: auto grid-template-areas: none grid-template-columns: none grid-template-rows: none -height: 2295px +height: 2280px inline-size: 784px inset-block-end: auto inset-block-start: auto diff --git a/Tests/LibWeb/Text/expected/css/white-space.txt b/Tests/LibWeb/Text/expected/css/white-space.txt new file mode 100644 index 00000000000..b9c1bbe8591 --- /dev/null +++ b/Tests/LibWeb/Text/expected/css/white-space.txt @@ -0,0 +1,3 @@ +normal +normal +preserve discard-inner diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-cascade/all-prop-revert-layer.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-cascade/all-prop-revert-layer.txt index 7420828baa8..f8f8ba907cd 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-cascade/all-prop-revert-layer.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-cascade/all-prop-revert-layer.txt @@ -1,8 +1,8 @@ Harness status: OK -Found 200 tests +Found 199 tests -190 Pass +189 Pass 10 Fail Pass accent-color Pass border-collapse @@ -59,7 +59,6 @@ Pass text-justify Pass text-shadow Pass text-transform Pass visibility -Pass white-space Pass word-break Pass word-spacing Pass word-wrap diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-text/parsing/white-space-shorthand.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-text/parsing/white-space-shorthand.txt new file mode 100644 index 00000000000..6dd57f8bdee --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-text/parsing/white-space-shorthand.txt @@ -0,0 +1,51 @@ +Harness status: OK + +Found 45 tests + +40 Pass +5 Fail +Pass e.style['white-space'] = "collapse" should set the property value +Pass Property white-space value 'collapse' +Pass e.style['white-space'] = "wrap" should set the property value +Pass Property white-space value 'wrap' +Pass e.style['white-space'] = "collapse wrap" should set the property value +Pass Property white-space value 'collapse wrap' +Pass e.style['white-space'] = "wrap collapse" should set the property value +Pass Property white-space value 'wrap collapse' +Pass e.style['white-space'] = "preserve nowrap" should set the property value +Pass Property white-space value 'preserve nowrap' +Pass e.style['white-space'] = "nowrap preserve" should set the property value +Pass Property white-space value 'nowrap preserve' +Pass e.style['white-space'] = "nowrap" should set the property value +Pass Property white-space value 'nowrap' +Pass e.style['white-space'] = "collapse nowrap" should set the property value +Pass Property white-space value 'collapse nowrap' +Pass e.style['white-space'] = "nowrap collapse" should set the property value +Pass Property white-space value 'nowrap collapse' +Pass e.style['white-space'] = "preserve" should set the property value +Pass Property white-space value 'preserve' +Pass e.style['white-space'] = "preserve wrap" should set the property value +Pass Property white-space value 'preserve wrap' +Pass e.style['white-space'] = "wrap preserve" should set the property value +Pass Property white-space value 'wrap preserve' +Pass e.style['white-space'] = "break-spaces" should set the property value +Pass Property white-space value 'break-spaces' +Pass e.style['white-space'] = "break-spaces wrap" should set the property value +Pass Property white-space value 'break-spaces wrap' +Pass e.style['white-space'] = "wrap break-spaces" should set the property value +Pass Property white-space value 'wrap break-spaces' +Pass e.style['white-space'] = "preserve-breaks" should set the property value +Pass Property white-space value 'preserve-breaks' +Pass e.style['white-space'] = "preserve-breaks wrap" should set the property value +Pass Property white-space value 'preserve-breaks wrap' +Pass e.style['white-space'] = "wrap preserve-breaks" should set the property value +Pass Property white-space value 'wrap preserve-breaks' +Pass e.style['white-space'] = "preserve-breaks nowrap" should set the property value +Pass Property white-space value 'preserve-breaks nowrap' +Pass e.style['white-space'] = "nowrap preserve-breaks" should set the property value +Pass Property white-space value 'nowrap preserve-breaks' +Fail e.style['white-space'] = "balance" should not set the property value +Fail e.style['white-space'] = "collapse balance" should not set the property value +Fail e.style['white-space'] = "balance collapse" should not set the property value +Fail e.style['white-space'] = "preserve balance" should not set the property value +Fail e.style['white-space'] = "balance preserve" should not set the property value \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/css/white-space.html b/Tests/LibWeb/Text/input/css/white-space.html new file mode 100644 index 00000000000..4ebdb913b6d --- /dev/null +++ b/Tests/LibWeb/Text/input/css/white-space.html @@ -0,0 +1,25 @@ + + +
+
+
+ + \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/wpt-import/css/css-text/parsing/white-space-shorthand.html b/Tests/LibWeb/Text/input/wpt-import/css/css-text/parsing/white-space-shorthand.html new file mode 100644 index 00000000000..4f8ce94faf7 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/css/css-text/parsing/white-space-shorthand.html @@ -0,0 +1,49 @@ + +CSS Text Module Test: parsing white-space as a shorthand + + + + + +
+