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

Code before:
    CSS::CalculationResolutionContext calculation_context { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*m_current_node.ptr()) };
    auto font_feature_settings = computed_values.font_feature_settings();
    if (font_feature_settings.has_value()) {
        auto const& feature_settings = font_feature_settings.value();
        for (auto const& [key, feature_value] : feature_settings) {
            merged_features.set(key, feature_value.resolved(calculation_context).value_or(0));
        }
    }

    Gfx::ShapeFeatures shape_features;
    shape_features.ensure_capacity(merged_features.size());

    for (auto& it : merged_features) {
        shape_features.unchecked_append({ { it.key[0], it.key[1], it.key[2], it.key[3] }, static_cast<u32>(it.value) });
    }

    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();
            }

Review comment (suggestion):
The changes to InlineLevelIterator are separate enough that they belong in their own commit. (Generally, if you end up putting "and" or "also" in a commit message, it's a clue that it might want to be multiple commits. Sometimes that's not possible though.)

Code after:
    CSS::CalculationResolutionContext calculation_context { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*m_current_node.ptr()) };
    auto font_feature_settings = computed_values.font_feature_settings();
    if (font_feature_settings.has_value()) {
        auto const& feature_settings = font_feature_settings.value();
        for (auto const& [key, feature_value] : feature_settings) {
            merged_features.set(key, feature_value.resolved(calculation_context).value_or(0));
        }
    }

    Gfx::ShapeFeatures shape_features;
    shape_features.ensure_capacity(merged_features.size());

    for (auto& it : merged_features) {
        shape_features.unchecked_append({ { it.key[0], it.key[1], it.key[2], it.key[3] }, static_cast<u32>(it.value) });
    }

    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();
            }