From 7181cb3a9ce11736170ac6f7863413ad19e17fbd Mon Sep 17 00:00:00 2001 From: Max Wipfli Date: Tue, 18 May 2021 22:01:12 +0200 Subject: [PATCH] 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. --- Userland/Libraries/LibWeb/DOM/Position.cpp | 55 ++++++++++++++++++++++ Userland/Libraries/LibWeb/DOM/Position.h | 4 ++ Userland/Libraries/LibWeb/Page/Frame.cpp | 16 +++++++ Userland/Libraries/LibWeb/Page/Frame.h | 2 + 4 files changed, 77 insertions(+) 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 + * Copyright (c) 2021, Max Wipfli * * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include +#include 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(*m_node)) + return false; + + auto& node = downcast(*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(*m_node)) + return false; + + auto& node = downcast(*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(*m_node)) + return false; + + auto& node = downcast(*m_node); + auto text = node.data(); + return m_offset == text.length(); +} + } diff --git a/Userland/Libraries/LibWeb/DOM/Position.h b/Userland/Libraries/LibWeb/DOM/Position.h index 78206fefaa..73dd703da0 100644 --- a/Userland/Libraries/LibWeb/DOM/Position.h +++ b/Userland/Libraries/LibWeb/DOM/Position.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2021, Max Wipfli * * SPDX-License-Identifier: BSD-2-Clause */ @@ -25,7 +26,10 @@ public: const Node* node() const { return m_node; } unsigned offset() const { return m_offset; } + bool offset_is_at_end_of_node() const; void set_offset(unsigned value) { m_offset = value; } + bool increment_offset(); + bool decrement_offset(); bool operator==(const Position& other) const { diff --git a/Userland/Libraries/LibWeb/Page/Frame.cpp b/Userland/Libraries/LibWeb/Page/Frame.cpp index 31e3d42417..0d130f2fa8 100644 --- a/Userland/Libraries/LibWeb/Page/Frame.cpp +++ b/Userland/Libraries/LibWeb/Page/Frame.cpp @@ -297,4 +297,20 @@ bool Frame::is_frame_nesting_allowed(URL const& url) const return m_frame_nesting_levels.get(url).value_or(0) < 3; } +bool Frame::increment_cursor_position_offset() +{ + if (!m_cursor_position.increment_offset()) + return false; + reset_cursor_blink_cycle(); + return true; +} + +bool Frame::decrement_cursor_position_offset() +{ + if (!m_cursor_position.decrement_offset()) + return false; + reset_cursor_blink_cycle(); + return true; +} + } diff --git a/Userland/Libraries/LibWeb/Page/Frame.h b/Userland/Libraries/LibWeb/Page/Frame.h index daac863581..8a0346d0b7 100644 --- a/Userland/Libraries/LibWeb/Page/Frame.h +++ b/Userland/Libraries/LibWeb/Page/Frame.h @@ -74,6 +74,8 @@ public: const DOM::Position& cursor_position() const { return m_cursor_position; } void set_cursor_position(DOM::Position); + bool increment_cursor_position_offset(); + bool decrement_cursor_position_offset(); bool cursor_blink_state() const { return m_cursor_blink_state; }