summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb/DOM/Position.cpp
diff options
context:
space:
mode:
authorMax Wipfli <mail@maxwipfli.ch>2021-05-18 22:01:12 +0200
committerAndreas Kling <kling@serenityos.org>2021-05-21 21:57:03 +0200
commit7181cb3a9ce11736170ac6f7863413ad19e17fbd (patch)
tree6fc96269c71c91f38b6bcb901f5b92b7d55c6a1a /Userland/Libraries/LibWeb/DOM/Position.cpp
parent08d09c4afb341cea1d435e7acc226dbcfdec1a7e (diff)
downloadserenity-7181cb3a9ce11736170ac6f7863413ad19e17fbd.zip
LibWeb: Frame/Position: Implement cursor increment/decrement methods
This introduces methods to increment and decrement the cursor position. This is non-trivial as the cursor position is specified in bytes rather than codepoints. Thus, it sometimes needs to be incremented or decremented by more than one, depending on the codepoint to "jump over". Because the cursor blink cycle needs to be reset after moving the cursor, methods calling the ones in DOM::Position are implemented in Frame. Furthermore, this allows the cursor_position() getter to stay const. :^) Additionally, it adds a offset_is_at_end_of_node() method which checks if the current offset points to the end of the node.
Diffstat (limited to 'Userland/Libraries/LibWeb/DOM/Position.cpp')
-rw-r--r--Userland/Libraries/LibWeb/DOM/Position.cpp55
1 files changed, 55 insertions, 0 deletions
diff --git a/Userland/Libraries/LibWeb/DOM/Position.cpp b/Userland/Libraries/LibWeb/DOM/Position.cpp
index 4bd0135a23..155e94ecbe 100644
--- a/Userland/Libraries/LibWeb/DOM/Position.cpp
+++ b/Userland/Libraries/LibWeb/DOM/Position.cpp
@@ -1,11 +1,14 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Max Wipfli <mail@maxwipfli.ch>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
+#include <AK/Utf8View.h>
#include <LibWeb/DOM/Node.h>
#include <LibWeb/DOM/Position.h>
+#include <LibWeb/DOM/Text.h>
namespace Web::DOM {
@@ -26,4 +29,56 @@ String Position::to_string() const
return String::formatted("DOM::Position({} ({})), {})", node()->node_name(), node(), offset());
}
+bool Position::increment_offset()
+{
+ if (!is<DOM::Text>(*m_node))
+ return false;
+
+ auto& node = downcast<DOM::Text>(*m_node);
+ auto text = Utf8View(node.data());
+
+ for (auto iterator = text.begin(); !iterator.done(); ++iterator) {
+ if (text.byte_offset_of(iterator) >= m_offset) {
+ // NOTE: If the current offset is inside a multi-byte codepoint, it will be moved to the start of the next codepoint.
+ m_offset = text.byte_offset_of(++iterator);
+ return true;
+ }
+ }
+ // NOTE: Already at end of current node.
+ return false;
+}
+
+bool Position::decrement_offset()
+{
+ if (m_offset == 0 || !is<DOM::Text>(*m_node))
+ return false;
+
+ auto& node = downcast<DOM::Text>(*m_node);
+ auto text = Utf8View(node.data());
+
+ size_t last_smaller_offset = 0;
+
+ for (auto iterator = text.begin(); !iterator.done(); ++iterator) {
+ auto byte_offset = text.byte_offset_of(iterator);
+ if (byte_offset >= m_offset) {
+ break;
+ }
+ last_smaller_offset = text.byte_offset_of(iterator);
+ }
+
+ // NOTE: If the current offset is inside a multi-byte codepoint, it will be moved to the start of that codepoint.
+ m_offset = last_smaller_offset;
+ return true;
+}
+
+bool Position::offset_is_at_end_of_node() const
+{
+ if (!is<DOM::Text>(*m_node))
+ return false;
+
+ auto& node = downcast<DOM::Text>(*m_node);
+ auto text = node.data();
+ return m_offset == text.length();
+}
+
}