diff --git a/Libraries/LibWeb/CSS/SelectorEngine.cpp b/Libraries/LibWeb/CSS/SelectorEngine.cpp index 30f67d1f864..ad768939dee 100644 --- a/Libraries/LibWeb/CSS/SelectorEngine.cpp +++ b/Libraries/LibWeb/CSS/SelectorEngine.cpp @@ -552,8 +552,8 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla case CSS::PseudoClass::FocusVisible: return element.is_focused() && element.should_indicate_focus(); case CSS::PseudoClass::FocusWithin: { - auto* focused_element = element.document().focused_element(); - return focused_element && element.is_inclusive_ancestor_of(*focused_element); + auto focused_area = element.document().focused_area(); + return focused_area && element.is_inclusive_ancestor_of(*focused_area); } case CSS::PseudoClass::FirstChild: if (context.collect_per_element_selector_involvement_metadata) { diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index 7d826d2a563..57037fe6b39 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -547,7 +547,7 @@ void Document::visit_edges(Cell::Visitor& visitor) visitor.visit(m_highlighted_node); visitor.visit(m_active_favicon); visitor.visit(m_browsing_context); - visitor.visit(m_focused_element); + visitor.visit(m_focused_area); visitor.visit(m_active_element); visitor.visit(m_target_element); visitor.visit(m_implementation); @@ -2443,7 +2443,7 @@ String const& Document::compat_mode() const void Document::update_active_element() { // 1. Let candidate be this's node document's focused area's DOM anchor. - Node* candidate = focused_element(); + Node* candidate = focused_area(); // 2. Set candidate to the result of retargeting candidate against this. candidate = as(retarget(candidate, this)); @@ -2478,56 +2478,57 @@ void Document::update_active_element() set_active_element(nullptr); } -void Document::set_focused_element(GC::Ptr element) +void Document::set_focused_area(GC::Ptr node) { - if (m_focused_element.ptr() == element) + if (m_focused_area == node) return; - GC::Ptr old_focused_element = move(m_focused_element); + GC::Ptr old_focused_area = m_focused_area; - if (old_focused_element) + if (auto* old_focused_element = as_if(old_focused_area.ptr())) old_focused_element->did_lose_focus(); - auto* common_ancestor = find_common_ancestor(old_focused_element, element); + auto* common_ancestor = find_common_ancestor(old_focused_area, node); GC::Ptr old_focused_node_root = nullptr; GC::Ptr new_focused_node_root = nullptr; - if (old_focused_element) - old_focused_node_root = old_focused_element->root(); - if (element) - new_focused_node_root = element->root(); + if (old_focused_area) + old_focused_node_root = old_focused_area->root(); + if (node) + new_focused_node_root = node->root(); if (old_focused_node_root != new_focused_node_root) { if (old_focused_node_root) { - invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::Focus, m_focused_element, *old_focused_node_root, element); - invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusWithin, m_focused_element, *old_focused_node_root, element); - invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusVisible, m_focused_element, *old_focused_node_root, element); + invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::Focus, m_focused_area, *old_focused_node_root, node); + invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusWithin, m_focused_area, *old_focused_node_root, node); + invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusVisible, m_focused_area, *old_focused_node_root, node); } if (new_focused_node_root) { - invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::Focus, m_focused_element, *new_focused_node_root, element); - invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusWithin, m_focused_element, *new_focused_node_root, element); - invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusVisible, m_focused_element, *new_focused_node_root, element); + invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::Focus, m_focused_area, *new_focused_node_root, node); + invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusWithin, m_focused_area, *new_focused_node_root, node); + invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusVisible, m_focused_area, *new_focused_node_root, node); } } else { - invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::Focus, m_focused_element, *common_ancestor, element); - invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusWithin, m_focused_element, *common_ancestor, element); - invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusVisible, m_focused_element, *common_ancestor, element); + invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::Focus, m_focused_area, *common_ancestor, node); + invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusWithin, m_focused_area, *common_ancestor, node); + invalidate_style_for_elements_affected_by_pseudo_class_change(CSS::PseudoClass::FocusVisible, m_focused_area, *common_ancestor, node); } - m_focused_element = element; + m_focused_area = node; - if (m_focused_element) - m_focused_element->did_receive_focus(); + auto* new_focused_element = as_if(node.ptr()); + if (new_focused_element) + new_focused_element->did_receive_focus(); if (paintable()) paintable()->set_needs_display(); // Scroll the viewport if necessary to make the newly focused element visible. - if (m_focused_element) { - m_focused_element->queue_an_element_task(HTML::Task::Source::UserInteraction, [&]() { + if (new_focused_element) { + new_focused_element->queue_an_element_task(HTML::Task::Source::UserInteraction, [&] { ScrollIntoViewOptions scroll_options; scroll_options.block = Bindings::ScrollLogicalPosition::Nearest; scroll_options.inline_ = Bindings::ScrollLogicalPosition::Nearest; - (void)m_focused_element->scroll_into_view(scroll_options); + (void)as(*m_focused_area).scroll_into_view(scroll_options); }); } @@ -6338,38 +6339,38 @@ GC::Ref Document::parse_html_unsafe(JS::VM& vm, StringView html) InputEventsTarget* Document::active_input_events_target() { - auto* focused_element = this->focused_element(); - if (!focused_element) + auto focused_area = this->focused_area(); + if (!focused_area) return {}; - if (is(*focused_element)) - return static_cast(focused_element); - if (is(*focused_element)) - return static_cast(focused_element); - if (focused_element->is_editable_or_editing_host()) + if (auto* input_element = as_if(*focused_area)) + return input_element; + if (auto* text_area_element = as_if(*focused_area)) + return text_area_element; + if (focused_area->is_editable_or_editing_host()) return m_editing_host_manager; return nullptr; } GC::Ptr Document::cursor_position() const { - auto const* focused_element = this->focused_element(); - if (!focused_element) + auto const focused_area = this->focused_area(); + if (!focused_area) return nullptr; Optional target {}; - if (auto const* input_element = as_if(*focused_element)) { + if (auto const* input_element = as_if(*focused_area)) { // Some types of tags shouldn't have a cursor, like buttons if (!input_element->can_have_text_editing_cursor()) return nullptr; target = *input_element; - } else if (is(*focused_element)) - target = static_cast(*focused_element); + } else if (is(*focused_area)) + target = static_cast(*focused_area); if (target.has_value()) return target->cursor_position(); - if (focused_element->is_editable_or_editing_host()) + if (focused_area->is_editable_or_editing_host()) return m_selection->cursor_position(); return nullptr; diff --git a/Libraries/LibWeb/DOM/Document.h b/Libraries/LibWeb/DOM/Document.h index d7824f6b369..9967bc68faa 100644 --- a/Libraries/LibWeb/DOM/Document.h +++ b/Libraries/LibWeb/DOM/Document.h @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -431,10 +430,10 @@ public: void set_editable(bool editable) { m_editable = editable; } - Element* focused_element() { return m_focused_element.ptr(); } - Element const* focused_element() const { return m_focused_element.ptr(); } - - void set_focused_element(GC::Ptr); + // // https://html.spec.whatwg.org/multipage/interaction.html#focused-area-of-the-document + GC::Ptr focused_area() { return m_focused_area; } + GC::Ptr focused_area() const { return m_focused_area; } + void set_focused_area(GC::Ptr); HTML::FocusTrigger last_focus_trigger() const { return m_last_focus_trigger; } void set_last_focus_trigger(HTML::FocusTrigger trigger) { m_last_focus_trigger = trigger; } @@ -1017,7 +1016,9 @@ private: bool m_editable { false }; - GC::Ptr m_focused_element; + // https://html.spec.whatwg.org/multipage/interaction.html#focused-area-of-the-document + GC::Ptr m_focused_area; + HTML::FocusTrigger m_last_focus_trigger { HTML::FocusTrigger::Other }; GC::Ptr m_active_element; diff --git a/Libraries/LibWeb/DOM/Element.cpp b/Libraries/LibWeb/DOM/Element.cpp index ea2a05fbc85..17c86c5822a 100644 --- a/Libraries/LibWeb/DOM/Element.cpp +++ b/Libraries/LibWeb/DOM/Element.cpp @@ -1077,7 +1077,7 @@ WebIDL::ExceptionOr Element::inner_html() const bool Element::is_focused() const { - return document().focused_element() == this; + return document().focused_area() == this; } bool Element::is_active() const @@ -3291,8 +3291,8 @@ bool Element::is_relevant_to_the_user() return true; // Either the element or its contents are focused, as described in the focus section of the HTML spec. - auto* focused_element = document().focused_element(); - if (focused_element && is_inclusive_ancestor_of(*focused_element)) + auto focused_area = document().focused_area(); + if (focused_area && is_inclusive_ancestor_of(*focused_area)) return true; // Either the element or its contents are selected, where selection is described in the selection API. diff --git a/Libraries/LibWeb/HTML/Focus.cpp b/Libraries/LibWeb/HTML/Focus.cpp index b8fe2594af6..77156b08972 100644 --- a/Libraries/LibWeb/HTML/Focus.cpp +++ b/Libraries/LibWeb/HTML/Focus.cpp @@ -113,9 +113,9 @@ static void run_focus_update_steps(Vector> old_chain, Vector // 1. If entry is a focusable area: designate entry as the focused area of the document. // FIXME: This isn't entirely right. if (is(*entry)) - entry->document().set_focused_element(&static_cast(*entry)); + entry->document().set_focused_area(*entry); else if (is(*entry)) - entry->document().set_focused_element(static_cast(*entry).document_element()); + entry->document().set_focused_area(static_cast(*entry).document_element()); GC::Ptr focus_event_target; if (is(*entry)) { diff --git a/Libraries/LibWeb/HTML/TraversableNavigable.cpp b/Libraries/LibWeb/HTML/TraversableNavigable.cpp index 399a4879717..a1f7b05ac12 100644 --- a/Libraries/LibWeb/HTML/TraversableNavigable.cpp +++ b/Libraries/LibWeb/HTML/TraversableNavigable.cpp @@ -1369,17 +1369,17 @@ GC::Ptr TraversableNavigable::currently_focused_area() // 3. While candidate's focused area is a navigable container with a non-null content navigable: // set candidate to the active document of that navigable container's content navigable. - while (candidate->focused_element() - && is(candidate->focused_element()) - && static_cast(*candidate->focused_element()).content_navigable()) { - candidate = static_cast(*candidate->focused_element()).content_navigable()->active_document(); + while (candidate->focused_area() + && is(candidate->focused_area().ptr()) + && as(*candidate->focused_area()).content_navigable()) { + candidate = as(*candidate->focused_area()).content_navigable()->active_document(); } // 4. If candidate's focused area is non-null, set candidate to candidate's focused area. - if (candidate->focused_element()) { + if (candidate->focused_area()) { // NOTE: We return right away here instead of assigning to candidate, // since that would require compromising type safety. - return candidate->focused_element(); + return candidate->focused_area(); } // 5. Return candidate. diff --git a/Libraries/LibWeb/HTML/Window.h b/Libraries/LibWeb/HTML/Window.h index 3d7866d27ae..51d32ac5619 100644 --- a/Libraries/LibWeb/HTML/Window.h +++ b/Libraries/LibWeb/HTML/Window.h @@ -9,9 +9,7 @@ #include #include -#include #include -#include #include #include #include @@ -22,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/Libraries/LibWeb/Page/EventHandler.cpp b/Libraries/LibWeb/Page/EventHandler.cpp index 263fbd8b090..777c584719d 100644 --- a/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Libraries/LibWeb/Page/EventHandler.cpp @@ -683,8 +683,8 @@ EventResult EventHandler::handle_mousedown(CSSPixelPoint viewport_position, CSSP // Spec Note: Note that focusing is not an activation behavior, i.e. calling the click() method on an element or dispatching a synthetic click event on it won't cause the element to get focused. if (focus_candidate) HTML::run_focusing_steps(focus_candidate, nullptr, HTML::FocusTrigger::Click); - else if (auto* focused_element = document->focused_element()) - HTML::run_unfocusing_steps(focused_element); + else if (auto focused_area = document->focused_area()) + HTML::run_unfocusing_steps(focused_area); // https://drafts.csswg.org/css-ui/#valdef-user-select-none // Attempting to start a selection in an element where user-select is none, such as by clicking in it or starting @@ -1066,17 +1066,17 @@ EventResult EventHandler::focus_next_element() return EventResult::Dropped; }; - auto* element = m_navigable->active_document()->focused_element(); - if (!element) + auto node = m_navigable->active_document()->focused_area(); + if (!node) return set_focus_to_first_focusable_element(); - for (element = element->next_element_in_pre_order(); element && !element->is_focusable(); element = element->next_element_in_pre_order()) + for (node = node->next_in_pre_order(); node && !node->is_focusable(); node = node->next_in_pre_order()) ; - if (!element) + if (!node) return set_focus_to_first_focusable_element(); - HTML::run_focusing_steps(element, nullptr, HTML::FocusTrigger::Key); + HTML::run_focusing_steps(node, nullptr, HTML::FocusTrigger::Key); return EventResult::Handled; } @@ -1101,17 +1101,17 @@ EventResult EventHandler::focus_previous_element() return EventResult::Dropped; }; - auto* element = m_navigable->active_document()->focused_element(); - if (!element) + auto node = m_navigable->active_document()->focused_area(); + if (!node) return set_focus_to_last_focusable_element(); - for (element = element->previous_element_in_pre_order(); element && !element->is_focusable(); element = element->previous_element_in_pre_order()) + for (node = node->previous_in_pre_order(); node && !node->is_focusable(); node = node->previous_in_pre_order()) ; - if (!element) + if (!node) return set_focus_to_last_focusable_element(); - HTML::run_focusing_steps(element, nullptr, HTML::FocusTrigger::Key); + HTML::run_focusing_steps(node, nullptr, HTML::FocusTrigger::Key); return EventResult::Handled; } @@ -1132,15 +1132,15 @@ EventResult EventHandler::fire_keyboard_event(FlyString const& event_name, HTML: if (!document->is_fully_active()) return EventResult::Dropped; - if (GC::Ptr focused_element = document->focused_element()) { - if (is(*focused_element)) { - auto& navigable_container = as(*focused_element); + if (GC::Ptr focused_area = document->focused_area()) { + if (is(*focused_area)) { + auto& navigable_container = as(*focused_area); if (navigable_container.content_navigable()) return fire_keyboard_event(event_name, *navigable_container.content_navigable(), key, modifiers, code_point, repeat); } auto event = UIEvents::KeyboardEvent::create_from_platform_event(document->realm(), event_name, key, modifiers, code_point, repeat); - return focused_element->dispatch_event(event) ? EventResult::Accepted : EventResult::Cancelled; + return focused_area->dispatch_event(event) ? EventResult::Accepted : EventResult::Cancelled; } // FIXME: De-duplicate this. This is just to prevent wasting a KeyboardEvent allocation when recursing into an (i)frame. @@ -1207,15 +1207,15 @@ EventResult EventHandler::input_event(FlyString const& event_name, FlyString con input_event_init.input_type = input_type; - if (auto* focused_element = document->focused_element()) { - if (is(*focused_element)) { - auto& navigable_container = as(*focused_element); + if (auto focused_area = document->focused_area()) { + if (is(*focused_area)) { + auto& navigable_container = as(*focused_area); if (navigable_container.content_navigable()) return input_event(event_name, input_type, *navigable_container.content_navigable(), move(code_point_or_string)); } auto event = UIEvents::InputEvent::create_from_platform_event(document->realm(), event_name, input_event_init, target_ranges_for_input_event(*document)); - return focused_element->dispatch_event(event) ? EventResult::Accepted : EventResult::Cancelled; + return focused_area->dispatch_event(event) ? EventResult::Accepted : EventResult::Cancelled; } auto event = UIEvents::InputEvent::create_from_platform_event(document->realm(), event_name, input_event_init, target_ranges_for_input_event(*document)); @@ -1270,8 +1270,8 @@ EventResult EventHandler::handle_keydown(UIEvents::KeyCode key, u32 modifiers, u // instead interpret this interaction as some other action, instead of interpreting it as a close request. } - auto* focused_element = m_navigable->active_document()->focused_element(); - if (auto* media_element = as_if(focused_element)) { + auto focused_area = m_navigable->active_document()->focused_area(); + if (auto* media_element = as_if(focused_area.ptr())) { if (media_element->handle_keydown({}, key, modifiers).release_value_but_fixme_should_propagate_errors()) return EventResult::Handled; } @@ -1347,8 +1347,8 @@ EventResult EventHandler::handle_keydown(UIEvents::KeyCode key, u32 modifiers, u auto input_type = modifiers == UIEvents::Mod_Shift ? UIEvents::InputTypes::insertLineBreak : UIEvents::InputTypes::insertParagraph; // If the editing host is contenteditable="plaintext-only", we force a line break. - if (focused_element) { - if (auto editing_host = focused_element->editing_host(); editing_host + if (focused_area) { + if (auto editing_host = focused_area->editing_host(); editing_host && as(*editing_host).content_editable_state() == HTML::ContentEditableState::PlaintextOnly) input_type = UIEvents::InputTypes::insertLineBreak; } diff --git a/Libraries/LibWeb/Painting/PaintableFragment.cpp b/Libraries/LibWeb/Painting/PaintableFragment.cpp index b988c2fcd63..e5e06b30ce1 100644 --- a/Libraries/LibWeb/Painting/PaintableFragment.cpp +++ b/Libraries/LibWeb/Painting/PaintableFragment.cpp @@ -180,12 +180,12 @@ Gfx::Orientation PaintableFragment::orientation() const CSSPixelRect PaintableFragment::selection_rect() const { - if (auto const* focused_element = paintable().document().focused_element(); focused_element && is(*focused_element)) { + if (auto focused_area = paintable().document().focused_area(); is(focused_area.ptr())) { HTML::FormAssociatedTextControlElement const* text_control_element = nullptr; - if (is(*focused_element)) { - text_control_element = static_cast(focused_element); - } else if (is(*focused_element)) { - text_control_element = static_cast(focused_element); + if (auto const* input_element = as_if(*focused_area)) { + text_control_element = input_element; + } else if (auto const* text_area_element = as_if(*focused_area)) { + text_control_element = text_area_element; } else { VERIFY_NOT_REACHED(); } diff --git a/Libraries/LibWeb/Selection/Selection.cpp b/Libraries/LibWeb/Selection/Selection.cpp index 6391939b154..013d2c60523 100644 --- a/Libraries/LibWeb/Selection/Selection.cpp +++ b/Libraries/LibWeb/Selection/Selection.cpp @@ -552,7 +552,7 @@ void Selection::set_range(GC::Ptr range) GC::Ref new_editing_host = *range->start_container()->editing_host(); while (new_editing_host->parent() && new_editing_host->parent()->is_editing_host()) new_editing_host = *new_editing_host->parent(); - if (document()->focused_element() != new_editing_host) { + if (document()->focused_area() != new_editing_host) { // FIXME: Determine and propagate the right focus trigger. HTML::run_focusing_steps(new_editing_host, nullptr, HTML::FocusTrigger::Other); } diff --git a/Services/WebContent/WebDriverConnection.cpp b/Services/WebContent/WebDriverConnection.cpp index a0ba0b48812..7749840b9d2 100644 --- a/Services/WebContent/WebDriverConnection.cpp +++ b/Services/WebContent/WebDriverConnection.cpp @@ -1961,7 +1961,7 @@ Web::WebDriver::Response WebDriverConnection::element_send_keys_impl(StringView else if (is(*element) && static_cast(*element).is_content_editable()) { // If element does not currently have focus, set the text insertion caret after any child content. auto* document = current_browsing_context().active_document(); - document->set_focused_element(element); + document->set_focused_area(element); } // -> otherwise else if (is(*element)) {