diff --git a/Libraries/LibWeb/Editing/Commands.cpp b/Libraries/LibWeb/Editing/Commands.cpp index b82feb09e72..a059babdc31 100644 --- a/Libraries/LibWeb/Editing/Commands.cpp +++ b/Libraries/LibWeb/Editing/Commands.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -500,6 +501,98 @@ bool command_font_name_action(DOM::Document& document, String const& value) return true; } +enum class FontSizeMode : u8 { + Absolute, + RelativePlus, + RelativeMinus, +}; + +// https://w3c.github.io/editing/docs/execCommand/#the-fontsize-command +bool command_font_size_action(DOM::Document& document, String const& value) +{ + // 1. Strip leading and trailing whitespace from value. + auto resulting_value = MUST(value.trim_ascii_whitespace()); + + // 2. If value is not a valid floating point number, and would not be a valid floating point number if a single + // leading "+" character were stripped, return false. + if (!HTML::is_valid_floating_point_number(resulting_value)) { + if (!resulting_value.starts_with_bytes("+"sv) + || !HTML::is_valid_floating_point_number(MUST(resulting_value.substring_from_byte_offset(1)))) + return false; + } + + // 3. If the first character of value is "+", delete the character and let mode be "relative-plus". + auto mode = FontSizeMode::Absolute; + if (resulting_value.starts_with_bytes("+"sv)) { + resulting_value = MUST(resulting_value.substring_from_byte_offset(1)); + mode = FontSizeMode::RelativePlus; + } + + // 4. Otherwise, if the first character of value is "-", delete the character and let mode be "relative-minus". + else if (resulting_value.starts_with_bytes("-"sv)) { + resulting_value = MUST(resulting_value.substring_from_byte_offset(1)); + mode = FontSizeMode::RelativeMinus; + } + + // 5. Otherwise, let mode be "absolute". + // NOTE: This is the default set in step 3. + + // 6. Apply the rules for parsing non-negative integers to value, and let number be the result. + i64 number = HTML::parse_non_negative_integer(resulting_value).release_value(); + + // 7. If mode is "relative-plus", add three to number. + if (mode == FontSizeMode::RelativePlus) + number += 3; + + // 8. If mode is "relative-minus", negate number, then add three to it. + if (mode == FontSizeMode::RelativeMinus) + number = -number + 3; + + // 9. If number is less than one, let number equal 1. + number = AK::max(number, 1); + + // 10. If number is greater than seven, let number equal 7. + number = AK::min(number, 7); + + // 11. Set value to the string here corresponding to number: + // 1: x-small + // 2: small + // 3: medium + // 4: large + // 5: x-large + // 6: xx-large + // 7: xxx-large + auto const& font_sizes = named_font_sizes(); + resulting_value = MUST(String::from_utf8(font_sizes[number - 1])); + + // 12. Set the selection's value to value. + set_the_selections_value(document, CommandNames::fontSize, resulting_value); + + // 13. Return true. + return true; +} + +// https://w3c.github.io/editing/docs/execCommand/#the-fontsize-command +String command_font_size_value(DOM::Document const& document) +{ + // 1. If the active range is null, return the empty string. + auto range = active_range(document); + if (!range) + return {}; + + // 2. Let pixel size be the effective command value of the first formattable node that is effectively contained in + // the active range, or if there is no such node, the effective command value of the active range's start node, + // in either case interpreted as a number of pixels. + auto first_formattable_node = first_formattable_node_effectively_contained(range); + auto value = effective_command_value( + first_formattable_node ? first_formattable_node : *range->start_container(), + CommandNames::fontSize); + auto pixel_size = font_size_to_pixel_size(value.value_or({})); + + // 3. Return the legacy font size for pixel size. + return legacy_font_size(pixel_size.to_int()); +} + // https://w3c.github.io/editing/docs/execCommand/#the-forwarddelete-command bool command_forward_delete_action(DOM::Document& document, String const&) { @@ -1129,6 +1222,13 @@ static Array const commands { .action = command_font_name_action, .relevant_css_property = CSS::PropertyID::FontFamily, }, + // https://w3c.github.io/editing/docs/execCommand/#the-fontsize-command + CommandDefinition { + .command = CommandNames::fontSize, + .action = command_font_size_action, + .value = command_font_size_value, + .relevant_css_property = CSS::PropertyID::FontSize, + }, // https://w3c.github.io/editing/docs/execCommand/#the-forwarddelete-command CommandDefinition { .command = CommandNames::forwardDelete, diff --git a/Libraries/LibWeb/Editing/Commands.h b/Libraries/LibWeb/Editing/Commands.h index 62df3b2d996..af971161fda 100644 --- a/Libraries/LibWeb/Editing/Commands.h +++ b/Libraries/LibWeb/Editing/Commands.h @@ -36,6 +36,8 @@ bool command_default_paragraph_separator_action(DOM::Document&, String const&); String command_default_paragraph_separator_value(DOM::Document const&); bool command_delete_action(DOM::Document&, String const&); bool command_font_name_action(DOM::Document&, String const&); +bool command_font_size_action(DOM::Document&, String const&); +String command_font_size_value(DOM::Document const&); bool command_forward_delete_action(DOM::Document&, String const&); bool command_insert_linebreak_action(DOM::Document&, String const&); bool command_insert_paragraph_action(DOM::Document&, String const&); diff --git a/Libraries/LibWeb/Editing/Internal/Algorithms.cpp b/Libraries/LibWeb/Editing/Internal/Algorithms.cpp index 1597657f6ce..5d0bc7900a4 100644 --- a/Libraries/LibWeb/Editing/Internal/Algorithms.cpp +++ b/Libraries/LibWeb/Editing/Internal/Algorithms.cpp @@ -3961,7 +3961,12 @@ GC::Ptr first_formattable_node_effectively_contained(GC::Ptr= 2 && font_size.substring_view(font_size.length() - 2).equals_ignoring_ascii_case("px"sv)) { + auto optional_number = font_size.substring_view(0, font_size.length() - 2).to_number(); + if (optional_number.has_value()) + return CSSPixels::nearest_value_for(optional_number.value()); + } // Try to map the font size directly to a keyword (e.g. medium or x-large) auto keyword = CSS::keyword_from_string(font_size); @@ -3971,6 +3976,7 @@ CSSPixels font_size_to_pixel_size(StringView font_size) keyword = HTML::HTMLFontElement::parse_legacy_font_size(font_size); // If that also failed, give up + auto pixel_size = CSS::StyleComputer::default_user_font_size(); if (!keyword.has_value()) return pixel_size; diff --git a/Tests/LibWeb/Text/expected/Editing/execCommand-fontSize.txt b/Tests/LibWeb/Text/expected/Editing/execCommand-fontSize.txt new file mode 100644 index 00000000000..c70bbba9c28 --- /dev/null +++ b/Tests/LibWeb/Text/expected/Editing/execCommand-fontSize.txt @@ -0,0 +1,6 @@ +div: "foobar" +fontSize value: 3 +div: "foobar" +fontSize value: 5 +div: "foobar" +fontSize value: 4 diff --git a/Tests/LibWeb/Text/input/Editing/execCommand-fontSize.html b/Tests/LibWeb/Text/input/Editing/execCommand-fontSize.html new file mode 100644 index 00000000000..f8508dbf870 --- /dev/null +++ b/Tests/LibWeb/Text/input/Editing/execCommand-fontSize.html @@ -0,0 +1,26 @@ + +
foobar
+