From 78b47109af9ffbb2f2d8eceb24a1f79107aae2f9 Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Mon, 27 Apr 2026 16:25:50 +0100 Subject: [PATCH] LibWeb: Use the ASCII line segmenter for eligible text --- Libraries/LibWeb/DOM/CharacterData.cpp | 13 +++++++++---- Libraries/LibWeb/GraphemeEdgeTracker.cpp | 5 ++++- Libraries/LibWeb/Layout/TextNode.cpp | 9 +++++++-- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Libraries/LibWeb/DOM/CharacterData.cpp b/Libraries/LibWeb/DOM/CharacterData.cpp index 2ab9ee2228..4f8b1c0ad8 100644 --- a/Libraries/LibWeb/DOM/CharacterData.cpp +++ b/Libraries/LibWeb/DOM/CharacterData.cpp @@ -146,8 +146,9 @@ WebIDL::ExceptionOr CharacterData::replace_data(size_t offset, size_t coun if (m_grapheme_segmenter) m_grapheme_segmenter->set_segmented_text(m_data); - if (m_line_segmenter) - m_line_segmenter->set_segmented_text(m_data); + // The line segmenter may be the ASCII fast-path variant, which only accepts a subset of inputs; let the + // lazy getter re-pick the implementation against the new data. + m_line_segmenter = nullptr; if (m_word_segmenter) m_word_segmenter->set_segmented_text(m_data); @@ -190,8 +191,12 @@ Unicode::Segmenter& CharacterData::grapheme_segmenter() const Unicode::Segmenter& CharacterData::line_segmenter() const { if (!m_line_segmenter) { - m_line_segmenter = document().line_segmenter().clone(); - m_line_segmenter->set_segmented_text(m_data); + if (auto ascii = Unicode::Segmenter::try_create_for_ascii_line(m_data.utf16_view())) { + m_line_segmenter = ascii.release_nonnull(); + } else { + m_line_segmenter = document().line_segmenter().clone(); + m_line_segmenter->set_segmented_text(m_data); + } } return *m_line_segmenter; diff --git a/Libraries/LibWeb/GraphemeEdgeTracker.cpp b/Libraries/LibWeb/GraphemeEdgeTracker.cpp index e52d71e245..d785869f3a 100644 --- a/Libraries/LibWeb/GraphemeEdgeTracker.cpp +++ b/Libraries/LibWeb/GraphemeEdgeTracker.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -38,7 +39,9 @@ static float measure_text_width(Layout::TextNode const& text_node, Utf16View con auto grapheme_segmenter = text_node.grapheme_segmenter().clone(); grapheme_segmenter->set_segmented_text(text); - auto line_segmenter = text_node.line_segmenter().clone(); + // NB: The text node's cached line segmenter may be the ASCII fast-path variant, which only accepts a subset + // of inputs; route through the document's ICU segmenter so arbitrary subviews are handled. + auto line_segmenter = text_node.document().line_segmenter().clone(); line_segmenter->set_segmented_text(text); Layout::TextNode::ChunkIterator iterator { text_node, text, *grapheme_segmenter, *line_segmenter, CSS::WordBreak::Normal, false, false }; diff --git a/Libraries/LibWeb/Layout/TextNode.cpp b/Libraries/LibWeb/Layout/TextNode.cpp index 73345b7969..50cf142b48 100644 --- a/Libraries/LibWeb/Layout/TextNode.cpp +++ b/Libraries/LibWeb/Layout/TextNode.cpp @@ -416,8 +416,13 @@ Unicode::Segmenter& TextNode::grapheme_segmenter() const Unicode::Segmenter& TextNode::line_segmenter() const { if (!m_line_segmenter) { - m_line_segmenter = document().line_segmenter().clone(); - m_line_segmenter->set_segmented_text(text_for_rendering()); + auto const& text = text_for_rendering(); + if (auto ascii = Unicode::Segmenter::try_create_for_ascii_line(text.utf16_view())) { + m_line_segmenter = ascii.release_nonnull(); + } else { + m_line_segmenter = document().line_segmenter().clone(); + m_line_segmenter->set_segmented_text(text); + } } return *m_line_segmenter;