mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Add internal pseudo element for input
Signed-off-by: stevennovaryo <steven.novaryo@gmail.com>
This commit is contained in:
parent
47899c4fdf
commit
1a3dd44f78
8 changed files with 114 additions and 91 deletions
24
Cargo.lock
generated
24
Cargo.lock
generated
|
@ -6607,7 +6607,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "selectors"
|
name = "selectors"
|
||||||
version = "0.28.0"
|
version = "0.28.0"
|
||||||
source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620"
|
source = "git+https://github.com/stevennovaryo/stylo?branch=input-text-internal-pseudo-selector#b0123d478e727125f8f6862e7afb5cf8ebf8ba17"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"cssparser",
|
"cssparser",
|
||||||
|
@ -6902,7 +6902,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servo_arc"
|
name = "servo_arc"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620"
|
source = "git+https://github.com/stevennovaryo/stylo?branch=input-text-internal-pseudo-selector#b0123d478e727125f8f6862e7afb5cf8ebf8ba17"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"stable_deref_trait",
|
"stable_deref_trait",
|
||||||
|
@ -7363,7 +7363,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stylo"
|
name = "stylo"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620"
|
source = "git+https://github.com/stevennovaryo/stylo?branch=input-text-internal-pseudo-selector#b0123d478e727125f8f6862e7afb5cf8ebf8ba17"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"app_units",
|
"app_units",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
|
@ -7421,7 +7421,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stylo_atoms"
|
name = "stylo_atoms"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620"
|
source = "git+https://github.com/stevennovaryo/stylo?branch=input-text-internal-pseudo-selector#b0123d478e727125f8f6862e7afb5cf8ebf8ba17"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"string_cache",
|
"string_cache",
|
||||||
"string_cache_codegen",
|
"string_cache_codegen",
|
||||||
|
@ -7430,12 +7430,12 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stylo_config"
|
name = "stylo_config"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620"
|
source = "git+https://github.com/stevennovaryo/stylo?branch=input-text-internal-pseudo-selector#b0123d478e727125f8f6862e7afb5cf8ebf8ba17"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stylo_derive"
|
name = "stylo_derive"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620"
|
source = "git+https://github.com/stevennovaryo/stylo?branch=input-text-internal-pseudo-selector#b0123d478e727125f8f6862e7afb5cf8ebf8ba17"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling",
|
"darling",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -7447,7 +7447,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stylo_dom"
|
name = "stylo_dom"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620"
|
source = "git+https://github.com/stevennovaryo/stylo?branch=input-text-internal-pseudo-selector#b0123d478e727125f8f6862e7afb5cf8ebf8ba17"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"stylo_malloc_size_of",
|
"stylo_malloc_size_of",
|
||||||
|
@ -7456,7 +7456,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stylo_malloc_size_of"
|
name = "stylo_malloc_size_of"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620"
|
source = "git+https://github.com/stevennovaryo/stylo?branch=input-text-internal-pseudo-selector#b0123d478e727125f8f6862e7afb5cf8ebf8ba17"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"app_units",
|
"app_units",
|
||||||
"cssparser",
|
"cssparser",
|
||||||
|
@ -7473,12 +7473,12 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stylo_static_prefs"
|
name = "stylo_static_prefs"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620"
|
source = "git+https://github.com/stevennovaryo/stylo?branch=input-text-internal-pseudo-selector#b0123d478e727125f8f6862e7afb5cf8ebf8ba17"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stylo_traits"
|
name = "stylo_traits"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620"
|
source = "git+https://github.com/stevennovaryo/stylo?branch=input-text-internal-pseudo-selector#b0123d478e727125f8f6862e7afb5cf8ebf8ba17"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"app_units",
|
"app_units",
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
|
@ -7887,7 +7887,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "to_shmem"
|
name = "to_shmem"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620"
|
source = "git+https://github.com/stevennovaryo/stylo?branch=input-text-internal-pseudo-selector#b0123d478e727125f8f6862e7afb5cf8ebf8ba17"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cssparser",
|
"cssparser",
|
||||||
"servo_arc",
|
"servo_arc",
|
||||||
|
@ -7900,7 +7900,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "to_shmem_derive"
|
name = "to_shmem_derive"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/servo/stylo?branch=2025-05-01#945b70e9a1984cd44ee56b7a674c302b19a4f620"
|
source = "git+https://github.com/stevennovaryo/stylo?branch=input-text-internal-pseudo-selector#b0123d478e727125f8f6862e7afb5cf8ebf8ba17"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling",
|
"darling",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
|
18
Cargo.toml
18
Cargo.toml
|
@ -119,7 +119,7 @@ rustls-pemfile = "2.0"
|
||||||
rustls-pki-types = "1.12"
|
rustls-pki-types = "1.12"
|
||||||
script_layout_interface = { path = "components/shared/script_layout" }
|
script_layout_interface = { path = "components/shared/script_layout" }
|
||||||
script_traits = { path = "components/shared/script" }
|
script_traits = { path = "components/shared/script" }
|
||||||
selectors = { git = "https://github.com/servo/stylo", branch = "2025-05-01" }
|
selectors = { git = "https://github.com/stevennovaryo/stylo", branch = "input-text-internal-pseudo-selector" }
|
||||||
serde = "1.0.219"
|
serde = "1.0.219"
|
||||||
serde_bytes = "0.11"
|
serde_bytes = "0.11"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
@ -127,7 +127,7 @@ servo-media = { git = "https://github.com/servo/media" }
|
||||||
servo-media-dummy = { git = "https://github.com/servo/media" }
|
servo-media-dummy = { git = "https://github.com/servo/media" }
|
||||||
servo-media-gstreamer = { git = "https://github.com/servo/media" }
|
servo-media-gstreamer = { git = "https://github.com/servo/media" }
|
||||||
servo-tracing = { path = "components/servo_tracing" }
|
servo-tracing = { path = "components/servo_tracing" }
|
||||||
servo_arc = { git = "https://github.com/servo/stylo", branch = "2025-05-01" }
|
servo_arc = { git = "https://github.com/stevennovaryo/stylo", branch = "input-text-internal-pseudo-selector" }
|
||||||
smallbitvec = "2.6.0"
|
smallbitvec = "2.6.0"
|
||||||
smallvec = "1.15"
|
smallvec = "1.15"
|
||||||
snapshot = { path = "./components/shared/snapshot" }
|
snapshot = { path = "./components/shared/snapshot" }
|
||||||
|
@ -136,12 +136,12 @@ string_cache = "0.8"
|
||||||
string_cache_codegen = "0.5"
|
string_cache_codegen = "0.5"
|
||||||
strum = "0.26"
|
strum = "0.26"
|
||||||
strum_macros = "0.26"
|
strum_macros = "0.26"
|
||||||
stylo = { git = "https://github.com/servo/stylo", branch = "2025-05-01" }
|
stylo = { git = "https://github.com/stevennovaryo/stylo", branch = "input-text-internal-pseudo-selector" }
|
||||||
stylo_atoms = { git = "https://github.com/servo/stylo", branch = "2025-05-01" }
|
stylo_atoms = { git = "https://github.com/stevennovaryo/stylo", branch = "input-text-internal-pseudo-selector" }
|
||||||
stylo_config = { git = "https://github.com/servo/stylo", branch = "2025-05-01" }
|
stylo_config = { git = "https://github.com/stevennovaryo/stylo", branch = "input-text-internal-pseudo-selector" }
|
||||||
stylo_dom = { git = "https://github.com/servo/stylo", branch = "2025-05-01" }
|
stylo_dom = { git = "https://github.com/stevennovaryo/stylo", branch = "input-text-internal-pseudo-selector" }
|
||||||
stylo_malloc_size_of = { git = "https://github.com/servo/stylo", branch = "2025-05-01" }
|
stylo_malloc_size_of = { git = "https://github.com/stevennovaryo/stylo", branch = "input-text-internal-pseudo-selector" }
|
||||||
stylo_traits = { git = "https://github.com/servo/stylo", branch = "2025-05-01" }
|
stylo_traits = { git = "https://github.com/stevennovaryo/stylo", branch = "input-text-internal-pseudo-selector" }
|
||||||
surfman = { git = "https://github.com/servo/surfman", rev = "f7688b4585f9e0b5d4bf8ee8e4a91e82349610b1", features = ["chains"] }
|
surfman = { git = "https://github.com/servo/surfman", rev = "f7688b4585f9e0b5d4bf8ee8e4a91e82349610b1", features = ["chains"] }
|
||||||
syn = { version = "2", default-features = false, features = ["clone-impls", "derive", "parsing"] }
|
syn = { version = "2", default-features = false, features = ["clone-impls", "derive", "parsing"] }
|
||||||
synstructure = "0.13"
|
synstructure = "0.13"
|
||||||
|
@ -233,7 +233,7 @@ codegen-units = 1
|
||||||
# stylo_dom = { path = "../stylo/stylo_dom" }
|
# stylo_dom = { path = "../stylo/stylo_dom" }
|
||||||
# stylo_malloc_size_of = { path = "../stylo/malloc_size_of" }
|
# stylo_malloc_size_of = { path = "../stylo/malloc_size_of" }
|
||||||
# stylo_traits = { path = "../stylo/style_traits" }
|
# stylo_traits = { path = "../stylo/style_traits" }
|
||||||
#
|
# #
|
||||||
# Or for WebRender:
|
# Or for WebRender:
|
||||||
#
|
#
|
||||||
# [patch."https://github.com/servo/webrender"]
|
# [patch."https://github.com/servo/webrender"]
|
||||||
|
|
|
@ -88,7 +88,20 @@ impl<'dom> NodeAndStyleInfo<'dom> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_selected_style(&self) -> ServoArc<ComputedValues> {
|
pub(crate) fn get_selected_style(&self) -> ServoArc<ComputedValues> {
|
||||||
self.node.to_threadsafe().selected_style()
|
// The Selection of an inner editor of a `<input>` should follow its
|
||||||
|
// Shadow Host's selection style.
|
||||||
|
if self.node.is_text_control_inner_editor() {
|
||||||
|
self.node
|
||||||
|
.as_element()
|
||||||
|
.expect("Inner editor should be an element")
|
||||||
|
.containing_shadow_host()
|
||||||
|
.expect("Unassociated inner editor")
|
||||||
|
.as_node()
|
||||||
|
.to_threadsafe()
|
||||||
|
.selected_style()
|
||||||
|
} else {
|
||||||
|
self.node.to_threadsafe().selected_style()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_selection_range(&self) -> Option<Range<ByteIndex>> {
|
pub(crate) fn get_selection_range(&self) -> Option<Range<ByteIndex>> {
|
||||||
|
|
|
@ -19,6 +19,32 @@ textarea {
|
||||||
font-size: 0.8333em;
|
font-size: 0.8333em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::-servo-text-control-inner-editor {
|
||||||
|
overflow-wrap: normal;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-servo-text-control-inner-container {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-servo-text-control-inner-editor, ::-servo-text-control-placeholder {
|
||||||
|
white-space: pre;
|
||||||
|
margin-block: auto !important;
|
||||||
|
inset-block: 0 !important;
|
||||||
|
block-size: fit-content !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-servo-text-control-placeholder {
|
||||||
|
overflow: hidden !important;
|
||||||
|
position: absolute !important;
|
||||||
|
color: grey !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
input::selection,
|
input::selection,
|
||||||
textarea::selection {
|
textarea::selection {
|
||||||
background: rgba(176, 214, 255, 1.0);
|
background: rgba(176, 214, 255, 1.0);
|
||||||
|
|
|
@ -33,6 +33,7 @@ use script_bindings::codegen::GenericBindings::ShadowRootBinding::{
|
||||||
ShadowRootMode, SlotAssignmentMode,
|
ShadowRootMode, SlotAssignmentMode,
|
||||||
};
|
};
|
||||||
use style::attr::AttrValue;
|
use style::attr::AttrValue;
|
||||||
|
use style::selector_parser::PseudoElement;
|
||||||
use style::str::{split_commas, str_join};
|
use style::str::{split_commas, str_join};
|
||||||
use stylo_atoms::Atom;
|
use stylo_atoms::Atom;
|
||||||
use stylo_dom::ElementState;
|
use stylo_dom::ElementState;
|
||||||
|
@ -134,44 +135,6 @@ struct InputTypeColorShadowTree {
|
||||||
color_value: Dom<HTMLDivElement>,
|
color_value: Dom<HTMLDivElement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: These styles should be inside UA stylesheet, but it is not possible without internal pseudo element support.
|
|
||||||
const TEXT_TREE_STYLE: &str = "
|
|
||||||
#input-editor::selection {
|
|
||||||
background: rgba(176, 214, 255, 1.0);
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host:not(:placeholder-shown) #input-placeholder {
|
|
||||||
visibility: hidden !important
|
|
||||||
}
|
|
||||||
|
|
||||||
#input-editor {
|
|
||||||
overflow-wrap: normal;
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#input-container {
|
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
|
||||||
pointer-events: none;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
#input-editor, #input-placeholder {
|
|
||||||
white-space: pre;
|
|
||||||
margin-block: auto !important;
|
|
||||||
inset-block: 0 !important;
|
|
||||||
block-size: fit-content !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
#input-placeholder {
|
|
||||||
overflow: hidden !important;
|
|
||||||
position: absolute !important;
|
|
||||||
color: grey;
|
|
||||||
pointer-events: none !important;
|
|
||||||
}
|
|
||||||
";
|
|
||||||
|
|
||||||
#[derive(Clone, JSTraceable, MallocSizeOf)]
|
#[derive(Clone, JSTraceable, MallocSizeOf)]
|
||||||
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
|
@ -1149,8 +1112,8 @@ impl HTMLInputElement {
|
||||||
let inner_container =
|
let inner_container =
|
||||||
HTMLDivElement::new(local_name!("div"), None, &document, None, can_gc);
|
HTMLDivElement::new(local_name!("div"), None, &document, None, can_gc);
|
||||||
inner_container
|
inner_container
|
||||||
.upcast::<Element>()
|
.upcast::<Node>()
|
||||||
.SetId(DOMString::from("input-container"), can_gc);
|
.set_pseudo_element(PseudoElement::ServoTextControlInnerContainer);
|
||||||
shadow_root
|
shadow_root
|
||||||
.upcast::<Node>()
|
.upcast::<Node>()
|
||||||
.AppendChild(inner_container.upcast::<Node>(), can_gc)
|
.AppendChild(inner_container.upcast::<Node>(), can_gc)
|
||||||
|
@ -1159,8 +1122,8 @@ impl HTMLInputElement {
|
||||||
let placeholder_container =
|
let placeholder_container =
|
||||||
HTMLDivElement::new(local_name!("div"), None, &document, None, can_gc);
|
HTMLDivElement::new(local_name!("div"), None, &document, None, can_gc);
|
||||||
placeholder_container
|
placeholder_container
|
||||||
.upcast::<Element>()
|
.upcast::<Node>()
|
||||||
.SetId(DOMString::from("input-placeholder"), can_gc);
|
.set_pseudo_element(PseudoElement::ServoTextControlPlaceholder);
|
||||||
inner_container
|
inner_container
|
||||||
.upcast::<Node>()
|
.upcast::<Node>()
|
||||||
.AppendChild(placeholder_container.upcast::<Node>(), can_gc)
|
.AppendChild(placeholder_container.upcast::<Node>(), can_gc)
|
||||||
|
@ -1168,8 +1131,8 @@ impl HTMLInputElement {
|
||||||
|
|
||||||
let text_container = HTMLDivElement::new(local_name!("div"), None, &document, None, can_gc);
|
let text_container = HTMLDivElement::new(local_name!("div"), None, &document, None, can_gc);
|
||||||
text_container
|
text_container
|
||||||
.upcast::<Element>()
|
.upcast::<Node>()
|
||||||
.SetId(DOMString::from("input-editor"), can_gc);
|
.set_pseudo_element(PseudoElement::ServoTextControlInnerEditor);
|
||||||
text_container
|
text_container
|
||||||
.upcast::<Node>()
|
.upcast::<Node>()
|
||||||
.set_text_control_inner_editor();
|
.set_text_control_inner_editor();
|
||||||
|
@ -1178,24 +1141,6 @@ impl HTMLInputElement {
|
||||||
.AppendChild(text_container.upcast::<Node>(), can_gc)
|
.AppendChild(text_container.upcast::<Node>(), can_gc)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let style = HTMLStyleElement::new(
|
|
||||||
local_name!("style"),
|
|
||||||
None,
|
|
||||||
&document,
|
|
||||||
None,
|
|
||||||
ElementCreator::ScriptCreated,
|
|
||||||
can_gc,
|
|
||||||
);
|
|
||||||
// TODO(stevennovaryo): Either use UA stylesheet with internal pseudo element or preemptively parse
|
|
||||||
// the stylesheet to reduce the costly operation and avoid CSP related error.
|
|
||||||
style
|
|
||||||
.upcast::<Node>()
|
|
||||||
.SetTextContent(Some(DOMString::from(TEXT_TREE_STYLE)), can_gc);
|
|
||||||
shadow_root
|
|
||||||
.upcast::<Node>()
|
|
||||||
.AppendChild(style.upcast::<Node>(), can_gc)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let _ = self
|
let _ = self
|
||||||
.shadow_tree
|
.shadow_tree
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
|
@ -1662,6 +1607,7 @@ impl HTMLInputElementMethods<crate::DomTypeHolder> for HTMLInputElement {
|
||||||
// normally being done in the attributed mutated. And, being
|
// normally being done in the attributed mutated. And, being
|
||||||
// done in another scope to prevent borrow checker issues.
|
// done in another scope to prevent borrow checker issues.
|
||||||
self.update_placeholder_shown_state();
|
self.update_placeholder_shown_state();
|
||||||
|
self.update_text_shadow_tree_placeholder(can_gc);
|
||||||
},
|
},
|
||||||
ValueMode::Default | ValueMode::DefaultOn => {
|
ValueMode::Default | ValueMode::DefaultOn => {
|
||||||
self.upcast::<Element>()
|
self.upcast::<Element>()
|
||||||
|
@ -2251,10 +2197,17 @@ impl HTMLInputElement {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ideally we are not supposed to handle visibility of the placeholder.
|
||||||
|
// But we are doing so because UA stylesheet does not support `:host` selector yet.
|
||||||
|
let placeholder_text = match self.upcast::<Element>().placeholder_shown_state() {
|
||||||
|
true => self.placeholder.borrow().clone(),
|
||||||
|
false => "".into(),
|
||||||
|
};
|
||||||
|
|
||||||
self.text_shadow_tree(can_gc)
|
self.text_shadow_tree(can_gc)
|
||||||
.placeholder_container
|
.placeholder_container
|
||||||
.upcast::<Node>()
|
.upcast::<Node>()
|
||||||
.SetTextContent(Some(self.placeholder.borrow().clone()), can_gc);
|
.SetTextContent(Some(placeholder_text), can_gc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#file-upload-state-(type=file)
|
// https://html.spec.whatwg.org/multipage/#file-upload-state-(type=file)
|
||||||
|
@ -2882,8 +2835,8 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
self.update_text_shadow_tree_placeholder(can_gc);
|
|
||||||
self.update_placeholder_shown_state();
|
self.update_placeholder_shown_state();
|
||||||
|
self.update_text_shadow_tree_placeholder(can_gc);
|
||||||
},
|
},
|
||||||
// FIXME(stevennovaryo): This is only reachable by Default and DefaultOn value mode. While others
|
// FIXME(stevennovaryo): This is only reachable by Default and DefaultOn value mode. While others
|
||||||
// are being handled in [Self::SetValue]. Should we merge this two together?
|
// are being handled in [Self::SetValue]. Should we merge this two together?
|
||||||
|
@ -2894,6 +2847,7 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
self.sanitize_value(&mut value);
|
self.sanitize_value(&mut value);
|
||||||
self.textinput.borrow_mut().set_content(value);
|
self.textinput.borrow_mut().set_content(value);
|
||||||
self.update_placeholder_shown_state();
|
self.update_placeholder_shown_state();
|
||||||
|
self.update_text_shadow_tree_placeholder(can_gc);
|
||||||
|
|
||||||
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||||
},
|
},
|
||||||
|
@ -2935,8 +2889,8 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
.extend(attr.value().chars().filter(|&c| c != '\n' && c != '\r'));
|
.extend(attr.value().chars().filter(|&c| c != '\n' && c != '\r'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.update_text_shadow_tree_placeholder(can_gc);
|
|
||||||
self.update_placeholder_shown_state();
|
self.update_placeholder_shown_state();
|
||||||
|
self.update_text_shadow_tree_placeholder(can_gc);
|
||||||
},
|
},
|
||||||
local_name!("readonly") => {
|
local_name!("readonly") => {
|
||||||
if self.input_type().is_textual() {
|
if self.input_type().is_textual() {
|
||||||
|
@ -3094,6 +3048,7 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
}
|
}
|
||||||
self.value_dirty.set(true);
|
self.value_dirty.set(true);
|
||||||
self.update_placeholder_shown_state();
|
self.update_placeholder_shown_state();
|
||||||
|
self.update_text_shadow_tree_placeholder(can_gc);
|
||||||
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||||
event.mark_as_handled();
|
event.mark_as_handled();
|
||||||
},
|
},
|
||||||
|
|
|
@ -45,7 +45,7 @@ use smallvec::SmallVec;
|
||||||
use style::context::QuirksMode;
|
use style::context::QuirksMode;
|
||||||
use style::dom::OpaqueNode;
|
use style::dom::OpaqueNode;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::selector_parser::{SelectorImpl, SelectorParser};
|
use style::selector_parser::{PseudoElement, SelectorImpl, SelectorParser};
|
||||||
use style::stylesheets::{Stylesheet, UrlExtraData};
|
use style::stylesheets::{Stylesheet, UrlExtraData};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use xml5ever::{local_name, serialize as xml_serialize};
|
use xml5ever::{local_name, serialize as xml_serialize};
|
||||||
|
@ -1572,6 +1572,10 @@ impl Node {
|
||||||
next_node: move |n| n.parent_in_flat_tree(),
|
next_node: move |n| n.parent_in_flat_tree(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_pseudo_element(&self, pseudo_element: PseudoElement) {
|
||||||
|
self.ensure_rare_data().pseudo_element = Some(pseudo_element);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate through `nodes` until we find a `Node` that is not in `not_in`
|
/// Iterate through `nodes` until we find a `Node` that is not in `not_in`
|
||||||
|
@ -1659,6 +1663,7 @@ pub(crate) trait LayoutNodeHelpers<'dom> {
|
||||||
fn iframe_browsing_context_id(self) -> Option<BrowsingContextId>;
|
fn iframe_browsing_context_id(self) -> Option<BrowsingContextId>;
|
||||||
fn iframe_pipeline_id(self) -> Option<PipelineId>;
|
fn iframe_pipeline_id(self) -> Option<PipelineId>;
|
||||||
fn opaque(self) -> OpaqueNode;
|
fn opaque(self) -> OpaqueNode;
|
||||||
|
fn pseudo_element(&self) -> Option<PseudoElement>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'dom> LayoutDom<'dom, Node> {
|
impl<'dom> LayoutDom<'dom, Node> {
|
||||||
|
@ -1931,6 +1936,14 @@ impl<'dom> LayoutNodeHelpers<'dom> for LayoutDom<'dom, Node> {
|
||||||
fn opaque(self) -> OpaqueNode {
|
fn opaque(self) -> OpaqueNode {
|
||||||
unsafe { OpaqueNode(self.get_jsobject() as usize) }
|
unsafe { OpaqueNode(self.get_jsobject() as usize) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
fn pseudo_element(&self) -> Option<PseudoElement> {
|
||||||
|
self.unsafe_get()
|
||||||
|
.rare_data()
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|data| data.pseudo_element)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use euclid::default::Rect;
|
use euclid::default::Rect;
|
||||||
|
use style::selector_parser::PseudoElement;
|
||||||
use stylo_atoms::Atom;
|
use stylo_atoms::Atom;
|
||||||
|
|
||||||
use crate::dom::bindings::root::{Dom, MutNullableDom};
|
use crate::dom::bindings::root::{Dom, MutNullableDom};
|
||||||
|
@ -46,6 +47,10 @@ pub(crate) struct NodeRareData {
|
||||||
|
|
||||||
/// The live list of children return by .childNodes.
|
/// The live list of children return by .childNodes.
|
||||||
pub(crate) child_list: MutNullableDom<NodeList>,
|
pub(crate) child_list: MutNullableDom<NodeList>,
|
||||||
|
|
||||||
|
/// Internal Pseudo Element type
|
||||||
|
#[no_trace]
|
||||||
|
pub(crate) pseudo_element: Option<PseudoElement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, JSTraceable, MallocSizeOf)]
|
#[derive(Default, JSTraceable, MallocSizeOf)]
|
||||||
|
|
|
@ -244,7 +244,10 @@ pub struct ServoThreadSafeLayoutNode<'dom> {
|
||||||
impl<'dom> ServoThreadSafeLayoutNode<'dom> {
|
impl<'dom> ServoThreadSafeLayoutNode<'dom> {
|
||||||
/// Creates a new `ServoThreadSafeLayoutNode` from the given `ServoLayoutNode`.
|
/// Creates a new `ServoThreadSafeLayoutNode` from the given `ServoLayoutNode`.
|
||||||
pub fn new(node: ServoLayoutNode<'dom>) -> Self {
|
pub fn new(node: ServoLayoutNode<'dom>) -> Self {
|
||||||
ServoThreadSafeLayoutNode { node, pseudo: None }
|
ServoThreadSafeLayoutNode {
|
||||||
|
node,
|
||||||
|
pseudo: node.node.pseudo_element(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the interior of this node as a `LayoutDom`. This is highly unsafe for layout to
|
/// Returns the interior of this node as a `LayoutDom`. This is highly unsafe for layout to
|
||||||
|
@ -440,13 +443,18 @@ pub struct ServoThreadSafeLayoutNodeChildrenIterator<'dom> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'dom> ServoThreadSafeLayoutNodeChildrenIterator<'dom> {
|
impl<'dom> ServoThreadSafeLayoutNodeChildrenIterator<'dom> {
|
||||||
|
// MYNOTES: This seems to be unused anywhere.
|
||||||
pub fn new(parent: ServoThreadSafeLayoutNode<'dom>) -> Self {
|
pub fn new(parent: ServoThreadSafeLayoutNode<'dom>) -> Self {
|
||||||
let first_child = match parent.pseudo_element() {
|
let first_child = match parent.pseudo_element() {
|
||||||
None => parent
|
None => parent
|
||||||
.with_pseudo(PseudoElement::Before)
|
.with_pseudo(PseudoElement::Before)
|
||||||
.or_else(|| parent.with_pseudo(PseudoElement::DetailsSummary))
|
.or_else(|| parent.with_pseudo(PseudoElement::DetailsSummary))
|
||||||
.or_else(|| unsafe { parent.dangerous_first_child() }),
|
.or_else(|| unsafe { parent.dangerous_first_child() }),
|
||||||
Some(PseudoElement::DetailsContent) | Some(PseudoElement::DetailsSummary) => unsafe {
|
Some(PseudoElement::DetailsContent) |
|
||||||
|
Some(PseudoElement::DetailsSummary) |
|
||||||
|
Some(PseudoElement::ServoTextControlInnerContainer) |
|
||||||
|
Some(PseudoElement::ServoTextControlInnerEditor) |
|
||||||
|
Some(PseudoElement::ServoTextControlPlaceholder) => unsafe {
|
||||||
parent.dangerous_first_child()
|
parent.dangerous_first_child()
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -516,7 +524,10 @@ impl<'dom> Iterator for ServoThreadSafeLayoutNodeChildrenIterator<'dom> {
|
||||||
Some(PseudoElement::DetailsSummary) => {
|
Some(PseudoElement::DetailsSummary) => {
|
||||||
self.parent_node.with_pseudo(PseudoElement::DetailsContent)
|
self.parent_node.with_pseudo(PseudoElement::DetailsContent)
|
||||||
},
|
},
|
||||||
Some(PseudoElement::DetailsContent) => {
|
Some(PseudoElement::DetailsContent) |
|
||||||
|
Some(PseudoElement::ServoTextControlInnerContainer) |
|
||||||
|
Some(PseudoElement::ServoTextControlInnerEditor) |
|
||||||
|
Some(PseudoElement::ServoTextControlPlaceholder) => {
|
||||||
self.parent_node.with_pseudo(PseudoElement::After)
|
self.parent_node.with_pseudo(PseudoElement::After)
|
||||||
},
|
},
|
||||||
Some(PseudoElement::After) => None,
|
Some(PseudoElement::After) => None,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue