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

Code before:
    return shape_features;
}

Optional<InlineLevelIterator::Item> InlineLevelIterator::next_without_lookahead()
{
    if (!m_current_node)
        return {};

    if (is<Layout::TextNode>(*m_current_node)) {
        auto const& text_node = static_cast<Layout::TextNode const&>(*m_current_node);

        if (!m_text_node_context.has_value())
            enter_text_node(text_node);
        else
            m_text_node_context->is_first_chunk = false;

        if (!m_text_node_context->chunk_iterator.peek(0).has_value())
            m_text_node_context->is_last_chunk = true;

        auto chunk_opt = m_text_node_context->chunk_iterator.next();
        auto is_empty_editable = false;
        if (!chunk_opt.has_value()) {
            auto const is_only_chunk = m_text_node_context->is_first_chunk && m_text_node_context->is_last_chunk;
            if (is_only_chunk && text_node.text_for_rendering().is_empty()) {
                if (auto const* shadow_root = as_if<DOM::ShadowRoot>(text_node.dom_node().root()))
                    is_empty_editable = shadow_root->host() && (is<HTML::FormAssociatedTextControlElement>(shadow_root->host()) || shadow_root->host()->is_editable_or_editing_host());
            }

            if (is_empty_editable) {
                chunk_opt = m_text_node_context->chunk_iterator.create_empty_chunk();
            } else {
                m_text_node_context = {};
                skip_to_next();
                return next_without_lookahead();
            }
        }

        auto& chunk = chunk_opt.value();
        auto text_type = chunk.text_type;
        if (text_type == Gfx::GlyphRun::TextType::Ltr || text_type == Gfx::GlyphRun::TextType::Rtl)
            m_text_node_context->last_known_direction = text_type;

        if (m_text_node_context->do_respect_linebreaks && chunk.has_breaking_newline) {
            m_text_node_context->is_last_chunk = true;
            if (chunk.is_all_whitespace)
                text_type = Gfx::GlyphRun::TextType::EndPadding;
        }

        if (text_type == Gfx::GlyphRun::TextType::ContextDependent)
            text_type = resolve_text_direction_from_context();


Review comment (suggestion):
If you have a `FormAssociatedTextControlElement`, shouldn't we also look at `::is_mutable()`? If the control element is disabled or readonly, we probably shouldn't entertain adding empty fragments.

Code after:
    return shape_features;
}

Optional<InlineLevelIterator::Item> InlineLevelIterator::next_without_lookahead()
{
    if (!m_current_node)
        return {};

    if (auto* text_node = as_if<Layout::TextNode>(*m_current_node)) {
        if (!m_text_node_context.has_value())
            enter_text_node(*text_node);
        else
            m_text_node_context->is_first_chunk = false;

        if (!m_text_node_context->chunk_iterator.peek(0).has_value())
            m_text_node_context->is_last_chunk = true;

        auto chunk_opt = m_text_node_context->chunk_iterator.next();
        auto is_empty_editable = false;
        if (!chunk_opt.has_value()) {
            auto const is_only_chunk = m_text_node_context->is_first_chunk && m_text_node_context->is_last_chunk;
            if (is_only_chunk && text_node->text_for_rendering().is_empty()) {
                if (auto const* shadow_root = as_if<DOM::ShadowRoot>(text_node->dom_node().root()))
                    if (auto const* form_associated_element = as_if<HTML::FormAssociatedTextControlElement>(shadow_root->host()))
                        is_empty_editable = form_associated_element->is_mutable();
                is_empty_editable |= text_node->dom_node().parent() && text_node->dom_node().parent()->is_editing_host();
            }

            if (is_empty_editable) {
                chunk_opt = m_text_node_context->chunk_iterator.create_empty_chunk();
            } else {
                m_text_node_context = {};
                skip_to_next();
                return next_without_lookahead();
            }
        }

        auto& chunk = chunk_opt.value();
        auto text_type = chunk.text_type;
        if (text_type == Gfx::GlyphRun::TextType::Ltr || text_type == Gfx::GlyphRun::TextType::Rtl)
            m_text_node_context->last_known_direction = text_type;

        auto do_respect_linebreak = m_text_node_context->chunk_iterator.should_respect_linebreaks();
        if (do_respect_linebreak && chunk.has_breaking_newline) {
            m_text_node_context->is_last_chunk = true;
            if (chunk.is_all_whitespace)
                text_type = Gfx::GlyphRun::TextType::EndPadding;
        }

        if (text_type == Gfx::GlyphRun::TextType::ContextDependent)
            text_type = resolve_text_direction_from_context();