mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
style: Basic implementation of Custom Highlight API
Added WebIDL interfaces as per spec, added some necessary changes to support maplike and setlike structures to be accessed from C++. Added `::highlight(foo)` pseudo element to CSS engine. Implemented Highlight as new kind of `Selection` using `HighlightType::eHighlight`. This implies Selections being added/removed during runtime (one `Selection` object per highlight identifier), therefore a dynamic container for highlight `Selection` objects was added to `nsFrameSelection`. Also, the painting code queries the highlight style for highlight Selections. Implementation is currently hidden behind a pref `dom.customHighlightAPI.enabled`. Differential Revision: https://phabricator.services.mozilla.com/D164203
This commit is contained in:
parent
29c6094c80
commit
896aac5e4a
5 changed files with 65 additions and 5 deletions
|
@ -2920,6 +2920,7 @@ pub mod tests {
|
|||
pub enum PseudoElement {
|
||||
Before,
|
||||
After,
|
||||
Highlight(String),
|
||||
}
|
||||
|
||||
impl parser::PseudoElement for PseudoElement {
|
||||
|
@ -2973,6 +2974,11 @@ pub mod tests {
|
|||
match *self {
|
||||
PseudoElement::Before => dest.write_str("::before"),
|
||||
PseudoElement::After => dest.write_str("::after"),
|
||||
PseudoElement::Highlight(ref name) => {
|
||||
dest.write_str("::highlight(")?;
|
||||
serialize_identifier(&name, dest)?;
|
||||
dest.write_char(')')
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3133,6 +3139,23 @@ pub mod tests {
|
|||
)
|
||||
}
|
||||
|
||||
fn parse_functional_pseudo_element<'t>(
|
||||
&self,
|
||||
name: CowRcStr<'i>,
|
||||
parser: &mut CssParser<'i, 't>,
|
||||
) -> Result<PseudoElement, SelectorParseError<'i>> {
|
||||
match_ignore_ascii_case! {&name,
|
||||
"highlight" => return Ok(PseudoElement::Highlight(parser.expect_ident()?.as_ref().to_owned())),
|
||||
_ => {}
|
||||
}
|
||||
Err(
|
||||
parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
|
||||
name,
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fn default_namespace(&self) -> Option<DummyAtom> {
|
||||
self.default_ns.clone()
|
||||
}
|
||||
|
@ -3660,6 +3683,8 @@ pub mod tests {
|
|||
)]))
|
||||
);
|
||||
|
||||
assert!(parse("::highlight(foo)").is_ok());
|
||||
|
||||
assert!(parse("::slotted()").is_err());
|
||||
assert!(parse("::slotted(div)").is_ok());
|
||||
assert!(parse("::slotted(div).foo").is_err());
|
||||
|
|
|
@ -14,8 +14,10 @@ use crate::properties::{ComputedValues, PropertyFlags};
|
|||
use crate::selector_parser::{PseudoElementCascadeType, SelectorImpl};
|
||||
use crate::str::{starts_with_ignore_ascii_case, string_as_ascii_lowercase};
|
||||
use crate::string_cache::Atom;
|
||||
use crate::values::AtomIdent;
|
||||
use crate::values::serialize_atom_identifier;
|
||||
use cssparser::ToCss;
|
||||
use static_prefs::pref;
|
||||
use std::fmt;
|
||||
|
||||
include!(concat!(
|
||||
|
@ -153,6 +155,19 @@ impl PseudoElement {
|
|||
!self.is_eager() && !self.is_precomputed()
|
||||
}
|
||||
|
||||
/// The identifier of the highlight this pseudo-element represents.
|
||||
pub fn highlight_name(&self) -> Option<&AtomIdent> {
|
||||
match &*self {
|
||||
PseudoElement::Highlight(name) => Some(&name),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this pseudo-element is the ::highlight pseudo.
|
||||
pub fn is_highlight(&self) -> bool {
|
||||
matches!(*self, PseudoElement::Highlight(_))
|
||||
}
|
||||
|
||||
/// Whether this pseudo-element supports user action selectors.
|
||||
pub fn supports_user_action_state(&self) -> bool {
|
||||
(self.flags() & structs::CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE) != 0
|
||||
|
@ -160,7 +175,10 @@ impl PseudoElement {
|
|||
|
||||
/// Whether this pseudo-element is enabled for all content.
|
||||
pub fn enabled_in_content(&self) -> bool {
|
||||
self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME == 0
|
||||
if self.is_highlight() && !pref!("dom.customHighlightAPI.enabled") {
|
||||
return false;
|
||||
}
|
||||
return self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME == 0
|
||||
}
|
||||
|
||||
/// Whether this pseudo is enabled explicitly in UA sheets.
|
||||
|
|
|
@ -12,6 +12,8 @@ pub enum PseudoElement {
|
|||
/// ${pseudo.value}
|
||||
% if pseudo.is_tree_pseudo_element():
|
||||
${pseudo.capitalized_pseudo()}(Box<Box<[Atom]>>),
|
||||
% elif pseudo.pseudo_ident == "highlight":
|
||||
${pseudo.capitalized_pseudo()}(AtomIdent),
|
||||
% else:
|
||||
${pseudo.capitalized_pseudo()},
|
||||
% endif
|
||||
|
@ -25,7 +27,7 @@ pub enum PseudoElement {
|
|||
/// nsCSSPseudoElements::IsEagerlyCascadedInServo.
|
||||
<% EAGER_PSEUDOS = ["Before", "After", "FirstLine", "FirstLetter"] %>
|
||||
<% TREE_PSEUDOS = [pseudo for pseudo in PSEUDOS if pseudo.is_tree_pseudo_element()] %>
|
||||
<% SIMPLE_PSEUDOS = [pseudo for pseudo in PSEUDOS if not pseudo.is_tree_pseudo_element()] %>
|
||||
<% SIMPLE_PSEUDOS = [pseudo for pseudo in PSEUDOS if pseudo.is_simple_pseudo_element()] %>
|
||||
|
||||
/// The number of eager pseudo-elements.
|
||||
pub const EAGER_PSEUDO_COUNT: usize = ${len(EAGER_PSEUDOS)};
|
||||
|
@ -47,7 +49,7 @@ pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [
|
|||
];
|
||||
|
||||
<%def name="pseudo_element_variant(pseudo, tree_arg='..')">\
|
||||
PseudoElement::${pseudo.capitalized_pseudo()}${"({})".format(tree_arg) if pseudo.is_tree_pseudo_element() else ""}\
|
||||
PseudoElement::${pseudo.capitalized_pseudo()}${"({})".format(tree_arg) if not pseudo.is_simple_pseudo_element() else ""}\
|
||||
</%def>
|
||||
|
||||
impl PseudoElement {
|
||||
|
@ -131,7 +133,7 @@ impl PseudoElement {
|
|||
pub fn from_pseudo_type(type_: PseudoStyleType) -> Option<Self> {
|
||||
match type_ {
|
||||
% for pseudo in PSEUDOS:
|
||||
% if not pseudo.is_tree_pseudo_element():
|
||||
% if pseudo.is_simple_pseudo_element():
|
||||
PseudoStyleType::${pseudo.pseudo_ident} => {
|
||||
Some(${pseudo_element_variant(pseudo)})
|
||||
},
|
||||
|
@ -148,6 +150,8 @@ impl PseudoElement {
|
|||
% for pseudo in PSEUDOS:
|
||||
% if pseudo.is_tree_pseudo_element():
|
||||
PseudoElement::${pseudo.capitalized_pseudo()}(..) => PseudoStyleType::XULTree,
|
||||
% elif pseudo.pseudo_ident == "highlight":
|
||||
PseudoElement::${pseudo.capitalized_pseudo()}(..) => PseudoStyleType::${pseudo.pseudo_ident},
|
||||
% else:
|
||||
PseudoElement::${pseudo.capitalized_pseudo()} => PseudoStyleType::${pseudo.pseudo_ident},
|
||||
% endif
|
||||
|
@ -240,9 +244,14 @@ impl ToCss for PseudoElement {
|
|||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
dest.write_char(':')?;
|
||||
match *self {
|
||||
% for pseudo in PSEUDOS:
|
||||
% for pseudo in (p for p in PSEUDOS if p.pseudo_ident != "highlight"):
|
||||
${pseudo_element_variant(pseudo)} => dest.write_str("${pseudo.value}")?,
|
||||
% endfor
|
||||
PseudoElement::Highlight(ref name) => {
|
||||
dest.write_str(":highlight(")?;
|
||||
serialize_atom_identifier(name, dest)?;
|
||||
dest.write_char(')')?;
|
||||
}
|
||||
PseudoElement::UnknownWebkit(ref atom) => {
|
||||
dest.write_str(":-webkit-")?;
|
||||
serialize_atom_identifier(atom, dest)?;
|
||||
|
|
|
@ -90,6 +90,9 @@ class Atom:
|
|||
def is_tree_pseudo_element(self):
|
||||
return self.value.startswith(":-moz-tree-")
|
||||
|
||||
def is_simple_pseudo_element(self) -> bool:
|
||||
return not (self.is_tree_pseudo_element() or self.pseudo_ident == "highlight")
|
||||
|
||||
|
||||
def collect_atoms(objdir):
|
||||
atoms = []
|
||||
|
|
|
@ -443,6 +443,11 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
|
|||
return Ok(pseudo);
|
||||
}
|
||||
}
|
||||
} else if name.eq_ignore_ascii_case("highlight") {
|
||||
let pseudo = PseudoElement::Highlight(AtomIdent::from(parser.expect_ident()?.as_ref()));
|
||||
if self.is_pseudo_element_enabled(&pseudo) {
|
||||
return Ok(pseudo);
|
||||
}
|
||||
}
|
||||
Err(
|
||||
parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue