summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorMax Wipfli <mail@maxwipfli.ch>2021-06-03 22:33:53 +0200
committerAndreas Kling <kling@serenityos.org>2021-06-04 09:39:07 +0200
commit054c742d177452d7516ca26a7bed72f39b6365f0 (patch)
treeeb7d62e3bc7e88bdb9c49a95bdd072b364568c86 /Userland
parent9c0cfede593d41549095df7252429247abc34bb4 (diff)
downloadserenity-054c742d177452d7516ca26a7bed72f39b6365f0.zip
LibWeb: Remove Utf8View usage and try avoiding StringBuilder in TextNode
This patch completely reworks TextNode::compute_text_for_rendering(). It removes the unnecessary usage of Utf8View to find spaces in a String. Furthermore, it adds a couple fast return paths for common but trivial cases such as empty, single-character and whitespace-less strings. For the HTML spec bookmarks, around two thirds of all function calls (which amounts to around 10'000) use the fast paths and thus avoid allocating a StringBuilder just to build a copy of the already present String.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibWeb/Layout/TextNode.cpp60
1 files changed, 44 insertions, 16 deletions
diff --git a/Userland/Libraries/LibWeb/Layout/TextNode.cpp b/Userland/Libraries/LibWeb/Layout/TextNode.cpp
index 1520788d0c..e03097e0d9 100644
--- a/Userland/Libraries/LibWeb/Layout/TextNode.cpp
+++ b/Userland/Libraries/LibWeb/Layout/TextNode.cpp
@@ -103,35 +103,63 @@ void TextNode::paint_cursor_if_needed(PaintContext& context, const LineBoxFragme
context.painter().draw_rect(cursor_rect, computed_values().color());
}
+// NOTE: This collapes whitespace into a single ASCII space if collapse is true. If previous_is_empty_or_ends_in_whitespace, it also strips leading whitespace.
void TextNode::compute_text_for_rendering(bool collapse, bool previous_is_empty_or_ends_in_whitespace)
{
- if (!collapse) {
- m_text_for_rendering = dom_node().data();
+ auto& data = dom_node().data();
+ if (!collapse || data.is_empty()) {
+ m_text_for_rendering = data;
return;
}
- // Collapse whitespace into single spaces
- auto utf8_view = Utf8View(dom_node().data());
- StringBuilder builder(dom_node().data().length());
- auto it = utf8_view.begin();
- auto skip_over_whitespace = [&] {
- auto prev = it;
- while (it != utf8_view.end() && is_ascii_space(*it)) {
- prev = it;
- ++it;
+ // NOTE: A couple fast returns to avoid unnecessarily allocating a StringBuilder.
+ if (data.length() == 1) {
+ if (is_ascii_space(data[0])) {
+ if (previous_is_empty_or_ends_in_whitespace)
+ m_text_for_rendering = String::empty();
+ else {
+ static String s_single_space_string = " ";
+ m_text_for_rendering = s_single_space_string;
+ }
+ } else {
+ m_text_for_rendering = data;
+ }
+ return;
+ }
+
+ bool contains_space = false;
+ for (auto& c : data) {
+ if (is_ascii_space(c)) {
+ contains_space = true;
+ break;
}
- it = prev;
+ }
+ if (!contains_space) {
+ m_text_for_rendering = data;
+ return;
+ }
+
+ StringBuilder builder(data.length());
+ size_t index = 0;
+
+ auto skip_over_whitespace = [&index, &data] {
+ while (index < data.length() && is_ascii_space(data[index]))
+ ++index;
};
+
if (previous_is_empty_or_ends_in_whitespace)
skip_over_whitespace();
- for (; it != utf8_view.end(); ++it) {
- if (!is_ascii_space(*it)) {
- builder.append(StringView { it.underlying_code_point_bytes() });
- } else {
+ while (index < data.length()) {
+ if (is_ascii_space(data[index])) {
builder.append(' ');
+ ++index;
skip_over_whitespace();
+ } else {
+ builder.append(data[index]);
+ ++index;
}
}
+
m_text_for_rendering = builder.to_string();
}