mirror of
https://github.com/servo/servo.git
synced 2025-07-13 10:23:40 +01:00
Auto merge of #22167 - emilio:gecko-sync, r=emilio
style: Sync changes from mozilla-central. See each individual commit for details. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/22167) <!-- Reviewable:end -->
This commit is contained in:
commit
19b4f35de1
76 changed files with 1025 additions and 815 deletions
|
@ -29,6 +29,7 @@ log = "0.4"
|
|||
malloc_size_of = { path = "../malloc_size_of" }
|
||||
msg = {path = "../msg"}
|
||||
net_traits = {path = "../net_traits"}
|
||||
num-traits = "0.2"
|
||||
ordered-float = "1.0"
|
||||
parking_lot = "0.6"
|
||||
profile_traits = {path = "../profile_traits"}
|
||||
|
|
|
@ -49,6 +49,7 @@ use crate::table_wrapper::TableWrapperFlow;
|
|||
use euclid::{Point2D, Rect, Size2D, Vector2D};
|
||||
use gfx_traits::print_tree::PrintTree;
|
||||
use gfx_traits::StackingContextId;
|
||||
use num_traits::cast::FromPrimitive;
|
||||
use serde::ser::{Serialize, SerializeStruct, Serializer};
|
||||
use servo_geometry::{au_rect_to_f32_rect, f32_rect_to_au_rect, MaxRect};
|
||||
use std::fmt;
|
||||
|
|
|
@ -49,6 +49,7 @@ include = [
|
|||
"FontDisplay",
|
||||
"FontFaceSourceListComponent",
|
||||
"FontLanguageOverride",
|
||||
"OverflowWrap",
|
||||
"TimingFunction",
|
||||
"PathCommand",
|
||||
"UnicodeRange",
|
||||
|
|
|
@ -370,7 +370,7 @@ impl Parse for System {
|
|||
"symbolic" => Ok(System::Symbolic),
|
||||
"additive" => Ok(System::Additive),
|
||||
"fixed" => {
|
||||
let first_symbol_value = input.r#try(|i| Integer::parse(context, i)).ok();
|
||||
let first_symbol_value = input.try(|i| Integer::parse(context, i)).ok();
|
||||
Ok(System::Fixed { first_symbol_value: first_symbol_value })
|
||||
}
|
||||
"extends" => {
|
||||
|
@ -457,7 +457,7 @@ impl Parse for Negative {
|
|||
) -> Result<Self, ParseError<'i>> {
|
||||
Ok(Negative(
|
||||
Symbol::parse(context, input)?,
|
||||
input.r#try(|input| Symbol::parse(context, input)).ok(),
|
||||
input.try(|input| Symbol::parse(context, input)).ok(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -483,7 +483,7 @@ impl Parse for Ranges {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("auto"))
|
||||
.try(|input| input.expect_ident_matching("auto"))
|
||||
.is_ok()
|
||||
{
|
||||
Ok(Ranges(Vec::new()))
|
||||
|
@ -512,7 +512,7 @@ fn parse_bound<'i, 't>(
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<CounterBound, ParseError<'i>> {
|
||||
if let Ok(integer) = input.r#try(|input| Integer::parse(context, input)) {
|
||||
if let Ok(integer) = input.try(|input| Integer::parse(context, input)) {
|
||||
return Ok(CounterBound::Integer(integer));
|
||||
}
|
||||
input.expect_ident_matching("infinite")?;
|
||||
|
@ -556,7 +556,7 @@ impl Parse for Pad {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let pad_with = input.r#try(|input| Symbol::parse(context, input));
|
||||
let pad_with = input.try(|input| Symbol::parse(context, input));
|
||||
let min_length = Integer::parse_non_negative(context, input)?;
|
||||
let pad_with = pad_with.or_else(|_| Symbol::parse(context, input))?;
|
||||
Ok(Pad(min_length, pad_with))
|
||||
|
@ -588,7 +588,7 @@ impl Parse for Symbols {
|
|||
) -> Result<Self, ParseError<'i>> {
|
||||
let mut symbols = Vec::new();
|
||||
loop {
|
||||
if let Ok(s) = input.r#try(|input| Symbol::parse(context, input)) {
|
||||
if let Ok(s) = input.try(|input| Symbol::parse(context, input)) {
|
||||
symbols.push(s)
|
||||
} else {
|
||||
if symbols.is_empty() {
|
||||
|
@ -640,7 +640,7 @@ impl Parse for AdditiveTuple {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let symbol = input.r#try(|input| Symbol::parse(context, input));
|
||||
let symbol = input.try(|input| Symbol::parse(context, input));
|
||||
let weight = Integer::parse_non_negative(context, input)?;
|
||||
let symbol = symbol.or_else(|_| Symbol::parse(context, input))?;
|
||||
Ok(AdditiveTuple {
|
||||
|
@ -673,7 +673,7 @@ impl Parse for SpeakAs {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let mut is_spell_out = false;
|
||||
let result = input.r#try(|input| {
|
||||
let result = input.try(|input| {
|
||||
let ident = input.expect_ident().map_err(|_| ())?;
|
||||
match_ignore_ascii_case! { &*ident,
|
||||
"auto" => Ok(SpeakAs::Auto),
|
||||
|
|
|
@ -553,7 +553,7 @@ fn parse_var_function<'i, 't>(
|
|||
let name = parse_name(&name).map_err(|()| {
|
||||
input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name.clone()))
|
||||
})?;
|
||||
if input.r#try(|input| input.expect_comma()).is_ok() {
|
||||
if input.try(|input| input.expect_comma()).is_ok() {
|
||||
parse_fallback(input)?;
|
||||
}
|
||||
if let Some(refs) = references {
|
||||
|
@ -569,7 +569,7 @@ fn parse_env_function<'i, 't>(
|
|||
// TODO(emilio): This should be <custom-ident> per spec, but no other
|
||||
// browser does that, see https://github.com/w3c/csswg-drafts/issues/3262.
|
||||
input.expect_ident()?;
|
||||
if input.r#try(|input| input.expect_comma()).is_ok() {
|
||||
if input.try(|input| input.expect_comma()).is_ok() {
|
||||
parse_fallback(input)?;
|
||||
}
|
||||
if let Some(references) = references {
|
||||
|
|
|
@ -14,12 +14,12 @@ use crate::shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
|
|||
use crate::str::CssStringWriter;
|
||||
use crate::values::computed::font::FamilyName;
|
||||
use crate::values::generics::font::FontStyle as GenericFontStyle;
|
||||
use crate::values::specified::font::SpecifiedFontStyle;
|
||||
use crate::values::specified::font::{AbsoluteFontWeight, FontStretch};
|
||||
#[cfg(feature = "gecko")]
|
||||
use crate::values::specified::font::{
|
||||
SpecifiedFontFeatureSettings, SpecifiedFontVariationSettings,
|
||||
};
|
||||
use crate::values::specified::font::SpecifiedFontFeatureSettings;
|
||||
use crate::values::specified::font::SpecifiedFontStyle;
|
||||
#[cfg(feature = "gecko")]
|
||||
use crate::values::specified::font::SpecifiedFontVariationSettings;
|
||||
use crate::values::specified::font::{AbsoluteFontWeight, FontStretch};
|
||||
use crate::values::specified::url::SpecifiedUrl;
|
||||
use crate::values::specified::Angle;
|
||||
#[cfg(feature = "gecko")]
|
||||
|
@ -120,7 +120,7 @@ macro_rules! impl_range {
|
|||
) -> Result<Self, ParseError<'i>> {
|
||||
let first = $component::parse(context, input)?;
|
||||
let second = input
|
||||
.r#try(|input| $component::parse(context, input))
|
||||
.try(|input| $component::parse(context, input))
|
||||
.unwrap_or_else(|_| first.clone());
|
||||
Ok($range(first, second))
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ impl Parse for FontStyle {
|
|||
GenericFontStyle::Italic => FontStyle::Italic,
|
||||
GenericFontStyle::Oblique(angle) => {
|
||||
let second_angle = input
|
||||
.r#try(|input| SpecifiedFontStyle::parse_angle(context, input))
|
||||
.try(|input| SpecifiedFontStyle::parse_angle(context, input))
|
||||
.unwrap_or_else(|_| angle.clone());
|
||||
|
||||
FontStyle::Oblique(angle, second_angle)
|
||||
|
@ -380,7 +380,7 @@ impl Parse for Source {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Source, ParseError<'i>> {
|
||||
if input
|
||||
.r#try(|input| input.expect_function_matching("local"))
|
||||
.try(|input| input.expect_function_matching("local"))
|
||||
.is_ok()
|
||||
{
|
||||
return input
|
||||
|
@ -392,7 +392,7 @@ impl Parse for Source {
|
|||
|
||||
// Parsing optional format()
|
||||
let format_hints = if input
|
||||
.r#try(|input| input.expect_function_matching("format"))
|
||||
.try(|input| input.expect_function_matching("format"))
|
||||
.is_ok()
|
||||
{
|
||||
input.parse_nested_block(|input| {
|
||||
|
|
|
@ -38,9 +38,8 @@ use crate::rule_tree::StrongRuleNode;
|
|||
use crate::shared_lock::Locked;
|
||||
use crate::stylesheets::keyframes_rule::Keyframe;
|
||||
use crate::stylesheets::{CounterStyleRule, CssRules, FontFaceRule, FontFeatureValuesRule};
|
||||
use crate::stylesheets::{
|
||||
DocumentRule, ImportRule, KeyframesRule, MediaRule, NamespaceRule, PageRule,
|
||||
};
|
||||
use crate::stylesheets::{DocumentRule, ImportRule, KeyframesRule, MediaRule};
|
||||
use crate::stylesheets::{NamespaceRule, PageRule};
|
||||
use crate::stylesheets::{StyleRule, StylesheetContents, SupportsRule};
|
||||
use servo_arc::{Arc, ArcBorrow};
|
||||
use std::{mem, ptr};
|
||||
|
|
|
@ -18,9 +18,8 @@ use crate::stylesheets::{Origin, RulesMutateError};
|
|||
use crate::values::computed::image::LineDirection;
|
||||
use crate::values::computed::url::ComputedImageUrl;
|
||||
use crate::values::computed::{Angle, CalcLengthOrPercentage, Gradient, Image};
|
||||
use crate::values::computed::{
|
||||
Integer, LengthOrPercentage, LengthOrPercentageOrAuto, NonNegativeLengthOrPercentageOrAuto,
|
||||
};
|
||||
use crate::values::computed::{Integer, LengthOrPercentage};
|
||||
use crate::values::computed::{LengthOrPercentageOrAuto, NonNegativeLengthOrPercentageOrAuto};
|
||||
use crate::values::computed::{Percentage, TextAlign};
|
||||
use crate::values::generics::box_::VerticalAlign;
|
||||
use crate::values::generics::grid::{TrackListValue, TrackSize};
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
//! Global style data
|
||||
|
||||
use crate::context::StyleSystemOptions;
|
||||
use crate::gecko_bindings::bindings::Gecko_SetJemallocThreadLocalArena;
|
||||
use crate::gecko_bindings::bindings::{
|
||||
Gecko_RegisterProfilerThread, Gecko_UnregisterProfilerThread,
|
||||
};
|
||||
use crate::gecko_bindings::bindings;
|
||||
use crate::parallel::STYLE_THREAD_STACK_SIZE_KB;
|
||||
use crate::shared_lock::SharedRwLock;
|
||||
use crate::thread_state;
|
||||
|
@ -43,20 +40,20 @@ fn thread_name(index: usize) -> String {
|
|||
fn thread_startup(index: usize) {
|
||||
thread_state::initialize_layout_worker_thread();
|
||||
unsafe {
|
||||
Gecko_SetJemallocThreadLocalArena(true);
|
||||
bindings::Gecko_SetJemallocThreadLocalArena(true);
|
||||
}
|
||||
let name = thread_name(index);
|
||||
let name = CString::new(name).unwrap();
|
||||
unsafe {
|
||||
// Gecko_RegisterProfilerThread copies the passed name here.
|
||||
Gecko_RegisterProfilerThread(name.as_ptr());
|
||||
bindings::Gecko_RegisterProfilerThread(name.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
fn thread_shutdown(_: usize) {
|
||||
unsafe {
|
||||
Gecko_UnregisterProfilerThread();
|
||||
Gecko_SetJemallocThreadLocalArena(false);
|
||||
bindings::Gecko_UnregisterProfilerThread();
|
||||
bindings::Gecko_SetJemallocThreadLocalArena(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,12 +27,14 @@ include!(concat!(
|
|||
impl ::selectors::parser::PseudoElement for PseudoElement {
|
||||
type Impl = SelectorImpl;
|
||||
|
||||
// ::slotted() should support all tree-abiding pseudo-elements, see
|
||||
// https://drafts.csswg.org/css-scoping/#slotted-pseudo
|
||||
// https://drafts.csswg.org/css-pseudo-4/#treelike
|
||||
fn valid_after_slotted(&self) -> bool {
|
||||
// TODO(emilio): Remove this function or this comment after [1] is
|
||||
// resolved.
|
||||
//
|
||||
// [1]: https://github.com/w3c/csswg-drafts/issues/3150
|
||||
self.is_before_or_after()
|
||||
matches!(
|
||||
*self,
|
||||
PseudoElement::Before | PseudoElement::After | PseudoElement::Placeholder
|
||||
)
|
||||
}
|
||||
|
||||
fn supports_pseudo_class(&self, pseudo_class: &NonTSPseudoClass) -> bool {
|
||||
|
|
|
@ -14,13 +14,12 @@ use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, Coor
|
|||
use crate::media_queries::Device;
|
||||
use crate::values::computed::basic_shape::ShapeRadius as ComputedShapeRadius;
|
||||
use crate::values::computed::FlexBasis as ComputedFlexBasis;
|
||||
use crate::values::computed::NonNegativeNumber;
|
||||
use crate::values::computed::{Angle, ExtremumLength, Length, LengthOrPercentage};
|
||||
use crate::values::computed::{LengthOrPercentageOrAuto, Percentage};
|
||||
use crate::values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage};
|
||||
use crate::values::computed::{MaxLength as ComputedMaxLength, MozLength as ComputedMozLength};
|
||||
use crate::values::computed::{
|
||||
NonNegativeLength, NonNegativeLengthOrPercentage, NonNegativeNumber,
|
||||
};
|
||||
use crate::values::computed::{NonNegativeLength, NonNegativeLengthOrPercentage};
|
||||
use crate::values::generics::basic_shape::ShapeRadius;
|
||||
use crate::values::generics::box_::Perspective;
|
||||
use crate::values::generics::flex::FlexBasis;
|
||||
|
|
|
@ -6,9 +6,8 @@
|
|||
|
||||
use crate::gecko_bindings::bindings;
|
||||
use crate::gecko_bindings::structs::{nsStyleCoord, nsStyleCoord_Calc, nsStyleCoord_CalcValue};
|
||||
use crate::gecko_bindings::structs::{
|
||||
nsStyleCorners, nsStyleSides, nsStyleUnion, nsStyleUnit, nscoord,
|
||||
};
|
||||
use crate::gecko_bindings::structs::{nsStyleCorners, nsStyleSides};
|
||||
use crate::gecko_bindings::structs::{nsStyleUnion, nsStyleUnit, nscoord};
|
||||
use std::mem;
|
||||
|
||||
impl nsStyleCoord {
|
||||
|
|
|
@ -14,7 +14,7 @@ use crate::gecko_bindings::bindings::Gecko_AddRefAtom;
|
|||
use crate::gecko_bindings::bindings::Gecko_Atomize;
|
||||
use crate::gecko_bindings::bindings::Gecko_Atomize16;
|
||||
use crate::gecko_bindings::bindings::Gecko_ReleaseAtom;
|
||||
use crate::gecko_bindings::structs::{nsAtom, nsAtom_AtomKind, nsDynamicAtom, nsStaticAtom};
|
||||
use crate::gecko_bindings::structs::{nsAtom, nsDynamicAtom, nsStaticAtom};
|
||||
use nsstring::{nsAString, nsStr};
|
||||
use precomputed_hash::PrecomputedHash;
|
||||
use std::borrow::{Borrow, Cow};
|
||||
|
@ -175,7 +175,7 @@ impl WeakAtom {
|
|||
/// Returns whether this atom is static.
|
||||
#[inline]
|
||||
pub fn is_static(&self) -> bool {
|
||||
unsafe { (*self.as_ptr()).mKind() == nsAtom_AtomKind::Static as u32 }
|
||||
unsafe { (*self.as_ptr()).mIsStatic() != 0 }
|
||||
}
|
||||
|
||||
/// Returns the length of the atom string.
|
||||
|
|
|
@ -143,6 +143,7 @@ pub mod media_queries;
|
|||
pub mod parallel;
|
||||
pub mod parser;
|
||||
pub mod rule_cache;
|
||||
pub mod rule_collector;
|
||||
pub mod rule_tree;
|
||||
pub mod scoped_tls;
|
||||
pub mod selector_map;
|
||||
|
|
|
@ -114,7 +114,7 @@ impl MediaCondition {
|
|||
|
||||
// ParenthesisBlock.
|
||||
let first_condition = Self::parse_paren_block(context, input)?;
|
||||
let operator = match input.r#try(Operator::parse) {
|
||||
let operator = match input.try(Operator::parse) {
|
||||
Ok(op) => op,
|
||||
Err(..) => return Ok(first_condition),
|
||||
};
|
||||
|
@ -133,7 +133,7 @@ impl MediaCondition {
|
|||
};
|
||||
|
||||
loop {
|
||||
if input.r#try(|i| i.expect_ident_matching(delim)).is_err() {
|
||||
if input.try(|i| i.expect_ident_matching(delim)).is_err() {
|
||||
return Ok(MediaCondition::Operation(
|
||||
conditions.into_boxed_slice(),
|
||||
operator,
|
||||
|
@ -159,7 +159,7 @@ impl MediaCondition {
|
|||
) -> Result<Self, ParseError<'i>> {
|
||||
input.parse_nested_block(|input| {
|
||||
// Base case.
|
||||
if let Ok(inner) = input.r#try(|i| Self::parse(context, i)) {
|
||||
if let Ok(inner) = input.try(|i| Self::parse(context, i)) {
|
||||
return Ok(MediaCondition::InParens(Box::new(inner)));
|
||||
}
|
||||
let expr = MediaFeatureExpression::parse_in_parenthesis_block(context, input)?;
|
||||
|
|
|
@ -221,14 +221,14 @@ fn consume_operation_or_colon(input: &mut Parser) -> Result<Option<Operator>, ()
|
|||
Ok(Some(match first_delim {
|
||||
'=' => Operator::Equal,
|
||||
'>' => {
|
||||
if input.r#try(|i| i.expect_delim('=')).is_ok() {
|
||||
if input.try(|i| i.expect_delim('=')).is_ok() {
|
||||
Operator::GreaterThanEqual
|
||||
} else {
|
||||
Operator::GreaterThan
|
||||
}
|
||||
},
|
||||
'<' => {
|
||||
if input.r#try(|i| i.expect_delim('=')).is_ok() {
|
||||
if input.try(|i| i.expect_delim('=')).is_ok() {
|
||||
Operator::LessThanEqual
|
||||
} else {
|
||||
Operator::LessThan
|
||||
|
@ -350,7 +350,7 @@ impl MediaFeatureExpression {
|
|||
}
|
||||
}
|
||||
|
||||
let operator = input.r#try(consume_operation_or_colon);
|
||||
let operator = input.try(consume_operation_or_colon);
|
||||
let operator = match operator {
|
||||
Err(..) => {
|
||||
// If there's no colon, this is a media query of the
|
||||
|
|
|
@ -125,8 +125,8 @@ impl MediaQuery {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let (qualifier, explicit_media_type) = input
|
||||
.r#try(|input| -> Result<_, ()> {
|
||||
let qualifier = input.r#try(Qualifier::parse).ok();
|
||||
.try(|input| -> Result<_, ()> {
|
||||
let qualifier = input.try(Qualifier::parse).ok();
|
||||
let ident = input.expect_ident().map_err(|_| ())?;
|
||||
let media_type = MediaQueryType::parse(&ident)?;
|
||||
Ok((qualifier, Some(media_type)))
|
||||
|
@ -135,7 +135,7 @@ impl MediaQuery {
|
|||
|
||||
let condition = if explicit_media_type.is_none() {
|
||||
Some(MediaCondition::parse(context, input)?)
|
||||
} else if input.r#try(|i| i.expect_ident_matching("and")).is_ok() {
|
||||
} else if input.try(|i| i.expect_ident_matching("and")).is_ok() {
|
||||
Some(MediaCondition::parse_disallow_or(context, input)?)
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -324,6 +324,7 @@ class Longhand(object):
|
|||
"Opacity",
|
||||
"OutlineStyle",
|
||||
"OverflowClipBox",
|
||||
"OverflowWrap",
|
||||
"OverscrollBehavior",
|
||||
"Percentage",
|
||||
"Resize",
|
||||
|
|
|
@ -1419,6 +1419,7 @@ impl Clone for ${style_struct.gecko_struct_name} {
|
|||
"NonNegativeNumber": impl_simple,
|
||||
"Number": impl_simple,
|
||||
"Opacity": impl_simple,
|
||||
"OverflowWrap": impl_simple,
|
||||
"Perspective": impl_style_coord,
|
||||
"Position": impl_position,
|
||||
"RGBAColor": impl_rgba_color,
|
||||
|
|
|
@ -2102,12 +2102,12 @@ impl Matrix3D {
|
|||
|
||||
/// <https://drafts.csswg.org/css-transforms-2/#propdef-rotate>
|
||||
impl ComputedRotate {
|
||||
fn resolve(rotate: &ComputedRotate) -> (Number, Number, Number, Angle) {
|
||||
fn resolve(&self) -> (Number, Number, Number, Angle) {
|
||||
// According to the spec:
|
||||
// https://drafts.csswg.org/css-transforms-2/#individual-transforms
|
||||
//
|
||||
// If the axis is unspecified, it defaults to "0 0 1"
|
||||
match *rotate {
|
||||
match *self {
|
||||
Rotate::None => (0., 0., 1., Angle::zero()),
|
||||
Rotate::Rotate3D(rx, ry, rz, angle) => (rx, ry, rz, angle),
|
||||
Rotate::Rotate(angle) => (0., 0., 1., angle),
|
||||
|
@ -2122,8 +2122,7 @@ impl Animate for ComputedRotate {
|
|||
other: &Self,
|
||||
procedure: Procedure,
|
||||
) -> Result<Self, ()> {
|
||||
let from = ComputedRotate::resolve(self);
|
||||
let to = ComputedRotate::resolve(other);
|
||||
let (from, to) = (self.resolve(), other.resolve());
|
||||
|
||||
let (mut fx, mut fy, mut fz, fa) =
|
||||
transform::get_normalized_vector_and_angle(from.0, from.1, from.2, from.3);
|
||||
|
@ -2163,24 +2162,17 @@ impl Animate for ComputedRotate {
|
|||
|
||||
/// <https://drafts.csswg.org/css-transforms-2/#propdef-translate>
|
||||
impl ComputedTranslate {
|
||||
fn resolve(
|
||||
translate: &ComputedTranslate,
|
||||
) -> (LengthOrPercentage, LengthOrPercentage, Length) {
|
||||
fn resolve(&self) -> (LengthOrPercentage, LengthOrPercentage, Length) {
|
||||
// According to the spec:
|
||||
// https://drafts.csswg.org/css-transforms-2/#individual-transforms
|
||||
//
|
||||
// Unspecified translations default to 0px
|
||||
match *translate {
|
||||
match *self {
|
||||
Translate::None => {
|
||||
(
|
||||
LengthOrPercentage::Length(Length::zero()),
|
||||
LengthOrPercentage::Length(Length::zero()),
|
||||
Length::zero(),
|
||||
)
|
||||
(LengthOrPercentage::zero(), LengthOrPercentage::zero(), Length::zero())
|
||||
},
|
||||
Translate::Translate3D(tx, ty, tz) => (tx, ty, tz),
|
||||
Translate::Translate(tx, ty) => (tx, ty, Length::zero()),
|
||||
Translate::TranslateX(tx) => (tx, LengthOrPercentage::Length(Length::zero()), Length::zero()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2192,23 +2184,31 @@ impl Animate for ComputedTranslate {
|
|||
other: &Self,
|
||||
procedure: Procedure,
|
||||
) -> Result<Self, ()> {
|
||||
let from = ComputedTranslate::resolve(self);
|
||||
let to = ComputedTranslate::resolve(other);
|
||||
|
||||
Ok(Translate::Translate3D(from.0.animate(&to.0, procedure)?,
|
||||
from.1.animate(&to.1, procedure)?,
|
||||
from.2.animate(&to.2, procedure)?))
|
||||
match (self, other) {
|
||||
(&Translate::None, &Translate::None) => Ok(Translate::None),
|
||||
(&Translate::Translate3D(_, ..), _) | (_, &Translate::Translate3D(_, ..)) => {
|
||||
let (from, to) = (self.resolve(), other.resolve());
|
||||
Ok(Translate::Translate3D(from.0.animate(&to.0, procedure)?,
|
||||
from.1.animate(&to.1, procedure)?,
|
||||
from.2.animate(&to.2, procedure)?))
|
||||
},
|
||||
(&Translate::Translate(_, ..), _) | (_, &Translate::Translate(_, ..)) => {
|
||||
let (from, to) = (self.resolve(), other.resolve());
|
||||
Ok(Translate::Translate(from.0.animate(&to.0, procedure)?,
|
||||
from.1.animate(&to.1, procedure)?))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/css-transforms-2/#propdef-scale>
|
||||
impl ComputedScale {
|
||||
fn resolve(scale: &ComputedScale) -> (Number, Number, Number) {
|
||||
fn resolve(&self) -> (Number, Number, Number) {
|
||||
// According to the spec:
|
||||
// https://drafts.csswg.org/css-transforms-2/#individual-transforms
|
||||
//
|
||||
// Unspecified scales default to 1
|
||||
match *scale {
|
||||
match *self {
|
||||
Scale::None => (1.0, 1.0, 1.0),
|
||||
Scale::Scale3D(sx, sy, sz) => (sx, sy, sz),
|
||||
Scale::Scale(sx, sy) => (sx, sy, 1.),
|
||||
|
@ -2226,8 +2226,7 @@ impl Animate for ComputedScale {
|
|||
match (self, other) {
|
||||
(&Scale::None, &Scale::None) => Ok(Scale::None),
|
||||
(&Scale::Scale3D(_, ..), _) | (_, &Scale::Scale3D(_, ..)) => {
|
||||
let from = ComputedScale::resolve(self);
|
||||
let to = ComputedScale::resolve(other);
|
||||
let (from, to) = (self.resolve(), other.resolve());
|
||||
// FIXME(emilio, bug 1464791): why does this do something different than
|
||||
// Scale3D / TransformOperation::Scale3D?
|
||||
if procedure == Procedure::Add {
|
||||
|
@ -2241,8 +2240,7 @@ impl Animate for ComputedScale {
|
|||
))
|
||||
},
|
||||
(&Scale::Scale(_, ..), _) | (_, &Scale::Scale(_, ..)) => {
|
||||
let from = ComputedScale::resolve(self);
|
||||
let to = ComputedScale::resolve(other);
|
||||
let (from, to) = (self.resolve(), other.resolve());
|
||||
// FIXME(emilio, bug 1464791): why does this do something different than
|
||||
// Scale / TransformOperation::Scale?
|
||||
if procedure == Procedure::Add {
|
||||
|
|
|
@ -370,7 +370,7 @@ ${helpers.predefined_type(
|
|||
"generics::transform::Translate::None",
|
||||
animation_value_type="ComputedValue",
|
||||
boxed=True,
|
||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB GETCS_NEEDS_LAYOUT_FLUSH",
|
||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
|
||||
gecko_pref="layout.css.individual-transform.enabled",
|
||||
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
|
||||
servo_restyle_damage="reflow_out_of_flow",
|
||||
|
|
|
@ -65,6 +65,7 @@ ${helpers.predefined_type(
|
|||
spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-color",
|
||||
)}
|
||||
|
||||
// FIXME: Remove enabled_in="ua" once column-span is enabled on nightly (bug 1423383).
|
||||
${helpers.single_keyword(
|
||||
"column-span",
|
||||
"none all",
|
||||
|
@ -72,6 +73,7 @@ ${helpers.single_keyword(
|
|||
animation_value_type="discrete",
|
||||
gecko_enum_prefix="StyleColumnSpan",
|
||||
gecko_pref="layout.css.column-span.enabled",
|
||||
enabled_in="ua",
|
||||
spec="https://drafts.csswg.org/css-multicol/#propdef-column-span",
|
||||
extra_prefixes="moz:layout.css.column-span.enabled",
|
||||
)}
|
||||
|
|
|
@ -61,15 +61,16 @@ ${helpers.predefined_type(
|
|||
servo_restyle_damage = "reflow",
|
||||
)}
|
||||
|
||||
// Also known as "word-wrap" (which is more popular because of IE), but this is the preferred
|
||||
// name per CSS-TEXT 6.2.
|
||||
${helpers.single_keyword(
|
||||
// Also known as "word-wrap" (which is more popular because of IE), but this is
|
||||
// the preferred name per CSS-TEXT 6.2.
|
||||
${helpers.predefined_type(
|
||||
"overflow-wrap",
|
||||
"normal break-word",
|
||||
gecko_constant_prefix="NS_STYLE_OVERFLOWWRAP",
|
||||
"OverflowWrap",
|
||||
"computed::OverflowWrap::Normal",
|
||||
animation_value_type="discrete",
|
||||
spec="https://drafts.csswg.org/css-text/#propdef-overflow-wrap",
|
||||
alias="word-wrap",
|
||||
needs_context=False,
|
||||
servo_restyle_damage="rebuild_and_reflow",
|
||||
)}
|
||||
|
||||
|
@ -136,7 +137,7 @@ ${helpers.single_keyword(
|
|||
${helpers.predefined_type(
|
||||
"text-align",
|
||||
"TextAlign",
|
||||
"computed::TextAlign::start()",
|
||||
"computed::TextAlign::Start",
|
||||
animation_value_type="discrete",
|
||||
flags="APPLIES_TO_PLACEHOLDER",
|
||||
spec="https://drafts.csswg.org/css-text/#propdef-text-align",
|
||||
|
|
391
components/style/rule_collector.rs
Normal file
391
components/style/rule_collector.rs
Normal file
|
@ -0,0 +1,391 @@
|
|||
/* 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 http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Collects a series of applicable rules for a given element.
|
||||
|
||||
use crate::applicable_declarations::{ApplicableDeclarationBlock, ApplicableDeclarationList};
|
||||
use crate::dom::{TElement, TShadowRoot};
|
||||
use crate::properties::{AnimationRules, PropertyDeclarationBlock};
|
||||
use crate::rule_tree::{CascadeLevel, ShadowCascadeOrder};
|
||||
use crate::selector_map::SelectorMap;
|
||||
use crate::selector_parser::PseudoElement;
|
||||
use crate::shared_lock::Locked;
|
||||
use crate::stylesheets::Origin;
|
||||
use crate::stylist::{AuthorStylesEnabled, Rule, RuleInclusion, Stylist};
|
||||
use selectors::matching::{ElementSelectorFlags, MatchingContext};
|
||||
use servo_arc::ArcBorrow;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
/// An object that we use with all the intermediate state needed for the
|
||||
/// cascade.
|
||||
///
|
||||
/// This is done basically to be able to organize the cascade in smaller
|
||||
/// functions, and be able to reason about it easily.
|
||||
pub struct RuleCollector<'a, 'b: 'a, E, F: 'a>
|
||||
where
|
||||
E: TElement,
|
||||
{
|
||||
element: E,
|
||||
rule_hash_target: E,
|
||||
stylist: &'a Stylist,
|
||||
pseudo_element: Option<&'a PseudoElement>,
|
||||
style_attribute: Option<ArcBorrow<'a, Locked<PropertyDeclarationBlock>>>,
|
||||
smil_override: Option<ArcBorrow<'a, Locked<PropertyDeclarationBlock>>>,
|
||||
animation_rules: AnimationRules,
|
||||
rule_inclusion: RuleInclusion,
|
||||
rules: &'a mut ApplicableDeclarationList,
|
||||
context: &'a mut MatchingContext<'b, E::Impl>,
|
||||
flags_setter: &'a mut F,
|
||||
shadow_cascade_order: ShadowCascadeOrder,
|
||||
matches_user_and_author_rules: bool,
|
||||
matches_document_author_rules: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a, E, F: 'a> RuleCollector<'a, 'b, E, F>
|
||||
where
|
||||
E: TElement,
|
||||
F: FnMut(&E, ElementSelectorFlags),
|
||||
{
|
||||
/// Trivially construct a new collector.
|
||||
pub fn new(
|
||||
stylist: &'a Stylist,
|
||||
element: E,
|
||||
pseudo_element: Option<&'a PseudoElement>,
|
||||
style_attribute: Option<ArcBorrow<'a, Locked<PropertyDeclarationBlock>>>,
|
||||
smil_override: Option<ArcBorrow<'a, Locked<PropertyDeclarationBlock>>>,
|
||||
animation_rules: AnimationRules,
|
||||
rule_inclusion: RuleInclusion,
|
||||
rules: &'a mut ApplicableDeclarationList,
|
||||
context: &'a mut MatchingContext<'b, E::Impl>,
|
||||
flags_setter: &'a mut F,
|
||||
) -> Self {
|
||||
let rule_hash_target = element.rule_hash_target();
|
||||
let matches_user_and_author_rules = rule_hash_target.matches_user_and_author_rules();
|
||||
|
||||
// Gecko definitely has pseudo-elements with style attributes, like
|
||||
// ::-moz-color-swatch.
|
||||
debug_assert!(
|
||||
cfg!(feature = "gecko") || style_attribute.is_none() || pseudo_element.is_none(),
|
||||
"Style attributes do not apply to pseudo-elements"
|
||||
);
|
||||
debug_assert!(pseudo_element.map_or(true, |p| !p.is_precomputed()));
|
||||
|
||||
Self {
|
||||
element,
|
||||
rule_hash_target,
|
||||
stylist,
|
||||
pseudo_element,
|
||||
style_attribute,
|
||||
smil_override,
|
||||
animation_rules,
|
||||
rule_inclusion,
|
||||
context,
|
||||
flags_setter,
|
||||
rules,
|
||||
matches_user_and_author_rules,
|
||||
shadow_cascade_order: 0,
|
||||
matches_document_author_rules: matches_user_and_author_rules,
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_stylist_rules(&mut self, origin: Origin) {
|
||||
let cascade_level = match origin {
|
||||
Origin::UserAgent => CascadeLevel::UANormal,
|
||||
Origin::User => CascadeLevel::UserNormal,
|
||||
Origin::Author => CascadeLevel::SameTreeAuthorNormal,
|
||||
};
|
||||
|
||||
let cascade_data = self.stylist.cascade_data().borrow_for_origin(origin);
|
||||
let map = match cascade_data.normal_rules(self.pseudo_element) {
|
||||
Some(m) => m,
|
||||
None => return,
|
||||
};
|
||||
|
||||
map.get_all_matching_rules(
|
||||
self.element,
|
||||
self.rule_hash_target,
|
||||
self.rules,
|
||||
self.context,
|
||||
self.flags_setter,
|
||||
cascade_level,
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
fn collect_user_agent_rules(&mut self) {
|
||||
self.collect_stylist_rules(Origin::UserAgent);
|
||||
}
|
||||
|
||||
fn collect_user_rules(&mut self) {
|
||||
if !self.matches_user_and_author_rules {
|
||||
return;
|
||||
}
|
||||
|
||||
self.collect_stylist_rules(Origin::User);
|
||||
}
|
||||
|
||||
/// Presentational hints.
|
||||
///
|
||||
/// These go before author rules, but after user rules, see:
|
||||
/// https://drafts.csswg.org/css-cascade/#preshint
|
||||
fn collect_presentational_hints(&mut self) {
|
||||
if self.pseudo_element.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
let length_before_preshints = self.rules.len();
|
||||
self.element
|
||||
.synthesize_presentational_hints_for_legacy_attributes(
|
||||
self.context.visited_handling(),
|
||||
self.rules,
|
||||
);
|
||||
if cfg!(debug_assertions) {
|
||||
if self.rules.len() != length_before_preshints {
|
||||
for declaration in &self.rules[length_before_preshints..] {
|
||||
assert_eq!(declaration.level(), CascadeLevel::PresHints);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_rules_in_shadow_tree(
|
||||
&mut self,
|
||||
shadow_host: E,
|
||||
map: &SelectorMap<Rule>,
|
||||
cascade_level: CascadeLevel,
|
||||
) {
|
||||
debug_assert!(shadow_host.shadow_root().is_some());
|
||||
let element = self.element;
|
||||
let rule_hash_target = self.rule_hash_target;
|
||||
let rules = &mut self.rules;
|
||||
let flags_setter = &mut self.flags_setter;
|
||||
let shadow_cascade_order = self.shadow_cascade_order;
|
||||
self.context.with_shadow_host(Some(shadow_host), |context| {
|
||||
map.get_all_matching_rules(
|
||||
element,
|
||||
rule_hash_target,
|
||||
rules,
|
||||
context,
|
||||
flags_setter,
|
||||
cascade_level,
|
||||
shadow_cascade_order,
|
||||
);
|
||||
});
|
||||
self.shadow_cascade_order += 1;
|
||||
}
|
||||
|
||||
/// Collects the rules for the ::slotted pseudo-element.
|
||||
fn collect_slotted_rules(&mut self) {
|
||||
let mut slots = SmallVec::<[_; 3]>::new();
|
||||
let mut current = self.rule_hash_target.assigned_slot();
|
||||
while let Some(slot) = current {
|
||||
debug_assert!(
|
||||
self.matches_user_and_author_rules,
|
||||
"We should not slot NAC anywhere"
|
||||
);
|
||||
slots.push(slot);
|
||||
current = slot.assigned_slot();
|
||||
}
|
||||
|
||||
// Match slotted rules in reverse order, so that the outer slotted rules
|
||||
// come before the inner rules (and thus have less priority).
|
||||
for slot in slots.iter().rev() {
|
||||
let shadow = slot.containing_shadow().unwrap();
|
||||
let data = match shadow.style_data() {
|
||||
Some(d) => d,
|
||||
None => continue,
|
||||
};
|
||||
let slotted_rules = match data.slotted_rules(self.pseudo_element) {
|
||||
Some(r) => r,
|
||||
None => continue,
|
||||
};
|
||||
self.collect_rules_in_shadow_tree(
|
||||
shadow.host(),
|
||||
slotted_rules,
|
||||
CascadeLevel::InnerShadowNormal,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_normal_rules_from_containing_shadow_tree(&mut self) {
|
||||
if !self.matches_user_and_author_rules {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut current_containing_shadow = self.rule_hash_target.containing_shadow();
|
||||
while let Some(containing_shadow) = current_containing_shadow {
|
||||
let cascade_data = containing_shadow.style_data();
|
||||
let host = containing_shadow.host();
|
||||
if let Some(map) = cascade_data.and_then(|data| data.normal_rules(self.pseudo_element))
|
||||
{
|
||||
self.collect_rules_in_shadow_tree(host, map, CascadeLevel::SameTreeAuthorNormal);
|
||||
}
|
||||
let host_is_svg_use_element =
|
||||
host.is_svg_element() && host.local_name() == &*local_name!("use");
|
||||
if !host_is_svg_use_element {
|
||||
self.matches_document_author_rules = false;
|
||||
break;
|
||||
}
|
||||
|
||||
debug_assert!(
|
||||
cascade_data.is_none(),
|
||||
"We allow no stylesheets in <svg:use> subtrees"
|
||||
);
|
||||
|
||||
// NOTE(emilio): Hack so <svg:use> matches the rules of the
|
||||
// enclosing tree.
|
||||
//
|
||||
// This is not a problem for invalidation and that kind of stuff
|
||||
// because they still don't match rules based on elements
|
||||
// outside of the shadow tree, and because the <svg:use>
|
||||
// subtrees are immutable and recreated each time the source
|
||||
// tree changes.
|
||||
//
|
||||
// We historically allow cross-document <svg:use> to have these
|
||||
// rules applied, but I think that's not great. Gecko is the
|
||||
// only engine supporting that.
|
||||
//
|
||||
// See https://github.com/w3c/svgwg/issues/504 for the relevant
|
||||
// spec discussion.
|
||||
current_containing_shadow = host.containing_shadow();
|
||||
self.matches_document_author_rules = current_containing_shadow.is_none();
|
||||
}
|
||||
}
|
||||
|
||||
/// Collects the rules for the :host pseudo-class.
|
||||
fn collect_host_rules(&mut self) {
|
||||
let shadow = match self.rule_hash_target.shadow_root() {
|
||||
Some(s) => s,
|
||||
None => return,
|
||||
};
|
||||
|
||||
debug_assert!(
|
||||
self.matches_user_and_author_rules,
|
||||
"NAC should not be a shadow host"
|
||||
);
|
||||
|
||||
let style_data = match shadow.style_data() {
|
||||
Some(d) => d,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let host_rules = match style_data.host_rules(self.pseudo_element) {
|
||||
Some(rules) => rules,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let rule_hash_target = self.rule_hash_target;
|
||||
self.collect_rules_in_shadow_tree(
|
||||
rule_hash_target,
|
||||
host_rules,
|
||||
CascadeLevel::InnerShadowNormal,
|
||||
);
|
||||
}
|
||||
|
||||
fn collect_document_author_rules(&mut self) {
|
||||
if !self.matches_document_author_rules {
|
||||
return;
|
||||
}
|
||||
|
||||
self.collect_stylist_rules(Origin::Author);
|
||||
}
|
||||
|
||||
fn collect_xbl_rules(&mut self) {
|
||||
let element = self.element;
|
||||
let cut_xbl_binding_inheritance =
|
||||
element.each_xbl_cascade_data(|cascade_data, quirks_mode| {
|
||||
let map = match cascade_data.normal_rules(self.pseudo_element) {
|
||||
Some(m) => m,
|
||||
None => return,
|
||||
};
|
||||
|
||||
// NOTE(emilio): This is needed because the XBL stylist may
|
||||
// think it has a different quirks mode than the document.
|
||||
let mut matching_context = MatchingContext::new(
|
||||
self.context.matching_mode(),
|
||||
self.context.bloom_filter,
|
||||
self.context.nth_index_cache.as_mut().map(|s| &mut **s),
|
||||
quirks_mode,
|
||||
);
|
||||
matching_context.pseudo_element_matching_fn =
|
||||
self.context.pseudo_element_matching_fn;
|
||||
|
||||
// SameTreeAuthorNormal instead of InnerShadowNormal to
|
||||
// preserve behavior, though that's kinda fishy...
|
||||
map.get_all_matching_rules(
|
||||
self.element,
|
||||
self.rule_hash_target,
|
||||
self.rules,
|
||||
&mut matching_context,
|
||||
self.flags_setter,
|
||||
CascadeLevel::SameTreeAuthorNormal,
|
||||
self.shadow_cascade_order,
|
||||
);
|
||||
});
|
||||
|
||||
self.matches_document_author_rules &= !cut_xbl_binding_inheritance;
|
||||
}
|
||||
|
||||
fn collect_style_attribute_and_animation_rules(&mut self) {
|
||||
if let Some(sa) = self.style_attribute {
|
||||
self.rules
|
||||
.push(ApplicableDeclarationBlock::from_declarations(
|
||||
sa.clone_arc(),
|
||||
CascadeLevel::StyleAttributeNormal,
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(so) = self.smil_override {
|
||||
self.rules
|
||||
.push(ApplicableDeclarationBlock::from_declarations(
|
||||
so.clone_arc(),
|
||||
CascadeLevel::SMILOverride,
|
||||
));
|
||||
}
|
||||
|
||||
// The animations sheet (CSS animations, script-generated
|
||||
// animations, and CSS transitions that are no longer tied to CSS
|
||||
// markup).
|
||||
if let Some(anim) = self.animation_rules.0.take() {
|
||||
self.rules
|
||||
.push(ApplicableDeclarationBlock::from_declarations(
|
||||
anim,
|
||||
CascadeLevel::Animations,
|
||||
));
|
||||
}
|
||||
|
||||
// The transitions sheet (CSS transitions that are tied to CSS
|
||||
// markup).
|
||||
if let Some(anim) = self.animation_rules.1.take() {
|
||||
self.rules
|
||||
.push(ApplicableDeclarationBlock::from_declarations(
|
||||
anim,
|
||||
CascadeLevel::Transitions,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// Collects all the rules, leaving the result in `self.rules`.
|
||||
///
|
||||
/// Note that `!important` rules are handled during rule tree insertion.
|
||||
pub fn collect_all(mut self) {
|
||||
self.collect_user_agent_rules();
|
||||
self.collect_user_rules();
|
||||
if self.rule_inclusion == RuleInclusion::DefaultOnly {
|
||||
return;
|
||||
}
|
||||
self.collect_presentational_hints();
|
||||
// FIXME(emilio): Should the author styles enabled stuff avoid the
|
||||
// presentational hints from getting pushed? See bug 1505770.
|
||||
if self.stylist.author_styles_enabled() == AuthorStylesEnabled::No {
|
||||
return;
|
||||
}
|
||||
self.collect_host_rules();
|
||||
self.collect_slotted_rules();
|
||||
self.collect_normal_rules_from_containing_shadow_tree();
|
||||
self.collect_xbl_rules();
|
||||
self.collect_document_author_rules();
|
||||
self.collect_style_attribute_and_animation_rules();
|
||||
}
|
||||
}
|
|
@ -13,9 +13,8 @@ use crate::invalidation::element::document_state::InvalidationMatchingData;
|
|||
use crate::invalidation::element::element_wrapper::ElementSnapshot;
|
||||
use crate::properties::longhands::display::computed_value::T as Display;
|
||||
use crate::properties::{ComputedValues, PropertyFlags};
|
||||
use crate::selector_parser::{
|
||||
AttrValue as SelectorAttrValue, PseudoElementCascadeType, SelectorParser,
|
||||
};
|
||||
use crate::selector_parser::AttrValue as SelectorAttrValue;
|
||||
use crate::selector_parser::{PseudoElementCascadeType, SelectorParser};
|
||||
use crate::{Atom, CaseSensitivityExt, LocalName, Namespace, Prefix};
|
||||
use cssparser::{serialize_identifier, CowRcStr, Parser as CssParser, SourceLocation, ToCss};
|
||||
use fxhash::FxHashMap;
|
||||
|
|
|
@ -15,9 +15,8 @@ use crate::rule_tree::StrongRuleNode;
|
|||
use crate::selector_parser::{PseudoElement, SelectorImpl};
|
||||
use crate::stylist::RuleInclusion;
|
||||
use log::Level::Trace;
|
||||
use selectors::matching::{
|
||||
ElementSelectorFlags, MatchingContext, MatchingMode, VisitedHandlingMode,
|
||||
};
|
||||
use selectors::matching::{ElementSelectorFlags, MatchingContext};
|
||||
use selectors::matching::{MatchingMode, VisitedHandlingMode};
|
||||
use servo_arc::Arc;
|
||||
|
||||
/// Whether pseudo-elements should be resolved or not.
|
||||
|
|
|
@ -135,7 +135,7 @@ impl DocumentMatchingFunction {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(url) = input.r#try(|input| CssUrl::parse(context, input)) {
|
||||
if let Ok(url) = input.try(|input| CssUrl::parse(context, input)) {
|
||||
return Ok(DocumentMatchingFunction::Url(url));
|
||||
}
|
||||
|
||||
|
|
|
@ -202,7 +202,7 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
|
|||
return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedNamespaceRule))
|
||||
}
|
||||
|
||||
let prefix = input.r#try(|i| i.expect_ident_cloned())
|
||||
let prefix = input.try(|i| i.expect_ident_cloned())
|
||||
.map(|s| Prefix::from(s.as_ref())).ok();
|
||||
let maybe_namespace = match input.expect_url_or_string() {
|
||||
Ok(url_or_string) => url_or_string,
|
||||
|
|
|
@ -7,9 +7,8 @@ use crate::error_reporting::{ContextualParseError, ParseErrorReporter};
|
|||
use crate::invalidation::media_queries::{MediaListKey, ToMediaListKey};
|
||||
use crate::media_queries::{Device, MediaList};
|
||||
use crate::parser::ParserContext;
|
||||
use crate::shared_lock::{
|
||||
DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard,
|
||||
};
|
||||
use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
|
||||
use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard};
|
||||
use crate::stylesheets::loader::StylesheetLoader;
|
||||
use crate::stylesheets::rule_parser::{State, TopLevelRuleParser};
|
||||
use crate::stylesheets::rules_iterator::{EffectiveRules, EffectiveRulesIterator};
|
||||
|
|
|
@ -103,7 +103,7 @@ impl SupportsCondition {
|
|||
///
|
||||
/// <https://drafts.csswg.org/css-conditional/#supports_condition>
|
||||
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
|
||||
if input.r#try(|i| i.expect_ident_matching("not")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("not")).is_ok() {
|
||||
let inner = SupportsCondition::parse_in_parens(input)?;
|
||||
return Ok(SupportsCondition::Not(Box::new(inner)));
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ impl SupportsCondition {
|
|||
loop {
|
||||
conditions.push(SupportsCondition::parse_in_parens(input)?);
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching(keyword))
|
||||
.try(|input| input.expect_ident_matching(keyword))
|
||||
.is_err()
|
||||
{
|
||||
// Did not find the expected keyword.
|
||||
|
@ -175,20 +175,20 @@ impl SupportsCondition {
|
|||
fn parse_in_parens<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
|
||||
// Whitespace is normally taken care of in `Parser::next`,
|
||||
// but we want to not include it in `pos` for the SupportsCondition::FutureSyntax cases.
|
||||
while input.r#try(Parser::expect_whitespace).is_ok() {}
|
||||
while input.try(Parser::expect_whitespace).is_ok() {}
|
||||
let pos = input.position();
|
||||
let location = input.current_source_location();
|
||||
// FIXME: remove clone() when lifetimes are non-lexical
|
||||
match input.next()?.clone() {
|
||||
Token::ParenthesisBlock => {
|
||||
let nested =
|
||||
input.r#try(|input| input.parse_nested_block(parse_condition_or_declaration));
|
||||
input.try(|input| input.parse_nested_block(parse_condition_or_declaration));
|
||||
if nested.is_ok() {
|
||||
return nested;
|
||||
}
|
||||
},
|
||||
Token::Function(ident) => {
|
||||
let nested = input.r#try(|input| {
|
||||
let nested = input.try(|input| {
|
||||
input.parse_nested_block(|input| {
|
||||
SupportsCondition::parse_functional(&ident, input)
|
||||
})
|
||||
|
@ -240,7 +240,7 @@ fn eval_moz_bool_pref(_: &CStr, _: &ParserContext) -> bool {
|
|||
pub fn parse_condition_or_declaration<'i, 't>(
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<SupportsCondition, ParseError<'i>> {
|
||||
if let Ok(condition) = input.r#try(SupportsCondition::parse) {
|
||||
if let Ok(condition) = input.try(SupportsCondition::parse) {
|
||||
Ok(SupportsCondition::Parenthesized(Box::new(condition)))
|
||||
} else {
|
||||
Declaration::parse(input).map(SupportsCondition::Declaration)
|
||||
|
@ -418,7 +418,7 @@ impl Declaration {
|
|||
PropertyDeclaration::parse_into(&mut declarations, id, &context, input)
|
||||
.map_err(|_| input.new_custom_error(()))
|
||||
})?;
|
||||
let _ = input.r#try(parse_important);
|
||||
let _ = input.try(parse_important);
|
||||
Ok(())
|
||||
})
|
||||
.is_ok()
|
||||
|
|
|
@ -265,7 +265,7 @@ fn parse_shorthand<'i, 't>(
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<(ViewportLength, ViewportLength), ParseError<'i>> {
|
||||
let min = ViewportLength::parse(context, input)?;
|
||||
match input.r#try(|i| ViewportLength::parse(context, i)) {
|
||||
match input.try(|i| ViewportLength::parse(context, i)) {
|
||||
Err(_) => Ok((min.clone(), min)),
|
||||
Ok(max) => Ok((min, max)),
|
||||
}
|
||||
|
@ -289,8 +289,8 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for ViewportRuleParser<'a, 'b> {
|
|||
) -> Result<Vec<ViewportDescriptorDeclaration>, ParseError<'i>> {
|
||||
macro_rules! declaration {
|
||||
($declaration:ident($parse:expr)) => {
|
||||
declaration!($declaration(value: r#try!($parse(input)),
|
||||
important: input.r#try(parse_important).is_ok()))
|
||||
declaration!($declaration(value: try!($parse(input)),
|
||||
important: input.try(parse_important).is_ok()))
|
||||
};
|
||||
($declaration:ident(value: $value:expr, important: $important:expr)) => {
|
||||
ViewportDescriptorDeclaration::new(
|
||||
|
@ -306,7 +306,7 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for ViewportRuleParser<'a, 'b> {
|
|||
};
|
||||
(shorthand -> [$min:ident, $max:ident]) => {{
|
||||
let shorthand = parse_shorthand(self.context, input)?;
|
||||
let important = input.r#try(parse_important).is_ok();
|
||||
let important = input.try(parse_important).is_ok();
|
||||
|
||||
Ok(vec![
|
||||
declaration!($min(value: shorthand.0, important: important)),
|
||||
|
|
|
@ -17,6 +17,7 @@ use crate::media_queries::Device;
|
|||
use crate::properties::{self, CascadeMode, ComputedValues};
|
||||
use crate::properties::{AnimationRules, PropertyDeclarationBlock};
|
||||
use crate::rule_cache::{RuleCache, RuleCacheConditions};
|
||||
use crate::rule_collector::RuleCollector;
|
||||
use crate::rule_tree::{CascadeLevel, RuleTree, ShadowCascadeOrder, StrongRuleNode, StyleSource};
|
||||
use crate::selector_map::{PrecomputedHashMap, PrecomputedHashSet, SelectorMap, SelectorMapEntry};
|
||||
use crate::selector_parser::{PerPseudoElementMap, PseudoElement, SelectorImpl, SnapshotMap};
|
||||
|
@ -47,7 +48,6 @@ use selectors::visitor::SelectorVisitor;
|
|||
use selectors::NthIndexCache;
|
||||
use servo_arc::{Arc, ArcBorrow};
|
||||
use smallbitvec::SmallBitVec;
|
||||
use smallvec::SmallVec;
|
||||
use std::ops;
|
||||
use std::sync::Mutex;
|
||||
use style_traits::viewport::ViewportConstraints;
|
||||
|
@ -180,10 +180,11 @@ impl UserAgentCascadeData {
|
|||
}
|
||||
}
|
||||
|
||||
/// All the computed information for a stylesheet.
|
||||
/// All the computed information for all the stylesheets that apply to the
|
||||
/// document.
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
||||
struct DocumentCascadeData {
|
||||
pub struct DocumentCascadeData {
|
||||
#[cfg_attr(
|
||||
feature = "servo",
|
||||
ignore_malloc_size_of = "Arc, owned by UserAgentCascadeDataCache"
|
||||
|
@ -210,7 +211,9 @@ impl<'a> Iterator for DocumentCascadeDataIter<'a> {
|
|||
}
|
||||
|
||||
impl DocumentCascadeData {
|
||||
fn borrow_for_origin(&self, origin: Origin) -> &CascadeData {
|
||||
/// Borrows the cascade data for a given origin.
|
||||
#[inline]
|
||||
pub fn borrow_for_origin(&self, origin: Origin) -> &CascadeData {
|
||||
match origin {
|
||||
Origin::UserAgent => &self.user_agent.cascade_data,
|
||||
Origin::Author => &self.author,
|
||||
|
@ -412,10 +415,16 @@ impl Stylist {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the cascade data for the author level.
|
||||
/// Returns the document cascade data.
|
||||
#[inline]
|
||||
pub fn author_cascade_data(&self) -> &CascadeData {
|
||||
&self.cascade_data.author
|
||||
pub fn cascade_data(&self) -> &DocumentCascadeData {
|
||||
&self.cascade_data
|
||||
}
|
||||
|
||||
/// Returns whether author styles are enabled or not.
|
||||
#[inline]
|
||||
pub fn author_styles_enabled(&self) -> AuthorStylesEnabled {
|
||||
self.author_styles_enabled
|
||||
}
|
||||
|
||||
/// Iterate through all the cascade datas from the document.
|
||||
|
@ -1098,11 +1107,6 @@ impl Stylist {
|
|||
}
|
||||
|
||||
/// Returns the applicable CSS declarations for the given element.
|
||||
///
|
||||
/// This corresponds to `ElementRuleCollector` in WebKit, and should push to
|
||||
/// elements in the list in the order defined by:
|
||||
///
|
||||
/// https://drafts.csswg.org/css-cascade/#cascade-origin
|
||||
pub fn push_applicable_declarations<E, F>(
|
||||
&self,
|
||||
element: E,
|
||||
|
@ -1118,284 +1122,19 @@ impl Stylist {
|
|||
E: TElement,
|
||||
F: FnMut(&E, ElementSelectorFlags),
|
||||
{
|
||||
// Gecko definitely has pseudo-elements with style attributes, like
|
||||
// ::-moz-color-swatch.
|
||||
debug_assert!(
|
||||
cfg!(feature = "gecko") || style_attribute.is_none() || pseudo_element.is_none(),
|
||||
"Style attributes do not apply to pseudo-elements"
|
||||
);
|
||||
debug_assert!(pseudo_element.map_or(true, |p| !p.is_precomputed()));
|
||||
|
||||
let rule_hash_target = element.rule_hash_target();
|
||||
|
||||
let matches_user_and_author_rules = rule_hash_target.matches_user_and_author_rules();
|
||||
|
||||
// Normal user-agent rules.
|
||||
if let Some(map) = self
|
||||
.cascade_data
|
||||
.user_agent
|
||||
.cascade_data
|
||||
.normal_rules(pseudo_element)
|
||||
{
|
||||
map.get_all_matching_rules(
|
||||
element,
|
||||
rule_hash_target,
|
||||
applicable_declarations,
|
||||
context,
|
||||
flags_setter,
|
||||
CascadeLevel::UANormal,
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
// NB: the following condition, although it may look somewhat
|
||||
// inaccurate, would be equivalent to something like:
|
||||
//
|
||||
// element.matches_user_and_author_rules() ||
|
||||
// (is_implemented_pseudo &&
|
||||
// rule_hash_target.matches_user_and_author_rules())
|
||||
//
|
||||
// Which may be more what you would probably expect.
|
||||
if matches_user_and_author_rules {
|
||||
// User normal rules.
|
||||
if let Some(map) = self.cascade_data.user.normal_rules(pseudo_element) {
|
||||
map.get_all_matching_rules(
|
||||
element,
|
||||
rule_hash_target,
|
||||
applicable_declarations,
|
||||
context,
|
||||
flags_setter,
|
||||
CascadeLevel::UserNormal,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if rule_inclusion == RuleInclusion::DefaultOnly {
|
||||
return;
|
||||
}
|
||||
|
||||
if pseudo_element.is_none() {
|
||||
// Presentational hints.
|
||||
//
|
||||
// These go before author rules, but after user rules, see:
|
||||
// https://drafts.csswg.org/css-cascade/#preshint
|
||||
let length_before_preshints = applicable_declarations.len();
|
||||
element.synthesize_presentational_hints_for_legacy_attributes(
|
||||
context.visited_handling(),
|
||||
applicable_declarations,
|
||||
);
|
||||
if cfg!(debug_assertions) {
|
||||
if applicable_declarations.len() != length_before_preshints {
|
||||
for declaration in &applicable_declarations[length_before_preshints..] {
|
||||
assert_eq!(declaration.level(), CascadeLevel::PresHints);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.author_styles_enabled == AuthorStylesEnabled::No {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut match_document_author_rules = matches_user_and_author_rules;
|
||||
let mut shadow_cascade_order = 0;
|
||||
|
||||
// XBL / Shadow DOM rules, which are author rules too.
|
||||
if let Some(shadow) = rule_hash_target.shadow_root() {
|
||||
debug_assert!(
|
||||
matches_user_and_author_rules,
|
||||
"NAC should not be a shadow host"
|
||||
);
|
||||
if let Some(map) = shadow
|
||||
.style_data()
|
||||
.and_then(|data| data.host_rules(pseudo_element))
|
||||
{
|
||||
context.with_shadow_host(Some(rule_hash_target), |context| {
|
||||
map.get_all_matching_rules(
|
||||
element,
|
||||
rule_hash_target,
|
||||
applicable_declarations,
|
||||
context,
|
||||
flags_setter,
|
||||
CascadeLevel::InnerShadowNormal,
|
||||
shadow_cascade_order,
|
||||
);
|
||||
});
|
||||
shadow_cascade_order += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Match slotted rules in reverse order, so that the outer slotted
|
||||
// rules come before the inner rules (and thus have less priority).
|
||||
let mut slots = SmallVec::<[_; 3]>::new();
|
||||
let mut current = rule_hash_target.assigned_slot();
|
||||
while let Some(slot) = current {
|
||||
debug_assert!(
|
||||
matches_user_and_author_rules,
|
||||
"We should not slot NAC anywhere"
|
||||
);
|
||||
slots.push(slot);
|
||||
current = slot.assigned_slot();
|
||||
}
|
||||
|
||||
for slot in slots.iter().rev() {
|
||||
let shadow = slot.containing_shadow().unwrap();
|
||||
if let Some(map) = shadow
|
||||
.style_data()
|
||||
.and_then(|data| data.slotted_rules(pseudo_element))
|
||||
{
|
||||
context.with_shadow_host(Some(shadow.host()), |context| {
|
||||
map.get_all_matching_rules(
|
||||
element,
|
||||
rule_hash_target,
|
||||
applicable_declarations,
|
||||
context,
|
||||
flags_setter,
|
||||
CascadeLevel::InnerShadowNormal,
|
||||
shadow_cascade_order,
|
||||
);
|
||||
});
|
||||
shadow_cascade_order += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if matches_user_and_author_rules {
|
||||
let mut current_containing_shadow = rule_hash_target.containing_shadow();
|
||||
while let Some(containing_shadow) = current_containing_shadow {
|
||||
let cascade_data = containing_shadow.style_data();
|
||||
let host = containing_shadow.host();
|
||||
if let Some(map) = cascade_data.and_then(|data| data.normal_rules(pseudo_element)) {
|
||||
context.with_shadow_host(Some(host), |context| {
|
||||
map.get_all_matching_rules(
|
||||
element,
|
||||
rule_hash_target,
|
||||
applicable_declarations,
|
||||
context,
|
||||
flags_setter,
|
||||
CascadeLevel::SameTreeAuthorNormal,
|
||||
shadow_cascade_order,
|
||||
);
|
||||
});
|
||||
shadow_cascade_order += 1;
|
||||
}
|
||||
|
||||
let host_is_svg_use_element =
|
||||
host.is_svg_element() && host.local_name() == &*local_name!("use");
|
||||
|
||||
if !host_is_svg_use_element {
|
||||
match_document_author_rules = false;
|
||||
break;
|
||||
}
|
||||
|
||||
debug_assert!(
|
||||
cascade_data.is_none(),
|
||||
"We allow no stylesheets in <svg:use> subtrees"
|
||||
);
|
||||
|
||||
// NOTE(emilio): Hack so <svg:use> matches the rules of the
|
||||
// enclosing tree.
|
||||
//
|
||||
// This is not a problem for invalidation and that kind of stuff
|
||||
// because they still don't match rules based on elements
|
||||
// outside of the shadow tree, and because the <svg:use>
|
||||
// subtrees are immutable and recreated each time the source
|
||||
// tree changes.
|
||||
//
|
||||
// We historically allow cross-document <svg:use> to have these
|
||||
// rules applied, but I think that's not great. Gecko is the
|
||||
// only engine supporting that.
|
||||
//
|
||||
// See https://github.com/w3c/svgwg/issues/504 for the relevant
|
||||
// spec discussion.
|
||||
current_containing_shadow = host.containing_shadow();
|
||||
match_document_author_rules = current_containing_shadow.is_none();
|
||||
}
|
||||
}
|
||||
|
||||
let cut_xbl_binding_inheritance =
|
||||
element.each_xbl_cascade_data(|cascade_data, quirks_mode| {
|
||||
if let Some(map) = cascade_data.normal_rules(pseudo_element) {
|
||||
// NOTE(emilio): This is needed because the XBL stylist may
|
||||
// think it has a different quirks mode than the document.
|
||||
let mut matching_context = MatchingContext::new(
|
||||
context.matching_mode(),
|
||||
context.bloom_filter,
|
||||
context.nth_index_cache.as_mut().map(|s| &mut **s),
|
||||
quirks_mode,
|
||||
);
|
||||
matching_context.pseudo_element_matching_fn =
|
||||
context.pseudo_element_matching_fn;
|
||||
|
||||
// SameTreeAuthorNormal instead of InnerShadowNormal to
|
||||
// preserve behavior, though that's kinda fishy...
|
||||
map.get_all_matching_rules(
|
||||
element,
|
||||
rule_hash_target,
|
||||
applicable_declarations,
|
||||
&mut matching_context,
|
||||
flags_setter,
|
||||
CascadeLevel::SameTreeAuthorNormal,
|
||||
shadow_cascade_order,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
match_document_author_rules &= !cut_xbl_binding_inheritance;
|
||||
|
||||
if match_document_author_rules {
|
||||
// Author normal rules.
|
||||
if let Some(map) = self.cascade_data.author.normal_rules(pseudo_element) {
|
||||
map.get_all_matching_rules(
|
||||
element,
|
||||
rule_hash_target,
|
||||
applicable_declarations,
|
||||
context,
|
||||
flags_setter,
|
||||
CascadeLevel::SameTreeAuthorNormal,
|
||||
shadow_cascade_order,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Style attribute ("Normal override declarations").
|
||||
if let Some(sa) = style_attribute {
|
||||
applicable_declarations.push(ApplicableDeclarationBlock::from_declarations(
|
||||
sa.clone_arc(),
|
||||
CascadeLevel::StyleAttributeNormal,
|
||||
));
|
||||
}
|
||||
|
||||
// Declarations from SVG SMIL animation elements.
|
||||
if let Some(so) = smil_override {
|
||||
applicable_declarations.push(ApplicableDeclarationBlock::from_declarations(
|
||||
so.clone_arc(),
|
||||
CascadeLevel::SMILOverride,
|
||||
));
|
||||
}
|
||||
|
||||
// The animations sheet (CSS animations, script-generated
|
||||
// animations, and CSS transitions that are no longer tied to CSS
|
||||
// markup).
|
||||
if let Some(anim) = animation_rules.0 {
|
||||
applicable_declarations.push(ApplicableDeclarationBlock::from_declarations(
|
||||
anim.clone(),
|
||||
CascadeLevel::Animations,
|
||||
));
|
||||
}
|
||||
|
||||
//
|
||||
// !important rules are handled during rule tree insertion.
|
||||
//
|
||||
|
||||
// The transitions sheet (CSS transitions that are tied to CSS
|
||||
// markup).
|
||||
if let Some(anim) = animation_rules.1 {
|
||||
applicable_declarations.push(ApplicableDeclarationBlock::from_declarations(
|
||||
anim.clone(),
|
||||
CascadeLevel::Transitions,
|
||||
));
|
||||
}
|
||||
RuleCollector::new(
|
||||
self,
|
||||
element,
|
||||
pseudo_element,
|
||||
style_attribute,
|
||||
smil_override,
|
||||
animation_rules,
|
||||
rule_inclusion,
|
||||
applicable_declarations,
|
||||
context,
|
||||
flags_setter,
|
||||
)
|
||||
.collect_all();
|
||||
}
|
||||
|
||||
/// Given an id, returns whether there might be any rules for that id in any
|
||||
|
@ -2100,18 +1839,21 @@ impl CascadeData {
|
|||
self.attribute_dependencies.contains(local_name)
|
||||
}
|
||||
|
||||
/// Returns the normal rule map for a given pseudo-element.
|
||||
#[inline]
|
||||
fn normal_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
|
||||
pub fn normal_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
|
||||
self.normal_rules.rules(pseudo)
|
||||
}
|
||||
|
||||
/// Returns the host pseudo rule map for a given pseudo-element.
|
||||
#[inline]
|
||||
fn host_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
|
||||
pub fn host_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
|
||||
self.host_rules.as_ref().and_then(|d| d.rules(pseudo))
|
||||
}
|
||||
|
||||
/// Returns the slotted rule map for a given pseudo-element.
|
||||
#[inline]
|
||||
fn slotted_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
|
||||
pub fn slotted_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
|
||||
self.slotted_rules.as_ref().and_then(|d| d.rules(pseudo))
|
||||
}
|
||||
|
||||
|
|
|
@ -13,9 +13,8 @@ use crate::gecko_bindings::{bindings, structs};
|
|||
use crate::values::animated::{ToAnimatedValue, ToAnimatedZero};
|
||||
use crate::values::computed::{Angle, Context, Integer, NonNegativeLength, NonNegativePercentage};
|
||||
use crate::values::computed::{Number, Percentage, ToComputedValue};
|
||||
use crate::values::generics::font::{
|
||||
self as generics, FeatureTagValue, FontSettings, VariationValue,
|
||||
};
|
||||
use crate::values::generics::font as generics;
|
||||
use crate::values::generics::font::{FeatureTagValue, FontSettings, VariationValue};
|
||||
use crate::values::specified::font::{self as specified, MAX_FONT_WEIGHT, MIN_FONT_WEIGHT};
|
||||
use crate::values::specified::length::{FontBaseSize, NoCalcLength};
|
||||
use crate::values::CSSFloat;
|
||||
|
@ -30,9 +29,8 @@ use std::slice;
|
|||
use style_traits::{CssWriter, ParseError, ToCss};
|
||||
|
||||
pub use crate::values::computed::Length as MozScriptMinSize;
|
||||
pub use crate::values::specified::font::{
|
||||
FontSynthesis, MozScriptSizeMultiplier, XLang, XTextZoom,
|
||||
};
|
||||
pub use crate::values::specified::font::{FontSynthesis, MozScriptSizeMultiplier};
|
||||
pub use crate::values::specified::font::{XLang, XTextZoom};
|
||||
|
||||
/// A value for the font-weight property per:
|
||||
///
|
||||
|
@ -374,7 +372,7 @@ impl SingleFontFamily {
|
|||
|
||||
/// Parse a font-family value
|
||||
pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(value) = input.r#try(|i| i.expect_string_cloned()) {
|
||||
if let Ok(value) = input.try(|i| i.expect_string_cloned()) {
|
||||
return Ok(SingleFontFamily::FamilyName(FamilyName {
|
||||
name: Atom::from(&*value),
|
||||
syntax: FamilyNameSyntax::Quoted,
|
||||
|
@ -419,7 +417,7 @@ impl SingleFontFamily {
|
|||
value.push(' ');
|
||||
value.push_str(&ident);
|
||||
}
|
||||
while let Ok(ident) = input.r#try(|i| i.expect_ident_cloned()) {
|
||||
while let Ok(ident) = input.try(|i| i.expect_ident_cloned()) {
|
||||
value.push(' ');
|
||||
value.push_str(&ident);
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@ use super::{Context, Number, Percentage, ToComputedValue};
|
|||
use app_units::Au;
|
||||
use crate::values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
|
||||
use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
|
||||
use crate::values::generics::length::{
|
||||
MaxLength as GenericMaxLength, MozLength as GenericMozLength,
|
||||
};
|
||||
use crate::values::generics::length::MaxLength as GenericMaxLength;
|
||||
use crate::values::generics::length::MozLength as GenericMozLength;
|
||||
use crate::values::generics::transform::IsZeroLength;
|
||||
use crate::values::generics::NonNegative;
|
||||
use crate::values::specified::length::ViewportPercentageLength;
|
||||
use crate::values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength};
|
||||
|
@ -496,6 +496,17 @@ impl ToComputedValue for specified::LengthOrPercentage {
|
|||
}
|
||||
}
|
||||
|
||||
impl IsZeroLength for LengthOrPercentage {
|
||||
#[inline]
|
||||
fn is_zero_length(&self) -> bool {
|
||||
match *self {
|
||||
LengthOrPercentage::Length(l) => l.0 == 0.0,
|
||||
LengthOrPercentage::Percentage(p) => p.0 == 0.0,
|
||||
LengthOrPercentage::Calc(c) => c.unclamped_length().0 == 0.0 && c.percentage() == 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[animate(fallback = "Self::animate_fallback")]
|
||||
#[css(derive_debug)]
|
||||
|
|
|
@ -77,8 +77,8 @@ pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
|
|||
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
|
||||
pub use self::table::XSpan;
|
||||
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, MozTabSize};
|
||||
pub use self::text::{OverflowWrap, TextOverflow, WordSpacing};
|
||||
pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle};
|
||||
pub use self::text::{TextOverflow, WordSpacing};
|
||||
pub use self::time::Time;
|
||||
pub use self::transform::{Rotate, Scale, Transform, TransformOperation};
|
||||
pub use self::transform::{TransformOrigin, TransformStyle, Translate};
|
||||
|
|
|
@ -12,13 +12,13 @@ use crate::values::generics::text::InitialLetter as GenericInitialLetter;
|
|||
use crate::values::generics::text::LineHeight as GenericLineHeight;
|
||||
use crate::values::generics::text::MozTabSize as GenericMozTabSize;
|
||||
use crate::values::generics::text::Spacing;
|
||||
use crate::values::specified::text::{
|
||||
TextEmphasisFillMode, TextEmphasisShapeKeyword, TextOverflowSide,
|
||||
};
|
||||
use crate::values::specified::text::TextOverflowSide;
|
||||
use crate::values::specified::text::{TextEmphasisFillMode, TextEmphasisShapeKeyword};
|
||||
use crate::values::{CSSFloat, CSSInteger};
|
||||
use std::fmt::{self, Write};
|
||||
use style_traits::{CssWriter, ToCss};
|
||||
|
||||
pub use crate::values::specified::OverflowWrap;
|
||||
pub use crate::values::specified::TextAlignKeyword as TextAlign;
|
||||
pub use crate::values::specified::TextEmphasisPosition;
|
||||
|
||||
|
|
|
@ -334,7 +334,6 @@ impl Translate {
|
|||
pub fn to_transform_operation(&self) -> Option<TransformOperation> {
|
||||
match *self {
|
||||
generic::Translate::None => None,
|
||||
generic::Translate::TranslateX(tx) => Some(generic::TransformOperation::TranslateX(tx)),
|
||||
generic::Translate::Translate(tx, ty) => {
|
||||
Some(generic::TransformOperation::Translate(tx, Some(ty)))
|
||||
},
|
||||
|
@ -347,7 +346,6 @@ impl Translate {
|
|||
/// Convert Translate to TransformOperation.
|
||||
pub fn from_transform_operation(operation: &TransformOperation) -> Translate {
|
||||
match *operation {
|
||||
generic::TransformOperation::TranslateX(tx) => generic::Translate::TranslateX(tx),
|
||||
generic::TransformOperation::Translate(tx, Some(ty)) => {
|
||||
generic::Translate::Translate(tx, ty)
|
||||
},
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
//! Generic types for CSS values related to backgrounds.
|
||||
|
||||
use crate::values::IsAuto;
|
||||
use std::fmt::{self, Write};
|
||||
use style_traits::{CssWriter, ToCss};
|
||||
use values::IsAuto;
|
||||
|
||||
/// A generic value for the `background-size` property.
|
||||
#[derive(
|
||||
|
|
|
@ -85,7 +85,7 @@ impl<T: Parse> Parse for FontSettings<T> {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input.r#try(|i| i.expect_ident_matching("normal")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("normal")).is_ok() {
|
||||
return Ok(Self::normal());
|
||||
}
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ impl Parse for GridLine<specified::Integer> {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let mut grid_line = Self::auto();
|
||||
if input.r#try(|i| i.expect_ident_matching("auto")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
|
||||
return Ok(grid_line);
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ impl Parse for GridLine<specified::Integer> {
|
|||
for _ in 0..3 {
|
||||
// Maximum possible entities for <grid-line>
|
||||
let location = input.current_source_location();
|
||||
if input.r#try(|i| i.expect_ident_matching("span")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("span")).is_ok() {
|
||||
if grid_line.is_span {
|
||||
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
}
|
||||
|
@ -109,14 +109,14 @@ impl Parse for GridLine<specified::Integer> {
|
|||
}
|
||||
|
||||
grid_line.is_span = true;
|
||||
} else if let Ok(i) = input.r#try(|i| specified::Integer::parse(context, i)) {
|
||||
} else if let Ok(i) = input.try(|i| specified::Integer::parse(context, i)) {
|
||||
// FIXME(emilio): Probably shouldn't reject if it's calc()...
|
||||
if i.value() == 0 || val_before_span || grid_line.line_num.is_some() {
|
||||
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
}
|
||||
|
||||
grid_line.line_num = Some(i);
|
||||
} else if let Ok(name) = input.r#try(|i| i.expect_ident_cloned()) {
|
||||
} else if let Ok(name) = input.try(|i| i.expect_ident_cloned()) {
|
||||
if val_before_span || grid_line.ident.is_some() {
|
||||
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
}
|
||||
|
@ -375,7 +375,7 @@ impl Parse for RepeatCount<specified::Integer> {
|
|||
) -> Result<Self, ParseError<'i>> {
|
||||
// Maximum number of repeat is 10000. The greater numbers should be clamped.
|
||||
const MAX_LINE: i32 = 10000;
|
||||
if let Ok(mut i) = input.r#try(|i| specified::Integer::parse_positive(context, i)) {
|
||||
if let Ok(mut i) = input.try(|i| specified::Integer::parse_positive(context, i)) {
|
||||
if i.value() > MAX_LINE {
|
||||
i = specified::Integer::new(MAX_LINE);
|
||||
}
|
||||
|
@ -605,14 +605,14 @@ impl Parse for LineNameList {
|
|||
let mut fill_idx = None;
|
||||
|
||||
loop {
|
||||
let repeat_parse_result = input.r#try(|input| {
|
||||
let repeat_parse_result = input.try(|input| {
|
||||
input.expect_function_matching("repeat")?;
|
||||
input.parse_nested_block(|input| {
|
||||
let count = RepeatCount::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let mut names_list = vec![];
|
||||
names_list.push(parse_line_names(input)?); // there should be at least one
|
||||
while let Ok(names) = input.r#try(parse_line_names) {
|
||||
while let Ok(names) = input.try(parse_line_names) {
|
||||
names_list.push(names);
|
||||
}
|
||||
|
||||
|
@ -643,7 +643,7 @@ impl Parse for LineNameList {
|
|||
},
|
||||
_ => return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
|
||||
}
|
||||
} else if let Ok(names) = input.r#try(parse_line_names) {
|
||||
} else if let Ok(names) = input.try(parse_line_names) {
|
||||
line_names.push(names);
|
||||
} else {
|
||||
break;
|
||||
|
|
|
@ -111,19 +111,16 @@ impl Parse for CounterStyleOrNone {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(name) = input.r#try(|i| parse_counter_style_name(i)) {
|
||||
if let Ok(name) = input.try(|i| parse_counter_style_name(i)) {
|
||||
return Ok(CounterStyleOrNone::Name(name));
|
||||
}
|
||||
if input.r#try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
return Ok(CounterStyleOrNone::None);
|
||||
}
|
||||
if input
|
||||
.r#try(|i| i.expect_function_matching("symbols"))
|
||||
.is_ok()
|
||||
{
|
||||
if input.try(|i| i.expect_function_matching("symbols")).is_ok() {
|
||||
return input.parse_nested_block(|input| {
|
||||
let symbols_type = input
|
||||
.r#try(|i| SymbolsType::parse(i))
|
||||
.try(|i| SymbolsType::parse(i))
|
||||
.unwrap_or(SymbolsType::Symbolic);
|
||||
let symbols = Symbols::parse(context, input)?;
|
||||
// There must be at least two symbols for alphabetic or
|
||||
|
|
|
@ -50,7 +50,7 @@ where
|
|||
Parse: Fn(&ParserContext, &mut Parser<'i, 't>) -> Result<T, ParseError<'i>>,
|
||||
{
|
||||
let first = parse(context, input)?;
|
||||
let second = if let Ok(second) = input.r#try(|i| parse(context, i)) {
|
||||
let second = if let Ok(second) = input.try(|i| parse(context, i)) {
|
||||
second
|
||||
} else {
|
||||
// <first>
|
||||
|
@ -61,13 +61,13 @@ where
|
|||
first,
|
||||
));
|
||||
};
|
||||
let third = if let Ok(third) = input.r#try(|i| parse(context, i)) {
|
||||
let third = if let Ok(third) = input.try(|i| parse(context, i)) {
|
||||
third
|
||||
} else {
|
||||
// <first> <second>
|
||||
return Ok(Self::new(first.clone(), second.clone(), first, second));
|
||||
};
|
||||
let fourth = if let Ok(fourth) = input.r#try(|i| parse(context, i)) {
|
||||
let fourth = if let Ok(fourth) = input.try(|i| parse(context, i)) {
|
||||
fourth
|
||||
} else {
|
||||
// <first> <second> <third>
|
||||
|
|
|
@ -55,7 +55,7 @@ impl<L> Size<L> {
|
|||
{
|
||||
let first = parse_one(context, input)?;
|
||||
let second = input
|
||||
.r#try(|i| parse_one(context, i))
|
||||
.try(|i| parse_one(context, i))
|
||||
.unwrap_or_else(|_| first.clone());
|
||||
Ok(Self::new(first, second))
|
||||
}
|
||||
|
|
|
@ -84,10 +84,10 @@ fn parse_fallback<'i, 't, ColorType: Parse>(
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Option<Either<ColorType, None_>> {
|
||||
if input.r#try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
Some(Either::Second(None_))
|
||||
} else {
|
||||
if let Ok(color) = input.r#try(|i| ColorType::parse(context, i)) {
|
||||
if let Ok(color) = input.try(|i| ColorType::parse(context, i)) {
|
||||
Some(Either::First(color))
|
||||
} else {
|
||||
None
|
||||
|
@ -100,12 +100,12 @@ impl<ColorType: Parse, UrlPaintServer: Parse> Parse for SVGPaint<ColorType, UrlP
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(url) = input.r#try(|i| UrlPaintServer::parse(context, i)) {
|
||||
if let Ok(url) = input.try(|i| UrlPaintServer::parse(context, i)) {
|
||||
Ok(SVGPaint {
|
||||
kind: SVGPaintKind::PaintServer(url),
|
||||
fallback: parse_fallback(context, input),
|
||||
})
|
||||
} else if let Ok(kind) = input.r#try(SVGPaintKind::parse_ident) {
|
||||
} else if let Ok(kind) = input.try(SVGPaintKind::parse_ident) {
|
||||
if let SVGPaintKind::None = kind {
|
||||
Ok(SVGPaint {
|
||||
kind: kind,
|
||||
|
@ -117,7 +117,7 @@ impl<ColorType: Parse, UrlPaintServer: Parse> Parse for SVGPaint<ColorType, UrlP
|
|||
fallback: parse_fallback(context, input),
|
||||
})
|
||||
}
|
||||
} else if let Ok(color) = input.r#try(|i| ColorType::parse(context, i)) {
|
||||
} else if let Ok(color) = input.try(|i| ColorType::parse(context, i)) {
|
||||
Ok(SVGPaint {
|
||||
kind: SVGPaintKind::Color(color),
|
||||
fallback: None,
|
||||
|
@ -158,7 +158,7 @@ impl<LengthOrPercentageType: Parse, NumberType: Parse> Parse
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(num) = input.r#try(|i| NumberType::parse(context, i)) {
|
||||
if let Ok(num) = input.try(|i| NumberType::parse(context, i)) {
|
||||
return Ok(SvgLengthOrPercentageOrNumber::Number(num));
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ impl<Value> Spacing<Value> {
|
|||
where
|
||||
F: FnOnce(&ParserContext, &mut Parser<'i, 't>) -> Result<Value, ParseError<'i>>,
|
||||
{
|
||||
if input.r#try(|i| i.expect_ident_matching("normal")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("normal")).is_ok() {
|
||||
return Ok(Spacing::Normal);
|
||||
}
|
||||
parse(context, input).map(Spacing::Value)
|
||||
|
|
|
@ -610,7 +610,6 @@ impl<Number: ToCss + PartialEq> ToCss for Scale<Number> {
|
|||
SpecifiedValueInfo,
|
||||
ToAnimatedZero,
|
||||
ToComputedValue,
|
||||
ToCss,
|
||||
)]
|
||||
/// A value of the `Translate` property
|
||||
///
|
||||
|
@ -618,14 +617,56 @@ impl<Number: ToCss + PartialEq> ToCss for Scale<Number> {
|
|||
pub enum Translate<LengthOrPercentage, Length> {
|
||||
/// 'none'
|
||||
None,
|
||||
/// '<length-percentage>'
|
||||
TranslateX(LengthOrPercentage),
|
||||
/// '<length-percentage> <length-percentage>'
|
||||
/// '<length-percentage>' or '<length-percentage> <length-percentage>'
|
||||
Translate(LengthOrPercentage, LengthOrPercentage),
|
||||
/// '<length-percentage> <length-percentage> <length>'
|
||||
Translate3D(LengthOrPercentage, LengthOrPercentage, Length),
|
||||
}
|
||||
|
||||
/// A trait to check if this is a zero length.
|
||||
/// An alternative way is use num_traits::Zero. However, in order to implement num_traits::Zero,
|
||||
/// we also have to implement Add, which may be complicated for LengthOrPercentage::Calc.
|
||||
/// We could do this if other types also need it. If so, we could drop this trait.
|
||||
pub trait IsZeroLength {
|
||||
/// Returns true if this is a zero length.
|
||||
fn is_zero_length(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<LoP: ToCss + IsZeroLength, L: ToCss> ToCss for Translate<LoP, L> {
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
W: fmt::Write,
|
||||
{
|
||||
// The spec says:
|
||||
// 1. If a 2d translation is specified, the property must serialize with only one or two
|
||||
// values (per usual, if the second value is 0px, the default, it must be omitted when
|
||||
// serializing).
|
||||
// 2. If a 3d translation is specified, all three values must be serialized.
|
||||
// https://drafts.csswg.org/css-transforms-2/#individual-transform-serialization
|
||||
//
|
||||
// We don't omit the 3rd component even if it is 0px for now, and the related
|
||||
// spec issue is https://github.com/w3c/csswg-drafts/issues/3305
|
||||
match *self {
|
||||
Translate::None => dest.write_str("none"),
|
||||
Translate::Translate(ref x, ref y) => {
|
||||
x.to_css(dest)?;
|
||||
if !y.is_zero_length() {
|
||||
dest.write_char(' ')?;
|
||||
y.to_css(dest)?;
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
Translate::Translate3D(ref x, ref y, ref z) => {
|
||||
x.to_css(dest)?;
|
||||
dest.write_char(' ')?;
|
||||
y.to_css(dest)?;
|
||||
dest.write_char(' ')?;
|
||||
z.to_css(dest)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[derive(
|
||||
Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss,
|
||||
|
|
|
@ -44,7 +44,7 @@ where
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<UrlOrNone<Url>, ParseError<'i>> {
|
||||
if let Ok(url) = input.r#try(|input| Url::parse(context, input)) {
|
||||
if let Ok(url) = input.try(|input| Url::parse(context, input)) {
|
||||
return Ok(UrlOrNone::Url(url));
|
||||
}
|
||||
input.expect_ident_matching("none")?;
|
||||
|
|
|
@ -155,7 +155,7 @@ impl<A: Parse, B: Parse> Parse for Either<A, B> {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Either<A, B>, ParseError<'i>> {
|
||||
if let Ok(v) = input.r#try(|i| A::parse(context, i)) {
|
||||
if let Ok(v) = input.try(|i| A::parse(context, i)) {
|
||||
Ok(Either::First(v))
|
||||
} else {
|
||||
B::parse(context, input).map(Either::Second)
|
||||
|
|
|
@ -195,25 +195,25 @@ impl ContentDistribution {
|
|||
// when this function is updated.
|
||||
|
||||
// Try to parse normal first
|
||||
if input.r#try(|i| i.expect_ident_matching("normal")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("normal")).is_ok() {
|
||||
return Ok(ContentDistribution::normal());
|
||||
}
|
||||
|
||||
// Parse <baseline-position>, but only on the block axis.
|
||||
if axis == AxisDirection::Block {
|
||||
if let Ok(value) = input.r#try(parse_baseline) {
|
||||
if let Ok(value) = input.try(parse_baseline) {
|
||||
return Ok(ContentDistribution::new(value));
|
||||
}
|
||||
}
|
||||
|
||||
// <content-distribution>
|
||||
if let Ok(value) = input.r#try(parse_content_distribution) {
|
||||
if let Ok(value) = input.try(parse_content_distribution) {
|
||||
return Ok(ContentDistribution::new(value));
|
||||
}
|
||||
|
||||
// <overflow-position>? <content-position>
|
||||
let overflow_position = input
|
||||
.r#try(parse_overflow_position)
|
||||
.try(parse_overflow_position)
|
||||
.unwrap_or(AlignFlags::empty());
|
||||
|
||||
let content_position = try_match_ident_ignore_ascii_case! { input,
|
||||
|
@ -358,18 +358,18 @@ impl SelfAlignment {
|
|||
//
|
||||
// It's weird that this accepts <baseline-position>, but not
|
||||
// justify-content...
|
||||
if let Ok(value) = input.r#try(parse_baseline) {
|
||||
if let Ok(value) = input.try(parse_baseline) {
|
||||
return Ok(SelfAlignment(value));
|
||||
}
|
||||
|
||||
// auto | normal | stretch
|
||||
if let Ok(value) = input.r#try(parse_auto_normal_stretch) {
|
||||
if let Ok(value) = input.try(parse_auto_normal_stretch) {
|
||||
return Ok(SelfAlignment(value));
|
||||
}
|
||||
|
||||
// <overflow-position>? <self-position>
|
||||
let overflow_position = input
|
||||
.r#try(parse_overflow_position)
|
||||
.try(parse_overflow_position)
|
||||
.unwrap_or(AlignFlags::empty());
|
||||
let self_position = parse_self_position(input, axis)?;
|
||||
Ok(SelfAlignment(overflow_position | self_position))
|
||||
|
@ -484,17 +484,17 @@ impl Parse for AlignItems {
|
|||
// this function is updated.
|
||||
|
||||
// <baseline-position>
|
||||
if let Ok(baseline) = input.r#try(parse_baseline) {
|
||||
if let Ok(baseline) = input.try(parse_baseline) {
|
||||
return Ok(AlignItems(baseline));
|
||||
}
|
||||
|
||||
// normal | stretch
|
||||
if let Ok(value) = input.r#try(parse_normal_stretch) {
|
||||
if let Ok(value) = input.try(parse_normal_stretch) {
|
||||
return Ok(AlignItems(value));
|
||||
}
|
||||
// <overflow-position>? <self-position>
|
||||
let overflow = input
|
||||
.r#try(parse_overflow_position)
|
||||
.try(parse_overflow_position)
|
||||
.unwrap_or(AlignFlags::empty());
|
||||
let self_position = parse_self_position(input, AxisDirection::Block)?;
|
||||
Ok(AlignItems(self_position | overflow))
|
||||
|
@ -542,23 +542,23 @@ impl Parse for JustifyItems {
|
|||
//
|
||||
// It's weird that this accepts <baseline-position>, but not
|
||||
// justify-content...
|
||||
if let Ok(baseline) = input.r#try(parse_baseline) {
|
||||
if let Ok(baseline) = input.try(parse_baseline) {
|
||||
return Ok(JustifyItems(baseline));
|
||||
}
|
||||
|
||||
// normal | stretch
|
||||
if let Ok(value) = input.r#try(parse_normal_stretch) {
|
||||
if let Ok(value) = input.try(parse_normal_stretch) {
|
||||
return Ok(JustifyItems(value));
|
||||
}
|
||||
|
||||
// legacy | [ legacy && [ left | right | center ] ]
|
||||
if let Ok(value) = input.r#try(parse_legacy) {
|
||||
if let Ok(value) = input.try(parse_legacy) {
|
||||
return Ok(JustifyItems(value));
|
||||
}
|
||||
|
||||
// <overflow-position>? <self-position>
|
||||
let overflow = input
|
||||
.r#try(parse_overflow_position)
|
||||
.try(parse_overflow_position)
|
||||
.unwrap_or(AlignFlags::empty());
|
||||
let self_position = parse_self_position(input, AxisDirection::Inline)?;
|
||||
Ok(JustifyItems(overflow | self_position))
|
||||
|
@ -714,7 +714,7 @@ fn parse_legacy<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseE
|
|||
// when this function is updated.
|
||||
let flags = try_match_ident_ignore_ascii_case! { input,
|
||||
"legacy" => {
|
||||
let flags = input.r#try(parse_left_right_center)
|
||||
let flags = input.try(parse_left_right_center)
|
||||
.unwrap_or(AlignFlags::empty());
|
||||
|
||||
return Ok(AlignFlags::LEGACY | flags)
|
||||
|
|
|
@ -19,9 +19,9 @@ impl Parse for BackgroundSize {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(width) = input.r#try(|i| NonNegativeLengthOrPercentageOrAuto::parse(context, i)) {
|
||||
if let Ok(width) = input.try(|i| NonNegativeLengthOrPercentageOrAuto::parse(context, i)) {
|
||||
let height = input
|
||||
.r#try(|i| NonNegativeLengthOrPercentageOrAuto::parse(context, i))
|
||||
.try(|i| NonNegativeLengthOrPercentageOrAuto::parse(context, i))
|
||||
.unwrap_or(NonNegativeLengthOrPercentageOrAuto::auto());
|
||||
return Ok(GenericBackgroundSize::Explicit { width, height });
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ impl Parse for BackgroundRepeat {
|
|||
},
|
||||
};
|
||||
|
||||
let vertical = input.r#try(BackgroundRepeatKeyword::parse).ok();
|
||||
let vertical = input.try(BackgroundRepeatKeyword::parse).ok();
|
||||
Ok(BackgroundRepeat::Keywords(horizontal, vertical))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,12 +70,12 @@ impl Parse for ClippingShape {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if is_clip_path_path_enabled(context) {
|
||||
if let Ok(p) = input.r#try(|i| Path::parse(context, i)) {
|
||||
if let Ok(p) = input.try(|i| Path::parse(context, i)) {
|
||||
return Ok(ShapeSource::Path(p));
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(url) = input.r#try(|i| SpecifiedUrl::parse(context, i)) {
|
||||
if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
|
||||
return Ok(ShapeSource::ImageOrUrl(url));
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,7 @@ impl Parse for FloatAreaShape {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(image) = input.r#try(|i| Image::parse_with_cors_anonymous(context, i)) {
|
||||
if let Ok(image) = input.try(|i| Image::parse_with_cors_anonymous(context, i)) {
|
||||
return Ok(ShapeSource::ImageOrUrl(image));
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@ where
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input.r#try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
return Ok(ShapeSource::None);
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,7 @@ where
|
|||
return false; // already parsed this component
|
||||
}
|
||||
|
||||
*component = input.r#try(|i| U::parse(context, i)).ok();
|
||||
*component = input.try(|i| U::parse(context, i)).ok();
|
||||
component.is_some()
|
||||
}
|
||||
|
||||
|
@ -147,7 +147,7 @@ impl Parse for GeometryBox {
|
|||
_context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(shape_box) = input.r#try(|i| ShapeBox::parse(i)) {
|
||||
if let Ok(shape_box) = input.try(|i| ShapeBox::parse(i)) {
|
||||
return Ok(GeometryBox::ShapeBox(shape_box));
|
||||
}
|
||||
|
||||
|
@ -197,7 +197,7 @@ impl InsetRect {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let rect = Rect::parse_with(context, input, LengthOrPercentage::parse)?;
|
||||
let round = if input.r#try(|i| i.expect_ident_matching("round")).is_ok() {
|
||||
let round = if input.try(|i| i.expect_ident_matching("round")).is_ok() {
|
||||
Some(BorderRadius::parse(context, input)?)
|
||||
} else {
|
||||
None
|
||||
|
@ -225,9 +225,9 @@ impl Circle {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let radius = input
|
||||
.r#try(|i| ShapeRadius::parse(context, i))
|
||||
.try(|i| ShapeRadius::parse(context, i))
|
||||
.unwrap_or_default();
|
||||
let position = if input.r#try(|i| i.expect_ident_matching("at")).is_ok() {
|
||||
let position = if input.try(|i| i.expect_ident_matching("at")).is_ok() {
|
||||
Position::parse(context, input)?
|
||||
} else {
|
||||
Position::center()
|
||||
|
@ -270,14 +270,14 @@ impl Ellipse {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let (a, b) = input
|
||||
.r#try(|i| -> Result<_, ParseError> {
|
||||
.try(|i| -> Result<_, ParseError> {
|
||||
Ok((
|
||||
ShapeRadius::parse(context, i)?,
|
||||
ShapeRadius::parse(context, i)?,
|
||||
))
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let position = if input.r#try(|i| i.expect_ident_matching("at")).is_ok() {
|
||||
let position = if input.try(|i| i.expect_ident_matching("at")).is_ok() {
|
||||
Position::parse(context, input)?
|
||||
} else {
|
||||
Position::center()
|
||||
|
@ -315,7 +315,7 @@ impl Parse for ShapeRadius {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(lop) = input.r#try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
|
||||
if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
|
||||
return Ok(generic::ShapeRadius::Length(lop));
|
||||
}
|
||||
|
||||
|
@ -419,7 +419,7 @@ impl Polygon {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let fill = input
|
||||
.r#try(|i| -> Result<_, ParseError> {
|
||||
.try(|i| -> Result<_, ParseError> {
|
||||
let fill = FillRule::parse(i)?;
|
||||
i.expect_comma()?; // only eat the comma if there is something before it
|
||||
Ok(fill)
|
||||
|
@ -457,7 +457,7 @@ impl Path {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let fill = input
|
||||
.r#try(|i| -> Result<_, ParseError> {
|
||||
.try(|i| -> Result<_, ParseError> {
|
||||
let fill = FillRule::parse(i)?;
|
||||
i.expect_comma()?;
|
||||
Ok(fill)
|
||||
|
|
|
@ -58,7 +58,7 @@ impl BorderSideWidth {
|
|||
allow_quirks: AllowQuirks,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(length) =
|
||||
input.r#try(|i| Length::parse_non_negative_quirky(context, i, allow_quirks))
|
||||
input.try(|i| Length::parse_non_negative_quirky(context, i, allow_quirks))
|
||||
{
|
||||
return Ok(BorderSideWidth::Length(length));
|
||||
}
|
||||
|
@ -115,11 +115,11 @@ impl Parse for BorderImageSideWidth {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input.r#try(|i| i.expect_ident_matching("auto")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
|
||||
return Ok(GenericBorderImageSideWidth::Auto);
|
||||
}
|
||||
|
||||
if let Ok(len) = input.r#try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
|
||||
if let Ok(len) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
|
||||
return Ok(GenericBorderImageSideWidth::Length(len));
|
||||
}
|
||||
|
||||
|
@ -133,10 +133,10 @@ impl Parse for BorderImageSlice {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let mut fill = input.r#try(|i| i.expect_ident_matching("fill")).is_ok();
|
||||
let mut fill = input.try(|i| i.expect_ident_matching("fill")).is_ok();
|
||||
let offsets = Rect::parse_with(context, input, NumberOrPercentage::parse_non_negative)?;
|
||||
if !fill {
|
||||
fill = input.r#try(|i| i.expect_ident_matching("fill")).is_ok();
|
||||
fill = input.try(|i| i.expect_ident_matching("fill")).is_ok();
|
||||
}
|
||||
Ok(GenericBorderImageSlice {
|
||||
offsets: offsets,
|
||||
|
@ -151,7 +151,7 @@ impl Parse for BorderRadius {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let widths = Rect::parse_with(context, input, LengthOrPercentage::parse_non_negative)?;
|
||||
let heights = if input.r#try(|i| i.expect_delim('/')).is_ok() {
|
||||
let heights = if input.try(|i| i.expect_delim('/')).is_ok() {
|
||||
Rect::parse_with(context, input, LengthOrPercentage::parse_non_negative)?
|
||||
} else {
|
||||
widths.clone()
|
||||
|
@ -236,7 +236,7 @@ impl Parse for BorderImageRepeat {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let horizontal = BorderImageRepeatKeyword::parse(input)?;
|
||||
let vertical = input.r#try(BorderImageRepeatKeyword::parse).ok();
|
||||
let vertical = input.try(BorderImageRepeatKeyword::parse).ok();
|
||||
Ok(BorderImageRepeat(
|
||||
horizontal,
|
||||
vertical.unwrap_or(horizontal),
|
||||
|
|
|
@ -6,9 +6,8 @@
|
|||
|
||||
use crate::custom_properties::Name as CustomPropertyName;
|
||||
use crate::parser::{Parse, ParserContext};
|
||||
use crate::properties::{
|
||||
LonghandId, PropertyDeclarationId, PropertyFlags, PropertyId, ShorthandId,
|
||||
};
|
||||
use crate::properties::{LonghandId, PropertyDeclarationId, PropertyFlags};
|
||||
use crate::properties::{PropertyId, ShorthandId};
|
||||
use crate::values::generics::box_::AnimationIterationCount as GenericAnimationIterationCount;
|
||||
use crate::values::generics::box_::Perspective as GenericPerspective;
|
||||
use crate::values::generics::box_::VerticalAlign as GenericVerticalAlign;
|
||||
|
@ -310,7 +309,7 @@ impl Parse for VerticalAlign {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(lop) =
|
||||
input.r#try(|i| LengthOrPercentage::parse_quirky(context, i, AllowQuirks::Yes))
|
||||
input.try(|i| LengthOrPercentage::parse_quirky(context, i, AllowQuirks::Yes))
|
||||
{
|
||||
return Ok(GenericVerticalAlign::Length(lop));
|
||||
}
|
||||
|
@ -341,7 +340,7 @@ impl Parse for AnimationIterationCount {
|
|||
input: &mut ::cssparser::Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("infinite"))
|
||||
.try(|input| input.expect_ident_matching("infinite"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(GenericAnimationIterationCount::Infinite);
|
||||
|
@ -394,7 +393,7 @@ impl Parse for AnimationName {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(name) = input.r#try(|input| KeyframesName::parse(context, input)) {
|
||||
if let Ok(name) = input.try(|input| KeyframesName::parse(context, input)) {
|
||||
return Ok(AnimationName(Some(name)));
|
||||
}
|
||||
|
||||
|
@ -557,7 +556,7 @@ impl Parse for WillChange {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<WillChange, ParseError<'i>> {
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("auto"))
|
||||
.try(|input| input.expect_ident_matching("auto"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(WillChange::Auto);
|
||||
|
@ -646,14 +645,14 @@ impl Parse for TouchAction {
|
|||
"none" => Ok(TouchAction::TOUCH_ACTION_NONE),
|
||||
"manipulation" => Ok(TouchAction::TOUCH_ACTION_MANIPULATION),
|
||||
"pan-x" => {
|
||||
if input.r#try(|i| i.expect_ident_matching("pan-y")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("pan-y")).is_ok() {
|
||||
Ok(TouchAction::TOUCH_ACTION_PAN_X | TouchAction::TOUCH_ACTION_PAN_Y)
|
||||
} else {
|
||||
Ok(TouchAction::TOUCH_ACTION_PAN_X)
|
||||
}
|
||||
},
|
||||
"pan-y" => {
|
||||
if input.r#try(|i| i.expect_ident_matching("pan-x")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("pan-x")).is_ok() {
|
||||
Ok(TouchAction::TOUCH_ACTION_PAN_X | TouchAction::TOUCH_ACTION_PAN_Y)
|
||||
} else {
|
||||
Ok(TouchAction::TOUCH_ACTION_PAN_Y)
|
||||
|
@ -757,7 +756,7 @@ impl Parse for Contain {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Contain, ParseError<'i>> {
|
||||
let mut result = Contain::empty();
|
||||
while let Ok(name) = input.r#try(|i| i.expect_ident_cloned()) {
|
||||
while let Ok(name) = input.try(|i| i.expect_ident_cloned()) {
|
||||
let flag = match_ignore_ascii_case! { &name,
|
||||
"size" => Some(Contain::SIZE),
|
||||
"layout" => Some(Contain::LAYOUT),
|
||||
|
@ -794,7 +793,7 @@ impl Parse for Perspective {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input.r#try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
return Ok(GenericPerspective::None);
|
||||
}
|
||||
Ok(GenericPerspective::Length(NonNegativeLength::parse(
|
||||
|
@ -1036,8 +1035,10 @@ pub enum Appearance {
|
|||
#[parse(condition = "in_ua_or_chrome_sheet")]
|
||||
Menuimage,
|
||||
/// A horizontal meter bar.
|
||||
Meterbar,
|
||||
#[parse(aliases = "meterbar")]
|
||||
Meter,
|
||||
/// The meter bar's meter indicator.
|
||||
#[parse(condition = "in_ua_or_chrome_sheet")]
|
||||
Meterchunk,
|
||||
/// The "arrowed" part of the dropdown button that open up a dropdown list.
|
||||
#[parse(condition = "in_ua_or_chrome_sheet")]
|
||||
|
@ -1045,13 +1046,13 @@ pub enum Appearance {
|
|||
/// For HTML's <input type=number>
|
||||
NumberInput,
|
||||
/// A horizontal progress bar.
|
||||
Progressbar,
|
||||
#[parse(aliases = "progressbar")]
|
||||
ProgressBar,
|
||||
/// The progress bar's progress indicator
|
||||
#[parse(condition = "in_ua_or_chrome_sheet")]
|
||||
Progresschunk,
|
||||
/// A vertical progress bar.
|
||||
ProgressbarVertical,
|
||||
/// A vertical progress chunk.
|
||||
ProgresschunkVertical,
|
||||
/// A checkbox element.
|
||||
Checkbox,
|
||||
/// A radio element within a radio group.
|
||||
|
|
|
@ -142,7 +142,7 @@ impl Parse for Color {
|
|||
input.reset(&start);
|
||||
|
||||
let compontent_parser = ColorComponentParser(&*context);
|
||||
match input.r#try(|i| CSSParserColor::parse_with(&compontent_parser, i)) {
|
||||
match input.try(|i| CSSParserColor::parse_with(&compontent_parser, i)) {
|
||||
Ok(value) => Ok(match value {
|
||||
CSSParserColor::CurrentColor => Color::CurrentColor,
|
||||
CSSParserColor::RGBA(rgba) => Color::Numeric {
|
||||
|
@ -245,7 +245,7 @@ impl Color {
|
|||
input: &mut Parser<'i, 't>,
|
||||
allow_quirks: AllowQuirks,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
input.r#try(|i| Self::parse(context, i)).or_else(|e| {
|
||||
input.try(|i| Self::parse(context, i)).or_else(|e| {
|
||||
if !allow_quirks.allowed(context.quirks_mode) {
|
||||
return Err(e);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ impl Parse for ColumnCount {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input.r#try(|i| i.expect_ident_matching("auto")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
|
||||
return Ok(GenericColumnCount::Auto);
|
||||
}
|
||||
Ok(GenericColumnCount::Integer(PositiveInteger::parse(
|
||||
|
|
|
@ -52,7 +52,7 @@ fn parse_counters<'i, 't>(
|
|||
default_value: i32,
|
||||
) -> Result<Vec<CounterPair<Integer>>, ParseError<'i>> {
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("none"))
|
||||
.try(|input| input.expect_ident_matching("none"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(vec![]);
|
||||
|
@ -68,7 +68,7 @@ fn parse_counters<'i, 't>(
|
|||
};
|
||||
|
||||
let value = input
|
||||
.r#try(|input| Integer::parse(context, input))
|
||||
.try(|input| Integer::parse(context, input))
|
||||
.unwrap_or(Integer::new(default_value));
|
||||
counters.push(CounterPair { name, value });
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ impl Content {
|
|||
#[cfg(feature = "servo")]
|
||||
fn parse_counter_style(_: &ParserContext, input: &mut Parser) -> ListStyleType {
|
||||
input
|
||||
.r#try(|input| {
|
||||
.try(|input| {
|
||||
input.expect_comma()?;
|
||||
ListStyleType::parse(input)
|
||||
})
|
||||
|
@ -100,7 +100,7 @@ impl Content {
|
|||
#[cfg(feature = "gecko")]
|
||||
fn parse_counter_style(context: &ParserContext, input: &mut Parser) -> CounterStyleOrNone {
|
||||
input
|
||||
.r#try(|input| {
|
||||
.try(|input| {
|
||||
input.expect_comma()?;
|
||||
CounterStyleOrNone::parse(context, input)
|
||||
})
|
||||
|
@ -117,13 +117,13 @@ impl Parse for Content {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("normal"))
|
||||
.try(|input| input.expect_ident_matching("normal"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(generics::Content::Normal);
|
||||
}
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("none"))
|
||||
.try(|input| input.expect_ident_matching("none"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(generics::Content::None);
|
||||
|
@ -131,7 +131,7 @@ impl Parse for Content {
|
|||
#[cfg(feature = "gecko")]
|
||||
{
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("-moz-alt-content"))
|
||||
.try(|input| input.expect_ident_matching("-moz-alt-content"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(generics::Content::MozAltContent);
|
||||
|
@ -142,7 +142,7 @@ impl Parse for Content {
|
|||
loop {
|
||||
#[cfg(feature = "gecko")]
|
||||
{
|
||||
if let Ok(url) = input.r#try(|i| SpecifiedImageUrl::parse(context, i)) {
|
||||
if let Ok(url) = input.try(|i| SpecifiedImageUrl::parse(context, i)) {
|
||||
content.push(generics::ContentItem::Url(url));
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -21,10 +21,10 @@ impl Parse for TimingFunction {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(keyword) = input.r#try(TimingKeyword::parse) {
|
||||
if let Ok(keyword) = input.try(TimingKeyword::parse) {
|
||||
return Ok(GenericTimingFunction::Keyword(keyword));
|
||||
}
|
||||
if let Ok(ident) = input.r#try(|i| i.expect_ident_cloned()) {
|
||||
if let Ok(ident) = input.try(|i| i.expect_ident_cloned()) {
|
||||
let position = match_ignore_ascii_case! { &ident,
|
||||
"step-start" => StepPosition::Start,
|
||||
"step-end" => StepPosition::End,
|
||||
|
@ -57,7 +57,7 @@ impl Parse for TimingFunction {
|
|||
},
|
||||
"steps" => {
|
||||
let steps = Integer::parse_positive(context, i)?;
|
||||
let position = i.r#try(|i| {
|
||||
let position = i.try(|i| {
|
||||
i.expect_comma()?;
|
||||
StepPosition::parse(context, i)
|
||||
}).unwrap_or(StepPosition::End);
|
||||
|
|
|
@ -7,9 +7,8 @@
|
|||
use crate::parser::{Parse, ParserContext};
|
||||
use crate::values::computed::effects::BoxShadow as ComputedBoxShadow;
|
||||
use crate::values::computed::effects::SimpleShadow as ComputedSimpleShadow;
|
||||
use crate::values::computed::{
|
||||
Context, NonNegativeNumber as ComputedNonNegativeNumber, ToComputedValue,
|
||||
};
|
||||
use crate::values::computed::NonNegativeNumber as ComputedNonNegativeNumber;
|
||||
use crate::values::computed::{Context, ToComputedValue};
|
||||
use crate::values::generics::effects::BoxShadow as GenericBoxShadow;
|
||||
use crate::values::generics::effects::Filter as GenericFilter;
|
||||
use crate::values::generics::effects::SimpleShadow as GenericSimpleShadow;
|
||||
|
@ -109,7 +108,7 @@ impl Parse for BoxShadow {
|
|||
loop {
|
||||
if !inset {
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("inset"))
|
||||
.try(|input| input.expect_ident_matching("inset"))
|
||||
.is_ok()
|
||||
{
|
||||
inset = true;
|
||||
|
@ -117,14 +116,14 @@ impl Parse for BoxShadow {
|
|||
}
|
||||
}
|
||||
if lengths.is_none() {
|
||||
let value = input.r#try::<_, _, ParseError>(|i| {
|
||||
let value = input.try::<_, _, ParseError>(|i| {
|
||||
let horizontal = Length::parse(context, i)?;
|
||||
let vertical = Length::parse(context, i)?;
|
||||
let (blur, spread) = match i
|
||||
.r#try::<_, _, ParseError>(|i| Length::parse_non_negative(context, i))
|
||||
.try::<_, _, ParseError>(|i| Length::parse_non_negative(context, i))
|
||||
{
|
||||
Ok(blur) => {
|
||||
let spread = i.r#try(|i| Length::parse(context, i)).ok();
|
||||
let spread = i.try(|i| Length::parse(context, i)).ok();
|
||||
(Some(blur.into()), spread)
|
||||
},
|
||||
Err(_) => (None, None),
|
||||
|
@ -137,7 +136,7 @@ impl Parse for BoxShadow {
|
|||
}
|
||||
}
|
||||
if color.is_none() {
|
||||
if let Ok(value) = input.r#try(|i| Color::parse(context, i)) {
|
||||
if let Ok(value) = input.try(|i| Color::parse(context, i)) {
|
||||
color = Some(value);
|
||||
continue;
|
||||
}
|
||||
|
@ -194,7 +193,7 @@ impl Parse for Filter {
|
|||
) -> Result<Self, ParseError<'i>> {
|
||||
#[cfg(feature = "gecko")]
|
||||
{
|
||||
if let Ok(url) = input.r#try(|i| SpecifiedUrl::parse(context, i)) {
|
||||
if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
|
||||
return Ok(GenericFilter::Url(url));
|
||||
}
|
||||
}
|
||||
|
@ -253,12 +252,12 @@ impl Parse for SimpleShadow {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let color = input.r#try(|i| Color::parse(context, i)).ok();
|
||||
let color = input.try(|i| Color::parse(context, i)).ok();
|
||||
let horizontal = Length::parse(context, input)?;
|
||||
let vertical = Length::parse(context, input)?;
|
||||
let blur = input.r#try(|i| Length::parse_non_negative(context, i)).ok();
|
||||
let blur = input.try(|i| Length::parse_non_negative(context, i)).ok();
|
||||
let blur = blur.map(NonNegative::<Length>);
|
||||
let color = color.or_else(|| input.r#try(|i| Color::parse(context, i)).ok());
|
||||
let color = color.or_else(|| input.try(|i| Color::parse(context, i)).ok());
|
||||
|
||||
Ok(SimpleShadow {
|
||||
color,
|
||||
|
|
|
@ -25,7 +25,7 @@ impl Parse for FlexBasis {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(width) = input.r#try(|i| Width::parse(context, i)) {
|
||||
if let Ok(width) = input.try(|i| Width::parse(context, i)) {
|
||||
return Ok(GenericFlexBasis::Width(width));
|
||||
}
|
||||
try_match_ident_ignore_ascii_case! { input,
|
||||
|
|
|
@ -11,10 +11,9 @@ use crate::gecko_bindings::bindings;
|
|||
use crate::parser::{Parse, ParserContext};
|
||||
use crate::properties::longhands::system_font::SystemFont;
|
||||
use crate::values::computed::font::{FamilyName, FontFamilyList, FontStyleAngle, SingleFontFamily};
|
||||
use crate::values::computed::{
|
||||
font as computed, Context, Length, NonNegativeLength, ToComputedValue,
|
||||
};
|
||||
use crate::values::computed::{font as computed, Length, NonNegativeLength};
|
||||
use crate::values::computed::{Angle as ComputedAngle, Percentage as ComputedPercentage};
|
||||
use crate::values::computed::{Context, ToComputedValue};
|
||||
use crate::values::generics::font::{self as generics, FeatureTagValue, FontSettings, FontTag};
|
||||
use crate::values::generics::font::{KeywordSize, VariationValue};
|
||||
use crate::values::generics::NonNegative;
|
||||
|
@ -117,7 +116,7 @@ impl Parse for FontWeight {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<FontWeight, ParseError<'i>> {
|
||||
if let Ok(absolute) = input.r#try(|input| AbsoluteFontWeight::parse(context, input)) {
|
||||
if let Ok(absolute) = input.try(|input| AbsoluteFontWeight::parse(context, input)) {
|
||||
return Ok(FontWeight::Absolute(absolute));
|
||||
}
|
||||
|
||||
|
@ -190,7 +189,7 @@ impl Parse for AbsoluteFontWeight {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(number) = input.r#try(|input| Number::parse(context, input)) {
|
||||
if let Ok(number) = input.try(|input| Number::parse(context, input)) {
|
||||
// We could add another AllowedNumericType value, but it doesn't
|
||||
// seem worth it just for a single property with such a weird range,
|
||||
// so we do the clamping here manually.
|
||||
|
@ -242,7 +241,7 @@ impl Parse for SpecifiedFontStyle {
|
|||
"normal" => generics::FontStyle::Normal,
|
||||
"italic" => generics::FontStyle::Italic,
|
||||
"oblique" => {
|
||||
let angle = input.r#try(|input| Self::parse_angle(context, input))
|
||||
let angle = input.try(|input| Self::parse_angle(context, input))
|
||||
.unwrap_or_else(|_| Self::default_angle());
|
||||
|
||||
generics::FontStyle::Oblique(angle)
|
||||
|
@ -481,8 +480,7 @@ impl Parse for FontStretch {
|
|||
//
|
||||
// Values less than 0% are not allowed and are treated as parse
|
||||
// errors.
|
||||
if let Ok(percentage) = input.r#try(|input| Percentage::parse_non_negative(context, input))
|
||||
{
|
||||
if let Ok(percentage) = input.try(|input| Percentage::parse_non_negative(context, input)) {
|
||||
return Ok(FontStretch::Stretch(percentage));
|
||||
}
|
||||
|
||||
|
@ -682,7 +680,7 @@ impl Parse for FontSizeAdjust {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<FontSizeAdjust, ParseError<'i>> {
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("none"))
|
||||
.try(|input| input.expect_ident_matching("none"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(FontSizeAdjust::None);
|
||||
|
@ -990,12 +988,12 @@ impl FontSize {
|
|||
allow_quirks: AllowQuirks,
|
||||
) -> Result<FontSize, ParseError<'i>> {
|
||||
if let Ok(lop) =
|
||||
input.r#try(|i| LengthOrPercentage::parse_non_negative_quirky(context, i, allow_quirks))
|
||||
input.try(|i| LengthOrPercentage::parse_non_negative_quirky(context, i, allow_quirks))
|
||||
{
|
||||
return Ok(FontSize::Length(lop));
|
||||
}
|
||||
|
||||
if let Ok(kw) = input.r#try(KeywordSize::parse) {
|
||||
if let Ok(kw) = input.try(KeywordSize::parse) {
|
||||
return Ok(FontSize::Keyword(kw.into()));
|
||||
}
|
||||
|
||||
|
@ -1177,7 +1175,7 @@ impl Parse for FontVariantAlternates {
|
|||
) -> Result<FontVariantAlternates, ParseError<'i>> {
|
||||
let mut alternates = Vec::new();
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("normal"))
|
||||
.try(|input| input.expect_ident_matching("normal"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(FontVariantAlternates::Value(VariantAlternatesList(
|
||||
|
@ -1194,7 +1192,7 @@ impl Parse for FontVariantAlternates {
|
|||
parsed_alternates |= $flag;
|
||||
)
|
||||
);
|
||||
while let Ok(_) = input.r#try(|input| {
|
||||
while let Ok(_) = input.try(|input| {
|
||||
// FIXME: remove clone() when lifetimes are non-lexical
|
||||
match input.next()?.clone() {
|
||||
Token::Ident(ref value) if value.eq_ignore_ascii_case("historical-forms") => {
|
||||
|
@ -1409,13 +1407,13 @@ impl Parse for FontVariantEastAsian {
|
|||
let mut result = VariantEastAsian::empty();
|
||||
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("normal"))
|
||||
.try(|input| input.expect_ident_matching("normal"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(FontVariantEastAsian::Value(result));
|
||||
}
|
||||
|
||||
while let Ok(flag) = input.r#try(|input| {
|
||||
while let Ok(flag) = input.try(|input| {
|
||||
Ok(
|
||||
match_ignore_ascii_case! { &input.expect_ident().map_err(|_| ())?,
|
||||
"jis78" =>
|
||||
|
@ -1633,19 +1631,19 @@ impl Parse for FontVariantLigatures {
|
|||
let mut result = VariantLigatures::empty();
|
||||
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("normal"))
|
||||
.try(|input| input.expect_ident_matching("normal"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(FontVariantLigatures::Value(result));
|
||||
}
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("none"))
|
||||
.try(|input| input.expect_ident_matching("none"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(FontVariantLigatures::Value(VariantLigatures::NONE));
|
||||
}
|
||||
|
||||
while let Ok(flag) = input.r#try(|input| {
|
||||
while let Ok(flag) = input.try(|input| {
|
||||
Ok(
|
||||
match_ignore_ascii_case! { &input.expect_ident().map_err(|_| ())?,
|
||||
"common-ligatures" =>
|
||||
|
@ -1842,13 +1840,13 @@ impl Parse for FontVariantNumeric {
|
|||
let mut result = VariantNumeric::empty();
|
||||
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("normal"))
|
||||
.try(|input| input.expect_ident_matching("normal"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(FontVariantNumeric::Value(result));
|
||||
}
|
||||
|
||||
while let Ok(flag) = input.r#try(|input| {
|
||||
while let Ok(flag) = input.try(|input| {
|
||||
Ok(
|
||||
match_ignore_ascii_case! { &input.expect_ident().map_err(|_| ())?,
|
||||
"ordinal" =>
|
||||
|
@ -1982,14 +1980,14 @@ impl Parse for FontSynthesis {
|
|||
"none" => Ok(result),
|
||||
"weight" => {
|
||||
result.weight = true;
|
||||
if input.r#try(|input| input.expect_ident_matching("style")).is_ok() {
|
||||
if input.try(|input| input.expect_ident_matching("style")).is_ok() {
|
||||
result.style = true;
|
||||
}
|
||||
Ok(result)
|
||||
},
|
||||
"style" => {
|
||||
result.style = true;
|
||||
if input.r#try(|input| input.expect_ident_matching("weight")).is_ok() {
|
||||
if input.try(|input| input.expect_ident_matching("weight")).is_ok() {
|
||||
result.weight = true;
|
||||
}
|
||||
Ok(result)
|
||||
|
@ -2128,7 +2126,7 @@ impl Parse for FontLanguageOverride {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<FontLanguageOverride, ParseError<'i>> {
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("normal"))
|
||||
.try(|input| input.expect_ident_matching("normal"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(FontLanguageOverride::Normal);
|
||||
|
@ -2195,7 +2193,7 @@ fn parse_one_feature_value<'i, 't>(
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Integer, ParseError<'i>> {
|
||||
if let Ok(integer) = input.r#try(|i| Integer::parse_non_negative(context, i)) {
|
||||
if let Ok(integer) = input.try(|i| Integer::parse_non_negative(context, i)) {
|
||||
return Ok(integer);
|
||||
}
|
||||
|
||||
|
@ -2213,7 +2211,7 @@ impl Parse for FeatureTagValue<Integer> {
|
|||
) -> Result<Self, ParseError<'i>> {
|
||||
let tag = FontTag::parse(context, input)?;
|
||||
let value = input
|
||||
.r#try(|i| parse_one_feature_value(context, i))
|
||||
.try(|i| parse_one_feature_value(context, i))
|
||||
.unwrap_or_else(|_| Integer::new(1));
|
||||
|
||||
Ok(Self { tag, value })
|
||||
|
@ -2331,7 +2329,7 @@ impl Parse for MozScriptLevel {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<MozScriptLevel, ParseError<'i>> {
|
||||
// We don't bother to handle calc here.
|
||||
if let Ok(i) = input.r#try(|i| i.expect_integer()) {
|
||||
if let Ok(i) = input.try(|i| i.expect_integer()) {
|
||||
return Ok(MozScriptLevel::Relative(i));
|
||||
}
|
||||
input.expect_ident_matching("auto")?;
|
||||
|
|
|
@ -25,7 +25,7 @@ impl Parse for ScrollSnapPoint {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input.r#try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
return Ok(GenericScrollSnapPoint::None);
|
||||
}
|
||||
input.expect_function_matching("repeat")?;
|
||||
|
|
|
@ -36,11 +36,11 @@ impl Parse for TrackBreadth<LengthOrPercentage> {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(lop) = input.r#try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
|
||||
if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
|
||||
return Ok(TrackBreadth::Breadth(lop));
|
||||
}
|
||||
|
||||
if let Ok(f) = input.r#try(parse_flex) {
|
||||
if let Ok(f) = input.try(parse_flex) {
|
||||
return Ok(TrackBreadth::Fr(f));
|
||||
}
|
||||
|
||||
|
@ -53,17 +53,14 @@ impl Parse for TrackSize<LengthOrPercentage> {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(b) = input.r#try(|i| TrackBreadth::parse(context, i)) {
|
||||
if let Ok(b) = input.try(|i| TrackBreadth::parse(context, i)) {
|
||||
return Ok(TrackSize::Breadth(b));
|
||||
}
|
||||
|
||||
if input
|
||||
.r#try(|i| i.expect_function_matching("minmax"))
|
||||
.is_ok()
|
||||
{
|
||||
if input.try(|i| i.expect_function_matching("minmax")).is_ok() {
|
||||
return input.parse_nested_block(|input| {
|
||||
let inflexible_breadth =
|
||||
match input.r#try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
|
||||
match input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
|
||||
Ok(lop) => TrackBreadth::Breadth(lop),
|
||||
Err(..) => {
|
||||
let keyword = TrackKeyword::parse(input)?;
|
||||
|
@ -95,7 +92,7 @@ pub fn parse_line_names<'i, 't>(
|
|||
input.expect_square_bracket_block()?;
|
||||
input.parse_nested_block(|input| {
|
||||
let mut values = vec![];
|
||||
while let Ok((loc, ident)) = input.r#try(|i| -> Result<_, CssParseError<()>> {
|
||||
while let Ok((loc, ident)) = input.try(|i| -> Result<_, CssParseError<()>> {
|
||||
Ok((i.current_source_location(), i.expect_ident_cloned()?))
|
||||
}) {
|
||||
let ident = CustomIdent::from_ident(loc, &ident, &["span", "auto"])?;
|
||||
|
@ -126,7 +123,7 @@ impl TrackRepeat<LengthOrPercentage, Integer> {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<(Self, RepeatType), ParseError<'i>> {
|
||||
input
|
||||
.r#try(|i| i.expect_function_matching("repeat").map_err(|e| e.into()))
|
||||
.try(|i| i.expect_function_matching("repeat").map_err(|e| e.into()))
|
||||
.and_then(|_| {
|
||||
input.parse_nested_block(|input| {
|
||||
let count = RepeatCount::parse(context, input)?;
|
||||
|
@ -146,9 +143,9 @@ impl TrackRepeat<LengthOrPercentage, Integer> {
|
|||
|
||||
loop {
|
||||
current_names = input
|
||||
.r#try(parse_line_names)
|
||||
.try(parse_line_names)
|
||||
.unwrap_or(vec![].into_boxed_slice());
|
||||
if let Ok(track_size) = input.r#try(|i| TrackSize::parse(context, i)) {
|
||||
if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) {
|
||||
if !track_size.is_fixed() {
|
||||
if is_auto {
|
||||
// should be <fixed-size> for <auto-repeat>
|
||||
|
@ -172,7 +169,7 @@ impl TrackRepeat<LengthOrPercentage, Integer> {
|
|||
// gecko implements new spec.
|
||||
names.push(
|
||||
input
|
||||
.r#try(parse_line_names)
|
||||
.try(parse_line_names)
|
||||
.unwrap_or(vec![].into_boxed_slice()),
|
||||
);
|
||||
break;
|
||||
|
@ -226,10 +223,10 @@ impl Parse for TrackList<LengthOrPercentage, Integer> {
|
|||
loop {
|
||||
current_names.extend_from_slice(
|
||||
&mut input
|
||||
.r#try(parse_line_names)
|
||||
.try(parse_line_names)
|
||||
.unwrap_or(vec![].into_boxed_slice()),
|
||||
);
|
||||
if let Ok(track_size) = input.r#try(|i| TrackSize::parse(context, i)) {
|
||||
if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) {
|
||||
if !track_size.is_fixed() {
|
||||
atleast_one_not_fixed = true;
|
||||
if auto_repeat.is_some() {
|
||||
|
@ -242,7 +239,7 @@ impl Parse for TrackList<LengthOrPercentage, Integer> {
|
|||
names.push(vec.into_boxed_slice());
|
||||
values.push(TrackListValue::TrackSize(track_size));
|
||||
} else if let Ok((repeat, type_)) =
|
||||
input.r#try(|i| TrackRepeat::parse_with_repeat_type(context, i))
|
||||
input.try(|i| TrackRepeat::parse_with_repeat_type(context, i))
|
||||
{
|
||||
if list_type == TrackListType::Explicit {
|
||||
list_type = TrackListType::Normal; // <explicit-track-list> doesn't contain repeat()
|
||||
|
@ -404,7 +401,7 @@ impl Parse for GridTemplateComponent<LengthOrPercentage, Integer> {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input.r#try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
return Ok(GridTemplateComponent::None);
|
||||
}
|
||||
|
||||
|
@ -419,7 +416,7 @@ impl GridTemplateComponent<LengthOrPercentage, Integer> {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if allow_grid_template_subgrids() {
|
||||
if let Ok(t) = input.r#try(|i| LineNameList::parse(context, i)) {
|
||||
if let Ok(t) = input.try(|i| LineNameList::parse(context, i)) {
|
||||
return Ok(GridTemplateComponent::Subgrid(t));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ impl ImageLayer {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(v) = input.r#try(|i| None_::parse(context, i)) {
|
||||
if let Ok(v) = input.try(|i| None_::parse(context, i)) {
|
||||
return Ok(Either::First(v));
|
||||
}
|
||||
Image::parse_with_cors_anonymous(context, input).map(Either::Second)
|
||||
|
@ -142,19 +142,19 @@ impl Parse for Image {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Image, ParseError<'i>> {
|
||||
if let Ok(url) = input.r#try(|input| SpecifiedImageUrl::parse(context, input)) {
|
||||
if let Ok(url) = input.try(|input| SpecifiedImageUrl::parse(context, input)) {
|
||||
return Ok(generic::Image::Url(url));
|
||||
}
|
||||
if let Ok(gradient) = input.r#try(|i| Gradient::parse(context, i)) {
|
||||
if let Ok(gradient) = input.try(|i| Gradient::parse(context, i)) {
|
||||
return Ok(generic::Image::Gradient(Box::new(gradient)));
|
||||
}
|
||||
#[cfg(feature = "servo")]
|
||||
{
|
||||
if let Ok(paint_worklet) = input.r#try(|i| PaintWorklet::parse(context, i)) {
|
||||
if let Ok(paint_worklet) = input.try(|i| PaintWorklet::parse(context, i)) {
|
||||
return Ok(generic::Image::PaintWorklet(paint_worklet));
|
||||
}
|
||||
}
|
||||
if let Ok(image_rect) = input.r#try(|input| MozImageRect::parse(context, input)) {
|
||||
if let Ok(image_rect) = input.try(|input| MozImageRect::parse(context, input)) {
|
||||
return Ok(generic::Image::Rect(Box::new(image_rect)));
|
||||
}
|
||||
Ok(generic::Image::Element(Image::parse_element(input)?))
|
||||
|
@ -172,7 +172,7 @@ impl Image {
|
|||
|
||||
/// Parses a `-moz-element(# <element-id>)`.
|
||||
fn parse_element<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Atom, ParseError<'i>> {
|
||||
input.r#try(|i| i.expect_function_matching("-moz-element"))?;
|
||||
input.try(|i| i.expect_function_matching("-moz-element"))?;
|
||||
let location = input.current_source_location();
|
||||
input.parse_nested_block(|i| match *i.next()? {
|
||||
Token::IDHash(ref id) => Ok(Atom::from(id.as_ref())),
|
||||
|
@ -190,7 +190,7 @@ impl Image {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Image, ParseError<'i>> {
|
||||
if let Ok(url) =
|
||||
input.r#try(|input| SpecifiedImageUrl::parse_with_cors_anonymous(context, input))
|
||||
input.try(|input| SpecifiedImageUrl::parse_with_cors_anonymous(context, input))
|
||||
{
|
||||
return Ok(generic::Image::Url(url));
|
||||
}
|
||||
|
@ -350,7 +350,7 @@ impl Gradient {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
input.r#try(|i| {
|
||||
input.try(|i| {
|
||||
let x = Component::parse(context, i)?;
|
||||
let y = Component::parse(context, i)?;
|
||||
|
||||
|
@ -413,13 +413,13 @@ impl Gradient {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(side) = input.r#try(|i| S::parse(context, i)) {
|
||||
if let Ok(side) = input.try(|i| S::parse(context, i)) {
|
||||
return Ok(Component::Side(side));
|
||||
}
|
||||
if let Ok(number) = input.r#try(|i| NumberOrPercentage::parse(context, i)) {
|
||||
if let Ok(number) = input.try(|i| NumberOrPercentage::parse(context, i)) {
|
||||
return Ok(Component::Number(number));
|
||||
}
|
||||
input.r#try(|i| i.expect_ident_matching("center"))?;
|
||||
input.try(|i| i.expect_ident_matching("center"))?;
|
||||
Ok(Component::Center)
|
||||
}
|
||||
}
|
||||
|
@ -477,7 +477,7 @@ impl Gradient {
|
|||
};
|
||||
|
||||
let mut items = input
|
||||
.r#try(|i| {
|
||||
.try(|i| {
|
||||
i.expect_comma()?;
|
||||
i.parse_comma_separated(|i| {
|
||||
let function = i.expect_function()?.clone();
|
||||
|
@ -572,16 +572,16 @@ impl GradientKind {
|
|||
input: &mut Parser<'i, 't>,
|
||||
compat_mode: &mut CompatMode,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let direction =
|
||||
if let Ok(d) = input.r#try(|i| LineDirection::parse(context, i, compat_mode)) {
|
||||
input.expect_comma()?;
|
||||
d
|
||||
} else {
|
||||
match *compat_mode {
|
||||
CompatMode::Modern => LineDirection::Vertical(Y::Bottom),
|
||||
_ => LineDirection::Vertical(Y::Top),
|
||||
}
|
||||
};
|
||||
let direction = if let Ok(d) = input.try(|i| LineDirection::parse(context, i, compat_mode))
|
||||
{
|
||||
input.expect_comma()?;
|
||||
d
|
||||
} else {
|
||||
match *compat_mode {
|
||||
CompatMode::Modern => LineDirection::Vertical(Y::Bottom),
|
||||
_ => LineDirection::Vertical(Y::Top),
|
||||
}
|
||||
};
|
||||
Ok(generic::GradientKind::Linear(direction))
|
||||
}
|
||||
|
||||
|
@ -592,16 +592,16 @@ impl GradientKind {
|
|||
) -> Result<Self, ParseError<'i>> {
|
||||
let (shape, position, angle, moz_position) = match *compat_mode {
|
||||
CompatMode::Modern => {
|
||||
let shape = input.r#try(|i| EndingShape::parse(context, i, *compat_mode));
|
||||
let position = input.r#try(|i| {
|
||||
let shape = input.try(|i| EndingShape::parse(context, i, *compat_mode));
|
||||
let position = input.try(|i| {
|
||||
i.expect_ident_matching("at")?;
|
||||
Position::parse(context, i)
|
||||
});
|
||||
(shape, position.ok(), None, None)
|
||||
},
|
||||
CompatMode::WebKit => {
|
||||
let position = input.r#try(|i| Position::parse(context, i));
|
||||
let shape = input.r#try(|i| {
|
||||
let position = input.try(|i| Position::parse(context, i));
|
||||
let shape = input.try(|i| {
|
||||
if position.is_ok() {
|
||||
i.expect_comma()?;
|
||||
}
|
||||
|
@ -620,13 +620,13 @@ impl GradientKind {
|
|||
// cover | contain
|
||||
// and <color-stop> = <color> [ <percentage> | <length> ]?
|
||||
CompatMode::Moz => {
|
||||
let mut position = input.r#try(|i| LegacyPosition::parse(context, i));
|
||||
let angle = input.r#try(|i| Angle::parse(context, i)).ok();
|
||||
let mut position = input.try(|i| LegacyPosition::parse(context, i));
|
||||
let angle = input.try(|i| Angle::parse(context, i)).ok();
|
||||
if position.is_err() {
|
||||
position = input.r#try(|i| LegacyPosition::parse(context, i));
|
||||
position = input.try(|i| LegacyPosition::parse(context, i));
|
||||
}
|
||||
|
||||
let shape = input.r#try(|i| {
|
||||
let shape = input.try(|i| {
|
||||
if position.is_ok() || angle.is_some() {
|
||||
i.expect_comma()?;
|
||||
}
|
||||
|
@ -768,18 +768,18 @@ impl LineDirection {
|
|||
compat_mode: &mut CompatMode,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let mut _angle = if *compat_mode == CompatMode::Moz {
|
||||
input.r#try(|i| Angle::parse(context, i)).ok()
|
||||
input.try(|i| Angle::parse(context, i)).ok()
|
||||
} else {
|
||||
// Gradients allow unitless zero angles as an exception, see:
|
||||
// https://github.com/w3c/csswg-drafts/issues/1162
|
||||
if let Ok(angle) = input.r#try(|i| Angle::parse_with_unitless(context, i)) {
|
||||
if let Ok(angle) = input.try(|i| Angle::parse_with_unitless(context, i)) {
|
||||
return Ok(LineDirection::Angle(angle));
|
||||
}
|
||||
None
|
||||
};
|
||||
|
||||
input.r#try(|i| {
|
||||
let to_ident = i.r#try(|i| i.expect_ident_matching("to"));
|
||||
input.try(|i| {
|
||||
let to_ident = i.try(|i| i.expect_ident_matching("to"));
|
||||
match *compat_mode {
|
||||
// `to` keyword is mandatory in modern syntax.
|
||||
CompatMode::Modern => to_ident?,
|
||||
|
@ -801,9 +801,9 @@ impl LineDirection {
|
|||
{
|
||||
// `-moz-` prefixed linear gradient can be both Angle and Position.
|
||||
if *compat_mode == CompatMode::Moz {
|
||||
let position = i.r#try(|i| LegacyPosition::parse(context, i)).ok();
|
||||
let position = i.try(|i| LegacyPosition::parse(context, i)).ok();
|
||||
if _angle.is_none() {
|
||||
_angle = i.r#try(|i| Angle::parse(context, i)).ok();
|
||||
_angle = i.try(|i| Angle::parse(context, i)).ok();
|
||||
};
|
||||
|
||||
if _angle.is_none() && position.is_none() {
|
||||
|
@ -813,14 +813,14 @@ impl LineDirection {
|
|||
}
|
||||
}
|
||||
|
||||
if let Ok(x) = i.r#try(X::parse) {
|
||||
if let Ok(y) = i.r#try(Y::parse) {
|
||||
if let Ok(x) = i.try(X::parse) {
|
||||
if let Ok(y) = i.try(Y::parse) {
|
||||
return Ok(LineDirection::Corner(x, y));
|
||||
}
|
||||
return Ok(LineDirection::Horizontal(x));
|
||||
}
|
||||
let y = Y::parse(i)?;
|
||||
if let Ok(x) = i.r#try(X::parse) {
|
||||
if let Ok(x) = i.try(X::parse) {
|
||||
return Ok(LineDirection::Corner(x, y));
|
||||
}
|
||||
Ok(LineDirection::Vertical(y))
|
||||
|
@ -850,20 +850,19 @@ impl EndingShape {
|
|||
input: &mut Parser<'i, 't>,
|
||||
compat_mode: CompatMode,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(extent) = input.r#try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) {
|
||||
if input.r#try(|i| i.expect_ident_matching("circle")).is_ok() {
|
||||
if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) {
|
||||
if input.try(|i| i.expect_ident_matching("circle")).is_ok() {
|
||||
return Ok(generic::EndingShape::Circle(Circle::Extent(extent)));
|
||||
}
|
||||
let _ = input.r#try(|i| i.expect_ident_matching("ellipse"));
|
||||
let _ = input.try(|i| i.expect_ident_matching("ellipse"));
|
||||
return Ok(generic::EndingShape::Ellipse(Ellipse::Extent(extent)));
|
||||
}
|
||||
if input.r#try(|i| i.expect_ident_matching("circle")).is_ok() {
|
||||
if let Ok(extent) = input.r#try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode))
|
||||
{
|
||||
if input.try(|i| i.expect_ident_matching("circle")).is_ok() {
|
||||
if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) {
|
||||
return Ok(generic::EndingShape::Circle(Circle::Extent(extent)));
|
||||
}
|
||||
if compat_mode == CompatMode::Modern {
|
||||
if let Ok(length) = input.r#try(|i| Length::parse(context, i)) {
|
||||
if let Ok(length) = input.try(|i| Length::parse(context, i)) {
|
||||
return Ok(generic::EndingShape::Circle(Circle::Radius(length)));
|
||||
}
|
||||
}
|
||||
|
@ -871,13 +870,12 @@ impl EndingShape {
|
|||
ShapeExtent::FarthestCorner,
|
||||
)));
|
||||
}
|
||||
if input.r#try(|i| i.expect_ident_matching("ellipse")).is_ok() {
|
||||
if let Ok(extent) = input.r#try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode))
|
||||
{
|
||||
if input.try(|i| i.expect_ident_matching("ellipse")).is_ok() {
|
||||
if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) {
|
||||
return Ok(generic::EndingShape::Ellipse(Ellipse::Extent(extent)));
|
||||
}
|
||||
if compat_mode == CompatMode::Modern {
|
||||
let pair: Result<_, ParseError> = input.r#try(|i| {
|
||||
let pair: Result<_, ParseError> = input.try(|i| {
|
||||
let x = LengthOrPercentage::parse(context, i)?;
|
||||
let y = LengthOrPercentage::parse(context, i)?;
|
||||
Ok((x, y))
|
||||
|
@ -893,10 +891,10 @@ impl EndingShape {
|
|||
// -moz- prefixed radial gradient doesn't allow EndingShape's Length or LengthOrPercentage
|
||||
// to come before shape keyword. Otherwise it conflicts with <position>.
|
||||
if compat_mode != CompatMode::Moz {
|
||||
if let Ok(length) = input.r#try(|i| Length::parse(context, i)) {
|
||||
if let Ok(y) = input.r#try(|i| LengthOrPercentage::parse(context, i)) {
|
||||
if let Ok(length) = input.try(|i| Length::parse(context, i)) {
|
||||
if let Ok(y) = input.try(|i| LengthOrPercentage::parse(context, i)) {
|
||||
if compat_mode == CompatMode::Modern {
|
||||
let _ = input.r#try(|i| i.expect_ident_matching("ellipse"));
|
||||
let _ = input.try(|i| i.expect_ident_matching("ellipse"));
|
||||
}
|
||||
return Ok(generic::EndingShape::Ellipse(Ellipse::Radii(
|
||||
length.into(),
|
||||
|
@ -904,7 +902,7 @@ impl EndingShape {
|
|||
)));
|
||||
}
|
||||
if compat_mode == CompatMode::Modern {
|
||||
let y = input.r#try(|i| {
|
||||
let y = input.try(|i| {
|
||||
i.expect_ident_matching("ellipse")?;
|
||||
LengthOrPercentage::parse(context, i)
|
||||
});
|
||||
|
@ -914,17 +912,17 @@ impl EndingShape {
|
|||
y,
|
||||
)));
|
||||
}
|
||||
let _ = input.r#try(|i| i.expect_ident_matching("circle"));
|
||||
let _ = input.try(|i| i.expect_ident_matching("circle"));
|
||||
}
|
||||
|
||||
return Ok(generic::EndingShape::Circle(Circle::Radius(length)));
|
||||
}
|
||||
}
|
||||
input.r#try(|i| {
|
||||
input.try(|i| {
|
||||
let x = Percentage::parse(context, i)?;
|
||||
let y = if let Ok(y) = i.r#try(|i| LengthOrPercentage::parse(context, i)) {
|
||||
let y = if let Ok(y) = i.try(|i| LengthOrPercentage::parse(context, i)) {
|
||||
if compat_mode == CompatMode::Modern {
|
||||
let _ = i.r#try(|i| i.expect_ident_matching("ellipse"));
|
||||
let _ = i.try(|i| i.expect_ident_matching("ellipse"));
|
||||
}
|
||||
y
|
||||
} else {
|
||||
|
@ -965,7 +963,7 @@ impl GradientItem {
|
|||
loop {
|
||||
input.parse_until_before(Delimiter::Comma, |input| {
|
||||
if seen_stop {
|
||||
if let Ok(hint) = input.r#try(|i| LengthOrPercentage::parse(context, i)) {
|
||||
if let Ok(hint) = input.try(|i| LengthOrPercentage::parse(context, i)) {
|
||||
seen_stop = false;
|
||||
items.push(generic::GradientItem::InterpolationHint(hint));
|
||||
return Ok(());
|
||||
|
@ -974,7 +972,7 @@ impl GradientItem {
|
|||
|
||||
let stop = ColorStop::parse(context, input)?;
|
||||
|
||||
if let Ok(multi_position) = input.r#try(|i| LengthOrPercentage::parse(context, i)) {
|
||||
if let Ok(multi_position) = input.try(|i| LengthOrPercentage::parse(context, i)) {
|
||||
let stop_color = stop.color.clone();
|
||||
items.push(generic::GradientItem::ColorStop(stop));
|
||||
items.push(generic::GradientItem::ColorStop(ColorStop {
|
||||
|
@ -1010,7 +1008,7 @@ impl Parse for ColorStop {
|
|||
) -> Result<Self, ParseError<'i>> {
|
||||
Ok(ColorStop {
|
||||
color: Color::parse(context, input)?,
|
||||
position: input.r#try(|i| LengthOrPercentage::parse(context, i)).ok(),
|
||||
position: input.try(|i| LengthOrPercentage::parse(context, i)).ok(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1024,7 +1022,7 @@ impl Parse for PaintWorklet {
|
|||
input.parse_nested_block(|input| {
|
||||
let name = Atom::from(&**input.expect_ident()?);
|
||||
let arguments = input
|
||||
.r#try(|input| {
|
||||
.try(|input| {
|
||||
input.expect_comma()?;
|
||||
input.parse_comma_separated(|input| SpecifiedValue::parse(input))
|
||||
})
|
||||
|
@ -1039,7 +1037,7 @@ impl Parse for MozImageRect {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
input.r#try(|i| i.expect_function_matching("-moz-image-rect"))?;
|
||||
input.try(|i| i.expect_function_matching("-moz-image-rect"))?;
|
||||
input.parse_nested_block(|i| {
|
||||
let string = i.expect_url_or_string()?;
|
||||
let url = SpecifiedImageUrl::parse_from_string(string.as_ref().to_owned(), context);
|
||||
|
|
|
@ -11,9 +11,9 @@ use app_units::Au;
|
|||
use crate::font_metrics::FontMetricsQueryResult;
|
||||
use crate::parser::{Parse, ParserContext};
|
||||
use crate::values::computed::{self, CSSPixelLength, Context, ExtremumLength};
|
||||
use crate::values::generics::length::{
|
||||
MaxLength as GenericMaxLength, MozLength as GenericMozLength,
|
||||
};
|
||||
use crate::values::generics::length::MaxLength as GenericMaxLength;
|
||||
use crate::values::generics::length::MozLength as GenericMozLength;
|
||||
use crate::values::generics::transform::IsZeroLength;
|
||||
use crate::values::generics::NonNegative;
|
||||
use crate::values::specified::calc::CalcNode;
|
||||
use crate::values::{Auto, CSSFloat, Either, IsAuto, Normal};
|
||||
|
@ -99,6 +99,16 @@ impl FontBaseSize {
|
|||
}
|
||||
|
||||
impl FontRelativeLength {
|
||||
/// Return true if this is a zero value.
|
||||
fn is_zero(&self) -> bool {
|
||||
match *self {
|
||||
FontRelativeLength::Em(v) |
|
||||
FontRelativeLength::Ex(v) |
|
||||
FontRelativeLength::Ch(v) |
|
||||
FontRelativeLength::Rem(v) => v == 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the font-relative length.
|
||||
pub fn to_computed_value(&self, context: &Context, base_size: FontBaseSize) -> CSSPixelLength {
|
||||
use std::f32;
|
||||
|
@ -232,6 +242,16 @@ pub enum ViewportPercentageLength {
|
|||
}
|
||||
|
||||
impl ViewportPercentageLength {
|
||||
/// Return true if this is a zero value.
|
||||
fn is_zero(&self) -> bool {
|
||||
match *self {
|
||||
ViewportPercentageLength::Vw(v) |
|
||||
ViewportPercentageLength::Vh(v) |
|
||||
ViewportPercentageLength::Vmin(v) |
|
||||
ViewportPercentageLength::Vmax(v) => v == 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the given viewport-relative length for the given viewport size.
|
||||
pub fn to_computed_value(&self, viewport_size: Size2D<Au>) -> CSSPixelLength {
|
||||
let (factor, length) = match *self {
|
||||
|
@ -487,6 +507,18 @@ impl NoCalcLength {
|
|||
|
||||
impl SpecifiedValueInfo for NoCalcLength {}
|
||||
|
||||
impl IsZeroLength for NoCalcLength {
|
||||
#[inline]
|
||||
fn is_zero_length(&self) -> bool {
|
||||
match *self {
|
||||
NoCalcLength::Absolute(v) => v.is_zero(),
|
||||
NoCalcLength::FontRelative(v) => v.is_zero(),
|
||||
NoCalcLength::ViewportPercentage(v) => v.is_zero(),
|
||||
NoCalcLength::ServoCharacterWidth(v) => v.0 == 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An extension to `NoCalcLength` to parse `calc` expressions.
|
||||
/// This is commonly used for the `<length>` values.
|
||||
///
|
||||
|
@ -841,6 +873,17 @@ impl LengthOrPercentage {
|
|||
}
|
||||
}
|
||||
|
||||
impl IsZeroLength for LengthOrPercentage {
|
||||
#[inline]
|
||||
fn is_zero_length(&self) -> bool {
|
||||
match *self {
|
||||
LengthOrPercentage::Length(l) => l.is_zero_length(),
|
||||
LengthOrPercentage::Percentage(p) => p.0 == 0.0,
|
||||
LengthOrPercentage::Calc(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Either a `<length>`, a `<percentage>`, or the `auto` keyword.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
|
||||
|
@ -1184,7 +1227,7 @@ impl LengthOrNumber {
|
|||
// We try to parse as a Number first because, for cases like
|
||||
// LengthOrNumber, we want "0" to be parsed as a plain Number rather
|
||||
// than a Length (0px); this matches the behaviour of all major browsers
|
||||
if let Ok(v) = input.r#try(|i| Number::parse_non_negative(context, i)) {
|
||||
if let Ok(v) = input.try(|i| Number::parse_non_negative(context, i)) {
|
||||
return Ok(Either::Second(v));
|
||||
}
|
||||
|
||||
|
@ -1228,7 +1271,7 @@ impl MozLength {
|
|||
input: &mut Parser<'i, 't>,
|
||||
allow_quirks: AllowQuirks,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(l) = input.r#try(ExtremumLength::parse) {
|
||||
if let Ok(l) = input.try(ExtremumLength::parse) {
|
||||
return Ok(GenericMozLength::ExtremumLength(l));
|
||||
}
|
||||
|
||||
|
@ -1280,7 +1323,7 @@ impl MaxLength {
|
|||
input: &mut Parser<'i, 't>,
|
||||
allow_quirks: AllowQuirks,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(l) = input.r#try(ExtremumLength::parse) {
|
||||
if let Ok(l) = input.try(ExtremumLength::parse) {
|
||||
return Ok(GenericMaxLength::ExtremumLength(l));
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ impl Parse for ListStyleType {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(style) = input.r#try(|i| CounterStyleOrNone::parse(context, i)) {
|
||||
if let Ok(style) = input.try(|i| CounterStyleOrNone::parse(context, i)) {
|
||||
return Ok(ListStyleType::CounterStyle(style));
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ impl Parse for Quotes {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Quotes, ParseError<'i>> {
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("none"))
|
||||
.try(|input| input.expect_ident_matching("none"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(Quotes(Arc::new(Box::new([]))));
|
||||
|
|
|
@ -75,8 +75,8 @@ pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
|
|||
pub use self::svg_path::SVGPathData;
|
||||
pub use self::table::XSpan;
|
||||
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, MozTabSize, TextAlign};
|
||||
pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle};
|
||||
pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing};
|
||||
pub use self::text::{TextEmphasisPosition, TextEmphasisStyle};
|
||||
pub use self::time::Time;
|
||||
pub use self::transform::{Rotate, Scale, Transform};
|
||||
pub use self::transform::{TransformOrigin, TransformStyle, Translate};
|
||||
|
@ -359,7 +359,7 @@ impl NumberOrPercentage {
|
|||
input: &mut Parser<'i, 't>,
|
||||
type_: AllowedNumericType,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(per) = input.r#try(|i| Percentage::parse_with_clamping_mode(context, i, type_)) {
|
||||
if let Ok(per) = input.try(|i| Percentage::parse_with_clamping_mode(context, i, type_)) {
|
||||
return Ok(NumberOrPercentage::Percentage(per));
|
||||
}
|
||||
|
||||
|
@ -703,7 +703,7 @@ impl ClipRect {
|
|||
allow_quirks: AllowQuirks,
|
||||
) -> Result<Option<Length>, ParseError<'i>> {
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("auto"))
|
||||
.try(|input| input.expect_ident_matching("auto"))
|
||||
.is_ok()
|
||||
{
|
||||
Ok(None)
|
||||
|
@ -720,7 +720,7 @@ impl ClipRect {
|
|||
let bottom;
|
||||
let left;
|
||||
|
||||
if input.r#try(|input| input.expect_comma()).is_ok() {
|
||||
if input.try(|input| input.expect_comma()).is_ok() {
|
||||
right = parse_argument(context, input, allow_quirks)?;
|
||||
input.expect_comma()?;
|
||||
bottom = parse_argument(context, input, allow_quirks)?;
|
||||
|
@ -751,7 +751,7 @@ impl ClipRectOrAuto {
|
|||
input: &mut Parser<'i, 't>,
|
||||
allow_quirks: AllowQuirks,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(v) = input.r#try(|i| ClipRect::parse_quirky(context, i, allow_quirks)) {
|
||||
if let Ok(v) = input.try(|i| ClipRect::parse_quirky(context, i, allow_quirks)) {
|
||||
Ok(Either::First(v))
|
||||
} else {
|
||||
Auto::parse(context, input).map(Either::Second)
|
||||
|
@ -816,8 +816,8 @@ impl Attr {
|
|||
) -> Result<Attr, ParseError<'i>> {
|
||||
// Syntax is `[namespace? `|`]? ident`
|
||||
// no spaces allowed
|
||||
let first = input.r#try(|i| i.expect_ident_cloned()).ok();
|
||||
if let Ok(token) = input.r#try(|i| i.next_including_whitespace().map(|t| t.clone())) {
|
||||
let first = input.try(|i| i.expect_ident_cloned()).ok();
|
||||
if let Ok(token) = input.try(|i| i.next_including_whitespace().map(|t| t.clone())) {
|
||||
match token {
|
||||
Token::Delim('|') => {
|
||||
let location = input.current_source_location();
|
||||
|
|
|
@ -50,7 +50,7 @@ impl Parse for OffsetPath {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
// Parse none.
|
||||
if input.r#try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
return Ok(OffsetPath::none());
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ impl Parse for OutlineStyle {
|
|||
_context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<OutlineStyle, ParseError<'i>> {
|
||||
if let Ok(border_style) = input.r#try(BorderStyle::parse) {
|
||||
if let Ok(border_style) = input.try(BorderStyle::parse) {
|
||||
if let BorderStyle::Hidden = border_style {
|
||||
return Err(input
|
||||
.new_custom_error(SelectorParseErrorKind::UnexpectedIdent("hidden".into())));
|
||||
|
|
|
@ -10,9 +10,8 @@
|
|||
use crate::hash::FxHashMap;
|
||||
use crate::parser::{Parse, ParserContext};
|
||||
use crate::str::HTML_SPACE_CHARACTERS;
|
||||
use crate::values::computed::{
|
||||
CalcLengthOrPercentage, LengthOrPercentage as ComputedLengthOrPercentage,
|
||||
};
|
||||
use crate::values::computed::CalcLengthOrPercentage;
|
||||
use crate::values::computed::LengthOrPercentage as ComputedLengthOrPercentage;
|
||||
use crate::values::computed::{Context, Percentage, ToComputedValue};
|
||||
use crate::values::generics::position::Position as GenericPosition;
|
||||
use crate::values::generics::position::ZIndex as GenericZIndex;
|
||||
|
@ -102,28 +101,28 @@ impl Position {
|
|||
input: &mut Parser<'i, 't>,
|
||||
allow_quirks: AllowQuirks,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
match input.r#try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) {
|
||||
match input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) {
|
||||
Ok(x_pos @ PositionComponent::Center) => {
|
||||
if let Ok(y_pos) =
|
||||
input.r#try(|i| PositionComponent::parse_quirky(context, i, allow_quirks))
|
||||
input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks))
|
||||
{
|
||||
return Ok(Self::new(x_pos, y_pos));
|
||||
}
|
||||
let x_pos = input
|
||||
.r#try(|i| PositionComponent::parse_quirky(context, i, allow_quirks))
|
||||
.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks))
|
||||
.unwrap_or(x_pos);
|
||||
let y_pos = PositionComponent::Center;
|
||||
return Ok(Self::new(x_pos, y_pos));
|
||||
},
|
||||
Ok(PositionComponent::Side(x_keyword, lop)) => {
|
||||
if input.r#try(|i| i.expect_ident_matching("center")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("center")).is_ok() {
|
||||
let x_pos = PositionComponent::Side(x_keyword, lop);
|
||||
let y_pos = PositionComponent::Center;
|
||||
return Ok(Self::new(x_pos, y_pos));
|
||||
}
|
||||
if let Ok(y_keyword) = input.r#try(Y::parse) {
|
||||
if let Ok(y_keyword) = input.try(Y::parse) {
|
||||
let y_lop = input
|
||||
.r#try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks))
|
||||
.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks))
|
||||
.ok();
|
||||
let x_pos = PositionComponent::Side(x_keyword, lop);
|
||||
let y_pos = PositionComponent::Side(y_keyword, y_lop);
|
||||
|
@ -134,30 +133,30 @@ impl Position {
|
|||
return Ok(Self::new(x_pos, y_pos));
|
||||
},
|
||||
Ok(x_pos @ PositionComponent::Length(_)) => {
|
||||
if let Ok(y_keyword) = input.r#try(Y::parse) {
|
||||
if let Ok(y_keyword) = input.try(Y::parse) {
|
||||
let y_pos = PositionComponent::Side(y_keyword, None);
|
||||
return Ok(Self::new(x_pos, y_pos));
|
||||
}
|
||||
if let Ok(y_lop) =
|
||||
input.r#try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks))
|
||||
input.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks))
|
||||
{
|
||||
let y_pos = PositionComponent::Length(y_lop);
|
||||
return Ok(Self::new(x_pos, y_pos));
|
||||
}
|
||||
let y_pos = PositionComponent::Center;
|
||||
let _ = input.r#try(|i| i.expect_ident_matching("center"));
|
||||
let _ = input.try(|i| i.expect_ident_matching("center"));
|
||||
return Ok(Self::new(x_pos, y_pos));
|
||||
},
|
||||
Err(_) => {},
|
||||
}
|
||||
let y_keyword = Y::parse(input)?;
|
||||
let lop_and_x_pos: Result<_, ParseError> = input.r#try(|i| {
|
||||
let lop_and_x_pos: Result<_, ParseError> = input.try(|i| {
|
||||
let y_lop = i
|
||||
.r#try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks))
|
||||
.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks))
|
||||
.ok();
|
||||
if let Ok(x_keyword) = i.r#try(X::parse) {
|
||||
if let Ok(x_keyword) = i.try(X::parse) {
|
||||
let x_lop = i
|
||||
.r#try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks))
|
||||
.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks))
|
||||
.ok();
|
||||
let x_pos = PositionComponent::Side(x_keyword, x_lop);
|
||||
return Ok((y_lop, x_pos));
|
||||
|
@ -230,16 +229,15 @@ impl<S: Parse> PositionComponent<S> {
|
|||
input: &mut Parser<'i, 't>,
|
||||
allow_quirks: AllowQuirks,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input.r#try(|i| i.expect_ident_matching("center")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("center")).is_ok() {
|
||||
return Ok(PositionComponent::Center);
|
||||
}
|
||||
if let Ok(lop) = input.r#try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks))
|
||||
{
|
||||
if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)) {
|
||||
return Ok(PositionComponent::Length(lop));
|
||||
}
|
||||
let keyword = S::parse(context, input)?;
|
||||
let lop = input
|
||||
.r#try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks))
|
||||
.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks))
|
||||
.ok();
|
||||
Ok(PositionComponent::Side(keyword, lop))
|
||||
}
|
||||
|
@ -360,51 +358,51 @@ impl LegacyPosition {
|
|||
input: &mut Parser<'i, 't>,
|
||||
allow_quirks: AllowQuirks,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
match input.r#try(|i| OriginComponent::parse(context, i)) {
|
||||
match input.try(|i| OriginComponent::parse(context, i)) {
|
||||
Ok(x_pos @ OriginComponent::Center) => {
|
||||
if let Ok(y_pos) = input.r#try(|i| OriginComponent::parse(context, i)) {
|
||||
if let Ok(y_pos) = input.try(|i| OriginComponent::parse(context, i)) {
|
||||
return Ok(Self::new(x_pos, y_pos));
|
||||
}
|
||||
let x_pos = input
|
||||
.r#try(|i| OriginComponent::parse(context, i))
|
||||
.try(|i| OriginComponent::parse(context, i))
|
||||
.unwrap_or(x_pos);
|
||||
let y_pos = OriginComponent::Center;
|
||||
return Ok(Self::new(x_pos, y_pos));
|
||||
},
|
||||
Ok(OriginComponent::Side(x_keyword)) => {
|
||||
if let Ok(y_keyword) = input.r#try(Y::parse) {
|
||||
if let Ok(y_keyword) = input.try(Y::parse) {
|
||||
let x_pos = OriginComponent::Side(x_keyword);
|
||||
let y_pos = OriginComponent::Side(y_keyword);
|
||||
return Ok(Self::new(x_pos, y_pos));
|
||||
}
|
||||
let x_pos = OriginComponent::Side(x_keyword);
|
||||
if let Ok(y_lop) =
|
||||
input.r#try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks))
|
||||
input.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks))
|
||||
{
|
||||
return Ok(Self::new(x_pos, OriginComponent::Length(y_lop)));
|
||||
}
|
||||
let _ = input.r#try(|i| i.expect_ident_matching("center"));
|
||||
let _ = input.try(|i| i.expect_ident_matching("center"));
|
||||
return Ok(Self::new(x_pos, OriginComponent::Center));
|
||||
},
|
||||
Ok(x_pos @ OriginComponent::Length(_)) => {
|
||||
if let Ok(y_keyword) = input.r#try(Y::parse) {
|
||||
if let Ok(y_keyword) = input.try(Y::parse) {
|
||||
let y_pos = OriginComponent::Side(y_keyword);
|
||||
return Ok(Self::new(x_pos, y_pos));
|
||||
}
|
||||
if let Ok(y_lop) =
|
||||
input.r#try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks))
|
||||
input.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks))
|
||||
{
|
||||
let y_pos = OriginComponent::Length(y_lop);
|
||||
return Ok(Self::new(x_pos, y_pos));
|
||||
}
|
||||
let _ = input.r#try(|i| i.expect_ident_matching("center"));
|
||||
let _ = input.try(|i| i.expect_ident_matching("center"));
|
||||
return Ok(Self::new(x_pos, OriginComponent::Center));
|
||||
},
|
||||
Err(_) => {},
|
||||
}
|
||||
let y_keyword = Y::parse(input)?;
|
||||
let x_pos: Result<_, ParseError> = input.r#try(|i| {
|
||||
if let Ok(x_keyword) = i.r#try(X::parse) {
|
||||
let x_pos: Result<_, ParseError> = input.try(|i| {
|
||||
if let Ok(x_keyword) = i.try(X::parse) {
|
||||
let x_pos = OriginComponent::Side(x_keyword);
|
||||
return Ok(x_pos);
|
||||
}
|
||||
|
@ -649,7 +647,7 @@ impl Parse for TemplateAreas {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let mut strings = vec![];
|
||||
while let Ok(string) = input.r#try(|i| i.expect_string().map(|s| s.as_ref().into())) {
|
||||
while let Ok(string) = input.try(|i| i.expect_string().map(|s| s.as_ref().into())) {
|
||||
strings.push(string);
|
||||
}
|
||||
|
||||
|
@ -743,7 +741,7 @@ impl Parse for ZIndex {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input.r#try(|i| i.expect_ident_matching("auto")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
|
||||
return Ok(GenericZIndex::Auto);
|
||||
}
|
||||
Ok(GenericZIndex::Integer(Integer::parse(context, input)?))
|
||||
|
|
|
@ -92,7 +92,7 @@ impl Parse for SourceSizeOrLength {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(size) = input.r#try(|input| SourceSize::parse(context, input)) {
|
||||
if let Ok(size) = input.try(|input| SourceSize::parse(context, input)) {
|
||||
return Ok(SourceSizeOrLength::SourceSize(size));
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,8 @@ use crate::parser::{Parse, ParserContext};
|
|||
use crate::values::generics::svg as generic;
|
||||
use crate::values::specified::color::Color;
|
||||
use crate::values::specified::url::SpecifiedUrl;
|
||||
use crate::values::specified::{
|
||||
LengthOrPercentage, NonNegativeLengthOrPercentage, NonNegativeNumber,
|
||||
};
|
||||
use crate::values::specified::LengthOrPercentage;
|
||||
use crate::values::specified::{NonNegativeLengthOrPercentage, NonNegativeNumber};
|
||||
use crate::values::specified::{Number, Opacity};
|
||||
use crate::values::CustomIdent;
|
||||
use cssparser::Parser;
|
||||
|
@ -63,7 +62,7 @@ impl Parse for SVGLength {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
input
|
||||
.r#try(|i| SvgLengthOrPercentageOrNumber::parse(context, i))
|
||||
.try(|i| SvgLengthOrPercentageOrNumber::parse(context, i))
|
||||
.map(Into::into)
|
||||
.or_else(|_| parse_context_value(input, generic::SVGLength::ContextValue))
|
||||
}
|
||||
|
@ -89,7 +88,7 @@ impl Parse for SVGWidth {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
input
|
||||
.r#try(|i| NonNegativeSvgLengthOrPercentageOrNumber::parse(context, i))
|
||||
.try(|i| NonNegativeSvgLengthOrPercentageOrNumber::parse(context, i))
|
||||
.map(Into::into)
|
||||
.or_else(|_| parse_context_value(input, generic::SVGLength::ContextValue))
|
||||
}
|
||||
|
@ -109,13 +108,13 @@ impl Parse for SVGStrokeDashArray {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(values) = input.r#try(|i| {
|
||||
if let Ok(values) = input.try(|i| {
|
||||
CommaWithSpace::parse(i, |i| {
|
||||
NonNegativeSvgLengthOrPercentageOrNumber::parse(context, i)
|
||||
})
|
||||
}) {
|
||||
Ok(generic::SVGStrokeDashArray::Values(values))
|
||||
} else if let Ok(_) = input.r#try(|i| i.expect_ident_matching("none")) {
|
||||
} else if let Ok(_) = input.try(|i| i.expect_ident_matching("none")) {
|
||||
Ok(generic::SVGStrokeDashArray::Values(vec![]))
|
||||
} else {
|
||||
parse_context_value(input, generic::SVGStrokeDashArray::ContextValue)
|
||||
|
@ -131,7 +130,7 @@ impl Parse for SVGOpacity {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(opacity) = input.r#try(|i| Opacity::parse(context, i)) {
|
||||
if let Ok(opacity) = input.try(|i| Opacity::parse(context, i)) {
|
||||
return Ok(generic::SVGOpacity::Opacity(opacity));
|
||||
}
|
||||
|
||||
|
@ -196,7 +195,7 @@ impl Parse for SVGPaintOrder {
|
|||
_context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<SVGPaintOrder, ParseError<'i>> {
|
||||
if let Ok(()) = input.r#try(|i| i.expect_ident_matching("normal")) {
|
||||
if let Ok(()) = input.try(|i| i.expect_ident_matching("normal")) {
|
||||
return Ok(SVGPaintOrder::normal());
|
||||
}
|
||||
|
||||
|
@ -207,7 +206,7 @@ impl Parse for SVGPaintOrder {
|
|||
let mut pos = 0;
|
||||
|
||||
loop {
|
||||
let result: Result<_, ParseError> = input.r#try(|input| {
|
||||
let result: Result<_, ParseError> = input.try(|input| {
|
||||
try_match_ident_ignore_ascii_case! { input,
|
||||
"fill" => Ok(PaintOrder::Fill),
|
||||
"stroke" => Ok(PaintOrder::Stroke),
|
||||
|
|
|
@ -15,9 +15,8 @@ use crate::values::generics::text::InitialLetter as GenericInitialLetter;
|
|||
use crate::values::generics::text::LineHeight as GenericLineHeight;
|
||||
use crate::values::generics::text::MozTabSize as GenericMozTabSize;
|
||||
use crate::values::generics::text::Spacing;
|
||||
use crate::values::specified::length::{
|
||||
FontRelativeLength, Length, LengthOrPercentage, NoCalcLength,
|
||||
};
|
||||
use crate::values::specified::length::{FontRelativeLength, Length};
|
||||
use crate::values::specified::length::{LengthOrPercentage, NoCalcLength};
|
||||
use crate::values::specified::length::{NonNegativeLength, NonNegativeLengthOrPercentage};
|
||||
use crate::values::specified::{AllowQuirks, Integer, NonNegativeNumber, Number};
|
||||
use cssparser::{Parser, Token};
|
||||
|
@ -45,11 +44,11 @@ impl Parse for InitialLetter {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input.r#try(|i| i.expect_ident_matching("normal")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("normal")).is_ok() {
|
||||
return Ok(GenericInitialLetter::Normal);
|
||||
}
|
||||
let size = Number::parse_at_least_one(context, input)?;
|
||||
let sink = input.r#try(|i| Integer::parse_positive(context, i)).ok();
|
||||
let sink = input.try(|i| Integer::parse_positive(context, i)).ok();
|
||||
Ok(GenericInitialLetter::Specified(size, sink))
|
||||
}
|
||||
}
|
||||
|
@ -81,10 +80,10 @@ impl Parse for LineHeight {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(number) = input.r#try(|i| NonNegativeNumber::parse(context, i)) {
|
||||
if let Ok(number) = input.try(|i| NonNegativeNumber::parse(context, i)) {
|
||||
return Ok(GenericLineHeight::Number(number));
|
||||
}
|
||||
if let Ok(nlop) = input.r#try(|i| NonNegativeLengthOrPercentage::parse(context, i)) {
|
||||
if let Ok(nlop) = input.try(|i| NonNegativeLengthOrPercentage::parse(context, i)) {
|
||||
return Ok(GenericLineHeight::Length(nlop));
|
||||
}
|
||||
let location = input.current_source_location();
|
||||
|
@ -215,7 +214,7 @@ impl Parse for TextOverflow {
|
|||
) -> Result<TextOverflow, ParseError<'i>> {
|
||||
let first = TextOverflowSide::parse(context, input)?;
|
||||
let second = input
|
||||
.r#try(|input| TextOverflowSide::parse(context, input))
|
||||
.try(|input| TextOverflowSide::parse(context, input))
|
||||
.ok();
|
||||
Ok(TextOverflow { first, second })
|
||||
}
|
||||
|
@ -295,14 +294,14 @@ macro_rules! impl_text_decoration_line {
|
|||
) -> Result<TextDecorationLine, ParseError<'i>> {
|
||||
let mut result = TextDecorationLine::NONE;
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("none"))
|
||||
.try(|input| input.expect_ident_matching("none"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
loop {
|
||||
let result = input.r#try(|input| {
|
||||
let result = input.try(|input| {
|
||||
let ident = input.expect_ident().map_err(|_| ())?;
|
||||
match_ignore_ascii_case! { ident,
|
||||
$(
|
||||
|
@ -380,71 +379,44 @@ impl TextDecorationLine {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! define_text_align_keyword {
|
||||
($(
|
||||
$(#[$($meta:tt)+])*
|
||||
$name: ident => $discriminant: expr,
|
||||
)+) => {
|
||||
/// Specified value of text-align keyword value.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq,
|
||||
SpecifiedValueInfo, ToComputedValue, ToCss)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum TextAlignKeyword {
|
||||
$(
|
||||
$(#[$($meta)+])*
|
||||
$name = $discriminant,
|
||||
)+
|
||||
}
|
||||
|
||||
impl TextAlignKeyword {
|
||||
/// Construct a TextAlignKeyword from u32.
|
||||
pub fn from_u32(discriminant: u32) -> Option<TextAlignKeyword> {
|
||||
match discriminant {
|
||||
$(
|
||||
$discriminant => Some(TextAlignKeyword::$name),
|
||||
)+
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(emilio): Why reinventing the world?
|
||||
#[cfg(feature = "gecko")]
|
||||
define_text_align_keyword! {
|
||||
Start => 0,
|
||||
End => 1,
|
||||
Left => 2,
|
||||
Right => 3,
|
||||
Center => 4,
|
||||
Justify => 5,
|
||||
MozCenter => 6,
|
||||
MozLeft => 7,
|
||||
MozRight => 8,
|
||||
/// Specified value of text-align keyword value.
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Eq,
|
||||
FromPrimitive,
|
||||
Hash,
|
||||
MallocSizeOf,
|
||||
Parse,
|
||||
PartialEq,
|
||||
SpecifiedValueInfo,
|
||||
ToComputedValue,
|
||||
ToCss,
|
||||
)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum TextAlignKeyword {
|
||||
Start,
|
||||
End,
|
||||
Left,
|
||||
Right,
|
||||
Center,
|
||||
Justify,
|
||||
#[cfg(feature = "gecko")]
|
||||
MozCenter,
|
||||
#[cfg(feature = "gecko")]
|
||||
MozLeft,
|
||||
#[cfg(feature = "gecko")]
|
||||
MozRight,
|
||||
#[cfg(feature = "servo")]
|
||||
ServoCenter,
|
||||
#[cfg(feature = "servo")]
|
||||
ServoLeft,
|
||||
#[cfg(feature = "servo")]
|
||||
ServoRight,
|
||||
#[css(skip)]
|
||||
Char => 10,
|
||||
}
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
define_text_align_keyword! {
|
||||
Start => 0,
|
||||
End => 1,
|
||||
Left => 2,
|
||||
Right => 3,
|
||||
Center => 4,
|
||||
Justify => 5,
|
||||
ServoCenter => 6,
|
||||
ServoLeft => 7,
|
||||
ServoRight => 8,
|
||||
}
|
||||
|
||||
impl TextAlignKeyword {
|
||||
/// Return the initial value of TextAlignKeyword.
|
||||
#[inline]
|
||||
pub fn start() -> TextAlignKeyword {
|
||||
TextAlignKeyword::Start
|
||||
}
|
||||
#[cfg(feature = "gecko")]
|
||||
Char,
|
||||
}
|
||||
|
||||
/// Specified value of text-align property.
|
||||
|
@ -471,7 +443,7 @@ impl Parse for TextAlign {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
// MozCenterOrInherit cannot be parsed, only set directly on the elements
|
||||
if let Ok(key) = input.r#try(TextAlignKeyword::parse) {
|
||||
if let Ok(key) = input.try(TextAlignKeyword::parse) {
|
||||
return Ok(TextAlign::Keyword(key));
|
||||
}
|
||||
#[cfg(feature = "gecko")]
|
||||
|
@ -510,7 +482,7 @@ impl ToComputedValue for TextAlign {
|
|||
// but we want to set it to right -- instead set it to the default (`start`),
|
||||
// which will do the right thing in this case (but not the general case)
|
||||
if _context.is_root_element {
|
||||
return TextAlignKeyword::start();
|
||||
return TextAlignKeyword::Start;
|
||||
}
|
||||
let parent = _context
|
||||
.builder
|
||||
|
@ -661,6 +633,8 @@ impl ToComputedValue for TextEmphasisStyle {
|
|||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||
match *self {
|
||||
TextEmphasisStyle::Keyword(ref keyword) => {
|
||||
// FIXME(emilio): This should set the rule_cache_conditions
|
||||
// properly.
|
||||
let default_shape = if context.style().get_inherited_box().clone_writing_mode() ==
|
||||
SpecifiedWritingMode::HorizontalTb
|
||||
{
|
||||
|
@ -682,6 +656,7 @@ impl ToComputedValue for TextEmphasisStyle {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||
match *computed {
|
||||
|
@ -702,22 +677,22 @@ impl Parse for TextEmphasisStyle {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("none"))
|
||||
.try(|input| input.expect_ident_matching("none"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(TextEmphasisStyle::None);
|
||||
}
|
||||
|
||||
if let Ok(s) = input.r#try(|i| i.expect_string().map(|s| s.as_ref().to_owned())) {
|
||||
if let Ok(s) = input.try(|i| i.expect_string().map(|s| s.as_ref().to_owned())) {
|
||||
// Handle <string>
|
||||
return Ok(TextEmphasisStyle::String(s));
|
||||
}
|
||||
|
||||
// Handle a pair of keywords
|
||||
let mut shape = input.r#try(TextEmphasisShapeKeyword::parse).ok();
|
||||
let fill = input.r#try(TextEmphasisFillMode::parse).ok();
|
||||
let mut shape = input.try(TextEmphasisShapeKeyword::parse).ok();
|
||||
let fill = input.try(TextEmphasisFillMode::parse).ok();
|
||||
if shape.is_none() {
|
||||
shape = input.r#try(TextEmphasisShapeKeyword::parse).ok();
|
||||
shape = input.try(TextEmphasisShapeKeyword::parse).ok();
|
||||
}
|
||||
|
||||
// At least one of shape or fill must be handled
|
||||
|
@ -817,7 +792,7 @@ impl Parse for TextEmphasisPosition {
|
|||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(horizontal) =
|
||||
input.r#try(|input| TextEmphasisHorizontalWritingModeValue::parse(input))
|
||||
input.try(|input| TextEmphasisHorizontalWritingModeValue::parse(input))
|
||||
{
|
||||
let vertical = TextEmphasisVerticalWritingModeValue::parse(input)?;
|
||||
Ok(TextEmphasisPosition(horizontal, vertical))
|
||||
|
@ -869,7 +844,7 @@ impl Parse for MozTabSize {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if let Ok(number) = input.r#try(|i| NonNegativeNumber::parse(context, i)) {
|
||||
if let Ok(number) = input.try(|i| NonNegativeNumber::parse(context, i)) {
|
||||
// Numbers need to be parsed first because `0` must be recognised
|
||||
// as the number `0` and not the length `0px`.
|
||||
return Ok(GenericMozTabSize::Number(number));
|
||||
|
@ -879,3 +854,24 @@ impl Parse for MozTabSize {
|
|||
)?))
|
||||
}
|
||||
}
|
||||
|
||||
/// Values for the `overflow-wrap` property.
|
||||
#[repr(u8)]
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Eq,
|
||||
MallocSizeOf,
|
||||
Parse,
|
||||
PartialEq,
|
||||
SpecifiedValueInfo,
|
||||
ToComputedValue,
|
||||
ToCss,
|
||||
)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum OverflowWrap {
|
||||
Normal,
|
||||
BreakWord,
|
||||
Anywhere,
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ impl Transform {
|
|||
use style_traits::{Separator, Space};
|
||||
|
||||
if input
|
||||
.r#try(|input| input.expect_ident_matching("none"))
|
||||
.try(|input| input.expect_ident_matching("none"))
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(generic::Transform(Vec::new()));
|
||||
|
@ -106,7 +106,7 @@ impl Transform {
|
|||
},
|
||||
"translate" => {
|
||||
let sx = specified::LengthOrPercentage::parse(context, input)?;
|
||||
if input.r#try(|input| input.expect_comma()).is_ok() {
|
||||
if input.try(|input| input.expect_comma()).is_ok() {
|
||||
let sy = specified::LengthOrPercentage::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::Translate(sx, Some(sy)))
|
||||
} else {
|
||||
|
@ -135,7 +135,7 @@ impl Transform {
|
|||
},
|
||||
"scale" => {
|
||||
let sx = Number::parse(context, input)?;
|
||||
if input.r#try(|input| input.expect_comma()).is_ok() {
|
||||
if input.try(|input| input.expect_comma()).is_ok() {
|
||||
let sy = Number::parse(context, input)?;
|
||||
Ok(generic::TransformOperation::Scale(sx, Some(sy)))
|
||||
} else {
|
||||
|
@ -191,7 +191,7 @@ impl Transform {
|
|||
},
|
||||
"skew" => {
|
||||
let ax = specified::Angle::parse_with_unitless(context, input)?;
|
||||
if input.r#try(|input| input.expect_comma()).is_ok() {
|
||||
if input.try(|input| input.expect_comma()).is_ok() {
|
||||
let ay = specified::Angle::parse_with_unitless(context, input)?;
|
||||
Ok(generic::TransformOperation::Skew(ax, Some(ay)))
|
||||
} else {
|
||||
|
@ -248,17 +248,17 @@ impl Parse for TransformOrigin {
|
|||
) -> Result<Self, ParseError<'i>> {
|
||||
let parse_depth = |input: &mut Parser| {
|
||||
input
|
||||
.r#try(|i| Length::parse(context, i))
|
||||
.try(|i| Length::parse(context, i))
|
||||
.unwrap_or(Length::from_px(0.))
|
||||
};
|
||||
match input.r#try(|i| OriginComponent::parse(context, i)) {
|
||||
match input.try(|i| OriginComponent::parse(context, i)) {
|
||||
Ok(x_origin @ OriginComponent::Center) => {
|
||||
if let Ok(y_origin) = input.r#try(|i| OriginComponent::parse(context, i)) {
|
||||
if let Ok(y_origin) = input.try(|i| OriginComponent::parse(context, i)) {
|
||||
let depth = parse_depth(input);
|
||||
return Ok(Self::new(x_origin, y_origin, depth));
|
||||
}
|
||||
let y_origin = OriginComponent::Center;
|
||||
if let Ok(x_keyword) = input.r#try(X::parse) {
|
||||
if let Ok(x_keyword) = input.try(X::parse) {
|
||||
let x_origin = OriginComponent::Side(x_keyword);
|
||||
let depth = parse_depth(input);
|
||||
return Ok(Self::new(x_origin, y_origin, depth));
|
||||
|
@ -267,7 +267,7 @@ impl Parse for TransformOrigin {
|
|||
return Ok(Self::new(x_origin, y_origin, depth));
|
||||
},
|
||||
Ok(x_origin) => {
|
||||
if let Ok(y_origin) = input.r#try(|i| OriginComponent::parse(context, i)) {
|
||||
if let Ok(y_origin) = input.try(|i| OriginComponent::parse(context, i)) {
|
||||
let depth = parse_depth(input);
|
||||
return Ok(Self::new(x_origin, y_origin, depth));
|
||||
}
|
||||
|
@ -279,12 +279,12 @@ impl Parse for TransformOrigin {
|
|||
}
|
||||
let y_keyword = Y::parse(input)?;
|
||||
let y_origin = OriginComponent::Side(y_keyword);
|
||||
if let Ok(x_keyword) = input.r#try(X::parse) {
|
||||
if let Ok(x_keyword) = input.try(X::parse) {
|
||||
let x_origin = OriginComponent::Side(x_keyword);
|
||||
let depth = parse_depth(input);
|
||||
return Ok(Self::new(x_origin, y_origin, depth));
|
||||
}
|
||||
if input.r#try(|i| i.expect_ident_matching("center")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("center")).is_ok() {
|
||||
let x_origin = OriginComponent::Center;
|
||||
let depth = parse_depth(input);
|
||||
return Ok(Self::new(x_origin, y_origin, depth));
|
||||
|
@ -303,10 +303,10 @@ where
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input.r#try(|i| i.expect_ident_matching("center")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("center")).is_ok() {
|
||||
return Ok(OriginComponent::Center);
|
||||
}
|
||||
if let Ok(lop) = input.r#try(|i| LengthOrPercentage::parse(context, i)) {
|
||||
if let Ok(lop) = input.try(|i| LengthOrPercentage::parse(context, i)) {
|
||||
return Ok(OriginComponent::Length(lop));
|
||||
}
|
||||
let keyword = S::parse(context, input)?;
|
||||
|
@ -353,11 +353,11 @@ impl Parse for Rotate {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input.r#try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
return Ok(generic::Rotate::None);
|
||||
}
|
||||
|
||||
if let Ok(rx) = input.r#try(|i| Number::parse(context, i)) {
|
||||
if let Ok(rx) = input.try(|i| Number::parse(context, i)) {
|
||||
// 'rotate: <number>{3} <angle>'
|
||||
let ry = Number::parse(context, input)?;
|
||||
let rz = Number::parse(context, input)?;
|
||||
|
@ -379,13 +379,13 @@ impl Parse for Translate {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input.r#try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
return Ok(generic::Translate::None);
|
||||
}
|
||||
|
||||
let tx = specified::LengthOrPercentage::parse(context, input)?;
|
||||
if let Ok(ty) = input.r#try(|i| specified::LengthOrPercentage::parse(context, i)) {
|
||||
if let Ok(tz) = input.r#try(|i| specified::Length::parse(context, i)) {
|
||||
if let Ok(ty) = input.try(|i| specified::LengthOrPercentage::parse(context, i)) {
|
||||
if let Ok(tz) = input.try(|i| specified::Length::parse(context, i)) {
|
||||
// 'translate: <length-percentage> <length-percentage> <length>'
|
||||
return Ok(generic::Translate::Translate3D(tx, ty, tz));
|
||||
}
|
||||
|
@ -395,7 +395,10 @@ impl Parse for Translate {
|
|||
}
|
||||
|
||||
// 'translate: <length-percentage> '
|
||||
Ok(generic::Translate::TranslateX(tx))
|
||||
Ok(generic::Translate::Translate(
|
||||
tx,
|
||||
specified::LengthOrPercentage::zero(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -407,13 +410,13 @@ impl Parse for Scale {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input.r#try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
return Ok(generic::Scale::None);
|
||||
}
|
||||
|
||||
let sx = Number::parse(context, input)?;
|
||||
if let Ok(sy) = input.r#try(|i| Number::parse(context, i)) {
|
||||
if let Ok(sz) = input.r#try(|i| Number::parse(context, i)) {
|
||||
if let Ok(sy) = input.try(|i| Number::parse(context, i)) {
|
||||
if let Ok(sz) = input.try(|i| Number::parse(context, i)) {
|
||||
// 'scale: <number> <number> <number>'
|
||||
return Ok(generic::Scale::Scale3D(sx, sy, sz));
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ impl Parse for Cursor {
|
|||
) -> Result<Self, ParseError<'i>> {
|
||||
let mut images = vec![];
|
||||
loop {
|
||||
match input.r#try(|input| CursorImage::parse(context, input)) {
|
||||
match input.try(|input| CursorImage::parse(context, input)) {
|
||||
Ok(image) => images.push(image),
|
||||
Err(_) => break,
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ impl Parse for CursorImage {
|
|||
) -> Result<Self, ParseError<'i>> {
|
||||
Ok(Self {
|
||||
url: SpecifiedImageUrl::parse(context, input)?,
|
||||
hotspot: match input.r#try(|input| Number::parse(context, input)) {
|
||||
hotspot: match input.try(|input| Number::parse(context, input)) {
|
||||
Ok(number) => Some((number, Number::parse(context, input)?)),
|
||||
Err(_) => None,
|
||||
},
|
||||
|
@ -131,7 +131,7 @@ impl Parse for ScrollbarColor {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input.r#try(|i| i.expect_ident_matching("auto")).is_ok() {
|
||||
if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
|
||||
return Ok(generics::ScrollbarColor::Auto);
|
||||
}
|
||||
Ok(generics::ScrollbarColor::Colors {
|
||||
|
|
|
@ -324,7 +324,7 @@ impl Separator for Space {
|
|||
let mut results = vec![parse_one(input)?];
|
||||
loop {
|
||||
input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less.
|
||||
if let Ok(item) = input.r#try(&mut parse_one) {
|
||||
if let Ok(item) = input.try(&mut parse_one) {
|
||||
results.push(item);
|
||||
} else {
|
||||
return Ok(results);
|
||||
|
@ -350,9 +350,9 @@ impl Separator for CommaWithSpace {
|
|||
loop {
|
||||
input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less.
|
||||
let comma_location = input.current_source_location();
|
||||
let comma = input.r#try(|i| i.expect_comma()).is_ok();
|
||||
let comma = input.try(|i| i.expect_comma()).is_ok();
|
||||
input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less.
|
||||
if let Ok(item) = input.r#try(&mut parse_one) {
|
||||
if let Ok(item) = input.try(&mut parse_one) {
|
||||
results.push(item);
|
||||
} else if comma {
|
||||
return Err(comma_location.new_unexpected_token_error(Token::Comma));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue