Support single-value <select> elements (#35684)

https://github.com/user-attachments/assets/9aba75ff-4190-4a85-89ed-d3f3aa53d3b0



Among other things this adds a new `EmbedderMsg::ShowSelectElementMenu`
to tell the embedder to display a select popup at the given location.

This is a draft because some small style adjustments need to be made:
* the select element should always have the width of the largest option
* the border should be part of the shadow tree

Apart from that, it's mostly ready for review.

<details><summary>HTML for demo video</summary>

```html
<html>

<body>
<select id="c" name="choice">
  <option value="first">First Value</option>
  <option value="second">Second Value</option>
  <option value="third">Third Value</option>
</select>
</body>
</html>
```
</details>

---

<!-- Thank you for contributing to Servo! Please replace each `[ ]` by
`[X]` when the step is complete, and replace `___` with appropriate
data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] Part of https://github.com/servo/servo/issues/3551
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because ___

<!-- Also, please make sure that "Allow edits from maintainers" checkbox
is checked, so that we can help you if you get stuck somewhere along the
way.-->

<!-- Pull requests that do not address these steps are welcome, but they
will require additional verification as part of the review process. -->

---------

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
This commit is contained in:
Simon Wülker 2025-04-03 14:11:55 +02:00 committed by GitHub
parent 6e9d01b908
commit 0e99539dab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 633 additions and 151 deletions

View file

@ -223,6 +223,27 @@ pub enum AllowOrDeny {
Deny,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SelectElementOption {
/// A unique identifier for the option that can be used to select it.
pub id: usize,
/// The label that should be used to display the option to the user.
pub label: String,
/// Whether or not the option is selectable
pub is_disabled: bool,
}
/// Represents the contents of either an `<option>` or an `<optgroup>` element
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum SelectElementOptionOrOptgroup {
Option(SelectElementOption),
Optgroup {
label: String,
options: Vec<SelectElementOption>,
},
}
#[derive(Deserialize, IntoStaticStr, Serialize)]
pub enum EmbedderMsg {
/// A status message to be displayed by the browser chrome.
@ -331,6 +352,16 @@ pub enum EmbedderMsg {
ShutdownComplete,
/// Request to display a notification.
ShowNotification(Option<WebViewId>, Notification),
/// Indicates that the user has activated a `<select>` element.
///
/// The embedder should respond with the new state of the `<select>` element.
ShowSelectElementMenu(
WebViewId,
Vec<SelectElementOptionOrOptgroup>,
Option<usize>,
DeviceIntRect,
IpcSender<Option<usize>>,
),
}
impl Debug for EmbedderMsg {
@ -655,3 +686,9 @@ pub struct ScreenGeometry {
/// of the `WebView`.
pub offset: DeviceIntPoint,
}
impl From<SelectElementOption> for SelectElementOptionOrOptgroup {
fn from(value: SelectElementOption) -> Self {
Self::Option(value)
}
}