libservo: Allow Servo to hide embedder controls (#39763)

In some situations, web content may need to hide embedder controls. For
example, when focus shifts when a `<select>` box is open or when the
element showing the control is removed from the DOM. This change adds a
new API to hide embedder controls when that happens.

Testing: This change adds a new API test.

Signed-off-by: Delan Azabani <dazabani@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
shuppy
2025-10-14 15:56:33 +08:00
committed by GitHub
parent 97546453ce
commit b88007c14b
10 changed files with 223 additions and 13 deletions

View File

@@ -50,6 +50,7 @@ use crate::dom::html::htmloptionscollection::HTMLOptionsCollection;
use crate::dom::node::{BindContext, ChildrenMutation, Node, NodeTraits, UnbindContext};
use crate::dom::nodelist::NodeList;
use crate::dom::text::Text;
use crate::dom::types::FocusEvent;
use crate::dom::validation::{Validatable, is_barred_by_datalist_ancestor};
use crate::dom::validitystate::{ValidationFlags, ValidityState};
use crate::dom::virtualmethods::VirtualMethods;
@@ -446,6 +447,11 @@ impl HTMLSelectElement {
.fire_bubbling_event(atom!("change"), CanGc::note());
}));
}
fn may_have_embedder_control(&self) -> bool {
let el = self.upcast::<Element>();
!el.disabled_state()
}
}
impl HTMLSelectElementMethods<crate::DomTypeHolder> for HTMLSelectElement {
@@ -662,6 +668,7 @@ impl VirtualMethods for HTMLSelectElement {
}
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
let could_have_had_embedder_control = self.may_have_embedder_control();
self.super_type()
.unwrap()
.attribute_mutated(attr, mutation, can_gc);
@@ -692,6 +699,11 @@ impl VirtualMethods for HTMLSelectElement {
},
_ => {},
}
if could_have_had_embedder_control && !self.may_have_embedder_control() {
self.owner_document()
.embedder_controls()
.hide_form_control(self.upcast());
}
}
fn bind_to_tree(&self, context: &BindContext, can_gc: CanGc) {
@@ -716,6 +728,10 @@ impl VirtualMethods for HTMLSelectElement {
} else {
el.check_disabled_attribute();
}
self.owner_document()
.embedder_controls()
.hide_form_control(self.upcast());
}
fn children_changed(&self, mutation: &ChildrenMutation) {
@@ -735,6 +751,17 @@ impl VirtualMethods for HTMLSelectElement {
.parse_plain_attribute(local_name, value),
}
}
fn handle_event(&self, event: &Event, can_gc: CanGc) {
self.super_type().unwrap().handle_event(event, can_gc);
if let Some(event) = event.downcast::<FocusEvent>() {
if *event.upcast::<Event>().type_() != *"blur" {
self.owner_document()
.embedder_controls()
.hide_form_control(self.upcast());
}
}
}
}
impl FormControl for HTMLSelectElement {