mirror of
https://github.com/servo/servo.git
synced 2025-08-07 22:45:34 +01:00
style: [css-properties-values-api] Parsing and serialization for @property syntax descriptor
Based off of @emilio's syntax parser at <https://github.com/emilio/css-typed-om-syntax>. Co-authored-by: Emilio Cobos Álvarez <emilio@crisal.io> Differential Revision: https://phabricator.services.mozilla.com/D178268
This commit is contained in:
parent
8823b63513
commit
87ce7045ef
13 changed files with 522 additions and 14 deletions
|
@ -45,7 +45,7 @@ fn rgb_to_hue_min_max(red: f32, green: f32, blue: f32) -> (f32, f32, f32) {
|
||||||
(red - green) / delta + 4.0
|
(red - green) / delta + 4.0
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
std::f32::NAN
|
f32::NAN
|
||||||
};
|
};
|
||||||
|
|
||||||
(hue, min, max)
|
(hue, min, max)
|
||||||
|
|
|
@ -107,6 +107,7 @@ pub mod media_queries;
|
||||||
pub mod parallel;
|
pub mod parallel;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
pub mod piecewise_linear;
|
pub mod piecewise_linear;
|
||||||
|
pub mod properties_and_values;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod queries;
|
pub mod queries;
|
||||||
pub mod rule_cache;
|
pub mod rule_cache;
|
||||||
|
|
9
components/style/properties_and_values/mod.rs
Normal file
9
components/style/properties_and_values/mod.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
//! Properties and Values
|
||||||
|
//!
|
||||||
|
//! https://drafts.css-houdini.org/css-properties-values-api-1/
|
||||||
|
|
||||||
|
pub mod syntax;
|
60
components/style/properties_and_values/syntax/ascii.rs
Normal file
60
components/style/properties_and_values/syntax/ascii.rs
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
/// Trims ASCII whitespace characters from a slice, and returns the trimmed input.
|
||||||
|
pub fn trim_ascii_whitespace(input: &str) -> &str {
|
||||||
|
if input.is_empty() {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut start = 0;
|
||||||
|
{
|
||||||
|
let mut iter = input.as_bytes().iter();
|
||||||
|
loop {
|
||||||
|
let byte = match iter.next() {
|
||||||
|
Some(b) => b,
|
||||||
|
None => return "",
|
||||||
|
};
|
||||||
|
|
||||||
|
if !byte.is_ascii_whitespace() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
start += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut end = input.len();
|
||||||
|
assert!(start < end);
|
||||||
|
{
|
||||||
|
let mut iter = input.as_bytes()[start..].iter().rev();
|
||||||
|
loop {
|
||||||
|
let byte = match iter.next() {
|
||||||
|
Some(b) => b,
|
||||||
|
None => {
|
||||||
|
debug_assert!(false, "We should have caught this in the loop above!");
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if !byte.is_ascii_whitespace() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
end -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&input[start..end]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn trim_ascii_whitespace_test() {
|
||||||
|
fn test(i: &str, o: &str) {
|
||||||
|
assert_eq!(trim_ascii_whitespace(i), o)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("", "");
|
||||||
|
test(" ", "");
|
||||||
|
test(" a b c ", "a b c");
|
||||||
|
test(" \t \t \ta b c \t \t \t \t", "a b c");
|
||||||
|
}
|
91
components/style/properties_and_values/syntax/data_type.rs
Normal file
91
components/style/properties_and_values/syntax/data_type.rs
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use super::{Component, ComponentName, Multiplier};
|
||||||
|
|
||||||
|
/// <https://drafts.css-houdini.org/css-properties-values-api-1/#supported-names>
|
||||||
|
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)]
|
||||||
|
pub enum DataType {
|
||||||
|
/// Any valid `<length>` value
|
||||||
|
Length,
|
||||||
|
/// `<number>` values
|
||||||
|
Number,
|
||||||
|
/// Any valid <percentage> value
|
||||||
|
Percentage,
|
||||||
|
/// Any valid `<length>` or `<percentage>` value, any valid `<calc()>` expression combining
|
||||||
|
/// `<length>` and `<percentage>` components.
|
||||||
|
LengthPercentage,
|
||||||
|
/// Any valid `<color>` value
|
||||||
|
Color,
|
||||||
|
/// Any valid `<image>` value
|
||||||
|
Image,
|
||||||
|
/// Any valid `<url>` value
|
||||||
|
Url,
|
||||||
|
/// Any valid `<integer>` value
|
||||||
|
Integer,
|
||||||
|
/// Any valid `<angle>` value
|
||||||
|
Angle,
|
||||||
|
/// Any valid `<time>` value
|
||||||
|
Time,
|
||||||
|
/// Any valid `<resolution>` value
|
||||||
|
Resolution,
|
||||||
|
/// Any valid `<transform-function>` value
|
||||||
|
TransformFunction,
|
||||||
|
/// A list of valid `<transform-function>` values. Note that "<transform-list>" is a pre-multiplied
|
||||||
|
/// data type name equivalent to "<transform-function>+"
|
||||||
|
TransformList,
|
||||||
|
/// Any valid `<custom-ident>` value
|
||||||
|
CustomIdent,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DataType {
|
||||||
|
pub fn unpremultiply(&self) -> Option<Component> {
|
||||||
|
match *self {
|
||||||
|
DataType::TransformList => Some(Component {
|
||||||
|
name: ComponentName::DataType(DataType::TransformFunction),
|
||||||
|
multiplier: Some(Multiplier::Space),
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_str(ty: &str) -> Option<Self> {
|
||||||
|
Some(match ty.as_bytes() {
|
||||||
|
b"length" => DataType::Length,
|
||||||
|
b"number" => DataType::Number,
|
||||||
|
b"percentage" => DataType::Percentage,
|
||||||
|
b"length-percentage" => DataType::LengthPercentage,
|
||||||
|
b"color" => DataType::Color,
|
||||||
|
b"image" => DataType::Image,
|
||||||
|
b"url" => DataType::Url,
|
||||||
|
b"integer" => DataType::Integer,
|
||||||
|
b"angle" => DataType::Angle,
|
||||||
|
b"time" => DataType::Time,
|
||||||
|
b"resolution" => DataType::Resolution,
|
||||||
|
b"transform-function" => DataType::TransformFunction,
|
||||||
|
b"custom-ident" => DataType::CustomIdent,
|
||||||
|
b"transform-list" => DataType::TransformList,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_str(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
DataType::Length => "length",
|
||||||
|
DataType::Number => "number",
|
||||||
|
DataType::Percentage => "percentage",
|
||||||
|
DataType::LengthPercentage => "length-percentage",
|
||||||
|
DataType::Color => "color",
|
||||||
|
DataType::Image => "image",
|
||||||
|
DataType::Url => "url",
|
||||||
|
DataType::Integer => "integer",
|
||||||
|
DataType::Angle => "angle",
|
||||||
|
DataType::Time => "time",
|
||||||
|
DataType::Resolution => "resolution",
|
||||||
|
DataType::TransformFunction => "transform-function",
|
||||||
|
DataType::CustomIdent => "custom-ident",
|
||||||
|
DataType::TransformList => "transform-list",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
328
components/style/properties_and_values/syntax/mod.rs
Normal file
328
components/style/properties_and_values/syntax/mod.rs
Normal file
|
@ -0,0 +1,328 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
//! Used for parsing and serializing the [`@property`] syntax string.
|
||||||
|
//!
|
||||||
|
//! <https://drafts.css-houdini.org/css-properties-values-api-1/#parsing-syntax>
|
||||||
|
|
||||||
|
use std::fmt::{self, Debug};
|
||||||
|
use std::{borrow::Cow, fmt::Write};
|
||||||
|
|
||||||
|
use crate::parser::{Parse, ParserContext};
|
||||||
|
use crate::values::CustomIdent;
|
||||||
|
use cssparser::{Parser as CSSParser, ParserInput as CSSParserInput};
|
||||||
|
use style_traits::{
|
||||||
|
CssWriter, ParseError as StyleParseError, PropertySyntaxParseError as ParseError,
|
||||||
|
StyleParseErrorKind, ToCss,
|
||||||
|
};
|
||||||
|
|
||||||
|
use self::data_type::DataType;
|
||||||
|
|
||||||
|
mod ascii;
|
||||||
|
mod data_type;
|
||||||
|
|
||||||
|
/// <https://drafts.css-houdini.org/css-properties-values-api-1/#parsing-syntax>
|
||||||
|
#[derive(Debug, Clone, MallocSizeOf)]
|
||||||
|
pub struct Descriptor {
|
||||||
|
components: Box<[Component]>,
|
||||||
|
css: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Descriptor {
|
||||||
|
/// Returns the universal syntax definition with the given CSS representation.
|
||||||
|
fn universal(css: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
components: Default::default(),
|
||||||
|
css: String::from(css),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the specified syntax string.
|
||||||
|
pub fn as_str(&self) -> &str {
|
||||||
|
&self.css
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Descriptor {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.components == other.components
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for Descriptor {
|
||||||
|
/// Parse a syntax descriptor.
|
||||||
|
fn parse<'i, 't>(
|
||||||
|
_context: &ParserContext,
|
||||||
|
parser: &mut CSSParser<'i, 't>,
|
||||||
|
) -> Result<Self, StyleParseError<'i>> {
|
||||||
|
// 1. Strip leading and trailing ASCII whitespace from string.
|
||||||
|
let input = parser.expect_string()?;
|
||||||
|
match parse_descriptor(input) {
|
||||||
|
Ok(syntax) => Ok(syntax),
|
||||||
|
Err(err) => Err(parser.new_custom_error(StyleParseErrorKind::PropertySyntaxField(err))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToCss for Descriptor {
|
||||||
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||||
|
where
|
||||||
|
W: Write,
|
||||||
|
{
|
||||||
|
self.css.to_css(dest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://drafts.css-houdini.org/css-properties-values-api-1/#multipliers>
|
||||||
|
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)]
|
||||||
|
pub enum Multiplier {
|
||||||
|
/// Indicates a space-separated list.
|
||||||
|
Space,
|
||||||
|
/// Indicates a comma-separated list.
|
||||||
|
Comma,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://drafts.css-houdini.org/css-properties-values-api-1/#syntax-component>
|
||||||
|
#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
|
||||||
|
pub struct Component {
|
||||||
|
name: ComponentName,
|
||||||
|
multiplier: Option<Multiplier>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component {
|
||||||
|
/// Returns the component's name.
|
||||||
|
#[inline]
|
||||||
|
pub fn name(&self) -> &ComponentName {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the component's multiplier, if one exists.
|
||||||
|
#[inline]
|
||||||
|
pub fn multiplier(&self) -> Option<Multiplier> {
|
||||||
|
self.multiplier
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If the component is premultiplied, return the un-premultiplied component.
|
||||||
|
#[inline]
|
||||||
|
pub fn unpremultiplied(&self) -> Cow<Self> {
|
||||||
|
match self.name.unpremultiply() {
|
||||||
|
Some(component) => {
|
||||||
|
debug_assert!(
|
||||||
|
self.multiplier.is_none(),
|
||||||
|
"Shouldn't have parsed a multiplier for a pre-multiplied data type name",
|
||||||
|
);
|
||||||
|
Cow::Owned(component)
|
||||||
|
},
|
||||||
|
None => Cow::Borrowed(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://drafts.css-houdini.org/css-properties-values-api-1/#syntax-component-name>
|
||||||
|
#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
|
||||||
|
pub enum ComponentName {
|
||||||
|
/// <https://drafts.css-houdini.org/css-properties-values-api-1/#data-type-name>
|
||||||
|
DataType(DataType),
|
||||||
|
/// <https://drafts.csswg.org/css-values-4/#custom-idents>
|
||||||
|
Ident(CustomIdent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ComponentName {
|
||||||
|
fn unpremultiply(&self) -> Option<Component> {
|
||||||
|
match *self {
|
||||||
|
ComponentName::DataType(ref t) => t.unpremultiply(),
|
||||||
|
ComponentName::Ident(..) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://drafts.css-houdini.org/css-properties-values-api-1/#pre-multiplied-data-type-name>
|
||||||
|
fn is_pre_multiplied(&self) -> bool {
|
||||||
|
self.unpremultiply().is_some()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse a syntax descriptor.
|
||||||
|
#[inline]
|
||||||
|
fn parse_descriptor(css: &str) -> Result<Descriptor, ParseError> {
|
||||||
|
// 1. Strip leading and trailing ASCII whitespace from string.
|
||||||
|
let input = ascii::trim_ascii_whitespace(css);
|
||||||
|
|
||||||
|
// 2. If string's length is 0, return failure.
|
||||||
|
if input.is_empty() {
|
||||||
|
return Err(ParseError::EmptyInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. If string's length is 1, and the only code point in string is U+002A
|
||||||
|
// ASTERISK (*), return the universal syntax descriptor.
|
||||||
|
if input.len() == 1 && input.as_bytes()[0] == b'*' {
|
||||||
|
return Ok(Descriptor::universal(css));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Let stream be an input stream created from the code points of string,
|
||||||
|
// preprocessed as specified in [css-syntax-3]. Let descriptor be an
|
||||||
|
// initially empty list of syntax components.
|
||||||
|
//
|
||||||
|
// NOTE(emilio): Instead of preprocessing we cheat and treat new-lines and
|
||||||
|
// nulls in the parser specially.
|
||||||
|
let mut components = vec![];
|
||||||
|
{
|
||||||
|
let mut parser = Parser::new(input, &mut components);
|
||||||
|
// 5. Repeatedly consume the next input code point from stream.
|
||||||
|
parser.parse()?;
|
||||||
|
}
|
||||||
|
Ok(Descriptor {
|
||||||
|
components: components.into_boxed_slice(),
|
||||||
|
css: String::from(css),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Parser<'a> {
|
||||||
|
input: &'a str,
|
||||||
|
position: usize,
|
||||||
|
output: &'a mut Vec<Component>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://drafts.csswg.org/css-syntax-3/#whitespace>
|
||||||
|
fn is_whitespace(byte: u8) -> bool {
|
||||||
|
match byte {
|
||||||
|
b'\t' | b'\n' | b'\r' | b' ' => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://drafts.csswg.org/css-syntax-3/#letter>
|
||||||
|
fn is_letter(byte: u8) -> bool {
|
||||||
|
match byte {
|
||||||
|
b'A'..=b'Z' | b'a'..=b'z' => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://drafts.csswg.org/css-syntax-3/#non-ascii-code-point>
|
||||||
|
fn is_non_ascii(byte: u8) -> bool {
|
||||||
|
byte >= 0x80
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://drafts.csswg.org/css-syntax-3/#name-start-code-point>
|
||||||
|
fn is_name_start(byte: u8) -> bool {
|
||||||
|
is_letter(byte) || is_non_ascii(byte) || byte == b'_'
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Parser<'a> {
|
||||||
|
fn new(input: &'a str, output: &'a mut Vec<Component>) -> Self {
|
||||||
|
Self {
|
||||||
|
input,
|
||||||
|
position: 0,
|
||||||
|
output,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek(&self) -> Option<u8> {
|
||||||
|
self.input.as_bytes().get(self.position).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(&mut self) -> Result<(), ParseError> {
|
||||||
|
// 5. Repeatedly consume the next input code point from stream:
|
||||||
|
loop {
|
||||||
|
let component = self.parse_component()?;
|
||||||
|
self.output.push(component);
|
||||||
|
self.skip_whitespace();
|
||||||
|
|
||||||
|
let byte = match self.peek() {
|
||||||
|
None => return Ok(()),
|
||||||
|
Some(b) => b,
|
||||||
|
};
|
||||||
|
|
||||||
|
if byte != b'|' {
|
||||||
|
return Err(ParseError::ExpectedPipeBetweenComponents);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.position += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn skip_whitespace(&mut self) {
|
||||||
|
loop {
|
||||||
|
match self.peek() {
|
||||||
|
Some(c) if is_whitespace(c) => self.position += 1,
|
||||||
|
_ => return,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://drafts.css-houdini.org/css-properties-values-api-1/#consume-data-type-name>
|
||||||
|
fn parse_data_type_name(&mut self) -> Result<DataType, ParseError> {
|
||||||
|
let start = self.position;
|
||||||
|
loop {
|
||||||
|
let byte = match self.peek() {
|
||||||
|
Some(b) => b,
|
||||||
|
None => return Err(ParseError::UnclosedDataTypeName),
|
||||||
|
};
|
||||||
|
if byte != b'>' {
|
||||||
|
self.position += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let ty = match DataType::from_str(&self.input[start..self.position]) {
|
||||||
|
Some(ty) => ty,
|
||||||
|
None => return Err(ParseError::UnknownDataTypeName),
|
||||||
|
};
|
||||||
|
self.position += 1;
|
||||||
|
return Ok(ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_name(&mut self) -> Result<ComponentName, ParseError> {
|
||||||
|
let b = match self.peek() {
|
||||||
|
Some(b) => b,
|
||||||
|
None => return Err(ParseError::UnexpectedEOF),
|
||||||
|
};
|
||||||
|
|
||||||
|
if b == b'<' {
|
||||||
|
self.position += 1;
|
||||||
|
return Ok(ComponentName::DataType(self.parse_data_type_name()?));
|
||||||
|
}
|
||||||
|
|
||||||
|
if b != b'\\' && !is_name_start(b) {
|
||||||
|
return Err(ParseError::InvalidNameStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
let input = &self.input[self.position..];
|
||||||
|
let mut input = CSSParserInput::new(input);
|
||||||
|
let mut input = CSSParser::new(&mut input);
|
||||||
|
let location = input.current_source_location();
|
||||||
|
let name = input
|
||||||
|
.expect_ident()
|
||||||
|
.ok()
|
||||||
|
.and_then(|name| CustomIdent::from_ident(location, name, &[]).ok());
|
||||||
|
let name = match name {
|
||||||
|
Some(name) => name,
|
||||||
|
None => return Err(ParseError::InvalidName),
|
||||||
|
};
|
||||||
|
self.position += input.position().byte_index();
|
||||||
|
return Ok(ComponentName::Ident(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_multiplier(&mut self) -> Option<Multiplier> {
|
||||||
|
let multiplier = match self.peek()? {
|
||||||
|
b'+' => Multiplier::Space,
|
||||||
|
b'#' => Multiplier::Comma,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
self.position += 1;
|
||||||
|
Some(multiplier)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://drafts.css-houdini.org/css-properties-values-api-1/#consume-a-syntax-component>
|
||||||
|
fn parse_component(&mut self) -> Result<Component, ParseError> {
|
||||||
|
// Consume as much whitespace as possible from stream.
|
||||||
|
self.skip_whitespace();
|
||||||
|
let name = self.parse_name()?;
|
||||||
|
let multiplier = if name.is_pre_multiplied() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
self.parse_multiplier()
|
||||||
|
};
|
||||||
|
Ok(Component { name, multiplier })
|
||||||
|
}
|
||||||
|
}
|
|
@ -197,8 +197,6 @@ impl Animate for i32 {
|
||||||
impl Animate for f32 {
|
impl Animate for f32 {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
||||||
use std::f32;
|
|
||||||
|
|
||||||
let ret = (*self as f64).animate(&(*other as f64), procedure)?;
|
let ret = (*self as f64).animate(&(*other as f64), procedure)?;
|
||||||
Ok(ret.min(f32::MAX as f64).max(f32::MIN as f64) as f32)
|
Ok(ret.min(f32::MAX as f64).max(f32::MIN as f64) as f32)
|
||||||
}
|
}
|
||||||
|
@ -208,8 +206,6 @@ impl Animate for f32 {
|
||||||
impl Animate for f64 {
|
impl Animate for f64 {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
||||||
use std::f64;
|
|
||||||
|
|
||||||
let (self_weight, other_weight) = procedure.weights();
|
let (self_weight, other_weight) = procedure.weights();
|
||||||
|
|
||||||
let ret = *self * self_weight + *other * other_weight;
|
let ret = *self * self_weight + *other * other_weight;
|
||||||
|
|
|
@ -383,8 +383,6 @@ impl Quaternion {
|
||||||
|
|
||||||
impl Animate for Quaternion {
|
impl Animate for Quaternion {
|
||||||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
||||||
use std::f64;
|
|
||||||
|
|
||||||
let (this_weight, other_weight) = procedure.weights();
|
let (this_weight, other_weight) = procedure.weights();
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
// Doule EPSILON since both this_weight and other_weght have calculation errors
|
// Doule EPSILON since both this_weight and other_weght have calculation errors
|
||||||
|
|
|
@ -26,7 +26,7 @@ impl ToComputedValue for specified::AnimationIterationCount {
|
||||||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||||
AnimationIterationCount(match *self {
|
AnimationIterationCount(match *self {
|
||||||
specified::AnimationIterationCount::Number(n) => n.to_computed_value(context).0,
|
specified::AnimationIterationCount::Number(n) => n.to_computed_value(context).0,
|
||||||
specified::AnimationIterationCount::Infinite => std::f32::INFINITY,
|
specified::AnimationIterationCount::Infinite => f32::INFINITY,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -168,7 +168,7 @@ impl<L> GenericPerspectiveFunction<L> {
|
||||||
/// Returns `f32::INFINITY` or the result of a function on the length value.
|
/// Returns `f32::INFINITY` or the result of a function on the length value.
|
||||||
pub fn infinity_or(&self, f: impl FnOnce(&L) -> f32) -> f32 {
|
pub fn infinity_or(&self, f: impl FnOnce(&L) -> f32) -> f32 {
|
||||||
match *self {
|
match *self {
|
||||||
Self::None => std::f32::INFINITY,
|
Self::None => f32::INFINITY,
|
||||||
Self::Length(ref l) => f(l),
|
Self::Length(ref l) => f(l),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -471,7 +471,6 @@ where
|
||||||
reference_box: Option<&Rect<ComputedLength>>,
|
reference_box: Option<&Rect<ComputedLength>>,
|
||||||
) -> Result<Transform3D<f64>, ()> {
|
) -> Result<Transform3D<f64>, ()> {
|
||||||
use self::TransformOperation::*;
|
use self::TransformOperation::*;
|
||||||
use std::f64;
|
|
||||||
|
|
||||||
let reference_width = reference_box.map(|v| v.size.width);
|
let reference_width = reference_box.map(|v| v.size.width);
|
||||||
let reference_height = reference_box.map(|v| v.size.height);
|
let reference_height = reference_box.map(|v| v.size.height);
|
||||||
|
@ -501,7 +500,7 @@ where
|
||||||
},
|
},
|
||||||
Perspective(ref p) => {
|
Perspective(ref p) => {
|
||||||
let px = match p {
|
let px = match p {
|
||||||
PerspectiveFunction::None => std::f32::INFINITY,
|
PerspectiveFunction::None => f32::INFINITY,
|
||||||
PerspectiveFunction::Length(ref p) => p.to_pixel_length(None)?,
|
PerspectiveFunction::Length(ref p) => p.to_pixel_length(None)?,
|
||||||
};
|
};
|
||||||
create_perspective_matrix(px).cast()
|
create_perspective_matrix(px).cast()
|
||||||
|
|
|
@ -20,7 +20,6 @@ use crate::values::serialize_atom_identifier;
|
||||||
use crate::values::specified::calc::CalcNode;
|
use crate::values::specified::calc::CalcNode;
|
||||||
use crate::{Atom, Namespace, One, Prefix, Zero};
|
use crate::{Atom, Namespace, One, Prefix, Zero};
|
||||||
use cssparser::{Parser, Token};
|
use cssparser::{Parser, Token};
|
||||||
use std::f32;
|
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
use style_traits::values::specified::AllowedNumericType;
|
use style_traits::values::specified::AllowedNumericType;
|
||||||
|
|
|
@ -996,8 +996,8 @@ fn parse_number(iter: &mut Peekable<Cloned<slice::Iter<u8>>>) -> Result<CSSFloat
|
||||||
|
|
||||||
if value.is_finite() {
|
if value.is_finite() {
|
||||||
Ok(value
|
Ok(value
|
||||||
.min(::std::f32::MAX as f64)
|
.min(f32::MAX as f64)
|
||||||
.max(::std::f32::MIN as f64) as CSSFloat)
|
.max(f32::MIN as f64) as CSSFloat)
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,8 @@ pub enum StyleParseErrorKind<'i> {
|
||||||
RangedExpressionWithNoValue,
|
RangedExpressionWithNoValue,
|
||||||
/// A function was encountered that was not expected.
|
/// A function was encountered that was not expected.
|
||||||
UnexpectedFunction(CowRcStr<'i>),
|
UnexpectedFunction(CowRcStr<'i>),
|
||||||
|
/// Error encountered parsing a @property's `syntax` descriptor
|
||||||
|
PropertySyntaxField(PropertySyntaxParseError),
|
||||||
/// @namespace must be before any rule but @charset and @import
|
/// @namespace must be before any rule but @charset and @import
|
||||||
UnexpectedNamespaceRule,
|
UnexpectedNamespaceRule,
|
||||||
/// @import must be before any rule but @charset
|
/// @import must be before any rule but @charset
|
||||||
|
@ -196,6 +198,31 @@ impl<'i> StyleParseErrorKind<'i> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Errors that can be encountered while parsing the @property rule's syntax descriptor.
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum PropertySyntaxParseError {
|
||||||
|
/// The string's length was 0.
|
||||||
|
EmptyInput,
|
||||||
|
/// A non-whitespace, non-pipe character was fount after parsing a component.
|
||||||
|
ExpectedPipeBetweenComponents,
|
||||||
|
/// The start of an identifier was expected but not found.
|
||||||
|
///
|
||||||
|
/// <https://drafts.csswg.org/css-syntax-3/#name-start-code-point>
|
||||||
|
InvalidNameStart,
|
||||||
|
/// The name is not a valid `<ident>`.
|
||||||
|
InvalidName,
|
||||||
|
/// The data type name was not closed.
|
||||||
|
///
|
||||||
|
/// <https://drafts.css-houdini.org/css-properties-values-api-1/#consume-data-type-name>
|
||||||
|
UnclosedDataTypeName,
|
||||||
|
/// The next byte was expected while parsing, but EOF was found instead.
|
||||||
|
UnexpectedEOF,
|
||||||
|
/// The data type is not a supported syntax component name.
|
||||||
|
///
|
||||||
|
/// <https://drafts.css-houdini.org/css-properties-values-api-1/#supported-names>
|
||||||
|
UnknownDataTypeName,
|
||||||
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// The mode to use when parsing values.
|
/// The mode to use when parsing values.
|
||||||
pub struct ParsingMode: u8 {
|
pub struct ParsingMode: u8 {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue