/* * Copyright (c) 2020, the SerenityOS developers. * Copyright (c) 2022, Luke Wilde * Copyright (c) 2022-2023, Andreas Kling * Copyright (c) 2024-2025, Jelle Raaijmakers * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include namespace Web::DOM { enum class RelativeBoundaryPointPosition { Equal, Before, After, }; // https://dom.spec.whatwg.org/#concept-range-bp-position RelativeBoundaryPointPosition position_of_boundary_point_relative_to_other_boundary_point(BoundaryPoint a, BoundaryPoint b); class Range final : public AbstractRange { WEB_PLATFORM_OBJECT(Range, AbstractRange); GC_DECLARE_ALLOCATOR(Range); public: [[nodiscard]] static GC::Ref create(Document&); [[nodiscard]] static GC::Ref create(HTML::Window&); [[nodiscard]] static GC::Ref create(GC::Ref start_container, WebIDL::UnsignedLong start_offset, GC::Ref end_container, WebIDL::UnsignedLong end_offset); static WebIDL::ExceptionOr> construct_impl(JS::Realm&); virtual ~Range() override; WebIDL::ExceptionOr set_start(GC::Ref node, WebIDL::UnsignedLong offset); WebIDL::ExceptionOr set_end(GC::Ref node, WebIDL::UnsignedLong offset); WebIDL::ExceptionOr set_start_before(GC::Ref node); WebIDL::ExceptionOr set_start_after(GC::Ref node); WebIDL::ExceptionOr set_end_before(GC::Ref node); WebIDL::ExceptionOr set_end_after(GC::Ref node); WebIDL::ExceptionOr select_node(GC::Ref node); void collapse(bool to_start); WebIDL::ExceptionOr select_node_contents(GC::Ref); void increase_start_offset(Badge, WebIDL::UnsignedLong); void increase_end_offset(Badge, WebIDL::UnsignedLong); void decrease_start_offset(Badge, WebIDL::UnsignedLong); void decrease_end_offset(Badge, WebIDL::UnsignedLong); // https://dom.spec.whatwg.org/#dom-range-start_to_start enum HowToCompareBoundaryPoints : WebIDL::UnsignedShort { START_TO_START = 0, START_TO_END = 1, END_TO_END = 2, END_TO_START = 3, }; WebIDL::ExceptionOr compare_boundary_points(WebIDL::UnsignedShort how, Range const& source_range) const; GC::Ref inverted() const; GC::Ref normalized() const; GC::Ref clone_range() const; GC::Ref common_ancestor_container() const; // https://dom.spec.whatwg.org/#dom-range-detach void detach() const { // The detach() method steps are to do nothing. // Note: Its functionality (disabling a Range object) was removed, but the method itself is preserved for compatibility. } bool intersects_node(GC::Ref) const; WebIDL::ExceptionOr is_point_in_range(GC::Ref, WebIDL::UnsignedLong offset) const; WebIDL::ExceptionOr compare_point(GC::Ref, WebIDL::UnsignedLong offset) const; WebIDL::ExceptionOr delete_contents(); WebIDL::ExceptionOr> extract_contents(); WebIDL::ExceptionOr> clone_contents(); WebIDL::ExceptionOr insert_node(GC::Ref); WebIDL::ExceptionOr surround_contents(GC::Ref new_parent); String to_string() const; static HashTable& live_ranges(); GC::Ref get_client_rects(); GC::Ref get_bounding_client_rect(); bool contains_node(GC::Ref) const; void set_associated_selection(Badge, GC::Ptr); WebIDL::ExceptionOr> create_contextual_fragment(String const& fragment); template void for_each_contained(Callback callback) const { return const_cast(this)->for_each_contained(move(callback)); } template void for_each_contained(Callback callback) { GC::Ptr end = m_end_container; while (end && !end->next_sibling()) end = end->parent(); if (end) end = end->next_sibling(); for (GC::Ptr node = m_start_container; node && node != end; node = node->next_in_pre_order()) { if (contains_node(*node)) { if (callback(*node) == IterationDecision::Break) return; } } } private: explicit Range(Document&); Range(GC::Ref start_container, WebIDL::UnsignedLong start_offset, GC::Ref end_container, WebIDL::UnsignedLong end_offset); virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; GC::Ref root() const; void update_associated_selection(); enum class StartOrEnd { Start, End, }; WebIDL::ExceptionOr set_start_or_end(GC::Ref node, u32 offset, StartOrEnd start_or_end); WebIDL::ExceptionOr select(GC::Ref node); WebIDL::ExceptionOr> extract(); WebIDL::ExceptionOr> clone_the_contents(); WebIDL::ExceptionOr insert(GC::Ref); bool partially_contains_node(GC::Ref) const; GC::Ptr m_associated_selection; }; }