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