mirror of
https://github.com/zebrajr/ladybird.git
synced 2025-12-06 00:19:53 +01:00
LibWeb: Convert Editing API internals to UTF-16
Both sides of the Editing internals now have to deal with some awkward converting between UTF-8 and UTF-16, but the upside is that it immediately exposed an issue with the `insertText` command: instead of dealing with code units, it was iterating over code points causing the selection to be updated only once instead of twice. This resulted in the final selection potentially ending up in between a surrogate pair. Fixes #5547 (pasting/typing surrogate pairs).
This commit is contained in:
parent
9a03ee1c24
commit
e029e785d2
|
|
@ -869,8 +869,8 @@ public:
|
|||
void reset_command_state_overrides() { m_command_state_override.clear(); }
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#value-override
|
||||
Optional<String const&> command_value_override(FlyString const& command) const { return m_command_value_override.get(command); }
|
||||
void set_command_value_override(FlyString const& command, String const& value);
|
||||
Optional<Utf16String const&> command_value_override(FlyString const& command) const { return m_command_value_override.get(command); }
|
||||
void set_command_value_override(FlyString const& command, Utf16String const& value);
|
||||
void clear_command_value_override(FlyString const& command);
|
||||
void reset_command_value_overrides() { m_command_value_override.clear(); }
|
||||
|
||||
|
|
@ -1255,7 +1255,7 @@ private:
|
|||
HashMap<FlyString, bool> m_command_state_override;
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#value-override
|
||||
HashMap<FlyString, String> m_command_value_override;
|
||||
HashMap<FlyString, Utf16String> m_command_value_override;
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/webstorage.html#session-storage-holder
|
||||
// A Document object has an associated session storage holder, which is null or a Storage object. It is initially null.
|
||||
|
|
|
|||
|
|
@ -27,39 +27,39 @@
|
|||
namespace Web::Editing {
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-backcolor-command
|
||||
bool command_back_color_action(DOM::Document& document, String const& value)
|
||||
bool command_back_color_action(DOM::Document& document, Utf16View const& value)
|
||||
{
|
||||
// 1. If value is not a valid CSS color, prepend "#" to it.
|
||||
auto resulting_value = value;
|
||||
if (!Color::from_string(resulting_value).has_value()) {
|
||||
resulting_value = MUST(String::formatted("#{}", resulting_value));
|
||||
auto resulting_value = Utf16String::from_utf16_without_validation(value);
|
||||
if (!Color::from_utf16_string(resulting_value).has_value()) {
|
||||
resulting_value = Utf16String::formatted("#{}", resulting_value);
|
||||
|
||||
// 2. If value is still not a valid CSS color, or if it is currentColor, return false.
|
||||
// AD-HOC: No browser does this. They always return true.
|
||||
if (!Color::from_string(resulting_value).has_value()) {
|
||||
if (!Color::from_utf16_string(resulting_value).has_value()) {
|
||||
// FIXME: Also return true in case of currentColor.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Set the selection's value to value.
|
||||
set_the_selections_value(document, CommandNames::backColor, resulting_value);
|
||||
set_the_selections_value(document, CommandNames::backColor, resulting_value.utf16_view());
|
||||
|
||||
// 4. Return true.
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-bold-command
|
||||
bool command_bold_action(DOM::Document& document, String const&)
|
||||
bool command_bold_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// If queryCommandState("bold") returns true, set the selection's value to "normal".
|
||||
if (MUST(document.query_command_state(CommandNames::bold))) {
|
||||
set_the_selections_value(document, CommandNames::bold, "normal"_string);
|
||||
set_the_selections_value(document, CommandNames::bold, u"normal"sv);
|
||||
}
|
||||
|
||||
// Otherwise set the selection's value to "bold".
|
||||
else {
|
||||
set_the_selections_value(document, CommandNames::bold, "bold"_string);
|
||||
set_the_selections_value(document, CommandNames::bold, u"bold"sv);
|
||||
}
|
||||
|
||||
// Either way, return true.
|
||||
|
|
@ -67,7 +67,7 @@ bool command_bold_action(DOM::Document& document, String const&)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-createlink-command
|
||||
bool command_create_link_action(DOM::Document& document, String const& value)
|
||||
bool command_create_link_action(DOM::Document& document, Utf16View const& value)
|
||||
{
|
||||
// 1. If value is the empty string, return false.
|
||||
if (value.is_empty())
|
||||
|
|
@ -82,7 +82,7 @@ bool command_create_link_action(DOM::Document& document, String const& value)
|
|||
return IterationDecision::Break;
|
||||
if (auto* anchor = as_if<HTML::HTMLAnchorElement>(*ancestor); anchor && anchor->is_editable()
|
||||
&& anchor->has_attribute(HTML::AttributeNames::href))
|
||||
MUST(anchor->set_href(value));
|
||||
MUST(anchor->set_href(value.to_utf8_but_should_be_ported_to_utf16()));
|
||||
visited_ancestors.set(ancestor.ptr());
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
|
@ -100,7 +100,7 @@ bool command_create_link_action(DOM::Document& document, String const& value)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-defaultparagraphseparator-command
|
||||
bool command_default_paragraph_separator_action(DOM::Document& document, String const& input_value)
|
||||
bool command_default_paragraph_separator_action(DOM::Document& document, Utf16View const& input_value)
|
||||
{
|
||||
// Let value be converted to ASCII lowercase.
|
||||
auto value = input_value.to_ascii_lowercase();
|
||||
|
|
@ -121,14 +121,14 @@ bool command_default_paragraph_separator_action(DOM::Document& document, String
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-defaultparagraphseparator-command
|
||||
String command_default_paragraph_separator_value(DOM::Document const& document)
|
||||
Utf16String command_default_paragraph_separator_value(DOM::Document const& document)
|
||||
{
|
||||
// Return the context object's default single-line container name.
|
||||
return document.default_single_line_container_name().to_string();
|
||||
return Utf16String::from_utf8_without_validation(document.default_single_line_container_name().to_string());
|
||||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-delete-command
|
||||
bool command_delete_action(DOM::Document& document, String const&)
|
||||
bool command_delete_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// 1. If the active range is not collapsed, delete the selection and return true.
|
||||
auto& selection = *document.get_selection();
|
||||
|
|
@ -495,7 +495,7 @@ bool command_delete_action(DOM::Document& document, String const&)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-fontname-command
|
||||
bool command_font_name_action(DOM::Document& document, String const& value)
|
||||
bool command_font_name_action(DOM::Document& document, Utf16View const& value)
|
||||
{
|
||||
// Set the selection's value to value, then return true.
|
||||
set_the_selections_value(document, CommandNames::fontName, value);
|
||||
|
|
@ -509,29 +509,29 @@ enum class FontSizeMode : u8 {
|
|||
};
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-fontsize-command
|
||||
bool command_font_size_action(DOM::Document& document, String const& value)
|
||||
bool command_font_size_action(DOM::Document& document, Utf16View const& value)
|
||||
{
|
||||
// 1. Strip leading and trailing whitespace from value.
|
||||
auto resulting_value = MUST(value.trim_ascii_whitespace());
|
||||
auto resulting_value = value.trim_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))))
|
||||
if (!HTML::is_valid_floating_point_number(resulting_value.to_utf8_but_should_be_ported_to_utf16())) {
|
||||
if (!resulting_value.starts_with("+"sv)
|
||||
|| !HTML::is_valid_floating_point_number(resulting_value.substring_view(1).to_utf8_but_should_be_ported_to_utf16()))
|
||||
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));
|
||||
if (resulting_value.starts_with("+"sv)) {
|
||||
resulting_value = resulting_value.substring_view(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));
|
||||
else if (resulting_value.starts_with("-"sv)) {
|
||||
resulting_value = resulting_value.substring_view(1);
|
||||
mode = FontSizeMode::RelativeMinus;
|
||||
}
|
||||
|
||||
|
|
@ -539,7 +539,7 @@ bool command_font_size_action(DOM::Document& document, String const& value)
|
|||
// 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();
|
||||
i64 number = HTML::parse_non_negative_integer(resulting_value.to_utf8_but_should_be_ported_to_utf16()).release_value();
|
||||
|
||||
// 7. If mode is "relative-plus", add three to number.
|
||||
if (mode == FontSizeMode::RelativePlus)
|
||||
|
|
@ -564,7 +564,7 @@ bool command_font_size_action(DOM::Document& document, String const& value)
|
|||
// 6: xx-large
|
||||
// 7: xxx-large
|
||||
auto const& font_sizes = named_font_sizes();
|
||||
resulting_value = MUST(String::from_utf8(font_sizes[number - 1]));
|
||||
resulting_value = font_sizes[number - 1];
|
||||
|
||||
// 12. Set the selection's value to value.
|
||||
set_the_selections_value(document, CommandNames::fontSize, resulting_value);
|
||||
|
|
@ -574,7 +574,7 @@ bool command_font_size_action(DOM::Document& document, String const& value)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-fontsize-command
|
||||
String command_font_size_value(DOM::Document const& document)
|
||||
Utf16String command_font_size_value(DOM::Document const& document)
|
||||
{
|
||||
// 1. If the active range is null, return the empty string.
|
||||
auto range = active_range(document);
|
||||
|
|
@ -595,16 +595,16 @@ String command_font_size_value(DOM::Document const& document)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-forecolor-command
|
||||
bool command_fore_color_action(DOM::Document& document, String const& value)
|
||||
bool command_fore_color_action(DOM::Document& document, Utf16View const& value)
|
||||
{
|
||||
// 1. If value is not a valid CSS color, prepend "#" to it.
|
||||
auto resulting_value = value;
|
||||
if (!Color::from_string(resulting_value).has_value()) {
|
||||
resulting_value = MUST(String::formatted("#{}", resulting_value));
|
||||
if (!Color::from_utf16_string(resulting_value).has_value()) {
|
||||
resulting_value = Utf16String::formatted("#{}", resulting_value);
|
||||
|
||||
// 2. If value is still not a valid CSS color, or if it is currentColor, return false.
|
||||
// AD-HOC: No browser does this. They always return true.
|
||||
if (!Color::from_string(resulting_value).has_value()) {
|
||||
if (!Color::from_utf16_string(resulting_value).has_value()) {
|
||||
// FIXME: Also return true in case of currentColor.
|
||||
return true;
|
||||
}
|
||||
|
|
@ -618,19 +618,20 @@ bool command_fore_color_action(DOM::Document& document, String const& value)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-formatblock-command
|
||||
bool command_format_block_action(DOM::Document& document, String const& value)
|
||||
bool command_format_block_action(DOM::Document& document, Utf16View const& value)
|
||||
{
|
||||
// 1. If value begins with a "<" character and ends with a ">" character, remove the first and last characters from
|
||||
// it.
|
||||
auto resulting_value = value;
|
||||
if (resulting_value.starts_with_bytes("<"sv) && resulting_value.ends_with_bytes(">"sv))
|
||||
resulting_value = MUST(resulting_value.substring_from_byte_offset(1, resulting_value.bytes_as_string_view().length() - 2));
|
||||
auto resulting_value = Utf16String::from_utf16_without_validation(
|
||||
value.starts_with("<"sv) && value.ends_with(">"sv)
|
||||
? value.substring_view(1, value.length_in_code_units() - 2)
|
||||
: value);
|
||||
|
||||
// 2. Let value be converted to ASCII lowercase.
|
||||
resulting_value = resulting_value.to_ascii_lowercase();
|
||||
|
||||
// 3. If value is not a formattable block name, return false.
|
||||
if (!is_formattable_block_name(resulting_value))
|
||||
if (!is_formattable_block_name(resulting_value.to_utf8_but_should_be_ported_to_utf16()))
|
||||
return false;
|
||||
|
||||
// 4. Block-extend the active range, and let new range be the result.
|
||||
|
|
@ -751,7 +752,7 @@ bool command_format_block_action(DOM::Document& document, String const& value)
|
|||
auto const* html_element = as_if<HTML::HTMLElement>(*sibling);
|
||||
return html_element && html_element->local_name() == resulting_value && !html_element->has_attributes();
|
||||
},
|
||||
[&] { return MUST(DOM::create_element(document, resulting_value, Namespace::HTML)); });
|
||||
[&] { return MUST(DOM::create_element(document, resulting_value.to_utf8_but_should_be_ported_to_utf16(), Namespace::HTML)); });
|
||||
if (result)
|
||||
fix_disallowed_ancestors_of_node(*result);
|
||||
}
|
||||
|
|
@ -820,7 +821,7 @@ bool command_format_block_indeterminate(DOM::Document const& document)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-formatblock-command
|
||||
String command_format_block_value(DOM::Document const& document)
|
||||
Utf16String command_format_block_value(DOM::Document const& document)
|
||||
{
|
||||
// 1. If the active range is null, return the empty string.
|
||||
auto range = active_range(document);
|
||||
|
|
@ -862,7 +863,7 @@ String command_format_block_value(DOM::Document const& document)
|
|||
return TraversalDecision::Continue;
|
||||
});
|
||||
if (!is_ancestor_of_prohibited_paragraph_child)
|
||||
return html_element->local_name().to_string().to_ascii_lowercase();
|
||||
return Utf16String::from_utf8(html_element->local_name().to_string().to_ascii_lowercase());
|
||||
}
|
||||
|
||||
// 6. Return the empty string.
|
||||
|
|
@ -870,7 +871,7 @@ String command_format_block_value(DOM::Document const& document)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-forwarddelete-command
|
||||
bool command_forward_delete_action(DOM::Document& document, String const&)
|
||||
bool command_forward_delete_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// 1. If the active range is not collapsed, delete the selection and return true.
|
||||
auto& selection = *document.get_selection();
|
||||
|
|
@ -1061,7 +1062,7 @@ bool command_forward_delete_action(DOM::Document& document, String const&)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-indent-command
|
||||
bool command_indent_action(DOM::Document& document, String const&)
|
||||
bool command_indent_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// 1. Let items be a list of all lis that are inclusive ancestors of the active range's start and/or end node.
|
||||
Vector<GC::Ref<DOM::Node>> items;
|
||||
|
|
@ -1136,7 +1137,7 @@ bool command_indent_action(DOM::Document& document, String const&)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-inserthorizontalrule-command
|
||||
bool command_insert_horizontal_rule_action(DOM::Document& document, String const&)
|
||||
bool command_insert_horizontal_rule_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// 1. Let start node, start offset, end node, and end offset be the active range's start and end nodes and offsets.
|
||||
auto range = active_range(document);
|
||||
|
|
@ -1205,7 +1206,7 @@ bool command_insert_horizontal_rule_action(DOM::Document& document, String const
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-inserthtml-command
|
||||
bool command_insert_html_action(DOM::Document& document, String const& value)
|
||||
bool command_insert_html_action(DOM::Document& document, Utf16View const& value)
|
||||
{
|
||||
// FIXME: 1. Set value to the result of invoking get trusted types compliant string with TrustedHTML, this's relevant
|
||||
// global object, value, "Document execCommand", and "script".
|
||||
|
|
@ -1221,7 +1222,7 @@ bool command_insert_html_action(DOM::Document& document, String const& value)
|
|||
return true;
|
||||
|
||||
// 4. Let frag be the result of calling createContextualFragment(value) on the active range.
|
||||
auto frag = MUST(range->create_contextual_fragment(resulting_value));
|
||||
auto frag = MUST(range->create_contextual_fragment(resulting_value.to_utf8_but_should_be_ported_to_utf16()));
|
||||
|
||||
// 5. Let last child be the lastChild of frag.
|
||||
GC::Ptr<DOM::Node> last_child = frag->last_child();
|
||||
|
|
@ -1277,7 +1278,7 @@ bool command_insert_html_action(DOM::Document& document, String const& value)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-insertimage-command
|
||||
bool command_insert_image_action(DOM::Document& document, String const& value)
|
||||
bool command_insert_image_action(DOM::Document& document, Utf16View const& value)
|
||||
{
|
||||
// 1. If value is the empty string, return false.
|
||||
if (value.is_empty())
|
||||
|
|
@ -1305,7 +1306,7 @@ bool command_insert_image_action(DOM::Document& document, String const& value)
|
|||
auto img = MUST(DOM::create_element(document, HTML::TagNames::img, Namespace::HTML));
|
||||
|
||||
// 7. Run setAttribute("src", value) on img.
|
||||
MUST(img->set_attribute(HTML::AttributeNames::src, value));
|
||||
MUST(img->set_attribute(HTML::AttributeNames::src, value.to_utf8_but_should_be_ported_to_utf16()));
|
||||
|
||||
// 8. Run insertNode(img) on range.
|
||||
MUST(range->insert_node(img));
|
||||
|
|
@ -1322,7 +1323,7 @@ bool command_insert_image_action(DOM::Document& document, String const& value)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-insertlinebreak-command
|
||||
bool command_insert_linebreak_action(DOM::Document& document, String const&)
|
||||
bool command_insert_linebreak_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// 1. Delete the selection, with strip wrappers false.
|
||||
auto& selection = *document.get_selection();
|
||||
|
|
@ -1396,7 +1397,7 @@ bool command_insert_linebreak_action(DOM::Document& document, String const&)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-insertorderedlist-command
|
||||
bool command_insert_ordered_list_action(DOM::Document& document, String const&)
|
||||
bool command_insert_ordered_list_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// Toggle lists with tag name "ol", then return true.
|
||||
toggle_lists(document, HTML::TagNames::ol);
|
||||
|
|
@ -1418,7 +1419,7 @@ bool command_insert_ordered_list_state(DOM::Document const& document)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-insertparagraph-command
|
||||
bool command_insert_paragraph_action(DOM::Document& document, String const&)
|
||||
bool command_insert_paragraph_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// 1. Delete the selection.
|
||||
auto& selection = *document.get_selection();
|
||||
|
|
@ -1729,7 +1730,7 @@ bool command_insert_paragraph_action(DOM::Document& document, String const&)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-inserttext-command
|
||||
bool command_insert_text_action(DOM::Document& document, String const& value)
|
||||
bool command_insert_text_action(DOM::Document& document, Utf16View const& value)
|
||||
{
|
||||
// 1. Delete the selection, with strip wrappers false.
|
||||
auto& selection = *document.get_selection();
|
||||
|
|
@ -1741,10 +1742,10 @@ bool command_insert_text_action(DOM::Document& document, String const& value)
|
|||
return true;
|
||||
|
||||
// 3. If value's length is greater than one:
|
||||
if (value.code_points().length() > 1) {
|
||||
if (value.length_in_code_units() > 1) {
|
||||
// 1. For each code unit el in value, take the action for the insertText command, with value equal to el.
|
||||
for (auto el : value.code_points())
|
||||
take_the_action_for_command(document, CommandNames::insertText, String::from_code_point(el));
|
||||
for (size_t i = 0; i < value.length_in_code_units(); ++i)
|
||||
take_the_action_for_command(document, CommandNames::insertText, value.substring_view(i, 1));
|
||||
|
||||
// 2. Return true.
|
||||
return true;
|
||||
|
|
@ -1795,7 +1796,7 @@ bool command_insert_text_action(DOM::Document& document, String const& value)
|
|||
// 13. If node is a Text node:
|
||||
if (is<DOM::Text>(*node)) {
|
||||
// 1. Call insertData(offset, value) on node.
|
||||
MUST(static_cast<DOM::Text&>(*node).insert_data(offset, value));
|
||||
MUST(static_cast<DOM::Text&>(*node).insert_data(offset, value.to_utf8_but_should_be_ported_to_utf16()));
|
||||
|
||||
// 2. Call collapse(node, offset) on the context object's selection.
|
||||
MUST(selection.collapse(node, offset));
|
||||
|
|
@ -1811,7 +1812,7 @@ bool command_insert_text_action(DOM::Document& document, String const& value)
|
|||
node->first_child()->remove();
|
||||
|
||||
// 2. Let text be the result of calling createTextNode(value) on the context object.
|
||||
auto text = document.create_text_node(value);
|
||||
auto text = document.create_text_node(value.to_utf8_but_should_be_ported_to_utf16());
|
||||
|
||||
// 3. Call insertNode(text) on the active range.
|
||||
MUST(active_range(document)->insert_node(text));
|
||||
|
|
@ -1844,7 +1845,7 @@ bool command_insert_text_action(DOM::Document& document, String const& value)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-insertunorderedlist-command
|
||||
bool command_insert_unordered_list_action(DOM::Document& document, String const&)
|
||||
bool command_insert_unordered_list_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// Toggle lists with tag name "ul", then return true.
|
||||
toggle_lists(document, HTML::TagNames::ul);
|
||||
|
|
@ -1866,16 +1867,16 @@ bool command_insert_unordered_list_state(DOM::Document const& document)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-italic-command
|
||||
bool command_italic_action(DOM::Document& document, String const&)
|
||||
bool command_italic_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// If queryCommandState("italic") returns true, set the selection's value to "normal".
|
||||
if (MUST(document.query_command_state(CommandNames::italic))) {
|
||||
set_the_selections_value(document, CommandNames::italic, "normal"_string);
|
||||
set_the_selections_value(document, CommandNames::italic, u"normal"sv);
|
||||
}
|
||||
|
||||
// Otherwise set the selection's value to "italic".
|
||||
else {
|
||||
set_the_selections_value(document, CommandNames::italic, "italic"_string);
|
||||
set_the_selections_value(document, CommandNames::italic, u"italic"sv);
|
||||
}
|
||||
|
||||
// Either way, return true.
|
||||
|
|
@ -1933,7 +1934,7 @@ static bool justify_state(DOM::Document const& document, JustifyAlignment alignm
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-justifycenter-command
|
||||
static String justify_value(DOM::Document const& document)
|
||||
static Utf16String justify_value(DOM::Document const& document)
|
||||
{
|
||||
// NOTE: This definition is taken from the "justifyCenter" spec and was made generic.
|
||||
|
||||
|
|
@ -1961,7 +1962,7 @@ static String justify_value(DOM::Document const& document)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-justifycenter-command
|
||||
bool command_justify_center_action(DOM::Document& document, String const&)
|
||||
bool command_justify_center_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// Justify the selection with alignment "center", then return true.
|
||||
justify_the_selection(document, JustifyAlignment::Center);
|
||||
|
|
@ -1981,13 +1982,13 @@ bool command_justify_center_state(DOM::Document const& document)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-justifycenter-command
|
||||
String command_justify_center_value(DOM::Document const& document)
|
||||
Utf16String command_justify_center_value(DOM::Document const& document)
|
||||
{
|
||||
return justify_value(document);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-justifyfull-command
|
||||
bool command_justify_full_action(DOM::Document& document, String const&)
|
||||
bool command_justify_full_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// Justify the selection with alignment "justify", then return true.
|
||||
justify_the_selection(document, JustifyAlignment::Justify);
|
||||
|
|
@ -2007,13 +2008,13 @@ bool command_justify_full_state(DOM::Document const& document)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-justifyfull-command
|
||||
String command_justify_full_value(DOM::Document const& document)
|
||||
Utf16String command_justify_full_value(DOM::Document const& document)
|
||||
{
|
||||
return justify_value(document);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-justifyleft-command
|
||||
bool command_justify_left_action(DOM::Document& document, String const&)
|
||||
bool command_justify_left_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// Justify the selection with alignment "left", then return true.
|
||||
justify_the_selection(document, JustifyAlignment::Left);
|
||||
|
|
@ -2033,13 +2034,13 @@ bool command_justify_left_state(DOM::Document const& document)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-justifyleft-command
|
||||
String command_justify_left_value(DOM::Document const& document)
|
||||
Utf16String command_justify_left_value(DOM::Document const& document)
|
||||
{
|
||||
return justify_value(document);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-justifyright-command
|
||||
bool command_justify_right_action(DOM::Document& document, String const&)
|
||||
bool command_justify_right_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// Justify the selection with alignment "right", then return true.
|
||||
justify_the_selection(document, JustifyAlignment::Right);
|
||||
|
|
@ -2059,13 +2060,13 @@ bool command_justify_right_state(DOM::Document const& document)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-justifyright-command
|
||||
String command_justify_right_value(DOM::Document const& document)
|
||||
Utf16String command_justify_right_value(DOM::Document const& document)
|
||||
{
|
||||
return justify_value(document);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-outdent-command
|
||||
bool command_outdent_action(DOM::Document& document, String const&)
|
||||
bool command_outdent_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// 1. Let items be a list of all lis that are inclusive ancestors of the active range's start and/or end node.
|
||||
Vector<GC::Ref<DOM::Node>> items;
|
||||
|
|
@ -2156,7 +2157,7 @@ bool command_outdent_action(DOM::Document& document, String const&)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-removeformat-command
|
||||
bool command_remove_format_action(DOM::Document& document, String const&)
|
||||
bool command_remove_format_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// 1. Let elements to remove be a list of every removeFormat candidate effectively contained in the active range.
|
||||
Vector<GC::Ref<DOM::Element>> elements_to_remove;
|
||||
|
|
@ -2231,7 +2232,7 @@ bool command_remove_format_action(DOM::Document& document, String const&)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-selectall-command
|
||||
bool command_select_all_action(DOM::Document& document, String const&)
|
||||
bool command_select_all_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// NOTE: The spec mentions "This is totally broken". So fair warning :^)
|
||||
|
||||
|
|
@ -2258,7 +2259,7 @@ bool command_select_all_action(DOM::Document& document, String const&)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-strikethrough-command
|
||||
bool command_strikethrough_action(DOM::Document& document, String const&)
|
||||
bool command_strikethrough_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// If queryCommandState("strikethrough") returns true, set the selection's value to null.
|
||||
if (MUST(document.query_command_state(CommandNames::strikethrough))) {
|
||||
|
|
@ -2267,7 +2268,7 @@ bool command_strikethrough_action(DOM::Document& document, String const&)
|
|||
|
||||
// Otherwise set the selection's value to "line-through".
|
||||
else {
|
||||
set_the_selections_value(document, CommandNames::strikethrough, "line-through"_string);
|
||||
set_the_selections_value(document, CommandNames::strikethrough, u"line-through"sv);
|
||||
}
|
||||
|
||||
// Either way, return true.
|
||||
|
|
@ -2275,7 +2276,7 @@ bool command_strikethrough_action(DOM::Document& document, String const&)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-stylewithcss-command
|
||||
bool command_style_with_css_action(DOM::Document& document, String const& value)
|
||||
bool command_style_with_css_action(DOM::Document& document, Utf16View const& value)
|
||||
{
|
||||
// If value is an ASCII case-insensitive match for the string "false", set the CSS styling flag to false.
|
||||
// Otherwise, set the CSS styling flag to true.
|
||||
|
|
@ -2293,7 +2294,7 @@ bool command_style_with_css_state(DOM::Document const& document)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-subscript-command
|
||||
bool command_subscript_action(DOM::Document& document, String const&)
|
||||
bool command_subscript_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// 1. Call queryCommandState("subscript"), and let state be the result.
|
||||
auto state = MUST(document.query_command_state(CommandNames::subscript));
|
||||
|
|
@ -2303,7 +2304,7 @@ bool command_subscript_action(DOM::Document& document, String const&)
|
|||
|
||||
// 3. If state is false, set the selection's value to "subscript".
|
||||
if (!state)
|
||||
set_the_selections_value(document, CommandNames::subscript, "subscript"_string);
|
||||
set_the_selections_value(document, CommandNames::subscript, u"subscript"sv);
|
||||
|
||||
// 4. Return true.
|
||||
return true;
|
||||
|
|
@ -2346,7 +2347,7 @@ bool command_subscript_indeterminate(DOM::Document const& document)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-superscript-command
|
||||
bool command_superscript_action(DOM::Document& document, String const&)
|
||||
bool command_superscript_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// 1. Call queryCommandState("superscript"), and let state be the result.
|
||||
auto state = MUST(document.query_command_state(CommandNames::superscript));
|
||||
|
|
@ -2356,7 +2357,7 @@ bool command_superscript_action(DOM::Document& document, String const&)
|
|||
|
||||
// 3. If state is false, set the selection's value to "superscript".
|
||||
if (!state)
|
||||
set_the_selections_value(document, CommandNames::superscript, "superscript"_string);
|
||||
set_the_selections_value(document, CommandNames::superscript, u"superscript"sv);
|
||||
|
||||
// 4. Return true.
|
||||
return true;
|
||||
|
|
@ -2399,7 +2400,7 @@ bool command_superscript_indeterminate(DOM::Document const& document)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-underline-command
|
||||
bool command_underline_action(DOM::Document& document, String const&)
|
||||
bool command_underline_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// If queryCommandState("underline") returns true, set the selection's value to null.
|
||||
if (MUST(document.query_command_state(CommandNames::underline))) {
|
||||
|
|
@ -2408,7 +2409,7 @@ bool command_underline_action(DOM::Document& document, String const&)
|
|||
|
||||
// Otherwise set the selection's value to "underline".
|
||||
else {
|
||||
set_the_selections_value(document, CommandNames::underline, "underline"_string);
|
||||
set_the_selections_value(document, CommandNames::underline, u"underline"sv);
|
||||
}
|
||||
|
||||
// Either way, return true.
|
||||
|
|
@ -2416,7 +2417,7 @@ bool command_underline_action(DOM::Document& document, String const&)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-unlink-command
|
||||
bool command_unlink_action(DOM::Document& document, String const&)
|
||||
bool command_unlink_action(DOM::Document& document, Utf16View const&)
|
||||
{
|
||||
// 1. Let hyperlinks be a list of every a element that has an href attribute and is contained in the active range or
|
||||
// is an ancestor of one of its boundary points.
|
||||
|
|
@ -2451,7 +2452,7 @@ bool command_unlink_action(DOM::Document& document, String const&)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#the-usecss-command
|
||||
bool command_use_css_action(DOM::Document& document, String const& value)
|
||||
bool command_use_css_action(DOM::Document& document, Utf16View const& value)
|
||||
{
|
||||
// If value is an ASCII case-insensitive match for the string "false", set the CSS styling flag to true.
|
||||
// Otherwise, set the CSS styling flag to false.
|
||||
|
|
|
|||
|
|
@ -13,17 +13,17 @@ namespace Web::Editing {
|
|||
// https://w3c.github.io/editing/docs/execCommand/#properties-of-commands
|
||||
struct CommandDefinition {
|
||||
FlyString const& command;
|
||||
Function<bool(DOM::Document&, String const&)> action {};
|
||||
Function<bool(DOM::Document&, Utf16View const&)> action {};
|
||||
Function<bool(DOM::Document const&)> indeterminate {};
|
||||
Function<bool(DOM::Document const&)> state {};
|
||||
Function<String(DOM::Document const&)> value {};
|
||||
Function<Utf16String(DOM::Document const&)> value {};
|
||||
Optional<CSS::PropertyID> relevant_css_property {};
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#preserves-overrides
|
||||
bool preserves_overrides { false };
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#inline-command-activated-values
|
||||
Vector<StringView> inline_activated_values {};
|
||||
Vector<Utf16View> inline_activated_values {};
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#dfn-map-an-edit-command-to-input-type-value
|
||||
FlyString mapped_value {};
|
||||
|
|
@ -32,62 +32,62 @@ struct CommandDefinition {
|
|||
Optional<CommandDefinition const&> find_command_definition(FlyString const&);
|
||||
|
||||
// Command implementations
|
||||
bool command_back_color_action(DOM::Document&, String const&);
|
||||
bool command_bold_action(DOM::Document&, String const&);
|
||||
bool command_create_link_action(DOM::Document&, String const&);
|
||||
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_fore_color_action(DOM::Document&, String const&);
|
||||
bool command_format_block_action(DOM::Document&, String const&);
|
||||
bool command_back_color_action(DOM::Document&, Utf16View const&);
|
||||
bool command_bold_action(DOM::Document&, Utf16View const&);
|
||||
bool command_create_link_action(DOM::Document&, Utf16View const&);
|
||||
bool command_default_paragraph_separator_action(DOM::Document&, Utf16View const&);
|
||||
Utf16String command_default_paragraph_separator_value(DOM::Document const&);
|
||||
bool command_delete_action(DOM::Document&, Utf16View const&);
|
||||
bool command_font_name_action(DOM::Document&, Utf16View const&);
|
||||
bool command_font_size_action(DOM::Document&, Utf16View const&);
|
||||
Utf16String command_font_size_value(DOM::Document const&);
|
||||
bool command_fore_color_action(DOM::Document&, Utf16View const&);
|
||||
bool command_format_block_action(DOM::Document&, Utf16View const&);
|
||||
bool command_format_block_indeterminate(DOM::Document const&);
|
||||
String command_format_block_value(DOM::Document const&);
|
||||
bool command_forward_delete_action(DOM::Document&, String const&);
|
||||
bool command_indent_action(DOM::Document&, String const&);
|
||||
bool command_insert_horizontal_rule_action(DOM::Document&, String const&);
|
||||
bool command_insert_html_action(DOM::Document&, String const&);
|
||||
bool command_insert_image_action(DOM::Document&, String const&);
|
||||
bool command_insert_linebreak_action(DOM::Document&, String const&);
|
||||
bool command_insert_ordered_list_action(DOM::Document&, String const&);
|
||||
Utf16String command_format_block_value(DOM::Document const&);
|
||||
bool command_forward_delete_action(DOM::Document&, Utf16View const&);
|
||||
bool command_indent_action(DOM::Document&, Utf16View const&);
|
||||
bool command_insert_horizontal_rule_action(DOM::Document&, Utf16View const&);
|
||||
bool command_insert_html_action(DOM::Document&, Utf16View const&);
|
||||
bool command_insert_image_action(DOM::Document&, Utf16View const&);
|
||||
bool command_insert_linebreak_action(DOM::Document&, Utf16View const&);
|
||||
bool command_insert_ordered_list_action(DOM::Document&, Utf16View const&);
|
||||
bool command_insert_ordered_list_indeterminate(DOM::Document const&);
|
||||
bool command_insert_ordered_list_state(DOM::Document const&);
|
||||
bool command_insert_paragraph_action(DOM::Document&, String const&);
|
||||
bool command_insert_text_action(DOM::Document&, String const&);
|
||||
bool command_insert_unordered_list_action(DOM::Document&, String const&);
|
||||
bool command_insert_paragraph_action(DOM::Document&, Utf16View const&);
|
||||
bool command_insert_text_action(DOM::Document&, Utf16View const&);
|
||||
bool command_insert_unordered_list_action(DOM::Document&, Utf16View const&);
|
||||
bool command_insert_unordered_list_indeterminate(DOM::Document const&);
|
||||
bool command_insert_unordered_list_state(DOM::Document const&);
|
||||
bool command_italic_action(DOM::Document&, String const&);
|
||||
bool command_justify_center_action(DOM::Document&, String const&);
|
||||
bool command_italic_action(DOM::Document&, Utf16View const&);
|
||||
bool command_justify_center_action(DOM::Document&, Utf16View const&);
|
||||
bool command_justify_center_indeterminate(DOM::Document const&);
|
||||
bool command_justify_center_state(DOM::Document const&);
|
||||
String command_justify_center_value(DOM::Document const&);
|
||||
bool command_justify_full_action(DOM::Document&, String const&);
|
||||
Utf16String command_justify_center_value(DOM::Document const&);
|
||||
bool command_justify_full_action(DOM::Document&, Utf16View const&);
|
||||
bool command_justify_full_indeterminate(DOM::Document const&);
|
||||
bool command_justify_full_state(DOM::Document const&);
|
||||
String command_justify_full_value(DOM::Document const&);
|
||||
bool command_justify_left_action(DOM::Document&, String const&);
|
||||
Utf16String command_justify_full_value(DOM::Document const&);
|
||||
bool command_justify_left_action(DOM::Document&, Utf16View const&);
|
||||
bool command_justify_left_indeterminate(DOM::Document const&);
|
||||
bool command_justify_left_state(DOM::Document const&);
|
||||
String command_justify_left_value(DOM::Document const&);
|
||||
bool command_justify_right_action(DOM::Document&, String const&);
|
||||
Utf16String command_justify_left_value(DOM::Document const&);
|
||||
bool command_justify_right_action(DOM::Document&, Utf16View const&);
|
||||
bool command_justify_right_indeterminate(DOM::Document const&);
|
||||
bool command_justify_right_state(DOM::Document const&);
|
||||
String command_justify_right_value(DOM::Document const&);
|
||||
bool command_outdent_action(DOM::Document&, String const&);
|
||||
bool command_remove_format_action(DOM::Document&, String const&);
|
||||
bool command_select_all_action(DOM::Document&, String const&);
|
||||
bool command_strikethrough_action(DOM::Document&, String const&);
|
||||
bool command_style_with_css_action(DOM::Document&, String const&);
|
||||
Utf16String command_justify_right_value(DOM::Document const&);
|
||||
bool command_outdent_action(DOM::Document&, Utf16View const&);
|
||||
bool command_remove_format_action(DOM::Document&, Utf16View const&);
|
||||
bool command_select_all_action(DOM::Document&, Utf16View const&);
|
||||
bool command_strikethrough_action(DOM::Document&, Utf16View const&);
|
||||
bool command_style_with_css_action(DOM::Document&, Utf16View const&);
|
||||
bool command_style_with_css_state(DOM::Document const&);
|
||||
bool command_subscript_action(DOM::Document&, String const&);
|
||||
bool command_subscript_action(DOM::Document&, Utf16View const&);
|
||||
bool command_subscript_indeterminate(DOM::Document const&);
|
||||
bool command_superscript_action(DOM::Document&, String const&);
|
||||
bool command_superscript_action(DOM::Document&, Utf16View const&);
|
||||
bool command_superscript_indeterminate(DOM::Document const&);
|
||||
bool command_underline_action(DOM::Document&, String const&);
|
||||
bool command_unlink_action(DOM::Document&, String const&);
|
||||
bool command_use_css_action(DOM::Document&, String const&);
|
||||
bool command_underline_action(DOM::Document&, Utf16View const&);
|
||||
bool command_unlink_action(DOM::Document&, Utf16View const&);
|
||||
bool command_use_css_action(DOM::Document&, Utf16View const&);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,7 +101,8 @@ WebIDL::ExceptionOr<bool> Document::exec_command(FlyString const& command, [[may
|
|||
auto old_character_data_version = character_data_version();
|
||||
|
||||
// 5. Take the action for command, passing value to the instructions as an argument.
|
||||
auto command_result = command_definition.action(*this, value);
|
||||
auto utf16_value = Utf16String::from_utf8_without_validation(value);
|
||||
auto command_result = command_definition.action(*this, utf16_value.utf16_view());
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#preserves-overrides
|
||||
// After taking the action, if the active range is collapsed, it must restore states and values from the recorded
|
||||
|
|
@ -249,7 +250,7 @@ WebIDL::ExceptionOr<bool> Document::query_command_indeterm(FlyString const& comm
|
|||
// effectively contained in the active range, there are two that have distinct effective command values.
|
||||
if (command_definition.command.is_one_of(Editing::CommandNames::backColor, Editing::CommandNames::fontName,
|
||||
Editing::CommandNames::foreColor, Editing::CommandNames::hiliteColor)) {
|
||||
Optional<String> first_node_value;
|
||||
Optional<Utf16String> first_node_value;
|
||||
auto range = Editing::active_range(*this);
|
||||
bool has_distinct_values = false;
|
||||
Editing::for_each_node_effectively_contained_in_range(range, [&](GC::Ref<Node> descendant) {
|
||||
|
|
@ -390,19 +391,19 @@ WebIDL::ExceptionOr<String> Document::query_command_value(FlyString const& comma
|
|||
// integer number of pixels and return the legacy font size for the result.
|
||||
if (command_definition.command == Editing::CommandNames::fontSize && value_override.has_value()) {
|
||||
auto pixel_size = Editing::font_size_to_pixel_size(value_override.release_value());
|
||||
return Editing::legacy_font_size(pixel_size.to_int());
|
||||
return Editing::legacy_font_size(pixel_size.to_int()).to_utf8_but_should_be_ported_to_utf16();
|
||||
}
|
||||
|
||||
// 3. If the value override for command is set, return it.
|
||||
if (value_override.has_value())
|
||||
return value_override.release_value();
|
||||
return value_override.release_value().to_utf8_but_should_be_ported_to_utf16();
|
||||
|
||||
// 4. Return command's value.
|
||||
return command_definition.value(*this);
|
||||
return command_definition.value(*this).to_utf8_but_should_be_ported_to_utf16();
|
||||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#value-override
|
||||
void Document::set_command_value_override(FlyString const& command, String const& value)
|
||||
void Document::set_command_value_override(FlyString const& command, Utf16String const& value)
|
||||
{
|
||||
m_command_value_override.set(command, value);
|
||||
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ void autolink(DOM::BoundaryPoint point)
|
|||
// characters.
|
||||
|
||||
// FIXME: 4. If some substring of search is an autolinkable URL:
|
||||
String href;
|
||||
Utf16String href;
|
||||
if (false) {
|
||||
// FIXME: 1. While there is no substring of node's data ending at end offset that is an autolinkable URL, decrement end
|
||||
// offset.
|
||||
|
|
@ -267,7 +267,7 @@ GC::Ptr<DOM::Node> block_node_of_node(GC::Ref<DOM::Node> input_node)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#canonical-space-sequence
|
||||
String canonical_space_sequence(u32 length, bool non_breaking_start, bool non_breaking_end)
|
||||
Utf16String canonical_space_sequence(size_t length, bool non_breaking_start, bool non_breaking_end)
|
||||
{
|
||||
auto n = length;
|
||||
|
||||
|
|
@ -278,14 +278,14 @@ String canonical_space_sequence(u32 length, bool non_breaking_start, bool non_br
|
|||
// 2. If n is one and both non-breaking start and non-breaking end are false, return a single
|
||||
// space (U+0020).
|
||||
if (n == 1 && !non_breaking_start && !non_breaking_end)
|
||||
return " "_string;
|
||||
return " "_utf16;
|
||||
|
||||
// 3. If n is one, return a single non-breaking space (U+00A0).
|
||||
if (n == 1)
|
||||
return "\u00A0"_string;
|
||||
return "\u00A0"_utf16;
|
||||
|
||||
// 4. Let buffer be the empty string.
|
||||
StringBuilder buffer;
|
||||
StringBuilder buffer { StringBuilder::Mode::UTF16 };
|
||||
|
||||
// 5. If non-breaking start is true, let repeated pair be U+00A0 U+0020. Otherwise, let it be
|
||||
// U+0020 U+00A0.
|
||||
|
|
@ -338,7 +338,7 @@ String canonical_space_sequence(u32 length, bool non_breaking_start, bool non_br
|
|||
buffer.append(non_breaking_end ? "\u00A0"sv : " "sv);
|
||||
|
||||
// 9. Return buffer.
|
||||
return MUST(buffer.to_string());
|
||||
return buffer.to_utf16_string();
|
||||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#canonicalize-whitespace
|
||||
|
|
@ -530,6 +530,7 @@ void canonicalize_whitespace(DOM::BoundaryPoint boundary, bool fix_collapsed_spa
|
|||
length,
|
||||
(start_offset == 0 && follows_a_line_break(start_node)) || length > 1,
|
||||
end_offset == end_node->length() && precedes_a_line_break(end_node));
|
||||
auto replacement_whitespace_view = replacement_whitespace.utf16_view();
|
||||
|
||||
// 10. While (start node, start offset) is before (end node, end offset):
|
||||
while (true) {
|
||||
|
|
@ -555,10 +556,8 @@ void canonicalize_whitespace(DOM::BoundaryPoint boundary, bool fix_collapsed_spa
|
|||
else {
|
||||
// 1. Remove the first code unit from replacement whitespace, and let element be that
|
||||
// code unit.
|
||||
// FIXME: Find a way to get code points directly from the UTF-8 string
|
||||
auto replacement_whitespace_utf16 = Utf16String::from_utf8(replacement_whitespace);
|
||||
replacement_whitespace = MUST(replacement_whitespace_utf16.substring_view(1).to_utf8());
|
||||
auto element = replacement_whitespace_utf16.code_point_at(0);
|
||||
auto element = replacement_whitespace_view.code_unit_at(0);
|
||||
replacement_whitespace_view = replacement_whitespace_view.substring_view(1);
|
||||
|
||||
// 2. If element is not the same as the start offsetth code unit of start node's data:
|
||||
auto start_node_data = Utf16String::from_utf8(*start_node->text_content());
|
||||
|
|
@ -1135,7 +1134,7 @@ GC::Ptr<DOM::Node> editing_host_of_node(GC::Ref<DOM::Node> node)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#effective-command-value
|
||||
Optional<String> effective_command_value(GC::Ptr<DOM::Node> node, FlyString const& command)
|
||||
Optional<Utf16String> effective_command_value(GC::Ptr<DOM::Node> node, FlyString const& command)
|
||||
{
|
||||
VERIFY(node);
|
||||
|
||||
|
|
@ -1159,7 +1158,7 @@ Optional<String> effective_command_value(GC::Ptr<DOM::Node> node, FlyString cons
|
|||
return {};
|
||||
|
||||
// 3. Return the value of node's href attribute.
|
||||
return node_as_element()->get_attribute_value(HTML::AttributeNames::href);
|
||||
return Utf16String::from_utf8_without_validation(node_as_element()->get_attribute_value(HTML::AttributeNames::href));
|
||||
}
|
||||
|
||||
// 4. If command is "backColor" or "hiliteColor":
|
||||
|
|
@ -1182,7 +1181,7 @@ Optional<String> effective_command_value(GC::Ptr<DOM::Node> node, FlyString cons
|
|||
auto resolved_value = resolved_background_color();
|
||||
if (!resolved_value.has_value())
|
||||
return {};
|
||||
return resolved_value.value()->to_string(CSS::SerializationMode::ResolvedValue);
|
||||
return Utf16String::from_utf8_without_validation(resolved_value.value()->to_string(CSS::SerializationMode::ResolvedValue));
|
||||
}
|
||||
|
||||
// 5. If command is "subscript" or "superscript":
|
||||
|
|
@ -1209,15 +1208,15 @@ Optional<String> effective_command_value(GC::Ptr<DOM::Node> node, FlyString cons
|
|||
|
||||
// 3. If affected by subscript and affected by superscript are both true, return the string "mixed".
|
||||
if (affected_by_subscript && affected_by_superscript)
|
||||
return "mixed"_string;
|
||||
return "mixed"_utf16;
|
||||
|
||||
// 4. If affected by subscript is true, return "subscript".
|
||||
if (affected_by_subscript)
|
||||
return "subscript"_string;
|
||||
return "subscript"_utf16;
|
||||
|
||||
// 5. If affected by superscript is true, return "superscript".
|
||||
if (affected_by_superscript)
|
||||
return "superscript"_string;
|
||||
return "superscript"_utf16;
|
||||
|
||||
// 6. Return null.
|
||||
return {};
|
||||
|
|
@ -1230,7 +1229,7 @@ Optional<String> effective_command_value(GC::Ptr<DOM::Node> node, FlyString cons
|
|||
do {
|
||||
auto text_decoration_line = resolved_value(*node, CSS::PropertyID::TextDecorationLine);
|
||||
if (text_decoration_line.has_value() && value_contains_keyword(text_decoration_line.value(), CSS::Keyword::LineThrough))
|
||||
return "line-through"_string;
|
||||
return "line-through"_utf16;
|
||||
inclusive_ancestor = inclusive_ancestor->parent();
|
||||
} while (inclusive_ancestor);
|
||||
|
||||
|
|
@ -1244,7 +1243,7 @@ Optional<String> effective_command_value(GC::Ptr<DOM::Node> node, FlyString cons
|
|||
do {
|
||||
auto text_decoration_line = resolved_value(*node, CSS::PropertyID::TextDecorationLine);
|
||||
if (text_decoration_line.has_value() && value_contains_keyword(text_decoration_line.value(), CSS::Keyword::Underline))
|
||||
return "underline"_string;
|
||||
return "underline"_utf16;
|
||||
inclusive_ancestor = inclusive_ancestor->parent();
|
||||
} while (inclusive_ancestor);
|
||||
|
||||
|
|
@ -1258,7 +1257,7 @@ Optional<String> effective_command_value(GC::Ptr<DOM::Node> node, FlyString cons
|
|||
auto optional_value = resolved_value(*node, command_definition.relevant_css_property.value());
|
||||
if (!optional_value.has_value())
|
||||
return {};
|
||||
return optional_value.value()->to_string(CSS::SerializationMode::ResolvedValue);
|
||||
return Utf16String::from_utf8_without_validation(optional_value.value()->to_string(CSS::SerializationMode::ResolvedValue));
|
||||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#first-equivalent-point
|
||||
|
|
@ -1390,7 +1389,7 @@ bool follows_a_line_break(GC::Ref<DOM::Node> node)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#force-the-value
|
||||
void force_the_value(GC::Ref<DOM::Node> node, FlyString const& command, Optional<String> new_value)
|
||||
void force_the_value(GC::Ref<DOM::Node> node, FlyString const& command, Optional<Utf16View const&> new_value)
|
||||
{
|
||||
// 1. Let command be the current command.
|
||||
|
||||
|
|
@ -1403,14 +1402,17 @@ void force_the_value(GC::Ref<DOM::Node> node, FlyString const& command, Optional
|
|||
return;
|
||||
|
||||
// 4. If node is an allowed child of "span":
|
||||
auto new_value_string = new_value.map([](Utf16View const& view) {
|
||||
return Utf16String::from_utf16_without_validation(view);
|
||||
});
|
||||
if (is_allowed_child_of_node(node, HTML::TagNames::span)) {
|
||||
// 1. Reorder modifiable descendants of node's previousSibling.
|
||||
if (node->previous_sibling())
|
||||
reorder_modifiable_descendants(*node->previous_sibling(), command, new_value);
|
||||
reorder_modifiable_descendants(*node->previous_sibling(), command, new_value_string);
|
||||
|
||||
// 2. Reorder modifiable descendants of node's nextSibling.
|
||||
if (node->next_sibling())
|
||||
reorder_modifiable_descendants(*node->next_sibling(), command, new_value);
|
||||
reorder_modifiable_descendants(*node->next_sibling(), command, new_value_string);
|
||||
|
||||
// 3. Wrap the one-node list consisting of node, with sibling criteria returning true for a simple modifiable
|
||||
// element whose specified command value is equivalent to new value and whose effective command value is
|
||||
|
|
@ -1420,7 +1422,7 @@ void force_the_value(GC::Ref<DOM::Node> node, FlyString const& command, Optional
|
|||
[&](GC::Ref<DOM::Node> sibling) {
|
||||
return is_simple_modifiable_element(sibling)
|
||||
&& specified_command_value(static_cast<DOM::Element&>(*sibling), command) == new_value
|
||||
&& values_are_loosely_equivalent(command, effective_command_value(sibling, command), new_value);
|
||||
&& values_are_loosely_equivalent(command, effective_command_value(sibling, command), new_value_string);
|
||||
},
|
||||
[] -> GC::Ptr<DOM::Node> { return {}; });
|
||||
}
|
||||
|
|
@ -1430,7 +1432,7 @@ void force_the_value(GC::Ref<DOM::Node> node, FlyString const& command, Optional
|
|||
return;
|
||||
|
||||
// 6. If the effective command value of command is loosely equivalent to new value on node, abort this algorithm.
|
||||
if (values_are_loosely_equivalent(command, effective_command_value(node, command), new_value))
|
||||
if (values_are_loosely_equivalent(command, effective_command_value(node, command), new_value_string))
|
||||
return;
|
||||
|
||||
// 7. If node is not an allowed child of "span":
|
||||
|
|
@ -1440,8 +1442,8 @@ void force_the_value(GC::Ref<DOM::Node> node, FlyString const& command, Optional
|
|||
Vector<GC::Ref<DOM::Node>> children;
|
||||
node->for_each_child([&](GC::Ref<DOM::Node> child) {
|
||||
if (is<DOM::Element>(*child)) {
|
||||
auto const& child_specified_value = specified_command_value(static_cast<DOM::Element&>(*child), command);
|
||||
if (child_specified_value.has_value() && !values_are_equivalent(command, child_specified_value.value(), new_value))
|
||||
auto const child_specified_value = specified_command_value(static_cast<DOM::Element&>(*child), command);
|
||||
if (child_specified_value.has_value() && !values_are_equivalent(command, child_specified_value.value(), new_value_string))
|
||||
return IterationDecision::Continue;
|
||||
}
|
||||
|
||||
|
|
@ -1459,7 +1461,7 @@ void force_the_value(GC::Ref<DOM::Node> node, FlyString const& command, Optional
|
|||
}
|
||||
|
||||
// 8. If the effective command value of command is loosely equivalent to new value on node, abort this algorithm.
|
||||
if (values_are_loosely_equivalent(command, effective_command_value(node, command), new_value))
|
||||
if (values_are_loosely_equivalent(command, effective_command_value(node, command), new_value_string))
|
||||
return;
|
||||
|
||||
// 9. Let new parent be null.
|
||||
|
|
@ -1491,7 +1493,7 @@ void force_the_value(GC::Ref<DOM::Node> node, FlyString const& command, Optional
|
|||
// 5. If command is "foreColor", and new value is fully opaque with red, green, and blue components in the
|
||||
// range 0 to 255:
|
||||
if (command == CommandNames::foreColor) {
|
||||
auto new_value_color = Color::from_string(new_value.value());
|
||||
auto new_value_color = Color::from_utf16_string(new_value.value());
|
||||
if (new_value_color->alpha() == NumericLimits<u8>::max()) {
|
||||
// 1. Let new parent be the result of calling createElement("font") on the ownerDocument of node.
|
||||
new_parent = MUST(DOM::create_element(document, HTML::TagNames::font, Namespace::HTML));
|
||||
|
|
@ -1506,7 +1508,7 @@ void force_the_value(GC::Ref<DOM::Node> node, FlyString const& command, Optional
|
|||
// ownerDocument of node, then set the face attribute of new parent to new value.
|
||||
if (command == CommandNames::fontName) {
|
||||
new_parent = MUST(DOM::create_element(document, HTML::TagNames::font, Namespace::HTML));
|
||||
MUST(new_parent->set_attribute(HTML::AttributeNames::face, new_value.value()));
|
||||
MUST(new_parent->set_attribute(HTML::AttributeNames::face, new_value.value().to_utf8_but_should_be_ported_to_utf16()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1516,7 +1518,7 @@ void force_the_value(GC::Ref<DOM::Node> node, FlyString const& command, Optional
|
|||
new_parent = MUST(DOM::create_element(document, HTML::TagNames::a, Namespace::HTML));
|
||||
|
||||
// 2. Set the href attribute of new parent to new value.
|
||||
MUST(new_parent->set_attribute(HTML::AttributeNames::href, new_value.value()));
|
||||
MUST(new_parent->set_attribute(HTML::AttributeNames::href, new_value.value().to_utf8_but_should_be_ported_to_utf16()));
|
||||
|
||||
// 3. Let ancestor be node's parent.
|
||||
GC::Ptr<DOM::Node> ancestor = node->parent();
|
||||
|
|
@ -1573,11 +1575,11 @@ void force_the_value(GC::Ref<DOM::Node> node, FlyString const& command, Optional
|
|||
// 17. If the effective command value of command for new parent is not loosely equivalent to new value, and the
|
||||
// relevant CSS property for command is not null, set that CSS property of new parent to new value (if the new
|
||||
// value would be valid).
|
||||
if (!values_are_loosely_equivalent(command, effective_command_value(new_parent, command), new_value)) {
|
||||
if (!values_are_loosely_equivalent(command, effective_command_value(new_parent, command), new_value_string)) {
|
||||
auto const& command_definition = find_command_definition(command);
|
||||
if (command_definition->relevant_css_property.has_value()) {
|
||||
auto inline_style = new_parent->style_for_bindings();
|
||||
MUST(inline_style->set_property(command_definition->relevant_css_property.value(), new_value.value()));
|
||||
MUST(inline_style->set_property(command_definition->relevant_css_property.value(), new_value.value().to_utf8_but_should_be_ported_to_utf16()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1603,7 +1605,8 @@ void force_the_value(GC::Ref<DOM::Node> node, FlyString const& command, Optional
|
|||
|
||||
// 21. If node is an Element and the effective command value of command for node is not loosely equivalent to new
|
||||
// value:
|
||||
if (is<DOM::Element>(*node) && !values_are_loosely_equivalent(command, effective_command_value(node, command), new_value)) {
|
||||
if (is<DOM::Element>(*node)
|
||||
&& !values_are_loosely_equivalent(command, effective_command_value(node, command), new_value_string)) {
|
||||
// 1. Insert node into the parent of new parent before new parent, preserving ranges.
|
||||
move_node_preserving_ranges(node, *new_parent->parent(), new_parent->index());
|
||||
|
||||
|
|
@ -1616,7 +1619,7 @@ void force_the_value(GC::Ref<DOM::Node> node, FlyString const& command, Optional
|
|||
node->for_each_child([&](GC::Ref<DOM::Node> child) {
|
||||
if (is<DOM::Element>(*child)) {
|
||||
auto child_value = specified_command_value(static_cast<DOM::Element&>(*child), command);
|
||||
if (child_value.has_value() && !values_are_equivalent(command, child_value.value(), new_value))
|
||||
if (child_value.has_value() && !values_are_equivalent(command, child_value.value(), new_value_string))
|
||||
return IterationDecision::Continue;
|
||||
}
|
||||
|
||||
|
|
@ -2769,34 +2772,34 @@ DOM::BoundaryPoint last_equivalent_point(DOM::BoundaryPoint boundary_point)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#legacy-font-size-for
|
||||
String legacy_font_size(int pixel_size)
|
||||
Utf16String legacy_font_size(int pixel_size)
|
||||
{
|
||||
// 1. Let returned size be 1.
|
||||
auto returned_size = 1;
|
||||
int returned_size = 1;
|
||||
|
||||
// 2. While returned size is less than 7:
|
||||
while (returned_size < 7) {
|
||||
// 1. Let lower bound be the resolved value of "font-size" in pixels of a font element whose size attribute is
|
||||
// set to returned size.
|
||||
auto lower_bound = font_size_to_pixel_size(MUST(String::formatted("{}", returned_size))).to_float();
|
||||
auto lower_bound = font_size_to_pixel_size(Utf16String::number(returned_size)).to_float();
|
||||
|
||||
// 2. Let upper bound be the resolved value of "font-size" in pixels of a font element whose size attribute is
|
||||
// set to one plus returned size.
|
||||
auto upper_bound = font_size_to_pixel_size(MUST(String::formatted("{}", returned_size + 1))).to_float();
|
||||
auto upper_bound = font_size_to_pixel_size(Utf16String::number(returned_size + 1)).to_float();
|
||||
|
||||
// 3. Let average be the average of upper bound and lower bound.
|
||||
auto average = (lower_bound + upper_bound) / 2;
|
||||
|
||||
// 4. If pixel size is less than average, return the one-code unit string consisting of the digit returned size.
|
||||
if (pixel_size < average)
|
||||
return MUST(String::formatted("{}", returned_size));
|
||||
return Utf16String::number(returned_size);
|
||||
|
||||
// 5. Add one to returned size.
|
||||
++returned_size;
|
||||
}
|
||||
|
||||
// 3. Return "7".
|
||||
return "7"_string;
|
||||
return "7"_utf16;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#preserving-ranges
|
||||
|
|
@ -3153,7 +3156,7 @@ Optional<DOM::BoundaryPoint> previous_equivalent_point(DOM::BoundaryPoint bounda
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#push-down-values
|
||||
void push_down_values(FlyString const& command, GC::Ref<DOM::Node> node, Optional<String> new_value)
|
||||
void push_down_values(FlyString const& command, GC::Ref<DOM::Node> node, Optional<Utf16String const&> new_value)
|
||||
{
|
||||
// 1. Let command be the current command.
|
||||
|
||||
|
|
@ -3237,7 +3240,10 @@ void push_down_values(FlyString const& command, GC::Ref<DOM::Node> node, Optiona
|
|||
continue;
|
||||
|
||||
// 4. Force the value of child, with command as in this algorithm and new value equal to propagated value.
|
||||
force_the_value(*child, command, propagated_value);
|
||||
force_the_value(
|
||||
*child,
|
||||
command,
|
||||
propagated_value.map([](Utf16String const& string) { return string.utf16_view(); }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3304,7 +3310,7 @@ Vector<RecordedOverride> record_current_states_and_values(DOM::Document const& d
|
|||
// 6. For each command in the list "fontName", "foreColor", "hiliteColor", in order: add (command, command's value)
|
||||
// to overrides.
|
||||
for (auto const& command : { CommandNames::fontName, CommandNames::foreColor, CommandNames::hiliteColor })
|
||||
overrides.empend(command, MUST(node->document().query_command_value(command)));
|
||||
overrides.empend(command, Utf16String::from_utf8_without_validation(MUST(node->document().query_command_value(command))));
|
||||
|
||||
// 7. Add ("fontSize", node's effective command value for "fontSize") to overrides.
|
||||
effective_value = effective_command_value(node, CommandNames::fontSize);
|
||||
|
|
@ -3438,7 +3444,7 @@ void remove_node_preserving_its_descendants(GC::Ref<DOM::Node> node)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#reorder-modifiable-descendants
|
||||
void reorder_modifiable_descendants(GC::Ref<DOM::Node> node, FlyString const& command, Optional<String> new_value)
|
||||
void reorder_modifiable_descendants(GC::Ref<DOM::Node> node, FlyString const& command, Optional<Utf16String const&> new_value)
|
||||
{
|
||||
// 1. Let candidate equal node.
|
||||
GC::Ptr<DOM::Node> candidate = node;
|
||||
|
|
@ -3495,9 +3501,9 @@ void restore_states_and_values(DOM::Document& document, Vector<RecordedOverride>
|
|||
// 2. Otherwise, if override is a string, and command is neither "createLink" nor "fontSize", and
|
||||
// queryCommandValue(command) returns something not equivalent to override, take the action for command,
|
||||
// with value equal to override.
|
||||
else if (override.value.has<String>() && !override.command.is_one_of(CommandNames::createLink, CommandNames::fontSize)
|
||||
&& MUST(document.query_command_value(override.command)) != override.value.get<String>()) {
|
||||
take_the_action_for_command(document, override.command, override.value.get<String>());
|
||||
else if (override.value.has<Utf16String>() && !override.command.is_one_of(CommandNames::createLink, CommandNames::fontSize)
|
||||
&& MUST(document.query_command_value(override.command)) != override.value.get<Utf16String>()) {
|
||||
take_the_action_for_command(document, override.command, override.value.get<Utf16String>());
|
||||
}
|
||||
|
||||
// 3. Otherwise, if override is a string; and command is "createLink"; and either there is a value override
|
||||
|
|
@ -3505,31 +3511,31 @@ void restore_states_and_values(DOM::Document& document, Vector<RecordedOverride>
|
|||
// node's effective command value for "createLink" is not equal to override: take the action for
|
||||
// "createLink", with value equal to override.
|
||||
else if (auto value_override = document.command_value_override(CommandNames::createLink);
|
||||
override.value.has<String>() && override.command == CommandNames::createLink
|
||||
&& ((value_override.has_value() && value_override.value() != override.value.get<String>())
|
||||
override.value.has<Utf16String>() && override.command == CommandNames::createLink
|
||||
&& ((value_override.has_value() && value_override.value() != override.value.get<Utf16String>())
|
||||
|| (!value_override.has_value()
|
||||
&& effective_command_value(node, CommandNames::createLink) != override.value.get<String>()))) {
|
||||
take_the_action_for_command(document, CommandNames::createLink, override.value.get<String>());
|
||||
&& effective_command_value(node, CommandNames::createLink) != override.value.get<Utf16String>()))) {
|
||||
take_the_action_for_command(document, CommandNames::createLink, override.value.get<Utf16String>());
|
||||
}
|
||||
|
||||
// 4. Otherwise, if override is a string; and command is "fontSize"; and either there is a value override
|
||||
// for "fontSize" that is not equal to override, or there is no value override for "fontSize" and node's
|
||||
// effective command value for "fontSize" is not loosely equivalent to override:
|
||||
else if (auto value_override = document.command_value_override(CommandNames::fontSize);
|
||||
override.value.has<String>() && override.command == CommandNames::fontSize
|
||||
&& ((value_override.has_value() && value_override.value() != override.value.get<String>())
|
||||
override.value.has<Utf16String>() && override.command == CommandNames::fontSize
|
||||
&& ((value_override.has_value() && value_override.value() != override.value.get<Utf16String>())
|
||||
|| (!value_override.has_value()
|
||||
&& !values_are_loosely_equivalent(
|
||||
CommandNames::fontSize,
|
||||
effective_command_value(node, CommandNames::fontSize),
|
||||
override.value.get<String>())))) {
|
||||
override.value.get<Utf16String>())))) {
|
||||
// 1. Convert override to an integer number of pixels, and set override to the legacy font size for the
|
||||
// result.
|
||||
auto override_pixel_size = font_size_to_pixel_size(override.value.get<String>());
|
||||
auto override_pixel_size = font_size_to_pixel_size(override.value.get<Utf16String>());
|
||||
override.value = legacy_font_size(override_pixel_size.to_int());
|
||||
|
||||
// 2. Take the action for "fontSize", with value equal to override.
|
||||
take_the_action_for_command(document, CommandNames::fontSize, override.value.get<String>());
|
||||
take_the_action_for_command(document, CommandNames::fontSize, override.value.get<Utf16String>());
|
||||
}
|
||||
|
||||
// 5. Otherwise, continue this loop from the beginning.
|
||||
|
|
@ -3550,7 +3556,7 @@ void restore_states_and_values(DOM::Document& document, Vector<RecordedOverride>
|
|||
// 2. If override is a string, set the value override for command to override.
|
||||
override.value.visit(
|
||||
[&](bool value) { document.set_command_state_override(override.command, value); },
|
||||
[&](String const& value) { document.set_command_value_override(override.command, value); });
|
||||
[&](Utf16String const& value) { document.set_command_value_override(override.command, value); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3559,7 +3565,7 @@ void restore_states_and_values(DOM::Document& document, Vector<RecordedOverride>
|
|||
void restore_the_values_of_nodes(Vector<RecordedNodeValue> const& values)
|
||||
{
|
||||
// 1. For each (node, command, value) triple in values:
|
||||
for (auto& recorded_node_value : values) {
|
||||
for (auto const& recorded_node_value : values) {
|
||||
auto node = recorded_node_value.node;
|
||||
auto const& command = recorded_node_value.command;
|
||||
auto value = recorded_node_value.specified_command_value;
|
||||
|
|
@ -3585,7 +3591,7 @@ void restore_the_values_of_nodes(Vector<RecordedNodeValue> const& values)
|
|||
// node.
|
||||
else if ((is<DOM::Element>(ancestor.ptr()) && specified_command_value(static_cast<DOM::Element&>(*ancestor), command) != value)
|
||||
|| (!is<DOM::Element>(ancestor.ptr()) && value.has_value())) {
|
||||
force_the_value(node, command, value);
|
||||
force_the_value(node, command, value->utf16_view());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3706,8 +3712,12 @@ SelectionsListState selections_list_state(DOM::Document const& document)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#set-the-selection's-value
|
||||
void set_the_selections_value(DOM::Document& document, FlyString const& command, Optional<String> new_value)
|
||||
void set_the_selections_value(DOM::Document& document, FlyString const& command, Optional<Utf16View const&> new_value)
|
||||
{
|
||||
auto new_value_string = new_value.map([](Utf16View const& view) {
|
||||
return Utf16String::from_utf16_without_validation(view);
|
||||
});
|
||||
|
||||
// 1. Let command be the current command.
|
||||
|
||||
// 2. If there is no formattable node effectively contained in the active range:
|
||||
|
|
@ -3743,7 +3753,7 @@ void set_the_selections_value(DOM::Document& document, FlyString const& command,
|
|||
|
||||
// 5. Otherwise, if command is "createLink" or it has a value specified, set the value override to new value.
|
||||
else if (command == CommandNames::createLink || !MUST(document.query_command_value(CommandNames::createLink)).is_empty()) {
|
||||
document.set_command_value_override(command, new_value.value());
|
||||
document.set_command_value_override(command, *new_value_string);
|
||||
}
|
||||
|
||||
// 6. Abort these steps.
|
||||
|
|
@ -3789,7 +3799,7 @@ void set_the_selections_value(DOM::Document& document, FlyString const& command,
|
|||
// 8. For each node in node list:
|
||||
for (auto node : node_list) {
|
||||
// 1. Push down values on node.
|
||||
push_down_values(command, node, new_value);
|
||||
push_down_values(command, node, new_value_string);
|
||||
|
||||
// 2. If node is an allowed child of "span", force the value of node.
|
||||
if (is_allowed_child_of_node(node, HTML::TagNames::span))
|
||||
|
|
@ -3831,7 +3841,7 @@ GC::Ref<DOM::Element> set_the_tag_name(GC::Ref<DOM::Element> element, FlyString
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#specified-command-value
|
||||
Optional<String> specified_command_value(GC::Ref<DOM::Element> element, FlyString const& command)
|
||||
Optional<Utf16String> specified_command_value(GC::Ref<DOM::Element> element, FlyString const& command)
|
||||
{
|
||||
// 1. If command is "backColor" or "hiliteColor" and the Element's display property does not have resolved value
|
||||
// "inline", return null.
|
||||
|
|
@ -3846,7 +3856,7 @@ Optional<String> specified_command_value(GC::Ref<DOM::Element> element, FlyStrin
|
|||
// 1. If element is an a element and has an href attribute, return the value of that attribute.
|
||||
auto href_attribute = element->get_attribute(HTML::AttributeNames::href);
|
||||
if (href_attribute.has_value())
|
||||
return href_attribute.release_value();
|
||||
return Utf16String::from_utf8_without_validation(href_attribute.release_value());
|
||||
|
||||
// 2. Return null.
|
||||
return {};
|
||||
|
|
@ -3856,11 +3866,11 @@ Optional<String> specified_command_value(GC::Ref<DOM::Element> element, FlyStrin
|
|||
if (command.is_one_of(CommandNames::subscript, CommandNames::superscript)) {
|
||||
// 1. If element is a sup, return "superscript".
|
||||
if (element->local_name() == HTML::TagNames::sup)
|
||||
return "superscript"_string;
|
||||
return "superscript"_utf16;
|
||||
|
||||
// 2. If element is a sub, return "subscript".
|
||||
if (element->local_name() == HTML::TagNames::sub)
|
||||
return "subscript"_string;
|
||||
return "subscript"_utf16;
|
||||
|
||||
// 3. Return null.
|
||||
return {};
|
||||
|
|
@ -3874,7 +3884,7 @@ Optional<String> specified_command_value(GC::Ref<DOM::Element> element, FlyStrin
|
|||
// 1. If element's style attribute sets "text-decoration" to a value containing "line-through", return
|
||||
// "line-through".
|
||||
if (value_contains_keyword(text_decoration_style.value(), CSS::Keyword::LineThrough))
|
||||
return "line-through"_string;
|
||||
return "line-through"_utf16;
|
||||
|
||||
// 2. Return null.
|
||||
return {};
|
||||
|
|
@ -3883,7 +3893,7 @@ Optional<String> specified_command_value(GC::Ref<DOM::Element> element, FlyStrin
|
|||
|
||||
// 5. If command is "strikethrough" and element is an s or strike element, return "line-through".
|
||||
if (command == CommandNames::strikethrough && element->local_name().is_one_of(HTML::TagNames::s, HTML::TagNames::strike))
|
||||
return "line-through"_string;
|
||||
return "line-through"_utf16;
|
||||
|
||||
// 6. If command is "underline", and element has a style attribute set, and that attribute sets "text-decoration":
|
||||
if (command == CommandNames::underline) {
|
||||
|
|
@ -3891,7 +3901,7 @@ Optional<String> specified_command_value(GC::Ref<DOM::Element> element, FlyStrin
|
|||
if (text_decoration_style.has_value()) {
|
||||
// 1. If element's style attribute sets "text-decoration" to a value containing "underline", return "underline".
|
||||
if (value_contains_keyword(text_decoration_style.value(), CSS::Keyword::Underline))
|
||||
return "underline"_string;
|
||||
return "underline"_utf16;
|
||||
|
||||
// 2. Return null.
|
||||
return {};
|
||||
|
|
@ -3900,7 +3910,7 @@ Optional<String> specified_command_value(GC::Ref<DOM::Element> element, FlyStrin
|
|||
|
||||
// 7. If command is "underline" and element is a u element, return "underline".
|
||||
if (command == CommandNames::underline && element->local_name() == HTML::TagNames::u)
|
||||
return "underline"_string;
|
||||
return "underline"_utf16;
|
||||
|
||||
// 8. Let property be the relevant CSS property for command.
|
||||
auto property = find_command_definition(command)->relevant_css_property;
|
||||
|
|
@ -3915,7 +3925,7 @@ Optional<String> specified_command_value(GC::Ref<DOM::Element> element, FlyStrin
|
|||
if (auto inline_style = element->inline_style()) {
|
||||
auto value = inline_style->get_property_value(string_from_property_id(property.value()));
|
||||
if (!value.is_empty())
|
||||
return value;
|
||||
return Utf16String::from_utf8_without_validation(value);
|
||||
}
|
||||
|
||||
// 11. If element is a font element that has an attribute whose effect is to create a presentational hint for
|
||||
|
|
@ -3927,7 +3937,7 @@ Optional<String> specified_command_value(GC::Ref<DOM::Element> element, FlyStrin
|
|||
font_element.apply_presentational_hints(cascaded_properties);
|
||||
auto property_value = cascaded_properties->property(property.value());
|
||||
if (property_value)
|
||||
return property_value->to_string(CSS::SerializationMode::Normal);
|
||||
return Utf16String::from_utf8_without_validation(property_value->to_string(CSS::SerializationMode::Normal));
|
||||
}
|
||||
|
||||
// 12. If element is in the following list, and property is equal to the CSS property name listed for it, return the
|
||||
|
|
@ -3935,9 +3945,9 @@ Optional<String> specified_command_value(GC::Ref<DOM::Element> element, FlyStrin
|
|||
// * b, strong: font-weight: "bold"
|
||||
// * i, em: font-style: "italic"
|
||||
if (element->local_name().is_one_of(HTML::TagNames::b, HTML::TagNames::strong) && *property == CSS::PropertyID::FontWeight)
|
||||
return "bold"_string;
|
||||
return "bold"_utf16;
|
||||
if (element->local_name().is_one_of(HTML::TagNames::i, HTML::TagNames::em) && *property == CSS::PropertyID::FontStyle)
|
||||
return "italic"_string;
|
||||
return "italic"_utf16;
|
||||
|
||||
// 13. Return null.
|
||||
return {};
|
||||
|
|
@ -4349,7 +4359,7 @@ void toggle_lists(DOM::Document& document, FlyString const& tag_name)
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#equivalent-values
|
||||
bool values_are_equivalent(FlyString const& command, Optional<String> a, Optional<String> b)
|
||||
bool values_are_equivalent(FlyString const& command, Optional<Utf16String const&> a, Optional<Utf16String const&> b)
|
||||
{
|
||||
// Two quantities are equivalent values for a command if either both are null,
|
||||
if (!a.has_value() && !b.has_value())
|
||||
|
|
@ -4363,8 +4373,8 @@ bool values_are_equivalent(FlyString const& command, Optional<String> a, Optiona
|
|||
if (command.is_one_of(CommandNames::backColor, CommandNames::foreColor, CommandNames::hiliteColor)) {
|
||||
// Either both strings are valid CSS colors and have the same red, green, blue, and alpha components, or neither
|
||||
// string is a valid CSS color.
|
||||
auto a_color = Color::from_string(a.value());
|
||||
auto b_color = Color::from_string(b.value());
|
||||
auto a_color = Color::from_utf16_string(a.value());
|
||||
auto b_color = Color::from_utf16_string(b.value());
|
||||
if (a_color.has_value())
|
||||
return a_color == b_color;
|
||||
return !a_color.has_value() && !b_color.has_value();
|
||||
|
|
@ -4388,7 +4398,7 @@ bool values_are_equivalent(FlyString const& command, Optional<String> a, Optiona
|
|||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#loosely-equivalent-values
|
||||
bool values_are_loosely_equivalent(FlyString const& command, Optional<String> a, Optional<String> b)
|
||||
bool values_are_loosely_equivalent(FlyString const& command, Optional<Utf16String const&> a, Optional<Utf16String const&> b)
|
||||
{
|
||||
// Two quantities are loosely equivalent values for a command if either they are equivalent values for the command,
|
||||
if (values_are_equivalent(command, a, b))
|
||||
|
|
@ -4398,9 +4408,9 @@ bool values_are_loosely_equivalent(FlyString const& command, Optional<String> a,
|
|||
// "x-large", "xx-large", or "xxx-large"; and the other quantity is the resolved value of "font-size" on a font
|
||||
// element whose size attribute has the corresponding value set ("1" through "7" respectively).
|
||||
if (command == CommandNames::fontSize && a.has_value() && b.has_value()) {
|
||||
static constexpr Array named_quantities { "x-small"sv, "small"sv, "medium"sv, "large"sv, "x-large"sv,
|
||||
"xx-large"sv, "xxx-large"sv };
|
||||
static constexpr Array size_quantities { "1"sv, "2"sv, "3"sv, "4"sv, "5"sv, "6"sv, "7"sv };
|
||||
static constexpr Array<Utf16View, 7> named_quantities { "x-small"sv, "small"sv, "medium"sv, "large"sv,
|
||||
"x-large"sv, "xx-large"sv, "xxx-large"sv };
|
||||
static constexpr Array<Utf16View, 7> size_quantities { "1"sv, "2"sv, "3"sv, "4"sv, "5"sv, "6"sv, "7"sv };
|
||||
static_assert(named_quantities.size() == size_quantities.size());
|
||||
|
||||
auto a_index = named_quantities.first_index_of(a.value())
|
||||
|
|
@ -4614,21 +4624,21 @@ GC::Ptr<DOM::Node> first_formattable_node_effectively_contained(GC::Ptr<DOM::Ran
|
|||
return node;
|
||||
}
|
||||
|
||||
CSSPixels font_size_to_pixel_size(StringView font_size)
|
||||
CSSPixels font_size_to_pixel_size(Utf16View const& font_size)
|
||||
{
|
||||
// If the font size ends in 'px', interpret the preceding as a number and return it.
|
||||
if (font_size.length() >= 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<float>();
|
||||
if (font_size.ends_with("px"sv)) {
|
||||
auto optional_number = font_size.substring_view(0, font_size.length_in_code_units() - 2).to_number<float>();
|
||||
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);
|
||||
auto keyword = CSS::keyword_from_string(font_size.to_utf8_but_should_be_ported_to_utf16());
|
||||
|
||||
// If that failed, try to interpret it as a legacy font size (e.g. 1 through 7)
|
||||
if (!keyword.has_value())
|
||||
keyword = HTML::HTMLFontElement::parse_legacy_font_size(font_size);
|
||||
keyword = HTML::HTMLFontElement::parse_legacy_font_size(font_size.to_utf8_but_should_be_ported_to_utf16());
|
||||
|
||||
// If that also failed, give up
|
||||
auto pixel_size = CSS::StyleComputer::default_user_font_size();
|
||||
|
|
@ -4680,22 +4690,22 @@ bool is_heading(FlyString const& local_name)
|
|||
HTML::TagNames::h6);
|
||||
}
|
||||
|
||||
String justify_alignment_to_string(JustifyAlignment alignment)
|
||||
Utf16String justify_alignment_to_string(JustifyAlignment alignment)
|
||||
{
|
||||
switch (alignment) {
|
||||
case JustifyAlignment::Center:
|
||||
return "center"_string;
|
||||
return "center"_utf16;
|
||||
case JustifyAlignment::Justify:
|
||||
return "justify"_string;
|
||||
return "justify"_utf16;
|
||||
case JustifyAlignment::Left:
|
||||
return "left"_string;
|
||||
return "left"_utf16;
|
||||
case JustifyAlignment::Right:
|
||||
return "right"_string;
|
||||
return "right"_utf16;
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
Array<StringView, 7> named_font_sizes()
|
||||
Array<Utf16View, 7> named_font_sizes()
|
||||
{
|
||||
return { "x-small"sv, "small"sv, "medium"sv, "large"sv, "x-large"sv, "xx-large"sv, "xxx-large"sv };
|
||||
}
|
||||
|
|
@ -4747,7 +4757,7 @@ Optional<NonnullRefPtr<CSS::CSSStyleValue const>> resolved_value(GC::Ref<DOM::No
|
|||
return optional_style_property.value().value;
|
||||
}
|
||||
|
||||
void take_the_action_for_command(DOM::Document& document, FlyString const& command, String const& value)
|
||||
void take_the_action_for_command(DOM::Document& document, FlyString const& command, Utf16View const& value)
|
||||
{
|
||||
auto const& command_definition = find_command_definition(command);
|
||||
command_definition->action(document, value);
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@ namespace Web::Editing {
|
|||
struct RecordedNodeValue {
|
||||
GC::Ref<DOM::Node> node;
|
||||
FlyString command;
|
||||
Optional<String> specified_command_value;
|
||||
Optional<Utf16String> specified_command_value;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#record-current-states-and-values
|
||||
struct RecordedOverride {
|
||||
FlyString command;
|
||||
Variant<String, bool> value;
|
||||
Variant<Utf16String, bool> value;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#selection's-list-state
|
||||
|
|
@ -54,17 +54,17 @@ JustifyAlignment alignment_value_of_node(GC::Ptr<DOM::Node>);
|
|||
void autolink(DOM::BoundaryPoint);
|
||||
GC::Ref<DOM::Range> block_extend_a_range(GC::Ref<DOM::Range>);
|
||||
GC::Ptr<DOM::Node> block_node_of_node(GC::Ref<DOM::Node>);
|
||||
String canonical_space_sequence(u32 length, bool non_breaking_start, bool non_breaking_end);
|
||||
Utf16String canonical_space_sequence(size_t length, bool non_breaking_start, bool non_breaking_end);
|
||||
void canonicalize_whitespace(DOM::BoundaryPoint, bool fix_collapsed_space = true);
|
||||
Vector<GC::Ref<DOM::Node>> clear_the_value(FlyString const&, GC::Ref<DOM::Element>);
|
||||
void delete_the_selection(Selection&, bool block_merging = true, bool strip_wrappers = true,
|
||||
Selection::Direction direction = Selection::Direction::Forwards);
|
||||
GC::Ptr<DOM::Node> editing_host_of_node(GC::Ref<DOM::Node>);
|
||||
Optional<String> effective_command_value(GC::Ptr<DOM::Node>, FlyString const& command);
|
||||
Optional<Utf16String> effective_command_value(GC::Ptr<DOM::Node>, FlyString const& command);
|
||||
DOM::BoundaryPoint first_equivalent_point(DOM::BoundaryPoint);
|
||||
void fix_disallowed_ancestors_of_node(GC::Ref<DOM::Node>);
|
||||
bool follows_a_line_break(GC::Ref<DOM::Node>);
|
||||
void force_the_value(GC::Ref<DOM::Node>, FlyString const&, Optional<String>);
|
||||
void force_the_value(GC::Ref<DOM::Node>, FlyString const&, Optional<Utf16View const&>);
|
||||
void indent(Vector<GC::Ref<DOM::Node>>);
|
||||
bool is_allowed_child_of_node(Variant<GC::Ref<DOM::Node>, FlyString> child, Variant<GC::Ref<DOM::Node>, FlyString> parent);
|
||||
bool is_block_boundary_point(DOM::BoundaryPoint);
|
||||
|
|
@ -96,14 +96,14 @@ bool is_visible_node(GC::Ref<DOM::Node>);
|
|||
bool is_whitespace_node(GC::Ref<DOM::Node>);
|
||||
void justify_the_selection(DOM::Document&, JustifyAlignment);
|
||||
DOM::BoundaryPoint last_equivalent_point(DOM::BoundaryPoint);
|
||||
String legacy_font_size(int);
|
||||
Utf16String legacy_font_size(int);
|
||||
void move_node_preserving_ranges(GC::Ref<DOM::Node>, GC::Ref<DOM::Node> new_parent, u32 new_index);
|
||||
Optional<DOM::BoundaryPoint> next_equivalent_point(DOM::BoundaryPoint);
|
||||
void normalize_sublists_in_node(GC::Ref<DOM::Node>);
|
||||
void outdent(GC::Ref<DOM::Node>);
|
||||
bool precedes_a_line_break(GC::Ref<DOM::Node>);
|
||||
Optional<DOM::BoundaryPoint> previous_equivalent_point(DOM::BoundaryPoint);
|
||||
void push_down_values(FlyString const&, GC::Ref<DOM::Node>, Optional<String>);
|
||||
void push_down_values(FlyString const&, GC::Ref<DOM::Node>, Optional<Utf16String const&>);
|
||||
Vector<RecordedOverride> record_current_overrides(DOM::Document const&);
|
||||
Vector<RecordedOverride> record_current_states_and_values(DOM::Document const&);
|
||||
Vector<RecordedNodeValue> record_the_values_of_nodes(Vector<GC::Ref<DOM::Node>> const&);
|
||||
|
|
@ -111,33 +111,33 @@ void remove_extraneous_line_breaks_at_the_end_of_node(GC::Ref<DOM::Node>);
|
|||
void remove_extraneous_line_breaks_before_node(GC::Ref<DOM::Node>);
|
||||
void remove_extraneous_line_breaks_from_a_node(GC::Ref<DOM::Node>);
|
||||
void remove_node_preserving_its_descendants(GC::Ref<DOM::Node>);
|
||||
void reorder_modifiable_descendants(GC::Ref<DOM::Node>, FlyString const&, Optional<String>);
|
||||
void reorder_modifiable_descendants(GC::Ref<DOM::Node>, FlyString const&, Optional<Utf16String const&>);
|
||||
void restore_states_and_values(DOM::Document&, Vector<RecordedOverride> const&);
|
||||
void restore_the_values_of_nodes(Vector<RecordedNodeValue> const&);
|
||||
SelectionsListState selections_list_state(DOM::Document const&);
|
||||
void set_the_selections_value(DOM::Document&, FlyString const&, Optional<String>);
|
||||
void set_the_selections_value(DOM::Document&, FlyString const&, Optional<Utf16View const&>);
|
||||
GC::Ref<DOM::Element> set_the_tag_name(GC::Ref<DOM::Element>, FlyString const&);
|
||||
Optional<String> specified_command_value(GC::Ref<DOM::Element>, FlyString const& command);
|
||||
Optional<Utf16String> specified_command_value(GC::Ref<DOM::Element>, FlyString const& command);
|
||||
void split_the_parent_of_nodes(Vector<GC::Ref<DOM::Node>> const&);
|
||||
void toggle_lists(DOM::Document&, FlyString const&);
|
||||
bool values_are_equivalent(FlyString const&, Optional<String>, Optional<String>);
|
||||
bool values_are_loosely_equivalent(FlyString const&, Optional<String>, Optional<String>);
|
||||
bool values_are_equivalent(FlyString const&, Optional<Utf16String const&>, Optional<Utf16String const&>);
|
||||
bool values_are_loosely_equivalent(FlyString const&, Optional<Utf16String const&>, Optional<Utf16String const&>);
|
||||
GC::Ptr<DOM::Node> wrap(Vector<GC::Ref<DOM::Node>>, Function<bool(GC::Ref<DOM::Node>)> sibling_criteria, Function<GC::Ptr<DOM::Node>()> new_parent_instructions);
|
||||
|
||||
// Utility methods:
|
||||
|
||||
GC::Ptr<DOM::Node> first_formattable_node_effectively_contained(GC::Ptr<DOM::Range>);
|
||||
CSSPixels font_size_to_pixel_size(StringView);
|
||||
CSSPixels font_size_to_pixel_size(Utf16View const&);
|
||||
void for_each_node_effectively_contained_in_range(GC::Ptr<DOM::Range>, Function<TraversalDecision(GC::Ref<DOM::Node>)>);
|
||||
bool has_visible_children(GC::Ref<DOM::Node>);
|
||||
bool is_heading(FlyString const&);
|
||||
String justify_alignment_to_string(JustifyAlignment);
|
||||
Array<StringView, 7> named_font_sizes();
|
||||
Utf16String justify_alignment_to_string(JustifyAlignment);
|
||||
Array<Utf16View, 7> named_font_sizes();
|
||||
Optional<NonnullRefPtr<CSS::CSSStyleValue const>> property_in_style_attribute(GC::Ref<DOM::Element>, CSS::PropertyID);
|
||||
Optional<CSS::Display> resolved_display(GC::Ref<DOM::Node>);
|
||||
Optional<CSS::Keyword> resolved_keyword(GC::Ref<DOM::Node>, CSS::PropertyID);
|
||||
Optional<NonnullRefPtr<CSS::CSSStyleValue const>> resolved_value(GC::Ref<DOM::Node>, CSS::PropertyID);
|
||||
void take_the_action_for_command(DOM::Document&, FlyString const&, String const&);
|
||||
void take_the_action_for_command(DOM::Document&, FlyString const&, Utf16View const&);
|
||||
bool value_contains_keyword(CSS::CSSStyleValue const&, CSS::Keyword);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +1,5 @@
|
|||
input triggered
|
||||
foobazbar
|
||||
#text 6 - #text 6
|
||||
input triggered
|
||||
#text 8 - #text 8
|
||||
foobaz🙂bar
|
||||
|
|
|
|||
|
|
@ -3,17 +3,29 @@
|
|||
<div contenteditable="true">foobar</div>
|
||||
<script>
|
||||
test(() => {
|
||||
const selection = getSelection();
|
||||
const reportSelection = () => {
|
||||
if (selection.rangeCount === 0) {
|
||||
println('No range.');
|
||||
return;
|
||||
}
|
||||
const range = selection.getRangeAt(0);
|
||||
println(`${range.startContainer.nodeName} ${range.startOffset} - ${range.endContainer.nodeName} ${range.endOffset}`);
|
||||
};
|
||||
|
||||
var divElm = document.querySelector('div');
|
||||
divElm.addEventListener('input', (e) => println('input triggered'));
|
||||
|
||||
// Put cursor between 'foo' and 'bar'
|
||||
var range = document.createRange();
|
||||
getSelection().addRange(range);
|
||||
range.setStart(divElm.childNodes[0], 3);
|
||||
range.setEnd(divElm.childNodes[0], 3);
|
||||
selection.setBaseAndExtent(divElm.childNodes[0], 3, divElm.childNodes[0], 3);
|
||||
|
||||
// Insert text
|
||||
document.execCommand('insertText', false, 'baz');
|
||||
reportSelection();
|
||||
|
||||
// Insert Unicode
|
||||
document.execCommand('insertText', false, '🙂');
|
||||
reportSelection();
|
||||
|
||||
println(divElm.innerHTML);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user