style: Parse errors in individual @font-face src components should cause only the bad component to be dropped, not the entire descriptor

Differential Revision: https://phabricator.services.mozilla.com/D163810
This commit is contained in:
Jonathan Kew 2022-12-06 13:44:50 +00:00 committed by Martin Robinson
parent d2bb508272
commit 6ea75b0646

View file

@ -30,7 +30,7 @@ use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
use cssparser::{CowRcStr, SourceLocation}; use cssparser::{CowRcStr, SourceLocation};
use selectors::parser::SelectorParseErrorKind; use selectors::parser::SelectorParseErrorKind;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{Comma, CssWriter, OneOrMoreSeparated, ParseError}; use style_traits::{CssWriter, ParseError};
use style_traits::{StyleParseErrorKind, ToCss}; use style_traits::{StyleParseErrorKind, ToCss};
/// A source for a font-face rule. /// A source for a font-face rule.
@ -44,8 +44,35 @@ pub enum Source {
Local(FamilyName), Local(FamilyName),
} }
impl OneOrMoreSeparated for Source { /// A list of sources for the font-face src descriptor.
type S = Comma; #[derive(Clone, Debug, Eq, PartialEq, ToCss, ToShmem)]
#[css(comma)]
pub struct SourceList(#[css(iterable)] pub Vec<Source>);
// We can't just use OneOrMoreSeparated to derive Parse for the Source list,
// because we want to filter out components that parsed as None, then fail if no
// valid components remain. So we provide our own implementation here.
impl Parse for SourceList {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
// Parse the comma-separated list, then let filter_map discard any None items.
let list = input
.parse_comma_separated(|input| {
let s = input.parse_entirely(|input| Source::parse(context, input));
while input.next().is_ok() {}
Ok(s.ok())
})?
.into_iter()
.filter_map(|s| s)
.collect::<Vec<Source>>();
if list.is_empty() {
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
} else {
Ok(SourceList(list))
}
}
} }
/// Keywords for the font-face src descriptor's format() function. /// Keywords for the font-face src descriptor's format() function.
@ -465,7 +492,7 @@ pub struct FontFace<'a>(&'a FontFaceRuleData);
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub struct EffectiveSources(Vec<Source>); pub struct EffectiveSources(SourceList);
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
impl<'a> FontFace<'a> { impl<'a> FontFace<'a> {
@ -645,7 +672,7 @@ macro_rules! font_face_descriptors_common {
$( $(
if let Some(ref value) = self.$ident { if let Some(ref value) = self.$ident {
dest.write_str(concat!($name, ": "))?; dest.write_str(concat!($name, ": "))?;
ToCss::to_css(value, &mut CssWriter::new(dest))?; value.to_css(&mut CssWriter::new(dest))?;
dest.write_str("; ")?; dest.write_str("; ")?;
} }
)* )*
@ -739,7 +766,7 @@ font_face_descriptors! {
"font-family" family / mFamily: FamilyName, "font-family" family / mFamily: FamilyName,
/// The alternative sources for this font face. /// The alternative sources for this font face.
"src" sources / mSrc: Vec<Source>, "src" sources / mSrc: SourceList,
] ]
optional descriptors = [ optional descriptors = [
/// The style of this font face. /// The style of this font face.
@ -787,7 +814,7 @@ font_face_descriptors! {
"font-family" family / mFamily: FamilyName, "font-family" family / mFamily: FamilyName,
/// The alternative sources for this font face. /// The alternative sources for this font face.
"src" sources / mSrc: Vec<Source>, "src" sources / mSrc: SourceList,
] ]
optional descriptors = [ optional descriptors = [
] ]