Fully support <input type=color> (#36992)

This change adds a shadow-tree widget for `<input type=color>` elements.
It also involves some changes to the way layout interacts with the DOM,
because currently all `input` and `textarea` elements are rendered as
plain text and their descendants are ignored. This obviously doesn't
work for `<input type={color, date, range, etc}>`.


![image](https://github.com/user-attachments/assets/4f16c3b0-1f79-4095-b19d-1153f5853dd5)

<details><summary>HTML used for the screenshot above</summary>

```html
<input type=color>
```

</details>



Testing: I doubt that this affects WPT tests, because the appearance and
behaviour of the widget is almost entirely unspecified.

---------

Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
This commit is contained in:
Simon Wülker 2025-05-15 19:30:38 +02:00 committed by GitHub
parent f9382fcaa0
commit b100a98e1d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 469 additions and 100 deletions

View file

@ -50,7 +50,6 @@ use style::stylesheets::{Stylesheet, UrlExtraData};
use uuid::Uuid;
use xml5ever::serialize as xml_serialize;
use super::globalscope::GlobalScope;
use crate::conversions::Convert;
use crate::document_loader::DocumentLoader;
use crate::dom::attr::Attr;
@ -92,13 +91,14 @@ use crate::dom::documenttype::DocumentType;
use crate::dom::element::{CustomElementCreationMode, Element, ElementCreator, SelectorWrapper};
use crate::dom::event::{Event, EventBubbles, EventCancelable};
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlbodyelement::HTMLBodyElement;
use crate::dom::htmlcanvaselement::{HTMLCanvasElement, LayoutHTMLCanvasElementHelpers};
use crate::dom::htmlcollection::HTMLCollection;
use crate::dom::htmlelement::HTMLElement;
use crate::dom::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementLayoutMethods};
use crate::dom::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers};
use crate::dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
use crate::dom::htmlinputelement::{HTMLInputElement, InputType, LayoutHTMLInputElementHelpers};
use crate::dom::htmllinkelement::HTMLLinkElement;
use crate::dom::htmlslotelement::{HTMLSlotElement, Slottable};
use crate::dom::htmlstyleelement::HTMLStyleElement;
@ -1612,6 +1612,8 @@ pub(crate) trait LayoutNodeHelpers<'dom> {
/// attempting to read or modify the opaque layout data of this node.
unsafe fn clear_style_and_layout_data(self);
/// Whether this element is a `<input>` rendered as text or a `<textarea>`.
fn is_text_input(&self) -> bool;
fn text_content(self) -> Cow<'dom, str>;
fn selection(self) -> Option<Range<usize>>;
fn image_url(self) -> Option<ServoUrl>;
@ -1776,6 +1778,25 @@ impl<'dom> LayoutNodeHelpers<'dom> for LayoutDom<'dom, Node> {
self.unsafe_get().layout_data.borrow_mut_for_layout().take();
}
fn is_text_input(&self) -> bool {
let type_id = self.type_id_for_layout();
if type_id ==
NodeTypeId::Element(ElementTypeId::HTMLElement(
HTMLElementTypeId::HTMLInputElement,
))
{
let input = self.unsafe_get().downcast::<HTMLInputElement>().unwrap();
// FIXME: All the non-color input types currently render as text
input.input_type() != InputType::Color
} else {
type_id ==
NodeTypeId::Element(ElementTypeId::HTMLElement(
HTMLElementTypeId::HTMLTextAreaElement,
))
}
}
fn text_content(self) -> Cow<'dom, str> {
if let Some(text) = self.downcast::<Text>() {
return text.upcast().data_for_layout().into();