mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
script: Use an implemented pseudo-element to fortype=color
::color-swatch
(#37427)
Implement internal pseudo element, which would be resolved as a "Implemented Pseudo Element" within style computation. This is an concrete element that would has a primary style after the style computation, but could match and style resolved like an pseudo element. Therefore, it would have a different behavior compared to how does `pseudo`s that `ServoLayoutNode` had. Where they would not have a concrete element behind it. Note that, due to the nature of these pseudo elements residing inside a UA widget, these pseudo elements would therefore not be accessible in JavaScript by default. This kind of element is required in order to implement the [form control pseudo element](https://drafts.csswg.org/css-forms-1/#pseudo-elements) like `::placeholder`, `::color-swatch`, `::field-text`, etc. See [this docs](https://hackmd.io/@ChaKweTiau/BJ3zRdLQlg) for more details of the implementation. Then, the implemented pseudo element is utilized to implement style matching for input `type=text`. Servo's side of: https://github.com/servo/stylo/pull/212 Testing: No WPT regression. --------- Signed-off-by: stevennovaryo <steven.novaryo@gmail.com>
This commit is contained in:
parent
d2ccf419c3
commit
378c4648e4
12 changed files with 201 additions and 163 deletions
|
@ -201,6 +201,22 @@ impl<'dom> style::dom::TElement for ServoLayoutElement<'dom> {
|
|||
self.as_node().traversal_parent()
|
||||
}
|
||||
|
||||
fn inheritance_parent(&self) -> Option<Self> {
|
||||
if self.is_pseudo_element() {
|
||||
// The inheritance parent of an implemented pseudo-element should be the
|
||||
// originating element, except if `is_element_backed()` is true, then it should
|
||||
// be the flat tree parent. Note `is_element_backed()` differs from the CSS term.
|
||||
// At the current time, `is_element_backed()` is always false in Servo.
|
||||
//
|
||||
// FIXME: handle the cases of element-backed pseudo-elements.
|
||||
return self.pseudo_element_originating_element();
|
||||
}
|
||||
|
||||
// FIXME: By default the inheritance parent would be the Self::parent_element
|
||||
// but probably we should use the flattened tree parent.
|
||||
self.parent_element()
|
||||
}
|
||||
|
||||
fn is_html_element(&self) -> bool {
|
||||
ServoLayoutElement::is_html_element(self)
|
||||
}
|
||||
|
@ -355,6 +371,21 @@ impl<'dom> style::dom::TElement for ServoLayoutElement<'dom> {
|
|||
.set_flag(NodeFlags::HAS_DIRTY_DESCENDANTS, false)
|
||||
}
|
||||
|
||||
/// Whether this element should match user and content rules.
|
||||
/// We would like to match rules from the same tree in all cases and optimize computation.
|
||||
/// UA Widget is an exception since we could have a pseudo element selector inside it.
|
||||
#[inline]
|
||||
fn matches_user_and_content_rules(&self) -> bool {
|
||||
!self.as_node().node.is_in_ua_widget()
|
||||
}
|
||||
|
||||
/// Returns the pseudo-element implemented by this element, if any. In other words,
|
||||
/// the element will match the specified pseudo element throughout the style computation.
|
||||
#[inline]
|
||||
fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
|
||||
self.as_node().node.implemented_pseudo_element()
|
||||
}
|
||||
|
||||
fn store_children_to_process(&self, n: isize) {
|
||||
let data = self.get_style_data().unwrap();
|
||||
data.parallel
|
||||
|
@ -585,6 +616,18 @@ impl<'dom> ::selectors::Element for ServoLayoutElement<'dom> {
|
|||
self.containing_shadow().map(|s| s.host())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_pseudo_element(&self) -> bool {
|
||||
self.implemented_pseudo_element().is_some()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pseudo_element_originating_element(&self) -> Option<Self> {
|
||||
debug_assert!(self.is_pseudo_element());
|
||||
debug_assert!(!self.matches_user_and_content_rules());
|
||||
self.containing_shadow_host()
|
||||
}
|
||||
|
||||
fn prev_sibling_element(&self) -> Option<Self> {
|
||||
let mut node = self.as_node();
|
||||
while let Some(sibling) = node.prev_sibling() {
|
||||
|
@ -663,18 +706,6 @@ impl<'dom> ::selectors::Element for ServoLayoutElement<'dom> {
|
|||
self.element.namespace() == other.element.namespace()
|
||||
}
|
||||
|
||||
fn is_pseudo_element(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn match_pseudo_element(
|
||||
&self,
|
||||
_pseudo: &PseudoElement,
|
||||
_context: &mut MatchingContext<Self::Impl>,
|
||||
) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn match_non_ts_pseudo_class(
|
||||
&self,
|
||||
pseudo_class: &NonTSPseudoClass,
|
||||
|
@ -733,6 +764,14 @@ impl<'dom> ::selectors::Element for ServoLayoutElement<'dom> {
|
|||
}
|
||||
}
|
||||
|
||||
fn match_pseudo_element(
|
||||
&self,
|
||||
pseudo: &PseudoElement,
|
||||
_context: &mut MatchingContext<Self::Impl>,
|
||||
) -> bool {
|
||||
self.implemented_pseudo_element() == Some(*pseudo)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_link(&self) -> bool {
|
||||
match self.as_node().script_type_id() {
|
||||
|
@ -934,21 +973,33 @@ impl ::selectors::Element for ServoThreadSafeLayoutElement<'_> {
|
|||
::selectors::OpaqueElement::new(unsafe { &*(self.as_node().opaque().0 as *const ()) })
|
||||
}
|
||||
|
||||
fn is_pseudo_element(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn parent_element(&self) -> Option<Self> {
|
||||
warn!("ServoThreadSafeLayoutElement::parent_element called");
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn parent_node_is_shadow_root(&self) -> bool {
|
||||
false
|
||||
self.element.parent_node_is_shadow_root()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn containing_shadow_host(&self) -> Option<Self> {
|
||||
None
|
||||
self.element
|
||||
.containing_shadow_host()
|
||||
.and_then(|element| element.as_node().to_threadsafe().as_element())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_pseudo_element(&self) -> bool {
|
||||
self.element.is_pseudo_element()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pseudo_element_originating_element(&self) -> Option<Self> {
|
||||
self.element
|
||||
.pseudo_element_originating_element()
|
||||
.and_then(|element| element.as_node().to_threadsafe().as_element())
|
||||
}
|
||||
|
||||
// Skips non-element nodes
|
||||
|
@ -993,14 +1044,6 @@ impl ::selectors::Element for ServoThreadSafeLayoutElement<'_> {
|
|||
self.element.namespace() == other.element.namespace()
|
||||
}
|
||||
|
||||
fn match_pseudo_element(
|
||||
&self,
|
||||
_pseudo: &PseudoElement,
|
||||
_context: &mut MatchingContext<Self::Impl>,
|
||||
) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn attr_matches(
|
||||
&self,
|
||||
ns: &NamespaceConstraint<&style::Namespace>,
|
||||
|
@ -1030,6 +1073,14 @@ impl ::selectors::Element for ServoThreadSafeLayoutElement<'_> {
|
|||
false
|
||||
}
|
||||
|
||||
fn match_pseudo_element(
|
||||
&self,
|
||||
pseudo: &PseudoElement,
|
||||
context: &mut MatchingContext<Self::Impl>,
|
||||
) -> bool {
|
||||
self.element.match_pseudo_element(pseudo, context)
|
||||
}
|
||||
|
||||
fn is_link(&self) -> bool {
|
||||
warn!("ServoThreadSafeLayoutElement::is_link called");
|
||||
false
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue