diff options
Diffstat (limited to 'components/style')
33 files changed, 384 insertions, 127 deletions
diff --git a/components/style/animation.rs b/components/style/animation.rs index 0a5a9921d2e..ed5a5c602f8 100644 --- a/components/style/animation.rs +++ b/components/style/animation.rs @@ -468,7 +468,8 @@ fn compute_style_for_animation_step(context: &SharedStyleContext, /* cascade_info = */ None, &*context.error_reporter, font_metrics_provider, - CascadeFlags::empty()); + CascadeFlags::empty(), + context.quirks_mode); computed } } diff --git a/components/style/encoding_support.rs b/components/style/encoding_support.rs index b61c743051f..2775de54893 100644 --- a/components/style/encoding_support.rs +++ b/components/style/encoding_support.rs @@ -6,6 +6,7 @@ extern crate encoding; +use context::QuirksMode; use cssparser::{stylesheet_encoding, EncodingSupport}; use error_reporting::ParseErrorReporter; use media_queries::MediaList; @@ -56,7 +57,8 @@ impl Stylesheet { media: MediaList, shared_lock: SharedRwLock, stylesheet_loader: Option<&StylesheetLoader>, - error_reporter: &ParseErrorReporter) + error_reporter: &ParseErrorReporter, + quirks_mode: QuirksMode) -> Stylesheet { let (string, _) = decode_stylesheet_bytes( bytes, protocol_encoding_label, environment_encoding); @@ -67,6 +69,7 @@ impl Stylesheet { shared_lock, stylesheet_loader, error_reporter, + quirks_mode, 0u64) } diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 4aff56ee8d5..8aa3b2da396 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -5,6 +5,7 @@ //! Gecko's media-query device and expression representation. use app_units::Au; +use context::QuirksMode; use cssparser::{CssStringWriter, Parser, Token}; use euclid::Size2D; use font_metrics::get_metrics_provider_for_product; @@ -521,7 +522,7 @@ impl Expression { } /// Returns whether this media query evaluates to true for the given device. - pub fn matches(&self, device: &Device) -> bool { + pub fn matches(&self, device: &Device, quirks_mode: QuirksMode) -> bool { let mut css_value = nsCSSValue::null(); unsafe { (self.feature.mGetter.unwrap())(device.pres_context, @@ -534,12 +535,13 @@ impl Expression { None => return false, }; - self.evaluate_against(device, &value) + self.evaluate_against(device, &value, quirks_mode) } fn evaluate_against(&self, device: &Device, - actual_value: &MediaExpressionValue) + actual_value: &MediaExpressionValue, + quirks_mode: QuirksMode) -> bool { use self::MediaExpressionValue::*; use std::cmp::Ordering; @@ -564,6 +566,8 @@ impl Expression { style: default_values.clone(), font_metrics_provider: &provider, in_media_query: true, + // TODO: pass the correct value here. + quirks_mode: quirks_mode, }; let required_value = match self.value { diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 62a2d835d1a..177aa5987b6 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -16,7 +16,7 @@ use app_units::Au; use atomic_refcell::AtomicRefCell; -use context::{SharedStyleContext, UpdateAnimationsTasks}; +use context::{QuirksMode, SharedStyleContext, UpdateAnimationsTasks}; use data::ElementData; use dom::{self, AnimationRules, DescendantsBit, LayoutIterator, NodeInfo, TElement, TNode, UnsafeNode}; use dom::{OpaqueNode, PresentationalHintsSynthetizer}; @@ -325,7 +325,7 @@ impl<'le> GeckoElement<'le> { /// Parse the style attribute of an element. pub fn parse_style_attribute(value: &str, url_data: &UrlExtraData) -> PropertyDeclarationBlock { - parse_style_attribute(value, url_data, &RustLogReporter) + parse_style_attribute(value, url_data, &RustLogReporter, QuirksMode::NoQuirks) } fn flags(&self) -> u32 { diff --git a/components/style/keyframes.rs b/components/style/keyframes.rs index fb8290fedf4..8113c06bb6c 100644 --- a/components/style/keyframes.rs +++ b/components/style/keyframes.rs @@ -131,7 +131,8 @@ impl Keyframe { &parent_stylesheet.url_data, &error_reporter, Some(CssRuleType::Keyframe), - LengthParsingMode::Default); + LengthParsingMode::Default, + parent_stylesheet.quirks_mode); let mut input = Parser::new(css); let mut rule_parser = KeyframeListParser { diff --git a/components/style/matching.rs b/components/style/matching.rs index b3696a0b7b7..2ac1e4d2e18 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -483,7 +483,8 @@ trait PrivateMatchMethods: TElement { Some(&mut cascade_info), &*shared_context.error_reporter, font_metrics_provider, - cascade_flags)); + cascade_flags, + shared_context.quirks_mode)); cascade_info.finish(&self.as_node()); values diff --git a/components/style/media_queries.rs b/components/style/media_queries.rs index 10a29509bd1..4f1b3d68a12 100644 --- a/components/style/media_queries.rs +++ b/components/style/media_queries.rs @@ -7,6 +7,7 @@ //! [mq]: https://drafts.csswg.org/mediaqueries/ use Atom; +use context::QuirksMode; use cssparser::{Delimiter, Parser, Token}; use parser::ParserContext; use serialize_comma_separated_list; @@ -280,7 +281,7 @@ pub fn parse_media_query_list(context: &ParserContext, input: &mut Parser) -> Me impl MediaList { /// Evaluate a whole `MediaList` against `Device`. - pub fn evaluate(&self, device: &Device) -> bool { + pub fn evaluate(&self, device: &Device, quirks_mode: QuirksMode) -> bool { // Check if it is an empty media query list or any queries match (OR condition) // https://drafts.csswg.org/mediaqueries-4/#mq-list self.media_queries.is_empty() || self.media_queries.iter().any(|mq| { @@ -290,7 +291,7 @@ impl MediaList { let query_match = media_match && mq.expressions.iter() - .all(|expression| expression.matches(&device)); + .all(|expression| expression.matches(&device, quirks_mode)); // Apply the logical NOT qualifier to the result match mq.qualifier { diff --git a/components/style/parser.rs b/components/style/parser.rs index b82d21ace4f..bac1252228a 100644 --- a/components/style/parser.rs +++ b/components/style/parser.rs @@ -6,6 +6,7 @@ #![deny(missing_docs)] +use context::QuirksMode; use cssparser::{Parser, SourcePosition, UnicodeRange}; use error_reporting::ParseErrorReporter; use style_traits::OneOrMoreCommaSeparated; @@ -44,6 +45,8 @@ pub struct ParserContext<'a> { pub line_number_offset: u64, /// The mode to use when parsing lengths. pub length_parsing_mode: LengthParsingMode, + /// The quirks mode of this stylesheet. + pub quirks_mode: QuirksMode, } impl<'a> ParserContext<'a> { @@ -52,7 +55,8 @@ impl<'a> ParserContext<'a> { url_data: &'a UrlExtraData, error_reporter: &'a ParseErrorReporter, rule_type: Option<CssRuleType>, - length_parsing_mode: LengthParsingMode) + length_parsing_mode: LengthParsingMode, + quirks_mode: QuirksMode) -> ParserContext<'a> { ParserContext { stylesheet_origin: stylesheet_origin, @@ -61,6 +65,7 @@ impl<'a> ParserContext<'a> { rule_type: rule_type, line_number_offset: 0u64, length_parsing_mode: length_parsing_mode, + quirks_mode: quirks_mode, } } @@ -68,9 +73,10 @@ impl<'a> ParserContext<'a> { pub fn new_for_cssom(url_data: &'a UrlExtraData, error_reporter: &'a ParseErrorReporter, rule_type: Option<CssRuleType>, - length_parsing_mode: LengthParsingMode) + length_parsing_mode: LengthParsingMode, + quirks_mode: QuirksMode) -> ParserContext<'a> { - Self::new(Origin::Author, url_data, error_reporter, rule_type, length_parsing_mode) + Self::new(Origin::Author, url_data, error_reporter, rule_type, length_parsing_mode, quirks_mode) } /// Create a parser context based on a previous context, but with a modified rule type. @@ -84,6 +90,7 @@ impl<'a> ParserContext<'a> { rule_type: rule_type, line_number_offset: context.line_number_offset, length_parsing_mode: context.length_parsing_mode, + quirks_mode: context.quirks_mode, } } @@ -92,7 +99,8 @@ impl<'a> ParserContext<'a> { url_data: &'a UrlExtraData, error_reporter: &'a ParseErrorReporter, line_number_offset: u64, - length_parsing_mode: LengthParsingMode) + length_parsing_mode: LengthParsingMode, + quirks_mode: QuirksMode) -> ParserContext<'a> { ParserContext { stylesheet_origin: stylesheet_origin, @@ -101,6 +109,7 @@ impl<'a> ParserContext<'a> { rule_type: None, line_number_offset: line_number_offset, length_parsing_mode: length_parsing_mode, + quirks_mode: quirks_mode, } } diff --git a/components/style/properties/data.py b/components/style/properties/data.py index c935e00a79f..8db09e6fe81 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -140,7 +140,7 @@ class Longhand(object): need_clone=False, need_index=False, gecko_ffi_name=None, depend_on_viewport_size=False, allowed_in_keyframe_block=True, complex_color=False, cast_type='u8', has_uncacheable_values=False, logical=False, alias=None, extra_prefixes=None, boxed=False, - flags=None, allowed_in_page_rule=False): + flags=None, allowed_in_page_rule=False, allow_quirks=False): self.name = name if not spec: raise TypeError("Spec should be specified for %s" % name) @@ -166,6 +166,7 @@ class Longhand(object): self.boxed = arg_to_bool(boxed) self.flags = flags.split() if flags else [] self.allowed_in_page_rule = arg_to_bool(allowed_in_page_rule) + self.allow_quirks = allow_quirks # https://drafts.csswg.org/css-animations/#keyframes # > The <declaration-list> inside of <keyframe-block> accepts any CSS property diff --git a/components/style/properties/declaration_block.rs b/components/style/properties/declaration_block.rs index d652ab21c96..7b53a49626a 100644 --- a/components/style/properties/declaration_block.rs +++ b/components/style/properties/declaration_block.rs @@ -6,6 +6,7 @@ #![deny(missing_docs)] +use context::QuirksMode; use cssparser::{DeclarationListParser, parse_important}; use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter}; use error_reporting::ParseErrorReporter; @@ -641,13 +642,15 @@ pub fn append_serialization<'a, W, I, N>(dest: &mut W, /// shared between Servo and Gecko. pub fn parse_style_attribute(input: &str, url_data: &UrlExtraData, - error_reporter: &ParseErrorReporter) + error_reporter: &ParseErrorReporter, + quirks_mode: QuirksMode) -> PropertyDeclarationBlock { let context = ParserContext::new(Origin::Author, url_data, error_reporter, Some(CssRuleType::Style), - LengthParsingMode::Default); + LengthParsingMode::Default, + quirks_mode); parse_property_declaration_list(&context, &mut Parser::new(input)) } @@ -660,13 +663,15 @@ pub fn parse_one_declaration(id: PropertyId, input: &str, url_data: &UrlExtraData, error_reporter: &ParseErrorReporter, - length_parsing_mode: LengthParsingMode) + length_parsing_mode: LengthParsingMode, + quirks_mode: QuirksMode) -> Result<ParsedDeclaration, ()> { let context = ParserContext::new(Origin::Author, url_data, error_reporter, Some(CssRuleType::Style), - length_parsing_mode); + length_parsing_mode, + quirks_mode); Parser::new(input).parse_entirely(|parser| { ParsedDeclaration::parse(id, &context, parser) .map_err(|_| ()) diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index 5d13f91e282..478e1be659b 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -8,11 +8,13 @@ %> <%def name="predefined_type(name, type, initial_value, parse_method='parse', - needs_context=True, vector=False, computed_type=None, initial_specified_value=None, **kwargs)"> + needs_context=True, vector=False, computed_type=None, initial_specified_value=None, + allow_quirks=False, **kwargs)"> <%def name="predefined_type_inner(name, type, initial_value, parse_method)"> #[allow(unused_imports)] use app_units::Au; use cssparser::{Color as CSSParserColor, RGBA}; + use values::specified::AllowQuirks; pub use values::specified::${type} as SpecifiedValue; pub mod computed_value { % if computed_type: @@ -30,7 +32,9 @@ pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { - % if needs_context: + % if allow_quirks: + specified::${type}::${parse_method}_quirky(context, input, AllowQuirks::Yes) + % elif needs_context: specified::${type}::${parse_method}(context, input) % else: specified::${type}::${parse_method}(input) @@ -277,6 +281,7 @@ % if not property.derived_from: { let custom_props = context.style().custom_properties(); + let quirks_mode = context.quirks_mode; ::properties::substitute_variables_${property.ident}( &declared_value, &custom_props, |value| { @@ -349,7 +354,7 @@ } } } - }, error_reporter); + }, error_reporter, quirks_mode); } % if property.custom_cascade: @@ -370,7 +375,11 @@ parse(context, input).map(|result| Box::new(result)) % else: -> Result<SpecifiedValue, ()> { - parse(context, input) + % if property.allow_quirks: + parse_quirky(context, input, specified::AllowQuirks::Yes) + % else: + parse(context, input) + % endif % endif } pub fn parse_declared(context: &ParserContext, input: &mut Parser) @@ -800,7 +809,8 @@ % endif </%def> -<%def name="four_sides_shorthand(name, sub_property_pattern, parser_function, needs_context=True, **kwargs)"> +<%def name="four_sides_shorthand(name, sub_property_pattern, parser_function, + needs_context=True, allow_quirks=False, **kwargs)"> <% sub_properties=' '.join(sub_property_pattern % side for side in ['top', 'right', 'bottom', 'left']) %> <%call expr="self.shorthand(name, sub_properties=sub_properties, **kwargs)"> #[allow(unused_imports)] @@ -810,7 +820,9 @@ pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { let (top, right, bottom, left) = - % if needs_context: + % if allow_quirks: + try!(parse_four_sides(input, |i| ${parser_function}_quirky(context, i, specified::AllowQuirks::Yes))); + % elif needs_context: try!(parse_four_sides(input, |i| ${parser_function}(context, i))); % else: try!(parse_four_sides(input, ${parser_function})); diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index cd384da294a..6e8cefc74c5 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -515,6 +515,7 @@ impl AnimationValue { % if prop.animatable: LonghandId::${prop.camel_case} => { let mut result = None; + let quirks_mode = context.quirks_mode; ::properties::substitute_variables_${prop.ident}_slow( &variables.css, variables.first_token_type, @@ -533,7 +534,8 @@ impl AnimationValue { }; result = AnimationValue::from_declaration(&declaration, context, initial); }, - &reporter); + &reporter, + quirks_mode); result }, % else: diff --git a/components/style/properties/longhand/border.mako.rs b/components/style/properties/longhand/border.mako.rs index df5cb06f1cc..a540b515a82 100644 --- a/components/style/properties/longhand/border.mako.rs +++ b/components/style/properties/longhand/border.mako.rs @@ -33,7 +33,9 @@ computed_type="::app_units::Au", alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-width"), spec=maybe_logical_spec(side, "width"), - animation_value_type="ComputedValue", logical=side[1])} + animation_value_type="ComputedValue", + logical=side[1], + allow_quirks=not side[1])} % endfor ${helpers.gecko_keyword_conversion(Keyword('border-style', diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 9afcae44701..9c445436d0f 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -264,6 +264,7 @@ ${helpers.single_keyword("position", "static absolute relative fixed", use std::fmt; use style_traits::ToCss; use values::HasViewportPercentage; + use values::specified::AllowQuirks; <% vertical_align = data.longhands_by_name["vertical-align"] %> <% vertical_align.keyword = Keyword("vertical-align", @@ -306,7 +307,7 @@ ${helpers.single_keyword("position", "static absolute relative fixed", /// baseline | sub | super | top | text-top | middle | bottom | text-bottom /// | <percentage> | <length> pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { - input.try(|i| specified::LengthOrPercentage::parse(context, i)) + input.try(|i| specified::LengthOrPercentage::parse_quirky(context, i, AllowQuirks::Yes)) .map(SpecifiedValue::LengthOrPercentage) .or_else(|_| { match_ignore_ascii_case! { &try!(input.expect_ident()), diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index 6bdc67037d3..02df590ee9d 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -550,14 +550,14 @@ ${helpers.single_keyword_system("font-variant-caps", </%helpers:longhand> <%helpers:longhand name="font-size" need_clone="True" animation_value_type="ComputedValue" - spec="https://drafts.csswg.org/css-fonts/#propdef-font-size"> + allow_quirks="True" spec="https://drafts.csswg.org/css-fonts/#propdef-font-size"> use app_units::Au; use properties::longhands::system_font::SystemFont; use properties::style_structs::Font; use std::fmt; use style_traits::ToCss; use values::{FONT_MEDIUM_PX, HasViewportPercentage}; - use values::specified::{FontRelativeLength, LengthOrPercentage, Length}; + use values::specified::{AllowQuirks, FontRelativeLength, LengthOrPercentage, Length}; use values::specified::{NoCalcLength, Percentage}; use values::specified::length::FontBaseSize; @@ -843,9 +843,19 @@ ${helpers.single_keyword_system("font-variant-caps", )) } } + /// <length> | <percentage> | <absolute-size> | <relative-size> pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { - if let Ok(lop) = input.try(|i| specified::LengthOrPercentage::parse_non_negative(context, i)) { + parse_quirky(context, input, AllowQuirks::No) + } + + /// Parses a font-size, with quirks. + pub fn parse_quirky(context: &ParserContext, + input: &mut Parser, + allow_quirks: AllowQuirks) + -> Result<SpecifiedValue, ()> { + use self::specified::LengthOrPercentage; + if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative_quirky(context, i, allow_quirks)) { return Ok(SpecifiedValue::Length(lop)) } diff --git a/components/style/properties/longhand/inherited_table.mako.rs b/components/style/properties/longhand/inherited_table.mako.rs index a66de2691db..5caaa17195d 100644 --- a/components/style/properties/longhand/inherited_table.mako.rs +++ b/components/style/properties/longhand/inherited_table.mako.rs @@ -26,6 +26,7 @@ ${helpers.single_keyword("caption-side", "top bottom", use std::fmt; use style_traits::ToCss; use values::HasViewportPercentage; + use values::specified::{AllowQuirks, Length}; pub mod computed_value { use app_units::Au; @@ -73,8 +74,8 @@ ${helpers.single_keyword("caption-side", "top bottom", #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct SpecifiedValue { - pub horizontal: specified::Length, - pub vertical: Option<specified::Length>, + pub horizontal: Length, + pub vertical: Option<Length>, } #[inline] @@ -130,11 +131,11 @@ ${helpers.single_keyword("caption-side", "top bottom", pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> { let mut first = None; let mut second = None; - match specified::Length::parse_non_negative(context, input) { + match Length::parse_non_negative_quirky(context, input, AllowQuirks::Yes) { Err(()) => (), Ok(length) => { first = Some(length); - if let Ok(len) = input.try(|input| specified::Length::parse_non_negative(context, input)) { + if let Ok(len) = input.try(|i| Length::parse_non_negative_quirky(context, i, AllowQuirks::Yes)) { second = Some(len); } } diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs index bbd2f51964d..c2e85e43b4b 100644 --- a/components/style/properties/longhand/inherited_text.mako.rs +++ b/components/style/properties/longhand/inherited_text.mako.rs @@ -184,7 +184,8 @@ ${helpers.predefined_type("text-indent", "LengthOrPercentage", "computed::LengthOrPercentage::Length(Au(0))", animation_value_type="ComputedValue", - spec="https://drafts.csswg.org/css-text/#propdef-text-indent")} + spec="https://drafts.csswg.org/css-text/#propdef-text-indent", + allow_quirks=True)} // Also known as "word-wrap" (which is more popular because of IE), but this is the preferred // name per CSS-TEXT 6.2. @@ -411,6 +412,7 @@ ${helpers.single_keyword("text-align-last", use std::fmt; use style_traits::ToCss; use values::HasViewportPercentage; + use values::specified::AllowQuirks; impl HasViewportPercentage for SpecifiedValue { fn has_viewport_percentage(&self) -> bool { @@ -487,7 +489,7 @@ ${helpers.single_keyword("text-align-last", if input.try(|input| input.expect_ident_matching("normal")).is_ok() { Ok(SpecifiedValue::Normal) } else { - specified::Length::parse(context, input).map(SpecifiedValue::Specified) + specified::Length::parse_quirky(context, input, AllowQuirks::Yes).map(SpecifiedValue::Specified) } } </%helpers:longhand> @@ -497,6 +499,7 @@ ${helpers.single_keyword("text-align-last", use std::fmt; use style_traits::ToCss; use values::HasViewportPercentage; + use values::specified::AllowQuirks; impl HasViewportPercentage for SpecifiedValue { fn has_viewport_percentage(&self) -> bool { @@ -572,7 +575,7 @@ ${helpers.single_keyword("text-align-last", if input.try(|input| input.expect_ident_matching("normal")).is_ok() { Ok(SpecifiedValue::Normal) } else { - specified::LengthOrPercentage::parse(context, input) + specified::LengthOrPercentage::parse_quirky(context, input, AllowQuirks::Yes) .map(SpecifiedValue::Specified) } } diff --git a/components/style/properties/longhand/margin.mako.rs b/components/style/properties/longhand/margin.mako.rs index 1fe4e7cca61..5c8a62aa01f 100644 --- a/components/style/properties/longhand/margin.mako.rs +++ b/components/style/properties/longhand/margin.mako.rs @@ -15,6 +15,7 @@ ${helpers.predefined_type("margin-%s" % side[0], "LengthOrPercentageOrAuto", "computed::LengthOrPercentageOrAuto::Length(Au(0))", alias=maybe_moz_logical_alias(product, side, "-moz-margin-%s"), + allow_quirks=not side[1], animation_value_type="ComputedValue", logical = side[1], spec = spec, allowed_in_page_rule=True)} % endfor diff --git a/components/style/properties/longhand/padding.mako.rs b/components/style/properties/longhand/padding.mako.rs index 593deb769ac..ce74320f220 100644 --- a/components/style/properties/longhand/padding.mako.rs +++ b/components/style/properties/longhand/padding.mako.rs @@ -18,5 +18,6 @@ alias=maybe_moz_logical_alias(product, side, "-moz-padding-%s"), animation_value_type="ComputedValue", logical = side[1], - spec = spec)} + spec = spec, + allow_quirks=not side[1])} % endfor diff --git a/components/style/properties/longhand/position.mako.rs b/components/style/properties/longhand/position.mako.rs index 3f995b10873..757c270bb49 100644 --- a/components/style/properties/longhand/position.mako.rs +++ b/components/style/properties/longhand/position.mako.rs @@ -13,7 +13,8 @@ ${helpers.predefined_type(side, "LengthOrPercentageOrAuto", "computed::LengthOrPercentageOrAuto::Auto", spec="https://www.w3.org/TR/CSS2/visuren.html#propdef-%s" % side, - animation_value_type="ComputedValue")} + animation_value_type="ComputedValue", + allow_quirks=True)} % endfor // offset-* logical properties, map to "top" / "left" / "bottom" / "right" % for side in LOGICAL_SIDES: @@ -157,6 +158,7 @@ ${helpers.predefined_type("flex-basis", "computed::LengthOrPercentageOrAuto::Auto", "parse_non_negative", spec=spec % size, + allow_quirks=not logical, animation_value_type="ComputedValue", logical = logical)} % if product == "gecko": % for min_max in ["min", "max"]: @@ -177,7 +179,7 @@ ${helpers.predefined_type("flex-basis", use std::fmt; use style_traits::ToCss; use values::HasViewportPercentage; - use values::specified::${MinMax}Length; + use values::specified::{AllowQuirks, ${MinMax}Length}; impl HasViewportPercentage for SpecifiedValue { fn has_viewport_percentage(&self) -> bool { @@ -199,7 +201,11 @@ ${helpers.predefined_type("flex-basis", ${MinMax}Length::${initial} } fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { + % if logical: let ret = ${MinMax}Length::parse(context, input); + % else: + let ret = ${MinMax}Length::parse_quirky(context, input, AllowQuirks::Yes); + % endif // Keyword values don't make sense in the block direction; don't parse them % if "block" in size: if let Ok(${MinMax}Length::ExtremumLength(..)) = ret { @@ -254,13 +260,17 @@ ${helpers.predefined_type("flex-basis", "computed::LengthOrPercentage::Length(Au(0))", "parse_non_negative", spec=spec % ("min-%s" % size), - animation_value_type="ComputedValue", logical = logical)} + animation_value_type="ComputedValue", + logical=logical, + allow_quirks=not logical)} ${helpers.predefined_type("max-%s" % size, "LengthOrPercentageOrNone", "computed::LengthOrPercentageOrNone::None", "parse_non_negative", spec=spec % ("min-%s" % size), - animation_value_type="ComputedValue", logical = logical)} + animation_value_type="ComputedValue", + logical=logical, + allow_quirks=not logical)} % endif % endfor diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 60da6d89704..4a736c38e36 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -21,6 +21,7 @@ use cssparser::{Parser, TokenSerializationType}; use error_reporting::ParseErrorReporter; #[cfg(feature = "servo")] use euclid::side_offsets::SideOffsets2D; use computed_values; +use context::QuirksMode; use font_metrics::FontMetricsProvider; #[cfg(feature = "gecko")] use gecko_bindings::bindings; #[cfg(feature = "gecko")] use gecko_bindings::structs::{self, nsCSSPropertyID}; @@ -328,7 +329,8 @@ impl PropertyDeclarationIdSet { % endif custom_properties: &Option<Arc<::custom_properties::ComputedValuesMap>>, f: F, - error_reporter: &ParseErrorReporter) + error_reporter: &ParseErrorReporter, + quirks_mode: QuirksMode) % if property.boxed: where F: FnOnce(&DeclaredValue<Box<longhands::${property.ident}::SpecifiedValue>>) % else: @@ -342,7 +344,8 @@ impl PropertyDeclarationIdSet { with_variables.from_shorthand, custom_properties, f, - error_reporter); + error_reporter, + quirks_mode); } else { f(value); } @@ -357,7 +360,8 @@ impl PropertyDeclarationIdSet { from_shorthand: Option<ShorthandId>, custom_properties: &Option<Arc<::custom_properties::ComputedValuesMap>>, f: F, - error_reporter: &ParseErrorReporter) + error_reporter: &ParseErrorReporter, + quirks_mode: QuirksMode) % if property.boxed: where F: FnOnce(&DeclaredValue<Box<longhands::${property.ident}::SpecifiedValue>>) % else: @@ -375,7 +379,8 @@ impl PropertyDeclarationIdSet { url_data, error_reporter, None, - LengthParsingMode::Default); + LengthParsingMode::Default, + quirks_mode); Parser::new(&css).parse_entirely(|input| { match from_shorthand { None => { @@ -2116,7 +2121,8 @@ pub fn cascade(device: &Device, cascade_info: Option<<&mut CascadeInfo>, error_reporter: &ParseErrorReporter, font_metrics_provider: &FontMetricsProvider, - flags: CascadeFlags) + flags: CascadeFlags, + quirks_mode: QuirksMode) -> ComputedValues { debug_assert_eq!(parent_style.is_some(), layout_parent_style.is_some()); let (is_root_element, inherited_style, layout_parent_style) = match parent_style { @@ -2162,7 +2168,8 @@ pub fn cascade(device: &Device, cascade_info, error_reporter, font_metrics_provider, - flags) + flags, + quirks_mode) } /// NOTE: This function expects the declaration with more priority to appear @@ -2177,7 +2184,8 @@ pub fn apply_declarations<'a, F, I>(device: &Device, mut cascade_info: Option<<&mut CascadeInfo>, error_reporter: &ParseErrorReporter, font_metrics_provider: &FontMetricsProvider, - flags: CascadeFlags) + flags: CascadeFlags, + quirks_mode: QuirksMode) -> ComputedValues where F: Fn() -> I, I: Iterator<Item = &'a PropertyDeclaration>, @@ -2230,6 +2238,7 @@ pub fn apply_declarations<'a, F, I>(device: &Device, style: starting_style, font_metrics_provider: font_metrics_provider, in_media_query: false, + quirks_mode: quirks_mode, }; // Set computed values, overwriting earlier declarations for the same diff --git a/components/style/properties/shorthand/background.mako.rs b/components/style/properties/shorthand/background.mako.rs index 8eaa94772f1..ab19507702f 100644 --- a/components/style/properties/shorthand/background.mako.rs +++ b/components/style/properties/shorthand/background.mako.rs @@ -194,8 +194,8 @@ sub_properties="background-position-x background-position-y" spec="https://drafts.csswg.org/css-backgrounds-4/#the-background-position"> use properties::longhands::{background_position_x,background_position_y}; + use values::specified::AllowQuirks; use values::specified::position::Position; - use parser::Parse; pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { let mut position_x = background_position_x::SpecifiedValue(Vec::new()); @@ -204,7 +204,7 @@ try!(input.parse_comma_separated(|input| { loop { - if let Ok(value) = input.try(|input| Position::parse(context, input)) { + if let Ok(value) = input.try(|input| Position::parse_quirky(context, input, AllowQuirks::Yes)) { position_x.0.push(value.horizontal); position_y.0.push(value.vertical); any = true; diff --git a/components/style/properties/shorthand/border.mako.rs b/components/style/properties/shorthand/border.mako.rs index 00fc89b0cec..223e5069d59 100644 --- a/components/style/properties/shorthand/border.mako.rs +++ b/components/style/properties/shorthand/border.mako.rs @@ -17,11 +17,12 @@ ${helpers.four_sides_shorthand("border-style", "border-%s-style", for side in PHYSICAL_SIDES)}" spec="https://drafts.csswg.org/css-backgrounds/#border-width"> use super::parse_four_sides; - use parser::Parse; - use values::specified; + use values::specified::{AllowQuirks, BorderWidth}; pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> { - let (top, right, bottom, left) = try!(parse_four_sides(input, |i| specified::BorderWidth::parse(context, i))); + let (top, right, bottom, left) = try!(parse_four_sides(input, |i| { + BorderWidth::parse_quirky(context, i, AllowQuirks::Yes) + })); Ok(Longhands { % for side in PHYSICAL_SIDES: ${to_rust_ident('border-%s-width' % side)}: ${side}, diff --git a/components/style/properties/shorthand/margin.mako.rs b/components/style/properties/shorthand/margin.mako.rs index 4dcaa71e626..07b6ba6bbed 100644 --- a/components/style/properties/shorthand/margin.mako.rs +++ b/components/style/properties/shorthand/margin.mako.rs @@ -6,4 +6,5 @@ ${helpers.four_sides_shorthand("margin", "margin-%s", "specified::LengthOrPercentageOrAuto::parse", spec="https://drafts.csswg.org/css-box/#propdef-margin", - allowed_in_page_rule=True)} + allowed_in_page_rule=True, + allow_quirks=True)} diff --git a/components/style/properties/shorthand/padding.mako.rs b/components/style/properties/shorthand/padding.mako.rs index a0e94f8bdcb..c07a80b1e04 100644 --- a/components/style/properties/shorthand/padding.mako.rs +++ b/components/style/properties/shorthand/padding.mako.rs @@ -5,4 +5,5 @@ <%namespace name="helpers" file="/helpers.mako.rs" /> ${helpers.four_sides_shorthand("padding", "padding-%s", "specified::LengthOrPercentage::parse", - spec="https://drafts.csswg.org/css-box-3/#propdef-padding")} + spec="https://drafts.csswg.org/css-box-3/#propdef-padding", + allow_quirks=True)} diff --git a/components/style/servo/media_queries.rs b/components/style/servo/media_queries.rs index c2ff1cb828d..4756d5bb705 100644 --- a/components/style/servo/media_queries.rs +++ b/components/style/servo/media_queries.rs @@ -5,6 +5,7 @@ //! Servo's media-query device and expression representation. use app_units::Au; +use context::QuirksMode; use cssparser::Parser; use euclid::{Size2D, TypedSize2D}; use font_metrics::ServoMetricsProvider; @@ -128,12 +129,12 @@ impl Expression { /// Evaluate this expression and return whether it matches the current /// device. - pub fn matches(&self, device: &Device) -> bool { + pub fn matches(&self, device: &Device, quirks_mode: QuirksMode) -> bool { let viewport_size = device.au_viewport_size(); let value = viewport_size.width; match self.0 { ExpressionKind::Width(ref range) => { - match range.to_computed_range(device) { + match range.to_computed_range(device, quirks_mode) { Range::Min(ref width) => { value >= *width }, Range::Max(ref width) => { value <= *width }, Range::Eq(ref width) => { value == *width }, @@ -175,7 +176,7 @@ pub enum Range<T> { } impl Range<specified::Length> { - fn to_computed_range(&self, device: &Device) -> Range<Au> { + fn to_computed_range(&self, device: &Device, quirks_mode: QuirksMode) -> Range<Au> { let default_values = device.default_computed_values(); // http://dev.w3.org/csswg/mediaqueries3/#units // em units are relative to the initial font-size. @@ -192,6 +193,7 @@ impl Range<specified::Length> { // ch units can exist in media queries. font_metrics_provider: &ServoMetricsProvider, in_media_query: true, + quirks_mode: quirks_mode, }; match *self { diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 9986328cb00..97dfce4c51f 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -7,6 +7,7 @@ #![deny(missing_docs)] use {Atom, Prefix, Namespace}; +use context::QuirksMode; use counter_style::{CounterStyleRule, parse_counter_style_name, parse_counter_style_body}; use cssparser::{AtRuleParser, Parser, QualifiedRuleParser}; use cssparser::{AtRuleType, RuleListParser, parse_one_rule}; @@ -263,6 +264,8 @@ pub struct Stylesheet { pub dirty_on_viewport_size_change: AtomicBool, /// Whether this stylesheet should be disabled. pub disabled: AtomicBool, + /// The quirks mode of this stylesheet. + pub quirks_mode: QuirksMode, } @@ -415,7 +418,8 @@ impl CssRule { &parent_stylesheet.url_data, &error_reporter, None, - LengthParsingMode::Default); + LengthParsingMode::Default, + parent_stylesheet.quirks_mode); let mut input = Parser::new(css); // nested rules are in the body state @@ -663,7 +667,7 @@ impl Stylesheet { let (rules, dirty_on_viewport_size_change) = Stylesheet::parse_rules( css, url_data, existing.origin, &mut namespaces, &existing.shared_lock, stylesheet_loader, error_reporter, - 0u64); + existing.quirks_mode, 0u64); *existing.namespaces.write() = namespaces; existing.dirty_on_viewport_size_change @@ -681,6 +685,7 @@ impl Stylesheet { shared_lock: &SharedRwLock, stylesheet_loader: Option<&StylesheetLoader>, error_reporter: &ParseErrorReporter, + quirks_mode: QuirksMode, line_number_offset: u64) -> (Vec<CssRule>, bool) { let mut rules = Vec::new(); @@ -691,7 +696,8 @@ impl Stylesheet { shared_lock: shared_lock, loader: stylesheet_loader, context: ParserContext::new_with_line_number_offset(origin, url_data, error_reporter, - line_number_offset, LengthParsingMode::Default), + line_number_offset, LengthParsingMode::Default, + quirks_mode), state: Cell::new(State::Start), }; @@ -726,11 +732,13 @@ impl Stylesheet { shared_lock: SharedRwLock, stylesheet_loader: Option<&StylesheetLoader>, error_reporter: &ParseErrorReporter, - line_number_offset: u64) -> Stylesheet { + quirks_mode: QuirksMode, + line_number_offset: u64) + -> Stylesheet { let mut namespaces = Namespaces::default(); let (rules, dirty_on_viewport_size_change) = Stylesheet::parse_rules( css, &url_data, origin, &mut namespaces, - &shared_lock, stylesheet_loader, error_reporter, line_number_offset + &shared_lock, stylesheet_loader, error_reporter, quirks_mode, line_number_offset, ); Stylesheet { origin: origin, @@ -741,6 +749,7 @@ impl Stylesheet { shared_lock: shared_lock, dirty_on_viewport_size_change: AtomicBool::new(dirty_on_viewport_size_change), disabled: AtomicBool::new(false), + quirks_mode: quirks_mode, } } @@ -769,7 +778,7 @@ impl Stylesheet { /// /// Always true if no associated MediaList exists. pub fn is_effective_for_device(&self, device: &Device, guard: &SharedRwLockReadGuard) -> bool { - self.media.read_with(guard).evaluate(device) + self.media.read_with(guard).evaluate(device, self.quirks_mode) } /// Return an iterator over the effective rules within the style-sheet, as @@ -781,7 +790,7 @@ impl Stylesheet { #[inline] pub fn effective_rules<F>(&self, device: &Device, guard: &SharedRwLockReadGuard, mut f: F) where F: FnMut(&CssRule) { - effective_rules(&self.rules.read_with(guard).0, device, guard, &mut f); + effective_rules(&self.rules.read_with(guard).0, device, self.quirks_mode, guard, &mut f); } /// Returns whether the stylesheet has been explicitly disabled through the @@ -802,17 +811,22 @@ impl Stylesheet { } } -fn effective_rules<F>(rules: &[CssRule], device: &Device, guard: &SharedRwLockReadGuard, f: &mut F) -where F: FnMut(&CssRule) { +fn effective_rules<F>(rules: &[CssRule], + device: &Device, + quirks_mode: QuirksMode, + guard: &SharedRwLockReadGuard, + f: &mut F) + where F: FnMut(&CssRule) +{ for rule in rules { f(rule); rule.with_nested_rules_and_mq(guard, |rules, mq| { if let Some(media_queries) = mq { - if !media_queries.evaluate(device) { + if !media_queries.evaluate(device, quirks_mode) { return } } - effective_rules(rules, device, guard, f) + effective_rules(rules, device, quirks_mode, guard, f) }) } } @@ -973,6 +987,7 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> { namespaces: RwLock::new(Namespaces::default()), dirty_on_viewport_size_change: AtomicBool::new(false), disabled: AtomicBool::new(false), + quirks_mode: self.context.quirks_mode, }) } }, &mut |import_rule| { diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 8791498f687..cb4848f3b98 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -8,6 +8,7 @@ use {Atom, LocalName}; use bit_vec::BitVec; +use context::QuirksMode; use data::ComputedStyle; use dom::{AnimationRules, PresentationalHintsSynthetizer, TElement}; use error_reporting::RustLogReporter; @@ -76,7 +77,7 @@ pub struct Stylist { viewport_constraints: Option<ViewportConstraints>, /// If true, the quirks-mode stylesheet is applied. - quirks_mode: bool, + quirks_mode: QuirksMode, /// If true, the device has changed, and the stylist needs to be updated. is_device_dirty: bool, @@ -166,7 +167,7 @@ impl Stylist { viewport_constraints: None, device: Arc::new(device), is_device_dirty: true, - quirks_mode: false, + quirks_mode: QuirksMode::NoQuirks, element_map: PerPseudoElementSelectorMap::new(), pseudos_map: Default::default(), @@ -240,7 +241,7 @@ impl Stylist { }; self.viewport_constraints = - ViewportConstraints::maybe_new(&self.device, &cascaded_rule); + ViewportConstraints::maybe_new(&self.device, &cascaded_rule, self.quirks_mode); if let Some(ref constraints) = self.viewport_constraints { Arc::get_mut(&mut self.device).unwrap() @@ -269,7 +270,7 @@ impl Stylist { self.add_stylesheet(&stylesheet, guards.ua_or_user, extra_data); } - if self.quirks_mode { + if self.quirks_mode != QuirksMode::NoQuirks { self.add_stylesheet(&ua_stylesheets.quirks_mode_stylesheet, guards.ua_or_user, extra_data); } @@ -424,7 +425,8 @@ impl Stylist { None, &RustLogReporter, font_metrics, - cascade_flags); + cascade_flags, + self.quirks_mode); ComputedStyle::new(rule_node, Arc::new(computed)) } @@ -548,7 +550,8 @@ impl Stylist { None, &RustLogReporter, font_metrics, - CascadeFlags::empty()); + CascadeFlags::empty(), + self.quirks_mode); Some(ComputedStyle::new(rule_node, Arc::new(computed))) } @@ -581,22 +584,22 @@ impl Stylist { }; self.viewport_constraints = - ViewportConstraints::maybe_new(&device, &cascaded_rule); + ViewportConstraints::maybe_new(&device, &cascaded_rule, self.quirks_mode); if let Some(ref constraints) = self.viewport_constraints { device.account_for_viewport_rule(constraints); } fn mq_eval_changed(guard: &SharedRwLockReadGuard, rules: &[CssRule], - before: &Device, after: &Device) -> bool { + before: &Device, after: &Device, quirks_mode: QuirksMode) -> bool { for rule in rules { let changed = rule.with_nested_rules_and_mq(guard, |rules, mq| { if let Some(mq) = mq { - if mq.evaluate(before) != mq.evaluate(after) { + if mq.evaluate(before, quirks_mode) != mq.evaluate(after, quirks_mode) { return true } } - mq_eval_changed(guard, rules, before, after) + mq_eval_changed(guard, rules, before, after, quirks_mode) }); if changed { return true @@ -606,11 +609,11 @@ impl Stylist { } self.is_device_dirty |= stylesheets.iter().any(|stylesheet| { let mq = stylesheet.media.read_with(guard); - if mq.evaluate(&self.device) != mq.evaluate(&device) { + if mq.evaluate(&self.device, self.quirks_mode) != mq.evaluate(&device, self.quirks_mode) { return true } - mq_eval_changed(guard, &stylesheet.rules.read_with(guard).0, &self.device, &device) + mq_eval_changed(guard, &stylesheet.rules.read_with(guard).0, &self.device, &device, self.quirks_mode) }); self.device = Arc::new(device); @@ -623,14 +626,14 @@ impl Stylist { } /// Sets the quirks mode of the document. - pub fn set_quirks_mode(&mut self, enabled: bool) { + pub fn set_quirks_mode(&mut self, quirks_mode: QuirksMode) { // FIXME(emilio): We don't seem to change the quirks mode dynamically // during multiple layout passes, but this is totally bogus, in the // sense that it's updated asynchronously. // // This should probably be an argument to `update`, and use the quirks // mode info in the `SharedLayoutContext`. - self.quirks_mode = enabled; + self.quirks_mode = quirks_mode; } /// Returns the applicable CSS declarations for the given element. @@ -893,7 +896,8 @@ impl Stylist { None, &RustLogReporter, &metrics, - CascadeFlags::empty())) + CascadeFlags::empty(), + self.quirks_mode)) } } diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 4b4588fbe4f..9f739660877 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -4,6 +4,7 @@ //! Computed values. +use context::QuirksMode; use euclid::size::Size2D; use font_metrics::FontMetricsProvider; use media_queries::Device; @@ -63,6 +64,9 @@ pub struct Context<'a> { /// Whether or not we are computing the media list in a media query pub in_media_query: bool, + + /// The quirks mode of this context. + pub quirks_mode: QuirksMode, } impl<'a> Context<'a> { diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index ff8bdaa548e..d3ebba44726 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -17,7 +17,7 @@ use std::ops::Mul; use style_traits::ToCss; use style_traits::values::specified::AllowedLengthType; use stylesheets::CssRuleType; -use super::{Angle, Number, SimplifiedValueNode, SimplifiedSumNode, Time, ToComputedValue}; +use super::{AllowQuirks, Angle, Number, SimplifiedValueNode, SimplifiedSumNode, Time, ToComputedValue}; use values::{Auto, CSSFloat, Either, FONT_MEDIUM_PX, HasViewportPercentage, None_, Normal}; use values::ExtremumLength; use values::computed::{ComputedValueAsSpecified, Context}; @@ -563,13 +563,17 @@ impl Length { } #[inline] - fn parse_internal(context: &ParserContext, input: &mut Parser, num_context: AllowedLengthType) + fn parse_internal(context: &ParserContext, + input: &mut Parser, + num_context: AllowedLengthType, + allow_quirks: AllowQuirks) -> Result<Length, ()> { match try!(input.next()) { Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) => Length::parse_dimension(context, value.value, unit), - Token::Number(ref value) => { - if value.value != 0. && !context.length_parsing_mode.allows_unitless_lengths() { + Token::Number(ref value) if num_context.is_ok(value.value) => { + if value.value != 0. && !context.length_parsing_mode.allows_unitless_lengths() && + !allow_quirks.allowed(context.quirks_mode) { return Err(()) } Ok(Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(value.value)))) @@ -585,7 +589,16 @@ impl Length { /// Parse a non-negative length #[inline] pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Length, ()> { - Self::parse_internal(context, input, AllowedLengthType::NonNegative) + Self::parse_non_negative_quirky(context, input, AllowQuirks::No) + } + + /// Parse a non-negative length, allowing quirks. + #[inline] + pub fn parse_non_negative_quirky(context: &ParserContext, + input: &mut Parser, + allow_quirks: AllowQuirks) + -> Result<Length, ()> { + Self::parse_internal(context, input, AllowedLengthType::NonNegative, allow_quirks) } /// Get an absolute length from a px value. @@ -605,7 +618,17 @@ impl Length { impl Parse for Length { fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { - Self::parse_internal(context, input, AllowedLengthType::All) + Self::parse_quirky(context, input, AllowQuirks::No) + } +} + +impl Length { + /// Parses a length, with quirks. + pub fn parse_quirky(context: &ParserContext, + input: &mut Parser, + allow_quirks: AllowQuirks) + -> Result<Self, ()> { + Self::parse_internal(context, input, AllowedLengthType::All, allow_quirks) } } @@ -616,7 +639,7 @@ impl<T: Parse> Either<Length, T> { if let Ok(v) = input.try(|input| T::parse(context, input)) { return Ok(Either::Second(v)); } - Length::parse_internal(context, input, AllowedLengthType::NonNegative).map(Either::First) + Length::parse_internal(context, input, AllowedLengthType::NonNegative, AllowQuirks::No).map(Either::First) } } @@ -1154,7 +1177,10 @@ impl LengthOrPercentage { LengthOrPercentage::Length(NoCalcLength::zero()) } - fn parse_internal(context: &ParserContext, input: &mut Parser, num_context: AllowedLengthType) + fn parse_internal(context: &ParserContext, + input: &mut Parser, + num_context: AllowedLengthType, + allow_quirks: AllowQuirks) -> Result<LengthOrPercentage, ()> { match try!(input.next()) { @@ -1162,12 +1188,9 @@ impl LengthOrPercentage { NoCalcLength::parse_dimension(context, value.value, unit).map(LengthOrPercentage::Length), Token::Percentage(ref value) if num_context.is_ok(value.unit_value) => Ok(LengthOrPercentage::Percentage(Percentage(value.unit_value))), - Token::Number(ref value) => { - if value.value != 0. && !context.length_parsing_mode.allows_unitless_lengths() { - return Err(()) - } - Ok(LengthOrPercentage::Length(NoCalcLength::Absolute(AbsoluteLength::Px(value.value)))) - } + Token::Number(value) if value.value == 0. || + (num_context.is_ok(value.value) && allow_quirks.allowed(context.quirks_mode)) => + Ok(LengthOrPercentage::Length(NoCalcLength::from_px(value.value))), Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { let calc = try!(input.parse_nested_block(|i| { CalcLengthOrPercentage::parse_length_or_percentage(context, i) @@ -1181,14 +1204,23 @@ impl LengthOrPercentage { /// Parse a non-negative length. #[inline] pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<LengthOrPercentage, ()> { - Self::parse_internal(context, input, AllowedLengthType::NonNegative) + Self::parse_non_negative_quirky(context, input, AllowQuirks::No) + } + + /// Parse a non-negative length, with quirks. + #[inline] + pub fn parse_non_negative_quirky(context: &ParserContext, + input: &mut Parser, + allow_quirks: AllowQuirks) + -> Result<LengthOrPercentage, ()> { + Self::parse_internal(context, input, AllowedLengthType::NonNegative, allow_quirks) } /// Parse a length, treating dimensionless numbers as pixels /// /// https://www.w3.org/TR/SVG2/types.html#presentation-attribute-css-value pub fn parse_numbers_are_pixels(context: &ParserContext, input: &mut Parser) -> Result<LengthOrPercentage, ()> { - if let Ok(lop) = input.try(|i| Self::parse_internal(context, i, AllowedLengthType::All)) { + if let Ok(lop) = input.try(|i| Self::parse(context, i)) { return Ok(lop) } @@ -1204,7 +1236,7 @@ impl LengthOrPercentage { pub fn parse_numbers_are_pixels_non_negative(context: &ParserContext, input: &mut Parser) -> Result<LengthOrPercentage, ()> { - if let Ok(lop) = input.try(|i| Self::parse_internal(context, i, AllowedLengthType::NonNegative)) { + if let Ok(lop) = input.try(|i| Self::parse_non_negative(context, i)) { return Ok(lop) } @@ -1230,7 +1262,18 @@ impl LengthOrPercentage { impl Parse for LengthOrPercentage { #[inline] fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { - Self::parse_internal(context, input, AllowedLengthType::All) + Self::parse_quirky(context, input, AllowQuirks::No) + } +} + +impl LengthOrPercentage { + /// Parses a length or a percentage, allowing the unitless length quirk. + /// https://quirks.spec.whatwg.org/#the-unitless-length-quirk + #[inline] + pub fn parse_quirky(context: &ParserContext, + input: &mut Parser, + allow_quirks: AllowQuirks) -> Result<Self, ()> { + Self::parse_internal(context, input, AllowedLengthType::All, allow_quirks) } } @@ -1283,15 +1326,19 @@ impl ToCss for LengthOrPercentageOrAuto { } impl LengthOrPercentageOrAuto { - fn parse_internal(context: &ParserContext, input: &mut Parser, num_context: AllowedLengthType) + fn parse_internal(context: &ParserContext, + input: &mut Parser, + num_context: AllowedLengthType, + allow_quirks: AllowQuirks) -> Result<Self, ()> { match try!(input.next()) { Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) => NoCalcLength::parse_dimension(context, value.value, unit).map(LengthOrPercentageOrAuto::Length), Token::Percentage(ref value) if num_context.is_ok(value.unit_value) => Ok(LengthOrPercentageOrAuto::Percentage(Percentage(value.unit_value))), - Token::Number(ref value) if value.value == 0. => { - if value.value != 0. && !context.length_parsing_mode.allows_unitless_lengths() { + Token::Number(ref value) if num_context.is_ok(value.value) => { + if value.value != 0. && !context.length_parsing_mode.allows_unitless_lengths() && + !allow_quirks.allowed(context.quirks_mode) { return Err(()) } Ok(LengthOrPercentageOrAuto::Length( @@ -1313,7 +1360,16 @@ impl LengthOrPercentageOrAuto { /// Parse a non-negative length, percentage, or auto. #[inline] pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<LengthOrPercentageOrAuto, ()> { - Self::parse_internal(context, input, AllowedLengthType::NonNegative) + Self::parse_non_negative_quirky(context, input, AllowQuirks::No) + } + + /// Parse a non-negative length, percentage, or auto. + #[inline] + pub fn parse_non_negative_quirky(context: &ParserContext, + input: &mut Parser, + allow_quirks: AllowQuirks) + -> Result<Self, ()> { + Self::parse_internal(context, input, AllowedLengthType::NonNegative, allow_quirks) } /// Returns the `auto` value. @@ -1330,7 +1386,18 @@ impl LengthOrPercentageOrAuto { impl Parse for LengthOrPercentageOrAuto { #[inline] fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { - Self::parse_internal(context, input, AllowedLengthType::All) + Self::parse_quirky(context, input, AllowQuirks::No) + } +} + +impl LengthOrPercentageOrAuto { + /// Parses, with quirks. + #[inline] + pub fn parse_quirky(context: &ParserContext, + input: &mut Parser, + allow_quirks: AllowQuirks) + -> Result<Self, ()> { + Self::parse_internal(context, input, AllowedLengthType::All, allow_quirks) } } @@ -1367,7 +1434,10 @@ impl ToCss for LengthOrPercentageOrNone { } } impl LengthOrPercentageOrNone { - fn parse_internal(context: &ParserContext, input: &mut Parser, num_context: AllowedLengthType) + fn parse_internal(context: &ParserContext, + input: &mut Parser, + num_context: AllowedLengthType, + allow_quirks: AllowQuirks) -> Result<LengthOrPercentageOrNone, ()> { match try!(input.next()) { @@ -1375,8 +1445,9 @@ impl LengthOrPercentageOrNone { NoCalcLength::parse_dimension(context, value.value, unit).map(LengthOrPercentageOrNone::Length), Token::Percentage(ref value) if num_context.is_ok(value.unit_value) => Ok(LengthOrPercentageOrNone::Percentage(Percentage(value.unit_value))), - Token::Number(ref value) if value.value == 0. => { - if value.value != 0. && !context.length_parsing_mode.allows_unitless_lengths() { + Token::Number(value) if num_context.is_ok(value.value) => { + if value.value != 0. && !context.length_parsing_mode.allows_unitless_lengths() && + !allow_quirks.allowed(context.quirks_mode) { return Err(()) } Ok(LengthOrPercentageOrNone::Length( @@ -1394,17 +1465,27 @@ impl LengthOrPercentageOrNone { _ => Err(()) } } + /// Parse a non-negative LengthOrPercentageOrNone. #[inline] pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { - Self::parse_internal(context, input, AllowedLengthType::NonNegative) + Self::parse_non_negative_quirky(context, input, AllowQuirks::No) + } + + /// Parse a non-negative LengthOrPercentageOrNone, with quirks. + #[inline] + pub fn parse_non_negative_quirky(context: &ParserContext, + input: &mut Parser, + allow_quirks: AllowQuirks) + -> Result<Self, ()> { + Self::parse_internal(context, input, AllowedLengthType::NonNegative, allow_quirks) } } impl Parse for LengthOrPercentageOrNone { #[inline] fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { - Self::parse_internal(context, input, AllowedLengthType::All) + Self::parse_internal(context, input, AllowedLengthType::All, AllowQuirks::No) } } @@ -1548,8 +1629,17 @@ impl ToCss for MinLength { impl Parse for MinLength { fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { + MinLength::parse_quirky(context, input, AllowQuirks::No) + } +} + +impl MinLength { + /// Parses, with quirks. + pub fn parse_quirky(context: &ParserContext, + input: &mut Parser, + allow_quirks: AllowQuirks) -> Result<Self, ()> { input.try(ExtremumLength::parse).map(MinLength::ExtremumLength) - .or_else(|()| input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) + .or_else(|()| input.try(|i| LengthOrPercentage::parse_non_negative_quirky(context, i, allow_quirks)) .map(MinLength::LengthOrPercentage)) .or_else(|()| input.expect_ident_matching("auto").map(|()| MinLength::Auto)) } @@ -1589,8 +1679,17 @@ impl ToCss for MaxLength { impl Parse for MaxLength { fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { + MaxLength::parse_quirky(context, input, AllowQuirks::No) + } +} + +impl MaxLength { + /// Parses, with quirks. + pub fn parse_quirky(context: &ParserContext, + input: &mut Parser, + allow_quirks: AllowQuirks) -> Result<Self, ()> { input.try(ExtremumLength::parse).map(MaxLength::ExtremumLength) - .or_else(|()| input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) + .or_else(|()| input.try(|i| LengthOrPercentage::parse_non_negative_quirky(context, i, allow_quirks)) .map(MaxLength::LengthOrPercentage)) .or_else(|()| { match_ignore_ascii_case! { &try!(input.expect_ident()), diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 040728d8e77..c51027b864a 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -7,6 +7,7 @@ //! TODO(emilio): Enhance docs. use app_units::Au; +use context::QuirksMode; use cssparser::{self, Parser, Token}; use euclid::size::Size2D; use parser::{ParserContext, Parse}; @@ -490,7 +491,17 @@ pub enum BorderWidth { impl Parse for BorderWidth { fn parse(context: &ParserContext, input: &mut Parser) -> Result<BorderWidth, ()> { - match input.try(|i| Length::parse_non_negative(context, i)) { + Self::parse_quirky(context, input, AllowQuirks::No) + } +} + +impl BorderWidth { + /// Parses a border width, allowing quirks. + pub fn parse_quirky(context: &ParserContext, + input: &mut Parser, + allow_quirks: AllowQuirks) + -> Result<BorderWidth, ()> { + match input.try(|i| Length::parse_non_negative_quirky(context, i, allow_quirks)) { Ok(length) => Ok(BorderWidth::Width(length)), Err(_) => match_ignore_ascii_case! { &try!(input.expect_ident()), "thin" => Ok(BorderWidth::Thin), @@ -1281,13 +1292,13 @@ impl ToComputedValue for ClipRect { impl Parse for ClipRect { fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { - use values::specified::Length; + use values::specified::{AllowQuirks, Length}; fn parse_argument(context: &ParserContext, input: &mut Parser) -> Result<Option<Length>, ()> { if input.try(|input| input.expect_ident_matching("auto")).is_ok() { Ok(None) } else { - Length::parse(context, input).map(Some) + Length::parse_quirky(context, input, AllowQuirks::Yes).map(Some) } } @@ -1327,3 +1338,19 @@ pub type ClipRectOrAuto = Either<ClipRect, Auto>; /// <color> | auto pub type ColorOrAuto = Either<CSSColor, Auto>; + +/// Whether quirks are allowed in this context. +#[derive(Clone, Copy, PartialEq)] +pub enum AllowQuirks { + /// Quirks are allowed. + Yes, + /// Quirks are not allowed. + No, +} + +impl AllowQuirks { + /// Returns `true` if quirks are allowed in this context. + pub fn allowed(self, quirks_mode: QuirksMode) -> bool { + self == AllowQuirks::Yes && quirks_mode == QuirksMode::Quirks + } +} diff --git a/components/style/values/specified/position.rs b/components/style/values/specified/position.rs index f8501e870c2..dfa05b36609 100644 --- a/components/style/values/specified/position.rs +++ b/components/style/values/specified/position.rs @@ -19,7 +19,7 @@ use values::computed::position as computed_position; use values::generics::position::{Position as GenericPosition, PositionValue, PositionWithKeyword}; use values::generics::position::HorizontalPosition as GenericHorizontalPosition; use values::generics::position::VerticalPosition as GenericVerticalPosition; -use values::specified::{LengthOrPercentage, Percentage}; +use values::specified::{AllowQuirks, LengthOrPercentage, Percentage}; pub use values::generics::position::Keyword; @@ -132,13 +132,23 @@ impl Position { impl Parse for Position { fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { - let first = input.try(|i| PositionComponent::parse(context, i))?; - let second = input.try(|i| PositionComponent::parse(context, i)) + Position::parse_quirky(context, input, AllowQuirks::No) + } +} + +impl Position { + /// Parses, with quirks. + pub fn parse_quirky(context: &ParserContext, + input: &mut Parser, + allow_quirks: AllowQuirks) + -> Result<Self, ()> { + let first = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks))?; + let second = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) .unwrap_or(Either::Second(Keyword::Center)); - if let Ok(third) = input.try(|i| PositionComponent::parse(context, i)) { + if let Ok(third) = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) { // There's a 3rd value. - if let Ok(fourth) = input.try(|i| PositionComponent::parse(context, i)) { + if let Ok(fourth) = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) { // There's a 4th value. Position::from_components(Some(second), Some(fourth), Some(first), Some(third)) } else { @@ -173,6 +183,17 @@ impl Parse for Position { } } +impl PositionComponent { + /// Parses, with quirks. + fn parse_quirky(context: &ParserContext, + input: &mut Parser, + allow_quirks: AllowQuirks) -> Result<Self, ()> { + input.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)) + .map(Either::First) + .or_else(|()| input.try(Keyword::parse).map(Either::Second)) + } +} + impl PositionValue<LengthOrPercentage> { /// Generic function for the computed value of a position. fn computed_value(&self, context: &Context) -> ComputedLengthOrPercentage { diff --git a/components/style/viewport.rs b/components/style/viewport.rs index 4c05ff52107..90811fa8549 100644 --- a/components/style/viewport.rs +++ b/components/style/viewport.rs @@ -10,6 +10,7 @@ #![deny(missing_docs)] use app_units::Au; +use context::QuirksMode; use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser, parse_important}; use cssparser::ToCss as ParserToCss; use euclid::size::TypedSize2D; @@ -588,13 +589,15 @@ pub trait MaybeNew { /// Create a ViewportConstraints from a viewport size and a `@viewport` /// rule. fn maybe_new(device: &Device, - rule: &ViewportRule) + rule: &ViewportRule, + quirks_mode: QuirksMode) -> Option<ViewportConstraints>; } impl MaybeNew for ViewportConstraints { fn maybe_new(device: &Device, - rule: &ViewportRule) + rule: &ViewportRule, + quirks_mode: QuirksMode) -> Option<ViewportConstraints> { use std::cmp; @@ -684,6 +687,7 @@ impl MaybeNew for ViewportConstraints { style: device.default_computed_values().clone(), font_metrics_provider: &provider, in_media_query: false, + quirks_mode: quirks_mode, }; // DEVICE-ADAPT § 9.3 Resolving 'extend-to-zoom' |