Repository: LadybirdBrowser/ladybird
File: Libraries/LibWeb/Selection/Selection.cpp (C++)

Code before:
    // If allowPartialContainment is true, the method must return true if and only if
    // start of its range is before or visually equivalent to the last boundary point in the node
    // and end of its range is after or visually equivalent to the first boundary point in the node.

    auto start_relative_position = DOM::position_of_boundary_point_relative_to_other_boundary_point(m_range->start(), { node, static_cast<WebIDL::UnsignedLong>(node->length()) });
    auto end_relative_position = DOM::position_of_boundary_point_relative_to_other_boundary_point(m_range->end(), { node, 0 });

    return (start_relative_position == DOM::RelativeBoundaryPointPosition::Before || start_relative_position == DOM::RelativeBoundaryPointPosition::Equal)
        && (end_relative_position == DOM::RelativeBoundaryPointPosition::Equal || end_relative_position == DOM::RelativeBoundaryPointPosition::After);
}

Optional<Utf16String> Selection::try_selected_text_from_form_control() const
{
    // FIXME: According to https://bugzilla.mozilla.org/show_bug.cgi?id=85686#c69,
    // sometimes you want the selection from a previously focused form text, probably
    // when a button or context menu has temporarily stolen focus but page scripts
    // still expect window.getSelection() to have the goodies.

    auto const* form_element = as_if<HTML::FormAssociatedTextControlElement>(m_document->active_element());
    if (!form_element)
        return {};
    size_t start = form_element->selection_start();
    size_t end = form_element->selection_end();
    if (start >= end)
        return {};
    return Utf16String::from_utf16(form_element->value().substring_view(start, end - start));
}

Utf16String Selection::to_string() const
{
    // https://w3c.github.io/selection-api/#dom-selection-stringifier
    // If the selection is within a textarea or input element, it must return the
    // selected substring in its value.
    if (auto form_text = try_selected_text_from_form_control(); form_text.has_value())
        return form_text.release_value();

    // FIXME: This needs more work to be compatible with other engines.
    //        See https://www.w3.org/Bugs/Public/show_bug.cgi?id=10583
    if (!m_range)
        return {};
    return m_range->to_string();
}

GC::Ref<DOM::Document> Selection::document() const
{
    return m_document;
}

GC::Ptr<DOM::Range> Selection::range() const
{
    return m_range;

Review comment (suggestion):
This seems to be only potentially behaviorally different for `<input>` elements and not `<textarea>`, but using  [relevant value](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-textarea/input-relevant-value) might be more correct here and definitely seems more clear.

I think it would be good to add a test case for `<input>` as well, and best with different types of `<input>`, the case that I am mentioning here seems applicable to certain types of input elements, such as checkbox which has a different implementation of `value()`: https://github.com/LadybirdBrowser/ladybird/blob/953b33d273849403741b7ec5ffd197509b22daf2/Libraries/LibWeb/HTML/HTMLInputElement.cpp#L670

Code after:
    // If allowPartialContainment is true, the method must return true if and only if
    // start of its range is before or visually equivalent to the last boundary point in the node
    // and end of its range is after or visually equivalent to the first boundary point in the node.

    auto start_relative_position = DOM::position_of_boundary_point_relative_to_other_boundary_point(m_range->start(), { node, static_cast<WebIDL::UnsignedLong>(node->length()) });
    auto end_relative_position = DOM::position_of_boundary_point_relative_to_other_boundary_point(m_range->end(), { node, 0 });

    return (start_relative_position == DOM::RelativeBoundaryPointPosition::Before || start_relative_position == DOM::RelativeBoundaryPointPosition::Equal)
        && (end_relative_position == DOM::RelativeBoundaryPointPosition::Equal || end_relative_position == DOM::RelativeBoundaryPointPosition::After);
}

Optional<Utf16String> Selection::try_form_control_selected_text_for_stringifier() const
{
    // FIXME: According to https://bugzilla.mozilla.org/show_bug.cgi?id=85686#c69,
    // sometimes you want the selection from a previously focused form text, probably
    // when a button or context menu has temporarily stolen focus but page scripts
    // still expect window.getSelection() to have the goodies.

    auto const* form_element = as_if<HTML::FormAssociatedTextControlElement>(m_document->active_element());
    if (!form_element)
        return {};
    return form_element->selected_text_for_stringifier();
}

Utf16String Selection::to_string() const
{
    // https://w3c.github.io/selection-api/#dom-selection-stringifier
    // If the selection is within a textarea or input element, it must return the
    // selected substring in its value.
    if (auto form_text = try_form_control_selected_text_for_stringifier(); form_text.has_value())
        return form_text.release_value();

    // FIXME: This needs more work to be compatible with other engines.
    //        See https://www.w3.org/Bugs/Public/show_bug.cgi?id=10583
    if (!m_range)
        return {};
    return m_range->to_string();
}

GC::Ref<DOM::Document> Selection::document() const
{
    return m_document;
}

GC::Ptr<DOM::Range> Selection::range() const
{
    return m_range;
}

void Selection::set_range(GC::Ptr<DOM::Range> range)
{