/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
usesuper::{
registry::{PropertyRegistration, PropertyRegistrationData},
syntax::Descriptor,
value::{
AllowComputationallyDependent, ComputedValue as ComputedRegisteredValue,
SpecifiedValue as SpecifiedRegisteredValue,
},
}; usecrate::custom_properties::{Name as CustomPropertyName, SpecifiedValue}; usecrate::error_reporting::ContextualParseError; usecrate::parser::{Parse, ParserContext}; usecrate::shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; usecrate::str::CssStringWriter; usecrate::values::{computed, serialize_atom_name}; use cssparser::{
AtRuleParser, BasicParseErrorKind, CowRcStr, DeclarationParser, ParseErrorKind, Parser,
ParserInput, QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser, SourceLocation,
}; #[cfg(feature = "gecko")] use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use selectors::parser::SelectorParseErrorKind; use servo_arc::Arc; use std::fmt::{self, Write}; use style_traits::{
CssWriter, ParseError, PropertyInheritsParseError, PropertySyntaxParseError,
StyleParseErrorKind, ToCss,
}; use to_shmem::{SharedMemoryBuilder, ToShmem};
/// Parse the block inside a `@property` rule. /// /// Valid `@property` rules result in a registered custom property, as if `registerProperty()` had /// been called with equivalent parameters. pubfn parse_property_block<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
name: PropertyRuleName,
source_location: SourceLocation,
) -> Result<PropertyRegistration, ParseError<'i>> { letmut descriptors = PropertyDescriptors::default(); letmut parser = PropertyRuleParser {
context,
descriptors: &mut descriptors,
}; letmut iter = RuleBodyParser::new(input, &mut parser); letmut syntax_err = None; letmut inherits_err = None; whilelet Some(declaration) = iter.next() { if !context.error_reporting_enabled() { continue;
} iflet Err((error, slice)) = declaration { let location = error.location; let error = match error.kind { // If the provided string is not a valid syntax string (if it // returns failure when consume a syntax definition is called on // it), the descriptor is invalid and must be ignored.
ParseErrorKind::Custom(StyleParseErrorKind::PropertySyntaxField(_)) => {
syntax_err = Some(error.clone());
ContextualParseError::UnsupportedValue(slice, error)
},
// If the provided string is not a valid inherits string, // the descriptor is invalid and must be ignored.
ParseErrorKind::Custom(StyleParseErrorKind::PropertyInheritsField(_)) => {
inherits_err = Some(error.clone());
ContextualParseError::UnsupportedValue(slice, error)
},
// Unknown descriptors are invalid and ignored, but do not // invalidate the @property rule.
_ => ContextualParseError::UnsupportedPropertyDescriptor(slice, error),
};
context.log_css_error(location, error);
}
}
// https://drafts.css-houdini.org/css-properties-values-api-1/#the-syntax-descriptor: // // The syntax descriptor is required for the @property rule to be valid; if it’s // missing, the @property rule is invalid. let Some(syntax) = descriptors.syntax else { return Err(iflet Some(err) = syntax_err {
err
} else { let err = input.new_custom_error(StyleParseErrorKind::PropertySyntaxField(
PropertySyntaxParseError::NoSyntax,
));
context.log_css_error(
source_location,
ContextualParseError::UnsupportedValue("", err.clone()),
);
err
});
};
// https://drafts.css-houdini.org/css-properties-values-api-1/#inherits-descriptor: // // The inherits descriptor is required for the @property rule to be valid; if it’s // missing, the @property rule is invalid. let Some(inherits) = descriptors.inherits else { return Err(iflet Some(err) = inherits_err {
err
} else { let err = input.new_custom_error(StyleParseErrorKind::PropertyInheritsField(
PropertyInheritsParseError::NoInherits,
));
context.log_css_error(
source_location,
ContextualParseError::UnsupportedValue("", err.clone()),
);
err
});
};
if PropertyRegistration::validate_initial_value(&syntax, descriptors.initial_value.as_deref())
.is_err()
{ return Err(input.new_error(BasicParseErrorKind::AtRuleBodyInvalid));
}
/// Default methods reject all at rules. impl<'a, 'b, 'i> AtRuleParser<'i> for PropertyRuleParser<'a, 'b> { type Prelude = (); type AtRule = (); type Error = StyleParseErrorKind<'i>;
}
impl<'a, 'b, 'i> QualifiedRuleParser<'i> for PropertyRuleParser<'a, 'b> { type Prelude = (); type QualifiedRule = (); type Error = StyleParseErrorKind<'i>;
}
impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyRuleParser<'a, 'b> { type Declaration = (); type Error = StyleParseErrorKind<'i>;
fn parse_value<'t>(
&mutself,
name: CowRcStr<'i>,
input: &mut Parser<'i, 't>,
) -> Result<(), ParseError<'i>> {
match_ignore_ascii_case! { &*name,
$(
$name => { // DeclarationParser also calls parse_entirely so we’d normally not need // to, but in this case we do because we set the value as a side effect // rather than returning it. let value = input.parse_entirely(|i| Parse::parse(self.context, i))?; self.descriptors.$ident = Some(value)
},
)*
_ => return Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name.clone()))),
}
Ok(())
}
}
}
}
/// Errors that can happen when registering a property. #[allow(missing_docs)] pubenum PropertyRegistrationError {
NoInitialValue,
InvalidInitialValue,
InitialValueNotComputationallyIndependent,
}
/// Performs syntax validation as per the initial value descriptor. /// https://drafts.css-houdini.org/css-properties-values-api-1/#initial-value-descriptor pubfn validate_initial_value(
syntax: &Descriptor,
initial_value: Option<&SpecifiedValue>,
) -> Result<(), PropertyRegistrationError> { usecrate::properties::CSSWideKeyword; // If the value of the syntax descriptor is the universal syntax definition, then the // initial-value descriptor is optional. If omitted, the initial value of the property is // the guaranteed-invalid value. if syntax.is_universal() && initial_value.is_none() { return Ok(());
}
// Otherwise, if the value of the syntax descriptor is not the universal syntax definition, // the following conditions must be met for the @property rule to be valid:
// The initial-value descriptor must be present. let Some(initial) = initial_value else { return Err(PropertyRegistrationError::NoInitialValue);
};
// A value that references the environment or other variables is not computationally // independent. if initial.has_references() { return Err(PropertyRegistrationError::InitialValueNotComputationallyIndependent);
}
// The initial-value cannot include CSS-wide keywords. if input.try_parse(CSSWideKeyword::parse).is_ok() { return Err(PropertyRegistrationError::InitialValueNotComputationallyIndependent);
}
/// A custom property name wrapper that includes the `--` prefix in its serialization #[derive(Clone, Debug, PartialEq, MallocSizeOf)] pubstruct PropertyRuleName(pub CustomPropertyName);
impl Parse for Inherits { fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { // FIXME(bug 1927012): Remove `return` from try_match_ident_ignore_ascii_case so the closure // can be removed. let result: Result<Inherits, ParseError> = (|| {
try_match_ident_ignore_ascii_case! { input, "true" => Ok(Inherits::True), "false" => Ok(Inherits::False),
}
})(); iflet Err(err) = result {
Err(ParseError {
kind: ParseErrorKind::Custom(StyleParseErrorKind::PropertyInheritsField(
PropertyInheritsParseError::InvalidInherits,
)),
location: err.location,
})
} else {
result
}
}
}
/// Specifies the initial value of the custom property registration represented by the @property /// rule, controlling the property’s initial value. /// /// The SpecifiedValue is wrapped in an Arc to avoid copying when using it. pubtype InitialValue = Arc<SpecifiedValue>;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.