diff --git a/components/layout/display_list/builder.rs b/components/layout/display_list/builder.rs index 17f946f7187..2c0f6d612e1 100644 --- a/components/layout/display_list/builder.rs +++ b/components/layout/display_list/builder.rs @@ -60,10 +60,10 @@ use style::logical_geometry::{LogicalMargin, LogicalPoint, LogicalRect}; use style::properties::{style_structs, ComputedValues}; use style::servo::restyle_damage::ServoRestyleDamage; use style::values::computed::effects::SimpleShadow; -use style::values::computed::image::{Image, ImageLayer}; +use style::values::computed::image::Image; use style::values::computed::{ClipRectOrAuto, Gradient, LengthOrAuto}; use style::values::generics::background::BackgroundSize; -use style::values::generics::image::{GradientKind, PaintWorklet}; +use style::values::generics::image::PaintWorklet; use style::values::specified::ui::CursorKind; use style::values::RGBA; use style_traits::ToCss; @@ -732,12 +732,8 @@ impl Fragment { // http://www.w3.org/TR/CSS21/colors.html#background let background = style.get_background(); for (i, background_image) in background.background_image.0.iter().enumerate().rev() { - let background_image = match *background_image { - ImageLayer::None => continue, - ImageLayer::Image(ref image) => image, - }; - match *background_image { + Image::None => {}, Image::Gradient(ref gradient) => { self.build_display_list_for_background_gradient( state, @@ -975,15 +971,15 @@ impl Fragment { display_list_section, ); - let display_item = match gradient.kind { - GradientKind::Linear(angle_or_corner) => { - let (gradient, stops) = gradient::linear( - style, - placement.tile_size, - &gradient.items[..], - angle_or_corner, - gradient.repeating, - ); + let display_item = match gradient { + Gradient::Linear { + ref direction, + ref items, + ref repeating, + compat_mode: _, + } => { + let (gradient, stops) = + gradient::linear(style, placement.tile_size, items, *direction, *repeating); let item = webrender_api::GradientDisplayItem { gradient, bounds: placement.bounds.to_f32_px(), @@ -993,14 +989,20 @@ impl Fragment { }; DisplayItem::Gradient(CommonDisplayItem::with_data(base, item, stops)) }, - GradientKind::Radial(ref shape, ref center) => { + Gradient::Radial { + ref shape, + ref position, + ref items, + ref repeating, + compat_mode: _, + } => { let (gradient, stops) = gradient::radial( style, placement.tile_size, - &gradient.items[..], + items, shape, - center, - gradient.repeating, + position, + *repeating, ); let item = webrender_api::RadialGradientDisplayItem { gradient, @@ -1011,6 +1013,7 @@ impl Fragment { }; DisplayItem::RadialGradient(CommonDisplayItem::with_data(base, item, stops)) }, + Gradient::Conic { .. } => unimplemented!(), }; state.add_display_item(display_item); }); @@ -1122,22 +1125,20 @@ impl Fragment { let border_radius = border::radii(bounds, border_style_struct); let border_widths = border.to_physical(style.writing_mode); - if let ImageLayer::Image(ref image) = border_style_struct.border_image_source { - if self - .build_display_list_for_border_image( - state, - style, - base.clone(), - bounds, - image, - border_widths, - ) - .is_some() - { - return; - } - // Fallback to rendering a solid border. + if self + .build_display_list_for_border_image( + state, + style, + base.clone(), + bounds, + &border_style_struct.border_image_source, + border_widths, + ) + .is_some() + { + return; } + if border_widths == SideOffsets2D::zero() { return; } @@ -1224,30 +1225,37 @@ impl Fragment { height = image.height; NinePatchBorderSource::Image(image.key?) }, - Image::Gradient(ref gradient) => match gradient.kind { - GradientKind::Linear(angle_or_corner) => { - let (wr_gradient, linear_stops) = gradient::linear( - style, - border_image_area, - &gradient.items[..], - angle_or_corner, - gradient.repeating, - ); + Image::Gradient(ref gradient) => match **gradient { + Gradient::Linear { + ref direction, + ref items, + ref repeating, + compat_mode: _, + } => { + let (wr_gradient, linear_stops) = + gradient::linear(style, border_image_area, items, *direction, *repeating); stops = linear_stops; NinePatchBorderSource::Gradient(wr_gradient) }, - GradientKind::Radial(ref shape, ref center) => { + Gradient::Radial { + ref shape, + ref position, + ref items, + ref repeating, + compat_mode: _, + } => { let (wr_gradient, radial_stops) = gradient::radial( style, border_image_area, - &gradient.items[..], + items, shape, - center, - gradient.repeating, + position, + *repeating, ); stops = radial_stops; NinePatchBorderSource::RadialGradient(wr_gradient) }, + Gradient::Conic { .. } => unimplemented!(), }, _ => return None, }; diff --git a/components/layout/display_list/gradient.rs b/components/layout/display_list/gradient.rs index e683bbb963c..b816bca753f 100644 --- a/components/layout/display_list/gradient.rs +++ b/components/layout/display_list/gradient.rs @@ -7,8 +7,8 @@ use app_units::Au; use euclid::default::{Point2D, Size2D, Vector2D}; use style::properties::ComputedValues; use style::values::computed::image::{EndingShape, LineDirection}; -use style::values::computed::{Angle, GradientItem, LengthPercentage, Percentage, Position}; -use style::values::generics::image::{Circle, ColorStop, Ellipse, ShapeExtent}; +use style::values::computed::{Angle, Color, LengthPercentage, Percentage, Position}; +use style::values::generics::image::{Circle, ColorStop, Ellipse, GradientItem, ShapeExtent}; use webrender_api::{ExtendMode, Gradient, GradientBuilder, GradientStop, RadialGradient}; /// A helper data structure for gradients. @@ -78,7 +78,7 @@ fn ellipse_size_keyword( fn convert_gradient_stops( style: &ComputedValues, - gradient_items: &[GradientItem], + gradient_items: &[GradientItem], total_length: Au, ) -> GradientBuilder { // Determine the position of each stop per CSS-IMAGES § 3.4. @@ -237,7 +237,7 @@ fn position_to_offset(position: &LengthPercentage, total_length: Au) -> f32 { pub fn linear( style: &ComputedValues, size: Size2D, - stops: &[GradientItem], + stops: &[GradientItem], direction: LineDirection, repeating: bool, ) -> (Gradient, Vec) { @@ -303,7 +303,7 @@ pub fn linear( pub fn radial( style: &ComputedValues, size: Size2D, - stops: &[GradientItem], + stops: &[GradientItem], shape: &EndingShape, center: &Position, repeating: bool, diff --git a/components/layout_2020/display_list/gradient.rs b/components/layout_2020/display_list/gradient.rs index f1e5c1a3c1a..09f5be610c2 100644 --- a/components/layout_2020/display_list/gradient.rs +++ b/components/layout_2020/display_list/gradient.rs @@ -4,9 +4,8 @@ use style::properties::ComputedValues; use style::values::computed::image::{EndingShape, Gradient, LineDirection}; -use style::values::computed::{GradientItem, Length, Position}; -use style::values::generics::image::GenericGradientKind as Kind; -use style::values::generics::image::{Circle, ColorStop, Ellipse, ShapeExtent}; +use style::values::computed::{Color, Length, LengthPercentage, Position}; +use style::values::generics::image::{Circle, ColorStop, Ellipse, GradientItem, ShapeExtent}; use webrender_api::{self as wr, units}; pub(super) fn build( @@ -15,36 +14,51 @@ pub(super) fn build( layer: &super::background::BackgroundLayer, builder: &mut super::DisplayListBuilder, ) { - let extend_mode = if gradient.repeating { - wr::ExtendMode::Repeat - } else { - wr::ExtendMode::Clamp - }; - match &gradient.kind { - Kind::Linear(line_direction) => build_linear( + match gradient { + Gradient::Linear { + ref items, + ref direction, + ref repeating, + compat_mode: _, + } => build_linear( style, - &gradient.items, - line_direction, - extend_mode, + items, + direction, + if *repeating { + wr::ExtendMode::Repeat + } else { + wr::ExtendMode::Clamp + }, &layer, builder, ), - Kind::Radial(ending_shape, center) => build_radial( + Gradient::Radial { + ref shape, + ref position, + ref items, + ref repeating, + compat_mode: _, + } => build_radial( style, - &gradient.items, - ending_shape, - center, - extend_mode, + items, + shape, + position, + if *repeating { + wr::ExtendMode::Repeat + } else { + wr::ExtendMode::Clamp + }, &layer, builder, ), + Gradient::Conic { .. } => unimplemented!(), } } /// https://drafts.csswg.org/css-images-3/#linear-gradients pub(super) fn build_linear( style: &ComputedValues, - items: &[GradientItem], + items: &[GradientItem], line_direction: &LineDirection, extend_mode: wr::ExtendMode, layer: &super::background::BackgroundLayer, @@ -144,7 +158,7 @@ pub(super) fn build_linear( /// https://drafts.csswg.org/css-images-3/#radial-gradients pub(super) fn build_radial( style: &ComputedValues, - items: &[GradientItem], + items: &[GradientItem], shape: &EndingShape, center: &Position, extend_mode: wr::ExtendMode, @@ -244,7 +258,7 @@ pub(super) fn build_radial( /// https://drafts.csswg.org/css-images-4/#color-stop-fixup fn fixup_stops( style: &ComputedValues, - items: &[GradientItem], + items: &[GradientItem], gradient_line_length: Length, ) -> Vec { // Remove color transititon hints, which are not supported yet. diff --git a/components/layout_2020/display_list/mod.rs b/components/layout_2020/display_list/mod.rs index dccee5ea71a..af0797d30b6 100644 --- a/components/layout_2020/display_list/mod.rs +++ b/components/layout_2020/display_list/mod.rs @@ -333,7 +333,7 @@ impl<'a> BuilderForBoxFragment<'a> { } fn build_background(&mut self, builder: &mut DisplayListBuilder) { - use style::values::computed::image::{Image, ImageLayer}; + use style::values::computed::image::Image; let b = self.fragment.style.get_background(); let background_color = self.fragment.style.resolve_color(b.background_color); if background_color.alpha > 0 { @@ -345,85 +345,80 @@ impl<'a> BuilderForBoxFragment<'a> { builder.wr.push_rect(&common, rgba(background_color)) } // Reverse because the property is top layer first, we want to paint bottom layer first. - for (index, layer) in b.background_image.0.iter().enumerate().rev() { - match layer { - ImageLayer::None => {}, - ImageLayer::Image(image) => match image { - Image::Gradient(gradient) => { - let intrinsic = IntrinsicSizes { - width: None, - height: None, - ratio: None, - }; - if let Some(layer) = - &background::layout_layer(self, builder, index, intrinsic) - { - gradient::build(&self.fragment.style, gradient, layer, builder) - } - }, - Image::Url(image_url) => { - // FIXME: images won’t always have in intrinsic width or height - // when support for SVG is added. - // Or a WebRender `ImageKey`, for that matter. - let (width, height, key) = match image_url.url() { - Some(url) => { - match builder.context.get_webrender_image_for_url( - self.fragment.tag, - url.clone(), - UsePlaceholder::No, - ) { - Some(WebRenderImageInfo { - width, - height, - key: Some(key), - }) => (width, height, key), - _ => continue, - } - }, - None => continue, - }; - - // FIXME: https://drafts.csswg.org/css-images-4/#the-image-resolution - let dppx = 1.0; - - let intrinsic = IntrinsicSizes { - width: Some(Length::new(width as f32 / dppx)), - height: Some(Length::new(height as f32 / dppx)), - // FIXME https://github.com/w3c/csswg-drafts/issues/4572 - ratio: Some(width as f32 / height as f32), - }; - - if let Some(layer) = - background::layout_layer(self, builder, index, intrinsic) - { - let image_rendering = - image_rendering(self.fragment.style.clone_image_rendering()); - if layer.repeat { - builder.wr.push_repeating_image( - &layer.common, - layer.bounds, - layer.tile_size, - layer.tile_spacing, - image_rendering, - wr::AlphaType::PremultipliedAlpha, - key, - wr::ColorF::WHITE, - ) - } else { - builder.wr.push_image( - &layer.common, - layer.bounds, - image_rendering, - wr::AlphaType::PremultipliedAlpha, - key, - wr::ColorF::WHITE, - ) - } - } - }, - // Gecko-only value, represented as a (boxed) empty enum on non-Gecko. - Image::Rect(rect) => match **rect {}, + for (index, image) in b.background_image.0.iter().enumerate().rev() { + match image { + Image::None => {}, + Image::Gradient(ref gradient) => { + let intrinsic = IntrinsicSizes { + width: None, + height: None, + ratio: None, + }; + if let Some(layer) = &background::layout_layer(self, builder, index, intrinsic) + { + gradient::build(&self.fragment.style, &gradient, layer, builder) + } }, + Image::Url(ref image_url) => { + // FIXME: images won’t always have in intrinsic width or height + // when support for SVG is added. + // Or a WebRender `ImageKey`, for that matter. + let (width, height, key) = match image_url.url() { + Some(url) => { + match builder.context.get_webrender_image_for_url( + self.fragment.tag, + url.clone(), + UsePlaceholder::No, + ) { + Some(WebRenderImageInfo { + width, + height, + key: Some(key), + }) => (width, height, key), + _ => continue, + } + }, + None => continue, + }; + + // FIXME: https://drafts.csswg.org/css-images-4/#the-image-resolution + let dppx = 1.0; + + let intrinsic = IntrinsicSizes { + width: Some(Length::new(width as f32 / dppx)), + height: Some(Length::new(height as f32 / dppx)), + // FIXME https://github.com/w3c/csswg-drafts/issues/4572 + ratio: Some(width as f32 / height as f32), + }; + + if let Some(layer) = background::layout_layer(self, builder, index, intrinsic) { + let image_rendering = + image_rendering(self.fragment.style.clone_image_rendering()); + if layer.repeat { + builder.wr.push_repeating_image( + &layer.common, + layer.bounds, + layer.tile_size, + layer.tile_spacing, + image_rendering, + wr::AlphaType::PremultipliedAlpha, + key, + wr::ColorF::WHITE, + ) + } else { + builder.wr.push_image( + &layer.common, + layer.bounds, + image_rendering, + wr::AlphaType::PremultipliedAlpha, + key, + wr::ColorF::WHITE, + ) + } + } + }, + // Gecko-only value, represented as a (boxed) empty enum on non-Gecko. + Image::Rect(ref rect) => match **rect {}, } } } diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 064ceb5148e..1ec4c92fcf0 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -914,10 +914,6 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> { false } - fn exported_part(&self, _: &Atom) -> Option { - None - } - fn imported_part(&self, _: &Atom) -> Option { None } @@ -1441,11 +1437,6 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> { false } - fn exported_part(&self, _: &Atom) -> Option { - debug!("ServoThreadSafeLayoutElement::exported_part called"); - None - } - fn imported_part(&self, _: &Atom) -> Option { debug!("ServoThreadSafeLayoutElement::imported_part called"); None diff --git a/components/layout_thread_2020/dom_wrapper.rs b/components/layout_thread_2020/dom_wrapper.rs index 92a9f3f005b..7b1da3454a0 100644 --- a/components/layout_thread_2020/dom_wrapper.rs +++ b/components/layout_thread_2020/dom_wrapper.rs @@ -922,10 +922,6 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> { false } - fn exported_part(&self, _: &Atom) -> Option { - None - } - fn imported_part(&self, _: &Atom) -> Option { None } @@ -1447,11 +1443,6 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> { false } - fn exported_part(&self, _: &Atom) -> Option { - debug!("ServoThreadSafeLayoutElement::exported_part called"); - None - } - fn imported_part(&self, _: &Atom) -> Option { debug!("ServoThreadSafeLayoutElement::imported_part called"); None diff --git a/components/script/dom/cssrulelist.rs b/components/script/dom/cssrulelist.rs index 18a41857923..812434fd180 100644 --- a/components/script/dom/cssrulelist.rs +++ b/components/script/dom/cssrulelist.rs @@ -17,7 +17,9 @@ use crate::stylesheet_loader::StylesheetLoader; use dom_struct::dom_struct; use servo_arc::Arc; use style::shared_lock::Locked; -use style::stylesheets::{CssRules, CssRulesHelpers, KeyframesRule, RulesMutateError}; +use style::stylesheets::{ + AllowImportRules, CssRules, CssRulesHelpers, KeyframesRule, RulesMutateError, +}; #[allow(unsafe_code)] unsafe_no_jsmanaged_fields!(RulesSource); @@ -116,6 +118,7 @@ impl CSSRuleList { index, nested, Some(&loader), + AllowImportRules::Yes, ) })?; diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 2fd6780cab0..baccc4e65aa 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -682,10 +682,7 @@ impl<'dom> LayoutElementHelpers<'dom> for LayoutDom<'dom, Element> { hints.push(from_declaration( shared_lock, PropertyDeclaration::BackgroundImage(background_image::SpecifiedValue( - vec![specified::ImageLayer::Image(specified::Image::for_cascade( - url.into(), - ))] - .into(), + vec![specified::Image::for_cascade(url.into())].into(), )), )); } @@ -3164,10 +3161,6 @@ impl<'a> SelectorsElement for DomRoot { false } - fn exported_part(&self, _: &Atom) -> Option { - None - } - fn imported_part(&self, _: &Atom) -> Option { None } diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index afa99d8d86b..6d10b0838f7 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -26,7 +26,7 @@ use servo_arc::Arc; use std::cell::Cell; use style::media_queries::MediaList; use style::parser::ParserContext as CssParserContext; -use style::stylesheets::{CssRuleType, Origin, Stylesheet}; +use style::stylesheets::{AllowImportRules, CssRuleType, Origin, Stylesheet}; use style_traits::ParsingMode; #[dom_struct] @@ -119,6 +119,7 @@ impl HTMLStyleElement { css_error_reporter, doc.quirks_mode(), self.line_number as u32, + AllowImportRules::Yes, ); let sheet = Arc::new(sheet); diff --git a/components/selectors/matching.rs b/components/selectors/matching.rs index 8993a5ea003..e8fd8afebca 100644 --- a/components/selectors/matching.rs +++ b/components/selectors/matching.rs @@ -676,19 +676,22 @@ where None => return false, }; - loop { - let outer_host = host.containing_shadow_host(); - if outer_host.as_ref().map(|h| h.opaque()) == context.shared.current_host { - break; + let current_host = context.shared.current_host; + if current_host != Some(host.opaque()) { + loop { + let outer_host = host.containing_shadow_host(); + if outer_host.as_ref().map(|h| h.opaque()) == current_host { + break; + } + let outer_host = match outer_host { + Some(h) => h, + None => return false, + }; + // TODO(emilio): if worth it, we could early return if + // host doesn't have the exportparts attribute. + hosts.push(host); + host = outer_host; } - let outer_host = match outer_host { - Some(h) => h, - None => return false, - }; - // TODO(emilio): if worth it, we could early return if - // host doesn't have the exportparts attribute. - hosts.push(host); - host = outer_host; } // Translate the part into the right scope. diff --git a/components/selectors/parser.rs b/components/selectors/parser.rs index 92a5b039b90..0f7cb9c6055 100644 --- a/components/selectors/parser.rs +++ b/components/selectors/parser.rs @@ -2013,27 +2013,48 @@ where input.skip_whitespace(); let mut empty = true; - if !parse_type_selector(parser, input, builder)? { - if let Some(url) = parser.default_namespace() { - // If there was no explicit type selector, but there is a - // default namespace, there is an implicit "|*" type - // selector. - builder.push_simple_selector(Component::DefaultNamespace(url)) - } - } else { + if parse_type_selector(parser, input, builder)? { empty = false; } let mut state = SelectorParsingState::empty(); loop { - let parse_result = match parse_one_simple_selector(parser, input, state)? { + let result = match parse_one_simple_selector(parser, input, state)? { None => break, Some(result) => result, }; + if empty { + if let Some(url) = parser.default_namespace() { + // If there was no explicit type selector, but there is a + // default namespace, there is an implicit "|*" type + // selector. Except for :host, where we ignore it. + // + // https://drafts.csswg.org/css-scoping/#host-element-in-tree: + // + // When considered within its own shadow trees, the shadow + // host is featureless. Only the :host, :host(), and + // :host-context() pseudo-classes are allowed to match it. + // + // https://drafts.csswg.org/selectors-4/#featureless: + // + // A featureless element does not match any selector at all, + // except those it is explicitly defined to match. If a + // given selector is allowed to match a featureless element, + // it must do so while ignoring the default namespace. + // + if !matches!( + result, + SimpleSelectorParseResult::SimpleSelector(Component::Host(..)) + ) { + builder.push_simple_selector(Component::DefaultNamespace(url)); + } + } + } + empty = false; - match parse_result { + match result { SimpleSelectorParseResult::SimpleSelector(s) => { builder.push_simple_selector(s); }, diff --git a/components/selectors/tree.rs b/components/selectors/tree.rs index d6198c5a5f5..ac90fa1f00c 100644 --- a/components/selectors/tree.rs +++ b/components/selectors/tree.rs @@ -117,13 +117,6 @@ pub trait Element: Sized + Clone + Debug { case_sensitivity: CaseSensitivity, ) -> bool; - /// Returns the mapping from the `exportparts` attribute in the regular - /// direction, that is, inner-tree -> outer-tree. - fn exported_part( - &self, - name: &::PartName, - ) -> Option<::PartName>; - /// Returns the mapping from the `exportparts` attribute in the reverse /// direction, that is, in an outer-tree -> inner-tree direction. fn imported_part( diff --git a/components/style/build.rs b/components/style/build.rs index 4477e648ac9..1d5211d690b 100644 --- a/components/style/build.rs +++ b/components/style/build.rs @@ -28,11 +28,11 @@ mod build_gecko { } lazy_static! { - pub static ref PYTHON: String = env::var("PYTHON").ok().unwrap_or_else(|| { + pub static ref PYTHON: String = env::var("PYTHON3").ok().unwrap_or_else(|| { let candidates = if cfg!(windows) { - ["python2.7.exe", "python27.exe", "python.exe"] + ["python3.exe"] } else { - ["python2.7", "python2", "python"] + ["python3"] }; for &name in &candidates { if Command::new(name) @@ -45,7 +45,7 @@ lazy_static! { } } panic!( - "Can't find python (tried {})! Try fixing PATH or setting the PYTHON env var", + "Can't find python (tried {})! Try fixing PATH or setting the PYTHON3 env var", candidates.join(", ") ) }); diff --git a/components/style/counter_style/mod.rs b/components/style/counter_style/mod.rs index d131f350393..9c4be49bb91 100644 --- a/components/style/counter_style/mod.rs +++ b/components/style/counter_style/mod.rs @@ -408,7 +408,9 @@ impl ToCss for System { } /// -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)] +#[derive( + Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToCss, ToShmem, +)] #[repr(u8)] pub enum Symbol { /// @@ -554,7 +556,9 @@ impl Parse for Fallback { } /// -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)] +#[derive( + Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToCss, ToShmem, +)] #[repr(C)] pub struct Symbols(#[css(iterable)] pub crate::OwnedSlice); diff --git a/components/style/custom_properties.rs b/components/style/custom_properties.rs index 76a72276a44..d0af57886db 100644 --- a/components/style/custom_properties.rs +++ b/components/style/custom_properties.rs @@ -579,7 +579,8 @@ impl<'a> CustomPropertiesBuilder<'a> { match result { Ok(new_value) => Arc::new(new_value), Err(..) => { - map.remove(name); + // Don't touch the map, this has the same effect as + // making it compute to the inherited one. return; }, } @@ -653,16 +654,22 @@ impl<'a> CustomPropertiesBuilder<'a> { None => return self.inherited.cloned(), }; if self.may_have_cycles { - substitute_all(&mut map, self.device); + let inherited = self.inherited.as_ref().map(|m| &***m); + substitute_all(&mut map, inherited, self.device); } Some(Arc::new(map)) } } -/// Resolve all custom properties to either substituted or invalid. +/// Resolve all custom properties to either substituted, invalid, or unset +/// (meaning we should use the inherited value). /// /// It does cycle dependencies removal at the same time as substitution. -fn substitute_all(custom_properties_map: &mut CustomPropertiesMap, device: &Device) { +fn substitute_all( + custom_properties_map: &mut CustomPropertiesMap, + inherited: Option<&CustomPropertiesMap>, + device: &Device, +) { // The cycle dependencies removal in this function is a variant // of Tarjan's algorithm. It is mostly based on the pseudo-code // listed in @@ -698,6 +705,9 @@ fn substitute_all(custom_properties_map: &mut CustomPropertiesMap, device: &Devi /// all unfinished strong connected components. stack: SmallVec<[usize; 5]>, map: &'a mut CustomPropertiesMap, + /// The inherited variables. We may need to restore some if we fail + /// substitution. + inherited: Option<&'a CustomPropertiesMap>, /// to resolve the environment to substitute `env()` variables. device: &'a Device, } @@ -831,17 +841,25 @@ fn substitute_all(custom_properties_map: &mut CustomPropertiesMap, device: &Devi return None; } - // Now we have shown that this variable is not in a loop, and - // all of its dependencies should have been resolved. We can - // start substitution now. + // Now we have shown that this variable is not in a loop, and all of its + // dependencies should have been resolved. We can start substitution + // now. let result = substitute_references_in_value(&value, &context.map, &context.device); - match result { Ok(computed_value) => { context.map.insert(name, Arc::new(computed_value)); }, Err(..) => { - context.map.remove(&name); + // This is invalid, reset it to the unset (inherited) value. + let inherited = context.inherited.and_then(|m| m.get(&name)).cloned(); + match inherited { + Some(computed_value) => { + context.map.insert(name, computed_value); + }, + None => { + context.map.remove(&name); + }, + }; }, } @@ -859,6 +877,7 @@ fn substitute_all(custom_properties_map: &mut CustomPropertiesMap, device: &Devi stack: SmallVec::new(), var_info: SmallVec::new(), map: custom_properties_map, + inherited, device, }; traverse(name, &mut context); diff --git a/components/style/dom.rs b/components/style/dom.rs index d07cac998ae..c1c1f74ef68 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -522,6 +522,14 @@ pub trait TElement: { } + /// Internal iterator for the part names that this element exports for a + /// given part name. + fn each_exported_part(&self, _name: &Atom, _callback: F) + where + F: FnMut(&Atom), + { + } + /// Whether a given element may generate a pseudo-element. /// /// This is useful to avoid computing, for example, pseudo styles for diff --git a/components/style/driver.rs b/components/style/driver.rs index e8dfe7cf3db..aa39f3482f4 100644 --- a/components/style/driver.rs +++ b/components/style/driver.rs @@ -89,7 +89,7 @@ pub fn traverse_dom( // ThreadLocalStyleContext on the main thread. If the main thread // ThreadLocalStyleContext has not released its TLS borrow by that point, // we'll panic on double-borrow. - let mut maybe_tls: Option>> = None; + let mut tls_slots = None; let mut tlc = ThreadLocalStyleContext::new(traversal.shared_context()); let mut context = StyleContext { shared: traversal.shared_context(), @@ -129,7 +129,7 @@ pub fn traverse_dom( // depth for all the children. if pool.is_some() && discovered.len() > WORK_UNIT_MAX { let pool = pool.unwrap(); - maybe_tls = Some(ScopedTLS::>::new(pool)); + let tls = ScopedTLS::>::new(pool); let root_opaque = root.as_node().opaque(); let drain = discovered.drain(..); pool.install(|| { @@ -151,10 +151,12 @@ pub fn traverse_dom( scope, pool, traversal, - maybe_tls.as_ref().unwrap(), + &tls, ); }); }); + + tls_slots = Some(tls.into_slots()); break; } nodes_remaining_at_current_depth = discovered.len(); @@ -164,9 +166,9 @@ pub fn traverse_dom( // Collect statistics from thread-locals if requested. if dump_stats || report_stats { let mut aggregate = mem::replace(&mut context.thread_local.statistics, Default::default()); - let parallel = maybe_tls.is_some(); - if let Some(tls) = maybe_tls { - for mut slot in tls.into_slots().into_vec() { + let parallel = tls_slots.is_some(); + if let Some(ref mut tls) = tls_slots { + for slot in tls.iter_mut() { if let Some(cx) = slot.get_mut() { aggregate += cx.statistics.clone(); } diff --git a/components/style/element_state.rs b/components/style/element_state.rs index 8165c73ef14..cf943cc3c4e 100644 --- a/components/style/element_state.rs +++ b/components/style/element_state.rs @@ -137,6 +137,10 @@ bitflags! { const IN_AUTOFILL_STATE = 1 << 50; /// Non-standard & undocumented. const IN_AUTOFILL_PREVIEW_STATE = 1 << 51; + /// :focus-visible + /// + /// https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo + const IN_FOCUS_VISIBLE_STATE = 1 << 52; } } diff --git a/components/style/encoding_support.rs b/components/style/encoding_support.rs index 5544487179f..1ba92953bb9 100644 --- a/components/style/encoding_support.rs +++ b/components/style/encoding_support.rs @@ -10,7 +10,7 @@ use crate::context::QuirksMode; use crate::error_reporting::ParseErrorReporter; use crate::media_queries::MediaList; use crate::shared_lock::SharedRwLock; -use crate::stylesheets::{Origin, Stylesheet, StylesheetLoader, UrlExtraData}; +use crate::stylesheets::{AllowImportRules, Origin, Stylesheet, StylesheetLoader, UrlExtraData}; use cssparser::{stylesheet_encoding, EncodingSupport}; use servo_arc::Arc; use std::borrow::Cow; @@ -78,6 +78,7 @@ impl Stylesheet { error_reporter, quirks_mode, 0, + AllowImportRules::Yes, ) } @@ -100,6 +101,7 @@ impl Stylesheet { stylesheet_loader, error_reporter, 0, + AllowImportRules::Yes, ) } } diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index 3deaeacadc8..ea3700a3235 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -10,244 +10,9 @@ #![allow(unsafe_code)] -use crate::gecko_bindings::bindings; -use crate::gecko_bindings::structs::{self, Matrix4x4Components}; -use crate::gecko_bindings::structs::{nsStyleImage, nsresult}; +use crate::gecko_bindings::structs::{nsresult, Matrix4x4Components}; use crate::stylesheets::RulesMutateError; use crate::values::computed::transform::Matrix3D; -use crate::values::computed::{Gradient, Image, TextAlign}; -use crate::values::generics::image::GenericImage; -use crate::values::generics::rect::Rect; - -impl nsStyleImage { - /// Set a given Servo `Image` value into this `nsStyleImage`. - pub fn set(&mut self, image: Image) { - match image { - GenericImage::Gradient(boxed_gradient) => self.set_gradient(boxed_gradient), - GenericImage::Url(ref url) => unsafe { - bindings::Gecko_SetLayerImageImageValue(self, url); - }, - GenericImage::Rect(ref image_rect) => { - unsafe { - bindings::Gecko_SetLayerImageImageValue(self, &image_rect.url); - bindings::Gecko_InitializeImageCropRect(self); - - // Set CropRect - let ref mut rect = *self.mCropRect.mPtr; - *rect = Rect( - image_rect.top, - image_rect.right, - image_rect.bottom, - image_rect.left, - ); - } - }, - GenericImage::Element(ref element) => unsafe { - bindings::Gecko_SetImageElement(self, element.as_ptr()); - }, - } - } - - fn set_gradient(&mut self, gradient: Box) { - unsafe { - bindings::Gecko_SetGradientImageValue(self, Box::into_raw(gradient)); - } - } - - /// Converts into Image. - pub unsafe fn into_image(self: &nsStyleImage) -> Option { - use crate::gecko_bindings::structs::nsStyleImageType; - use crate::values::computed::MozImageRect; - - match self.mType { - nsStyleImageType::eStyleImageType_Null => None, - nsStyleImageType::eStyleImageType_Image => { - let url = self.__bindgen_anon_1.mImage.as_ref().clone(); - if self.mCropRect.mPtr.is_null() { - Some(GenericImage::Url(url)) - } else { - let rect = &*self.mCropRect.mPtr; - Some(GenericImage::Rect(Box::new(MozImageRect { - url, - top: rect.0, - right: rect.1, - bottom: rect.2, - left: rect.3, - }))) - } - }, - nsStyleImageType::eStyleImageType_Gradient => { - let gradient: &Gradient = &**self.__bindgen_anon_1.mGradient.as_ref(); - Some(GenericImage::Gradient(Box::new(gradient.clone()))) - }, - nsStyleImageType::eStyleImageType_Element => { - use crate::gecko_string_cache::Atom; - let atom = bindings::Gecko_GetImageElement(self); - Some(GenericImage::Element(Atom::from_raw(atom))) - }, - } - } -} - -pub mod basic_shape { - //! Conversions from and to CSS shape representations. - use crate::gecko_bindings::structs::{ - StyleGeometryBox, StyleShapeSource, StyleShapeSourceType, - }; - use crate::values::computed::basic_shape::{BasicShape, ClippingShape, FloatAreaShape}; - use crate::values::computed::motion::OffsetPath; - use crate::values::generics::basic_shape::{GeometryBox, Path, ShapeBox, ShapeSource}; - use crate::values::specified::SVGPathData; - - impl StyleShapeSource { - /// Convert StyleShapeSource to ShapeSource except URL and Image - /// types. - fn into_shape_source( - &self, - ) -> Option> - where - ReferenceBox: From, - { - match self.mType { - StyleShapeSourceType::None => Some(ShapeSource::None), - StyleShapeSourceType::Box => Some(ShapeSource::Box(self.mReferenceBox.into())), - StyleShapeSourceType::Shape => { - let other_shape = unsafe { &*self.__bindgen_anon_1.mBasicShape.as_ref().mPtr }; - let shape = Box::new(other_shape.clone()); - let reference_box = if self.mReferenceBox == StyleGeometryBox::NoBox { - None - } else { - Some(self.mReferenceBox.into()) - }; - Some(ShapeSource::Shape(shape, reference_box)) - }, - StyleShapeSourceType::Image => None, - StyleShapeSourceType::Path => { - let path = self.to_svg_path().expect("expect an SVGPathData"); - let fill = unsafe { &*self.__bindgen_anon_1.mSVGPath.as_ref().mPtr }.mFillRule; - Some(ShapeSource::Path(Path { fill, path })) - }, - } - } - - /// Generate a SVGPathData from StyleShapeSource if possible. - fn to_svg_path(&self) -> Option { - match self.mType { - StyleShapeSourceType::Path => { - let gecko_path = unsafe { &*self.__bindgen_anon_1.mSVGPath.as_ref().mPtr }; - Some(SVGPathData(gecko_path.mPath.clone())) - }, - _ => None, - } - } - } - - impl<'a> From<&'a StyleShapeSource> for ClippingShape { - fn from(other: &'a StyleShapeSource) -> Self { - match other.mType { - StyleShapeSourceType::Image => unsafe { - use crate::values::generics::image::Image as GenericImage; - - let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr; - let image = shape_image.into_image().expect("Cannot convert to Image"); - match image { - GenericImage::Url(url) => ShapeSource::ImageOrUrl(url.0), - _ => panic!("ClippingShape doesn't support non-url images"), - } - }, - _ => other - .into_shape_source() - .expect("Couldn't convert to StyleSource!"), - } - } - } - - impl<'a> From<&'a StyleShapeSource> for FloatAreaShape { - fn from(other: &'a StyleShapeSource) -> Self { - match other.mType { - StyleShapeSourceType::Image => unsafe { - let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr; - let image = shape_image.into_image().expect("Cannot convert to Image"); - ShapeSource::ImageOrUrl(image) - }, - _ => other - .into_shape_source() - .expect("Couldn't convert to StyleSource!"), - } - } - } - - impl<'a> From<&'a StyleShapeSource> for OffsetPath { - fn from(other: &'a StyleShapeSource) -> Self { - use crate::values::generics::motion::GenericOffsetPath; - match other.mType { - StyleShapeSourceType::Path => GenericOffsetPath::Path( - other.to_svg_path().expect("Cannot convert to SVGPathData"), - ), - StyleShapeSourceType::None => OffsetPath::none(), - StyleShapeSourceType::Shape | - StyleShapeSourceType::Box | - StyleShapeSourceType::Image => unreachable!("Unsupported offset-path type"), - } - } - } - - impl From for StyleGeometryBox { - fn from(reference: ShapeBox) -> Self { - use crate::gecko_bindings::structs::StyleGeometryBox::*; - match reference { - ShapeBox::ContentBox => ContentBox, - ShapeBox::PaddingBox => PaddingBox, - ShapeBox::BorderBox => BorderBox, - ShapeBox::MarginBox => MarginBox, - } - } - } - - impl From for StyleGeometryBox { - fn from(reference: GeometryBox) -> Self { - use crate::gecko_bindings::structs::StyleGeometryBox::*; - match reference { - GeometryBox::ShapeBox(shape_box) => From::from(shape_box), - GeometryBox::FillBox => FillBox, - GeometryBox::StrokeBox => StrokeBox, - GeometryBox::ViewBox => ViewBox, - } - } - } - - // Will panic on NoBox - // Ideally these would be implemented on Option, - // but coherence doesn't like that and TryFrom isn't stable - impl From for GeometryBox { - fn from(reference: StyleGeometryBox) -> Self { - use crate::gecko_bindings::structs::StyleGeometryBox::*; - match reference { - ContentBox => GeometryBox::ShapeBox(ShapeBox::ContentBox), - PaddingBox => GeometryBox::ShapeBox(ShapeBox::PaddingBox), - BorderBox => GeometryBox::ShapeBox(ShapeBox::BorderBox), - MarginBox => GeometryBox::ShapeBox(ShapeBox::MarginBox), - FillBox => GeometryBox::FillBox, - StrokeBox => GeometryBox::StrokeBox, - ViewBox => GeometryBox::ViewBox, - _ => panic!("Unexpected StyleGeometryBox while converting to GeometryBox"), - } - } - } - - impl From for ShapeBox { - fn from(reference: StyleGeometryBox) -> Self { - use crate::gecko_bindings::structs::StyleGeometryBox::*; - match reference { - ContentBox => ShapeBox::ContentBox, - PaddingBox => ShapeBox::PaddingBox, - BorderBox => ShapeBox::BorderBox, - MarginBox => ShapeBox::MarginBox, - _ => panic!("Unexpected StyleGeometryBox while converting to ShapeBox"), - } - } - } -} impl From for nsresult { fn from(other: RulesMutateError) -> Self { @@ -260,39 +25,6 @@ impl From for nsresult { } } -impl TextAlign { - /// Obtain a specified value from a Gecko keyword value - /// - /// Intended for use with presentation attributes, not style structs - pub fn from_gecko_keyword(kw: u32) -> Self { - match kw { - structs::NS_STYLE_TEXT_ALIGN_LEFT => TextAlign::Left, - structs::NS_STYLE_TEXT_ALIGN_RIGHT => TextAlign::Right, - structs::NS_STYLE_TEXT_ALIGN_CENTER => TextAlign::Center, - structs::NS_STYLE_TEXT_ALIGN_JUSTIFY => TextAlign::Justify, - structs::NS_STYLE_TEXT_ALIGN_MOZ_LEFT => TextAlign::MozLeft, - structs::NS_STYLE_TEXT_ALIGN_MOZ_RIGHT => TextAlign::MozRight, - structs::NS_STYLE_TEXT_ALIGN_MOZ_CENTER => TextAlign::MozCenter, - structs::NS_STYLE_TEXT_ALIGN_CHAR => TextAlign::Char, - structs::NS_STYLE_TEXT_ALIGN_END => TextAlign::End, - _ => panic!("Found unexpected value in style struct for text-align property"), - } - } -} - -/// Convert to String from given chars pointer. -pub unsafe fn string_from_chars_pointer(p: *const u16) -> String { - use std::slice; - let mut length = 0; - let mut iter = p; - while *iter != 0 { - length += 1; - iter = iter.offset(1); - } - let char_vec = slice::from_raw_parts(p, length as usize); - String::from_utf16_lossy(char_vec) -} - impl<'a> From<&'a Matrix4x4Components> for Matrix3D { fn from(m: &'a Matrix4x4Components) -> Matrix3D { Matrix3D { diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 25ce9f5b3a1..27cb666fc6f 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -310,6 +310,17 @@ impl Device { /// Returns safe area insets pub fn safe_area_insets(&self) -> SideOffsets2D { - SideOffsets2D::zero() + let pc = match self.pres_context() { + Some(pc) => pc, + None => return SideOffsets2D::zero(), + }; + let mut top = 0.0; + let mut right = 0.0; + let mut bottom = 0.0; + let mut left = 0.0; + unsafe { + bindings::Gecko_GetSafeAreaInsets(pc, &mut top, &mut right, &mut bottom, &mut left) + }; + SideOffsets2D::new(top, right, bottom, left) } } diff --git a/components/style/gecko/non_ts_pseudo_class_list.rs b/components/style/gecko/non_ts_pseudo_class_list.rs index 8d9fc3d2d85..ea5db98030a 100644 --- a/components/style/gecko/non_ts_pseudo_class_list.rs +++ b/components/style/gecko/non_ts_pseudo_class_list.rs @@ -30,77 +30,78 @@ macro_rules! apply_non_ts_list { ($apply_macro:ident) => { $apply_macro! { [ - ("-moz-table-border-nonzero", MozTableBorderNonzero, mozTableBorderNonzero, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-browser-frame", MozBrowserFrame, mozBrowserFrame, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("link", Link, link, IN_UNVISITED_STATE, _), - ("any-link", AnyLink, anyLink, IN_VISITED_OR_UNVISITED_STATE, _), - ("visited", Visited, visited, IN_VISITED_STATE, _), - ("active", Active, active, IN_ACTIVE_STATE, _), - ("checked", Checked, checked, IN_CHECKED_STATE, _), - ("defined", Defined, defined, IN_DEFINED_STATE, _), - ("disabled", Disabled, disabled, IN_DISABLED_STATE, _), - ("enabled", Enabled, enabled, IN_ENABLED_STATE, _), - ("focus", Focus, focus, IN_FOCUS_STATE, _), - ("focus-within", FocusWithin, focusWithin, IN_FOCUS_WITHIN_STATE, _), - ("hover", Hover, hover, IN_HOVER_STATE, _), - ("-moz-drag-over", MozDragOver, mozDragOver, IN_DRAGOVER_STATE, _), - ("target", Target, target, IN_TARGET_STATE, _), - ("indeterminate", Indeterminate, indeterminate, IN_INDETERMINATE_STATE, _), - ("-moz-devtools-highlighted", MozDevtoolsHighlighted, mozDevtoolsHighlighted, IN_DEVTOOLS_HIGHLIGHTED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-styleeditor-transitioning", MozStyleeditorTransitioning, mozStyleeditorTransitioning, IN_STYLEEDITOR_TRANSITIONING_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("fullscreen", Fullscreen, fullscreen, IN_FULLSCREEN_STATE, _), + ("-moz-table-border-nonzero", MozTableBorderNonzero, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-browser-frame", MozBrowserFrame, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("link", Link, IN_UNVISITED_STATE, _), + ("any-link", AnyLink, IN_VISITED_OR_UNVISITED_STATE, _), + ("visited", Visited, IN_VISITED_STATE, _), + ("active", Active, IN_ACTIVE_STATE, _), + ("checked", Checked, IN_CHECKED_STATE, _), + ("defined", Defined, IN_DEFINED_STATE, _), + ("disabled", Disabled, IN_DISABLED_STATE, _), + ("enabled", Enabled, IN_ENABLED_STATE, _), + ("focus", Focus, IN_FOCUS_STATE, _), + ("focus-within", FocusWithin, IN_FOCUS_WITHIN_STATE, _), + ("focus-visible", FocusVisible, IN_FOCUS_VISIBLE_STATE, _), + ("hover", Hover, IN_HOVER_STATE, _), + ("-moz-drag-over", MozDragOver, IN_DRAGOVER_STATE, _), + ("target", Target, IN_TARGET_STATE, _), + ("indeterminate", Indeterminate, IN_INDETERMINATE_STATE, _), + ("-moz-devtools-highlighted", MozDevtoolsHighlighted, IN_DEVTOOLS_HIGHLIGHTED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-styleeditor-transitioning", MozStyleeditorTransitioning, IN_STYLEEDITOR_TRANSITIONING_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("fullscreen", Fullscreen, IN_FULLSCREEN_STATE, _), // TODO(emilio): This is inconsistently named (the capital R). - ("-moz-focusring", MozFocusRing, mozFocusRing, IN_FOCUSRING_STATE, _), - ("-moz-broken", MozBroken, mozBroken, IN_BROKEN_STATE, _), - ("-moz-loading", MozLoading, mozLoading, IN_LOADING_STATE, _), - ("-moz-suppressed", MozSuppressed, mozSuppressed, IN_SUPPRESSED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-has-dir-attr", MozHasDirAttr, mozHasDirAttr, IN_HAS_DIR_ATTR_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-dir-attr-ltr", MozDirAttrLTR, mozDirAttrLTR, IN_HAS_DIR_ATTR_LTR_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-dir-attr-rtl", MozDirAttrRTL, mozDirAttrRTL, IN_HAS_DIR_ATTR_RTL_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-dir-attr-like-auto", MozDirAttrLikeAuto, mozDirAttrLikeAuto, IN_HAS_DIR_ATTR_LIKE_AUTO_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-autofill", MozAutofill, mozAutofill, IN_AUTOFILL_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-autofill-preview", MozAutofillPreview, mozAutofillPreview, IN_AUTOFILL_PREVIEW_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-focusring", MozFocusRing, IN_FOCUSRING_STATE, _), + ("-moz-broken", MozBroken, IN_BROKEN_STATE, _), + ("-moz-loading", MozLoading, IN_LOADING_STATE, _), + ("-moz-suppressed", MozSuppressed, IN_SUPPRESSED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-has-dir-attr", MozHasDirAttr, IN_HAS_DIR_ATTR_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-dir-attr-ltr", MozDirAttrLTR, IN_HAS_DIR_ATTR_LTR_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-dir-attr-rtl", MozDirAttrRTL, IN_HAS_DIR_ATTR_RTL_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-dir-attr-like-auto", MozDirAttrLikeAuto, IN_HAS_DIR_ATTR_LIKE_AUTO_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-autofill", MozAutofill, IN_AUTOFILL_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-autofill-preview", MozAutofillPreview, IN_AUTOFILL_PREVIEW_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-handler-clicktoplay", MozHandlerClickToPlay, mozHandlerClickToPlay, IN_HANDLER_CLICK_TO_PLAY_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-handler-vulnerable-updatable", MozHandlerVulnerableUpdatable, mozHandlerVulnerableUpdatable, IN_HANDLER_VULNERABLE_UPDATABLE_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-handler-vulnerable-no-update", MozHandlerVulnerableNoUpdate, mozHandlerVulnerableNoUpdate, IN_HANDLER_VULNERABLE_NO_UPDATE_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-handler-clicktoplay", MozHandlerClickToPlay, IN_HANDLER_CLICK_TO_PLAY_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-handler-vulnerable-updatable", MozHandlerVulnerableUpdatable, IN_HANDLER_VULNERABLE_UPDATABLE_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-handler-vulnerable-no-update", MozHandlerVulnerableNoUpdate, IN_HANDLER_VULNERABLE_NO_UPDATE_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-handler-disabled", MozHandlerDisabled, mozHandlerDisabled, IN_HANDLER_DISABLED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-handler-blocked", MozHandlerBlocked, mozHandlerBlocked, IN_HANDLER_BLOCKED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-handler-crashed", MozHandlerCrashed, mozHandlerCrashed, IN_HANDLER_CRASHED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-math-increment-script-level", MozMathIncrementScriptLevel, mozMathIncrementScriptLevel, IN_INCREMENT_SCRIPT_LEVEL_STATE, _), + ("-moz-handler-disabled", MozHandlerDisabled, IN_HANDLER_DISABLED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-handler-blocked", MozHandlerBlocked, IN_HANDLER_BLOCKED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-handler-crashed", MozHandlerCrashed, IN_HANDLER_CRASHED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-math-increment-script-level", MozMathIncrementScriptLevel, IN_INCREMENT_SCRIPT_LEVEL_STATE, _), - ("required", Required, required, IN_REQUIRED_STATE, _), - ("optional", Optional, optional, IN_OPTIONAL_STATE, _), - ("valid", Valid, valid, IN_VALID_STATE, _), - ("invalid", Invalid, invalid, IN_INVALID_STATE, _), - ("in-range", InRange, inRange, IN_INRANGE_STATE, _), - ("out-of-range", OutOfRange, outOfRange, IN_OUTOFRANGE_STATE, _), - ("default", Default, defaultPseudo, IN_DEFAULT_STATE, _), - ("placeholder-shown", PlaceholderShown, placeholderShown, IN_PLACEHOLDER_SHOWN_STATE, _), - ("-moz-read-only", MozReadOnly, mozReadOnly, IN_MOZ_READONLY_STATE, _), - ("-moz-read-write", MozReadWrite, mozReadWrite, IN_MOZ_READWRITE_STATE, _), - ("-moz-submit-invalid", MozSubmitInvalid, mozSubmitInvalid, IN_MOZ_SUBMITINVALID_STATE, _), - ("-moz-ui-valid", MozUIValid, mozUIValid, IN_MOZ_UI_VALID_STATE, _), - ("-moz-ui-invalid", MozUIInvalid, mozUIInvalid, IN_MOZ_UI_INVALID_STATE, _), - ("-moz-meter-optimum", MozMeterOptimum, mozMeterOptimum, IN_OPTIMUM_STATE, _), - ("-moz-meter-sub-optimum", MozMeterSubOptimum, mozMeterSubOptimum, IN_SUB_OPTIMUM_STATE, _), - ("-moz-meter-sub-sub-optimum", MozMeterSubSubOptimum, mozMeterSubSubOptimum, IN_SUB_SUB_OPTIMUM_STATE, _), + ("required", Required, IN_REQUIRED_STATE, _), + ("optional", Optional, IN_OPTIONAL_STATE, _), + ("valid", Valid, IN_VALID_STATE, _), + ("invalid", Invalid, IN_INVALID_STATE, _), + ("in-range", InRange, IN_INRANGE_STATE, _), + ("out-of-range", OutOfRange, IN_OUTOFRANGE_STATE, _), + ("default", Default, IN_DEFAULT_STATE, _), + ("placeholder-shown", PlaceholderShown, IN_PLACEHOLDER_SHOWN_STATE, _), + ("-moz-read-only", MozReadOnly, IN_MOZ_READONLY_STATE, _), + ("-moz-read-write", MozReadWrite, IN_MOZ_READWRITE_STATE, _), + ("-moz-submit-invalid", MozSubmitInvalid, IN_MOZ_SUBMITINVALID_STATE, _), + ("-moz-ui-valid", MozUIValid, IN_MOZ_UI_VALID_STATE, _), + ("-moz-ui-invalid", MozUIInvalid, IN_MOZ_UI_INVALID_STATE, _), + ("-moz-meter-optimum", MozMeterOptimum, IN_OPTIMUM_STATE, _), + ("-moz-meter-sub-optimum", MozMeterSubOptimum, IN_SUB_OPTIMUM_STATE, _), + ("-moz-meter-sub-sub-optimum", MozMeterSubSubOptimum, IN_SUB_SUB_OPTIMUM_STATE, _), - ("-moz-user-disabled", MozUserDisabled, mozUserDisabled, IN_USER_DISABLED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), + ("-moz-user-disabled", MozUserDisabled, IN_USER_DISABLED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), - ("-moz-first-node", MozFirstNode, firstNode, _, _), - ("-moz-last-node", MozLastNode, lastNode, _, _), - ("-moz-only-whitespace", MozOnlyWhitespace, mozOnlyWhitespace, _, _), - ("-moz-native-anonymous", MozNativeAnonymous, mozNativeAnonymous, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-native-anonymous-no-specificity", MozNativeAnonymousNoSpecificity, mozNativeAnonymousNoSpecificity, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-use-shadow-tree-root", MozUseShadowTreeRoot, mozUseShadowTreeRoot, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), - ("-moz-is-html", MozIsHTML, mozIsHTML, _, _), - ("-moz-placeholder", MozPlaceholder, mozPlaceholder, _, _), - ("-moz-lwtheme", MozLWTheme, mozLWTheme, _, _), - ("-moz-lwtheme-brighttext", MozLWThemeBrightText, mozLWThemeBrightText, _, _), - ("-moz-lwtheme-darktext", MozLWThemeDarkText, mozLWThemeDarkText, _, _), - ("-moz-window-inactive", MozWindowInactive, mozWindowInactive, _, _), + ("-moz-first-node", MozFirstNode, _, _), + ("-moz-last-node", MozLastNode, _, _), + ("-moz-only-whitespace", MozOnlyWhitespace, _, _), + ("-moz-native-anonymous", MozNativeAnonymous, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-native-anonymous-no-specificity", MozNativeAnonymousNoSpecificity, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-use-shadow-tree-root", MozUseShadowTreeRoot, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), + ("-moz-is-html", MozIsHTML, _, _), + ("-moz-placeholder", MozPlaceholder, _, _), + ("-moz-lwtheme", MozLWTheme, _, _), + ("-moz-lwtheme-brighttext", MozLWThemeBrightText, _, _), + ("-moz-lwtheme-darktext", MozLWThemeDarkText, _, _), + ("-moz-window-inactive", MozWindowInactive, _, _), ] } } diff --git a/components/style/gecko/pseudo_element.rs b/components/style/gecko/pseudo_element.rs index 8d05dd9bbb1..d989380c02e 100644 --- a/components/style/gecko/pseudo_element.rs +++ b/components/style/gecko/pseudo_element.rs @@ -134,12 +134,6 @@ impl PseudoElement { *self == PseudoElement::FirstLine } - /// Whether this pseudo-element is ::-moz-fieldset-content. - #[inline] - pub fn is_fieldset_content(&self) -> bool { - *self == PseudoElement::FieldsetContent - } - /// Whether this pseudo-element is the ::-moz-color-swatch pseudo. #[inline] pub fn is_color_swatch(&self) -> bool { diff --git a/components/style/gecko/regen_atoms.py b/components/style/gecko/regen_atoms.py index cf7cc77c16f..5c59a5c566c 100755 --- a/components/style/gecko/regen_atoms.py +++ b/components/style/gecko/regen_atoms.py @@ -94,7 +94,7 @@ class FileAvoidWrite(BytesIO): self.name = filename def write(self, buf): - if isinstance(buf, unicode): + if isinstance(buf, str): buf = buf.encode('utf-8') BytesIO.write(self, buf) diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs index 9f5b49c5c13..3c944bbc6eb 100644 --- a/components/style/gecko/selector_parser.rs +++ b/components/style/gecko/selector_parser.rs @@ -42,7 +42,7 @@ bitflags! { pub type Lang = Atom; macro_rules! pseudo_class_name { - ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { + ([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => { /// Our representation of a non tree-structural pseudo-class. #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)] pub enum NonTSPseudoClass { @@ -72,7 +72,7 @@ impl ToCss for NonTSPseudoClass { W: fmt::Write, { macro_rules! pseudo_class_serialize { - ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { + ([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => { match *self { $(NonTSPseudoClass::$name => concat!(":", $css),)* NonTSPseudoClass::Lang(ref s) => { @@ -134,7 +134,7 @@ impl NonTSPseudoClass { /// in a particular state. pub fn parse_non_functional(name: &str) -> Option { macro_rules! pseudo_class_parse { - ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { + ([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => { match_ignore_ascii_case! { &name, $($css => Some(NonTSPseudoClass::$name),)* "-moz-full-screen" => Some(NonTSPseudoClass::Fullscreen), @@ -156,7 +156,7 @@ impl NonTSPseudoClass { }; } macro_rules! pseudo_class_check_is_enabled_in { - ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { + ([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => { match *self { $(NonTSPseudoClass::$name => check_flag!($flags),)* NonTSPseudoClass::MozLocaleDir(_) | @@ -172,6 +172,9 @@ impl NonTSPseudoClass { /// Returns whether the pseudo-class is enabled in content sheets. #[inline] fn is_enabled_in_content(&self) -> bool { + if matches!(*self, NonTSPseudoClass::FocusVisible) { + return static_prefs::pref!("layout.css.focus-visible.enabled"); + } !self.has_any_flag(NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME) } @@ -186,7 +189,7 @@ impl NonTSPseudoClass { }; } macro_rules! pseudo_class_state { - ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { + ([$(($css:expr, $name:ident, $state:tt, $flags:tt),)*]) => { match *self { $(NonTSPseudoClass::$name => flag!($state),)* NonTSPseudoClass::Dir(..) | diff --git a/components/style/gecko/snapshot.rs b/components/style/gecko/snapshot.rs index fa9914f6222..b2a66f709e2 100644 --- a/components/style/gecko/snapshot.rs +++ b/components/style/gecko/snapshot.rs @@ -193,11 +193,6 @@ impl ElementSnapshot for GeckoElementSnapshot { snapshot_helpers::has_class_or_part(name, CaseSensitivity::CaseSensitive, attr) } - #[inline] - fn exported_part(&self, name: &Atom) -> Option { - snapshot_helpers::exported_part(&*self.mAttrs, name) - } - #[inline] fn imported_part(&self, name: &Atom) -> Option { snapshot_helpers::imported_part(&*self.mAttrs, name) diff --git a/components/style/gecko/snapshot_helpers.rs b/components/style/gecko/snapshot_helpers.rs index cb3056e7bd5..bd905870353 100644 --- a/components/style/gecko/snapshot_helpers.rs +++ b/components/style/gecko/snapshot_helpers.rs @@ -83,16 +83,26 @@ pub fn get_id(attrs: &[structs::AttrArray_InternalAttr]) -> Option<&WeakAtom> { } #[inline(always)] -pub(super) fn exported_part( +pub(super) fn each_exported_part( attrs: &[structs::AttrArray_InternalAttr], name: &Atom, -) -> Option { - let attr = find_attr(attrs, &atom!("exportparts"))?; - let atom = unsafe { bindings::Gecko_Element_ExportedPart(attr, name.as_ptr()) }; - if atom.is_null() { - return None; + mut callback: impl FnMut(&Atom), +) { + let attr = match find_attr(attrs, &atom!("exportparts")) { + Some(attr) => attr, + None => return, + }; + let mut length = 0; + let atoms = unsafe { bindings::Gecko_Element_ExportedParts(attr, name.as_ptr(), &mut length) }; + if atoms.is_null() { + return; + } + + unsafe { + for atom in std::slice::from_raw_parts(atoms, length) { + Atom::with(*atom, &mut callback) + } } - Some(unsafe { Atom::from_raw(atom) }) } #[inline(always)] diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 2b842e72d9b..2b78c7e9181 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -72,7 +72,7 @@ use crate::values::computed::Length; use crate::values::specified::length::FontBaseSize; use crate::CaseSensitivityExt; use app_units::Au; -use atomic_refcell::{AtomicRefCell, AtomicRefMut}; +use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator}; use selectors::attr::{CaseSensitivity, NamespaceConstraint}; use selectors::matching::VisitedHandlingMode; @@ -557,8 +557,9 @@ impl<'le> fmt::Debug for GeckoElement<'le> { } impl<'le> GeckoElement<'le> { + /// Gets the raw `ElementData` refcell for the element. #[inline(always)] - fn get_data(&self) -> Option<&AtomicRefCell> { + pub fn get_data(&self) -> Option<&AtomicRefCell> { unsafe { self.0.mServoData.get().as_ref() } } @@ -1281,6 +1282,14 @@ impl<'le> TElement for GeckoElement<'le> { snapshot_helpers::each_class_or_part(attr, callback) } + #[inline] + fn each_exported_part(&self, name: &Atom, callback: F) + where + F: FnMut(&Atom), + { + snapshot_helpers::each_exported_part(self.attrs(), name, callback) + } + fn each_part(&self, callback: F) where F: FnMut(&Atom), @@ -1383,21 +1392,6 @@ impl<'le> TElement for GeckoElement<'le> { panic!("Atomic child count not implemented in Gecko"); } - /// Whether there is an ElementData container. - fn has_data(&self) -> bool { - self.get_data().is_some() - } - - /// Immutably borrows the ElementData. - fn borrow_data(&self) -> Option> { - self.get_data().map(|x| x.borrow()) - } - - /// Mutably borrows the ElementData. - fn mutate_data(&self) -> Option> { - self.get_data().map(|x| x.borrow_mut()) - } - unsafe fn ensure_data(&self) -> AtomicRefMut { if !self.has_data() { debug!("Creating ElementData for {:?}", self); @@ -1634,6 +1628,22 @@ impl<'le> TElement for GeckoElement<'le> { .any(|property| !transitions_to_keep.contains(*property)) } + /// Whether there is an ElementData container. + #[inline] + fn has_data(&self) -> bool { + self.get_data().is_some() + } + + /// Immutably borrows the ElementData. + fn borrow_data(&self) -> Option> { + self.get_data().map(|x| x.borrow()) + } + + /// Mutably borrows the ElementData. + fn mutate_data(&self) -> Option> { + self.get_data().map(|x| x.borrow_mut()) + } + #[inline] fn lang_attr(&self) -> Option { let ptr = unsafe { bindings::Gecko_LangValue(self.0) }; @@ -2064,6 +2074,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { NonTSPseudoClass::MozReadOnly | NonTSPseudoClass::MozReadWrite | NonTSPseudoClass::FocusWithin | + NonTSPseudoClass::FocusVisible | NonTSPseudoClass::MozDragOver | NonTSPseudoClass::MozDevtoolsHighlighted | NonTSPseudoClass::MozStyleeditorTransitioning | @@ -2225,11 +2236,6 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { snapshot_helpers::has_class_or_part(name, CaseSensitivity::CaseSensitive, attr) } - #[inline] - fn exported_part(&self, name: &Atom) -> Option { - snapshot_helpers::exported_part(self.attrs(), name) - } - #[inline] fn imported_part(&self, name: &Atom) -> Option { snapshot_helpers::imported_part(self.attrs(), name) diff --git a/components/style/gecko_string_cache/namespace.rs b/components/style/gecko_string_cache/namespace.rs index 2dba484e002..72de229f1d7 100644 --- a/components/style/gecko_string_cache/namespace.rs +++ b/components/style/gecko_string_cache/namespace.rs @@ -24,7 +24,18 @@ macro_rules! ns { } /// A Gecko namespace is just a wrapped atom. -#[derive(Clone, Debug, Default, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)] +#[derive( + Clone, + Debug, + Default, + Eq, + Hash, + MallocSizeOf, + PartialEq, + ToComputedValue, + ToResolvedValue, + ToShmem, +)] #[repr(transparent)] pub struct Namespace(pub Atom); diff --git a/components/style/invalidation/element/element_wrapper.rs b/components/style/invalidation/element/element_wrapper.rs index bc74527bf16..1154c136165 100644 --- a/components/style/invalidation/element/element_wrapper.rs +++ b/components/style/invalidation/element/element_wrapper.rs @@ -62,9 +62,6 @@ pub trait ElementSnapshot: Sized { /// called if `has_attrs()` returns true. fn is_part(&self, name: &Atom) -> bool; - /// See Element::exported_part. - fn exported_part(&self, name: &Atom) -> Option; - /// See Element::imported_part. fn imported_part(&self, name: &Atom) -> Option; @@ -371,13 +368,6 @@ where } } - fn exported_part(&self, name: &Atom) -> Option { - match self.snapshot() { - Some(snapshot) if snapshot.has_attrs() => snapshot.exported_part(name), - _ => self.element.exported_part(name), - } - } - fn imported_part(&self, name: &Atom) -> Option { match self.snapshot() { Some(snapshot) if snapshot.has_attrs() => snapshot.imported_part(name), diff --git a/components/style/properties/Mako-0.9.1.zip b/components/style/properties/Mako-0.9.1.zip deleted file mode 100644 index b7450e30012..00000000000 Binary files a/components/style/properties/Mako-0.9.1.zip and /dev/null differ diff --git a/components/style/properties/Mako-1.1.2-py2.py3-none-any.whl b/components/style/properties/Mako-1.1.2-py2.py3-none-any.whl new file mode 100644 index 00000000000..9593025a473 Binary files /dev/null and b/components/style/properties/Mako-1.1.2-py2.py3-none-any.whl differ diff --git a/components/style/properties/build.py b/components/style/properties/build.py index 45d8fa676ab..92966ce1b2d 100644 --- a/components/style/properties/build.py +++ b/components/style/properties/build.py @@ -8,7 +8,7 @@ import re import sys BASE = os.path.dirname(__file__.replace('\\', '/')) -sys.path.insert(0, os.path.join(BASE, "Mako-0.9.1.zip")) +sys.path.insert(0, os.path.join(BASE, "Mako-1.1.2-py2.py3-none-any.whl")) sys.path.insert(0, BASE) # For importing `data.py` from mako import exceptions @@ -130,7 +130,7 @@ def main(): def abort(message): - sys.stderr.write(message + b"\n") + print(message, file=sys.stderr) sys.exit(1) @@ -146,18 +146,18 @@ def render(filename, **context): strict_undefined=True) # Uncomment to debug generated Python code: # write("/tmp", "mako_%s.py" % os.path.basename(filename), template.code) - return template.render(**context).encode("utf8") + return template.render(**context) except Exception: # Uncomment to see a traceback in generated Python code: # raise - abort(exceptions.text_error_template().render().encode("utf8")) + abort(exceptions.text_error_template().render()) def write(directory, filename, content): if not os.path.exists(directory): os.makedirs(directory) full_path = os.path.join(directory, filename) - open(full_path, "wb").write(content) + open(full_path, "w", encoding="utf-8").write(content) python_addr = RE_PYTHON_ADDR.search(content) if python_addr: diff --git a/components/style/properties/cascade.rs b/components/style/properties/cascade.rs index 50029da8479..e9a34d6bf34 100644 --- a/components/style/properties/cascade.rs +++ b/components/style/properties/cascade.rs @@ -13,7 +13,7 @@ use crate::media_queries::Device; use crate::properties::{ComputedValues, StyleBuilder}; use crate::properties::{LonghandId, LonghandIdSet, CSSWideKeyword}; use crate::properties::{PropertyDeclaration, PropertyDeclarationId, DeclarationImportanceIterator}; -use crate::properties::CASCADE_PROPERTY; +use crate::properties::{CASCADE_PROPERTY, ComputedValueFlags}; use crate::rule_cache::{RuleCache, RuleCacheConditions}; use crate::rule_tree::StrongRuleNode; use crate::selector_parser::PseudoElement; @@ -337,89 +337,80 @@ where context.builder.build() } -/// How should a declaration behave when ignoring document colors? -enum DeclarationApplication { - /// We should apply the declaration. - Apply, - /// We should ignore the declaration. - Ignore, - /// We should apply the following declaration, only if any other declaration - /// hasn't set it before. - ApplyUnlessOverriden(PropertyDeclaration), -} +/// For ignored colors mode, we sometimes want to do something equivalent to +/// "revert-or-initial", where we `revert` for a given origin, but then apply a +/// given initial value if nothing in other origins did override it. +/// +/// This is a bit of a clunky way of achieving this. +type DeclarationsToApplyUnlessOverriden = SmallVec::<[PropertyDeclaration; 2]>; -fn application_when_ignoring_colors( +fn tweak_when_ignoring_colors( builder: &StyleBuilder, longhand_id: LonghandId, origin: Origin, - declaration: &PropertyDeclaration, -) -> DeclarationApplication { + declaration: &mut Cow, + declarations_to_apply_unless_overriden: &mut DeclarationsToApplyUnlessOverriden, +) { if !longhand_id.ignored_when_document_colors_disabled() { - return DeclarationApplication::Apply; + return; } let is_ua_or_user_rule = matches!(origin, Origin::User | Origin::UserAgent); if is_ua_or_user_rule { - return DeclarationApplication::Apply; + return; } // Don't override background-color on ::-moz-color-swatch. It is set as an // author style (via the style attribute), but it's pretty important for it // to show up for obvious reasons :) if builder.pseudo.map_or(false, |p| p.is_color_swatch()) && longhand_id == LonghandId::BackgroundColor { - return DeclarationApplication::Apply; + return; } - // Treat background-color a bit differently. If the specified color is - // anything other than a fully transparent color, convert it into the - // Device's default background color. - // Also: for now, we treat background-image a bit differently, too. - // background-image is marked as ignored, but really, we only ignore - // it when backplates are disabled (since then text may be unreadable over - // a background image, if we're ignoring document colors). - // Here we check backplate status to decide if ignoring background-image - // is the right decision. - match *declaration { + // A few special-cases ahead. + match **declaration { + // We honor color and background-color: transparent, and + // "revert-or-initial" otherwise. PropertyDeclaration::BackgroundColor(ref color) => { - if color.is_transparent() { - return DeclarationApplication::Apply; + if !color.is_transparent() { + let color = builder.device.default_background_color(); + declarations_to_apply_unless_overriden.push( + PropertyDeclaration::BackgroundColor(color.into()) + ) } - let color = builder.device.default_background_color(); - DeclarationApplication::ApplyUnlessOverriden( - PropertyDeclaration::BackgroundColor(color.into()) - ) } PropertyDeclaration::Color(ref color) => { + // otherwise. if color.0.is_transparent() { - return DeclarationApplication::Apply; - } - if builder.get_parent_inherited_text().clone_color().alpha != 0 { - return DeclarationApplication::Ignore; + return; } let color = builder.device.default_color(); - DeclarationApplication::ApplyUnlessOverriden( + declarations_to_apply_unless_overriden.push( PropertyDeclaration::Color(specified::ColorPropertyValue(color.into())) ) }, - // In the future, if/when we remove the backplate pref, we can remove this - // special case along with the 'ignored_when_colors_disabled=True' mako line - // for the "background-image" property. + // We honor url background-images if backplating. #[cfg(feature = "gecko")] - PropertyDeclaration::BackgroundImage(..) => { + PropertyDeclaration::BackgroundImage(ref bkg) => { + use crate::values::generics::image::Image; if static_prefs::pref!("browser.display.permit_backplate") { - DeclarationApplication::Apply - } else { - DeclarationApplication::Ignore + if bkg.0.iter().all(|image| matches!(*image, Image::Url(..))) { + return; + } } }, - _ => DeclarationApplication::Ignore, + _ => {}, } + + *declaration.to_mut() = PropertyDeclaration::css_wide_keyword(longhand_id, CSSWideKeyword::Revert); + } struct Cascade<'a, 'b: 'a> { context: &'a mut computed::Context<'b>, cascade_mode: CascadeMode<'a>, seen: LonghandIdSet, + author_specified: LonghandIdSet, reverted: PerOrigin, } @@ -429,6 +420,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { context, cascade_mode, seen: LonghandIdSet::default(), + author_specified: LonghandIdSet::default(), reverted: Default::default(), } } @@ -491,7 +483,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { let ignore_colors = !self.context.builder.device.use_document_colors(); let mut declarations_to_apply_unless_overriden = - SmallVec::<[PropertyDeclaration; 2]>::new(); + DeclarationsToApplyUnlessOverriden::new(); for (declaration, origin) in declarations { let declaration_id = declaration.id(); @@ -533,26 +525,23 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { continue; } - let declaration = self.substitute_variables_if_needed(declaration); + let mut declaration = self.substitute_variables_if_needed(declaration); // When document colors are disabled, do special handling of // properties that are marked as ignored in that mode. if ignore_colors { - let application = application_when_ignoring_colors( + tweak_when_ignoring_colors( &self.context.builder, longhand_id, origin, - &declaration, + &mut declaration, + &mut declarations_to_apply_unless_overriden, + ); + debug_assert_eq!( + declaration.id(), + PropertyDeclarationId::Longhand(longhand_id), + "Shouldn't change the declaration id!", ); - - match application { - DeclarationApplication::Ignore => continue, - DeclarationApplication::Apply => {}, - DeclarationApplication::ApplyUnlessOverriden(decl) => { - declarations_to_apply_unless_overriden.push(decl); - continue; - } - } } let css_wide_keyword = declaration.get_css_wide_keyword(); @@ -569,6 +558,9 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { } self.seen.insert(physical_longhand_id); + if origin == Origin::Author { + self.author_specified.insert(physical_longhand_id); + } let unset = css_wide_keyword.map_or(false, |css_wide_keyword| { match css_wide_keyword { @@ -691,6 +683,14 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { if let Some(svg) = builder.get_svg_if_mutated() { svg.fill_arrays(); } + + } + + if self.author_specified.contains_any(LonghandIdSet::border_background_properties()) { + builder.add_flags(ComputedValueFlags::HAS_AUTHOR_SPECIFIED_BORDER_BACKGROUND); + } + if self.author_specified.contains_any(LonghandIdSet::padding_properties()) { + builder.add_flags(ComputedValueFlags::HAS_AUTHOR_SPECIFIED_PADDING); } #[cfg(feature = "servo")] @@ -711,12 +711,26 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { None => return false, }; - let cached_style = match cache.find(guards, &self.context.builder) { + let builder = &mut self.context.builder; + + let cached_style = match cache.find(guards, &builder) { Some(style) => style, None => return false, }; - self.context.builder.copy_reset_from(cached_style); + builder.copy_reset_from(cached_style); + + // We're using the same reset style as another element, and we'll skip + // applying the relevant properties. So we need to do the relevant + // bookkeeping here to keep these two bits correct. + // + // Note that all the properties involved are non-inherited, so we don't + // need to do anything else other than just copying the bits over. + let reset_props_bits = + ComputedValueFlags::HAS_AUTHOR_SPECIFIED_BORDER_BACKGROUND | + ComputedValueFlags::HAS_AUTHOR_SPECIFIED_PADDING; + builder.add_flags(cached_style.flags & reset_props_bits); + true } diff --git a/components/style/properties/computed_value_flags.rs b/components/style/properties/computed_value_flags.rs index 4363f3f36e9..221363ba4b1 100644 --- a/components/style/properties/computed_value_flags.rs +++ b/components/style/properties/computed_value_flags.rs @@ -67,6 +67,23 @@ bitflags! { /// Whether this style is the style of the document element. const IS_ROOT_ELEMENT_STYLE = 1 << 11; + + /// Whether this element is inside an `opacity: 0` subtree. + const IS_IN_OPACITY_ZERO_SUBTREE = 1 << 12; + + /// Whether there are author-specified rules for border-* properties + /// (except border-image-*), background-color, or background-image. + /// + /// TODO(emilio): Maybe do include border-image, see: + /// + /// https://github.com/w3c/csswg-drafts/issues/4777#issuecomment-604424845 + const HAS_AUTHOR_SPECIFIED_BORDER_BACKGROUND = 1 << 13; + + /// Whether there are author-specified rules for padding-* properties. + /// + /// FIXME(emilio): Try to merge this with BORDER_BACKGROUND, see + /// https://github.com/w3c/csswg-drafts/issues/4777 + const HAS_AUTHOR_SPECIFIED_PADDING = 1 << 14; } } @@ -74,10 +91,11 @@ impl ComputedValueFlags { /// Flags that are unconditionally propagated to descendants. #[inline] fn inherited_flags() -> Self { - ComputedValueFlags::IS_RELEVANT_LINK_VISITED | - ComputedValueFlags::CAN_BE_FRAGMENTED | - ComputedValueFlags::IS_IN_PSEUDO_ELEMENT_SUBTREE | - ComputedValueFlags::HAS_TEXT_DECORATION_LINES + Self::IS_RELEVANT_LINK_VISITED | + Self::CAN_BE_FRAGMENTED | + Self::IS_IN_PSEUDO_ELEMENT_SUBTREE | + Self::HAS_TEXT_DECORATION_LINES | + Self::IS_IN_OPACITY_ZERO_SUBTREE } /// Flags that may be propagated to descendants. diff --git a/components/style/properties/data.py b/components/style/properties/data.py index 15ab380789b..472d1eb34dd 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -382,6 +382,7 @@ class Longhand(object): "ScrollSnapStrictness", "ScrollSnapType", "TextAlign", + "TextAlignLast", "TextDecorationLine", "TextEmphasisPosition", "TextTransform", @@ -602,7 +603,7 @@ class PropertiesData(object): longhand = Longhand(self.current_style_struct, name, **kwargs) self.add_prefixed_aliases(longhand) - longhand.alias = list(map(lambda xp: Alias(xp[0], longhand, xp[1]), longhand.alias)) + longhand.alias = [Alias(xp[0], longhand, xp[1]) for xp in longhand.alias] self.longhand_aliases += longhand.alias self.current_style_struct.longhands.append(longhand) self.longhands.append(longhand) @@ -620,7 +621,7 @@ class PropertiesData(object): sub_properties = [self.longhands_by_name[s] for s in sub_properties] shorthand = Shorthand(name, sub_properties, *args, **kwargs) self.add_prefixed_aliases(shorthand) - shorthand.alias = list(map(lambda xp: Alias(xp[0], shorthand, xp[1]), shorthand.alias)) + shorthand.alias = [Alias(xp[0], shorthand, xp[1]) for xp in shorthand.alias] self.shorthand_aliases += shorthand.alias self.shorthands.append(shorthand) self.shorthands_by_name[name] = shorthand @@ -669,17 +670,17 @@ def _remove_common_first_line_and_first_letter_properties(props, engine): class PropertyRestrictions: @staticmethod def logical_group(data, group): - return map(lambda p: p.name, data.longhands_by_logical_group[group]) + return [p.name for p in data.longhands_by_logical_group[group]] @staticmethod def shorthand(data, shorthand): if shorthand not in data.shorthands_by_name: return [] - return map(lambda p: p.name, data.shorthands_by_name[shorthand].sub_properties) + return [p.name for p in data.shorthands_by_name[shorthand].sub_properties] @staticmethod def spec(data, spec_path): - return map(lambda p: p.name, filter(lambda p: spec_path in p.spec, data.longhands)) + return [p.name for p in data.longhands if spec_path in p.spec] # https://drafts.csswg.org/css-pseudo/#first-letter-styling @staticmethod diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 6cfb4c859b4..f3db987d8f9 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -22,16 +22,14 @@ use crate::gecko_bindings::bindings::Gecko_CopyConstruct_${style_struct.gecko_ff use crate::gecko_bindings::bindings::Gecko_Destroy_${style_struct.gecko_ffi_name}; % endfor use crate::gecko_bindings::bindings::Gecko_CopyCounterStyle; -use crate::gecko_bindings::bindings::Gecko_CopyCursorArrayFrom; use crate::gecko_bindings::bindings::Gecko_CopyFontFamilyFrom; -use crate::gecko_bindings::bindings::Gecko_CopyImageValueFrom; use crate::gecko_bindings::bindings::Gecko_EnsureImageLayersLength; use crate::gecko_bindings::bindings::Gecko_nsStyleFont_SetLang; use crate::gecko_bindings::bindings::Gecko_nsStyleFont_CopyLangFrom; -use crate::gecko_bindings::bindings::Gecko_SetNullImageValue; use crate::gecko_bindings::structs; use crate::gecko_bindings::structs::nsCSSPropertyID; use crate::gecko_bindings::structs::mozilla::PseudoStyleType; +use crate::gecko::data::PerDocumentStyleData; use crate::gecko::values::round_border_to_device_pixels; use crate::logical_geometry::WritingMode; use crate::media_queries::Device; @@ -43,11 +41,9 @@ use std::mem::{forget, MaybeUninit}; use std::{cmp, ops, ptr}; use crate::values::{self, CustomIdent, Either, KeyframesName, None_}; use crate::values::computed::{Percentage, TransitionProperty}; -use crate::values::computed::url::ComputedImageUrl; use crate::values::computed::BorderStyle; use crate::values::computed::font::FontSize; use crate::values::generics::column::ColumnCount; -use crate::values::generics::image::ImageLayer; pub mod style_structs { @@ -392,112 +388,6 @@ def set_gecko_property(ffi_name, expr): } -<%def name="impl_svg_length(ident, gecko_ffi_name)"> - // When context-value is used on an SVG length, the corresponding flag is - // set on mContextFlags, and the length field is set to the initial value. - - pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { - use crate::values::generics::svg::SVGLength; - use crate::gecko_bindings::structs::nsStyleSVG_${ident.upper()}_CONTEXT as CONTEXT_VALUE; - let length = match v { - SVGLength::LengthPercentage(length) => { - self.gecko.mContextFlags &= !CONTEXT_VALUE; - length - } - SVGLength::ContextValue => { - self.gecko.mContextFlags |= CONTEXT_VALUE; - match longhands::${ident}::get_initial_value() { - SVGLength::LengthPercentage(length) => length, - _ => unreachable!("Initial value should not be context-value"), - } - } - }; - self.gecko.${gecko_ffi_name} = length; - } - - pub fn copy_${ident}_from(&mut self, other: &Self) { - use crate::gecko_bindings::structs::nsStyleSVG_${ident.upper()}_CONTEXT as CONTEXT_VALUE; - self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name}.clone(); - self.gecko.mContextFlags = - (self.gecko.mContextFlags & !CONTEXT_VALUE) | - (other.gecko.mContextFlags & CONTEXT_VALUE); - } - - pub fn reset_${ident}(&mut self, other: &Self) { - self.copy_${ident}_from(other) - } - - pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { - use crate::values::generics::svg::SVGLength; - use crate::gecko_bindings::structs::nsStyleSVG_${ident.upper()}_CONTEXT as CONTEXT_VALUE; - if (self.gecko.mContextFlags & CONTEXT_VALUE) != 0 { - return SVGLength::ContextValue; - } - SVGLength::LengthPercentage(self.gecko.${gecko_ffi_name}.clone()) - } - - -<%def name="impl_svg_opacity(ident, gecko_ffi_name)"> - <% source_prefix = ident.split("_")[0].upper() + "_OPACITY_SOURCE" %> - - pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { - use crate::gecko_bindings::structs::nsStyleSVG_${source_prefix}_MASK as MASK; - use crate::gecko_bindings::structs::nsStyleSVG_${source_prefix}_SHIFT as SHIFT; - use crate::gecko_bindings::structs::nsStyleSVGOpacitySource::*; - use crate::values::generics::svg::SVGOpacity; - self.gecko.mContextFlags &= !MASK; - match v { - SVGOpacity::Opacity(opacity) => { - self.gecko.mContextFlags |= - (eStyleSVGOpacitySource_Normal as u8) << SHIFT; - self.gecko.${gecko_ffi_name} = opacity; - } - SVGOpacity::ContextFillOpacity => { - self.gecko.mContextFlags |= - (eStyleSVGOpacitySource_ContextFillOpacity as u8) << SHIFT; - self.gecko.${gecko_ffi_name} = 1.; - } - SVGOpacity::ContextStrokeOpacity => { - self.gecko.mContextFlags |= - (eStyleSVGOpacitySource_ContextStrokeOpacity as u8) << SHIFT; - self.gecko.${gecko_ffi_name} = 1.; - } - } - } - - pub fn copy_${ident}_from(&mut self, other: &Self) { - use crate::gecko_bindings::structs::nsStyleSVG_${source_prefix}_MASK as MASK; - self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name}; - self.gecko.mContextFlags = - (self.gecko.mContextFlags & !MASK) | - (other.gecko.mContextFlags & MASK); - } - - pub fn reset_${ident}(&mut self, other: &Self) { - self.copy_${ident}_from(other) - } - - pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { - use crate::gecko_bindings::structs::nsStyleSVG_${source_prefix}_MASK as MASK; - use crate::gecko_bindings::structs::nsStyleSVG_${source_prefix}_SHIFT as SHIFT; - use crate::gecko_bindings::structs::nsStyleSVGOpacitySource::*; - use crate::values::generics::svg::SVGOpacity; - - let source = (self.gecko.mContextFlags & MASK) >> SHIFT; - if source == eStyleSVGOpacitySource_Normal as u8 { - return SVGOpacity::Opacity(self.gecko.${gecko_ffi_name}); - } else { - debug_assert_eq!(self.gecko.${gecko_ffi_name}, 1.0); - if source == eStyleSVGOpacitySource_ContextFillOpacity as u8 { - SVGOpacity::ContextFillOpacity - } else { - debug_assert_eq!(source, eStyleSVGOpacitySource_ContextStrokeOpacity as u8); - SVGOpacity::ContextStrokeOpacity - } - } - } - - <%def name="impl_non_negative_length(ident, gecko_ffi_name, inherit_from=None, round_to_pixels=False)"> #[allow(non_snake_case)] @@ -647,12 +537,7 @@ impl Clone for ${style_struct.gecko_struct_name} { -<%def name="impl_simple_type_with_conversion(ident, gecko_ffi_name=None)"> - <% - if gecko_ffi_name is None: - gecko_ffi_name = "m" + to_camel_case(ident) - %> - +<%def name="impl_simple_type_with_conversion(ident, gecko_ffi_name)"> #[allow(non_snake_case)] pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { self.gecko.${gecko_ffi_name} = From::from(v) @@ -711,9 +596,6 @@ impl Clone for ${style_struct.gecko_struct_name} { # Types used with predefined_type()-defined properties that we can auto-generate. predefined_types = { "MozScriptMinSize": impl_absolute_length, - "SVGLength": impl_svg_length, - "SVGOpacity": impl_svg_opacity, - "SVGWidth": impl_svg_length, } def longhand_method(longhand): @@ -778,8 +660,7 @@ fn static_assert() { for x in CORNERS]) %> <%self:impl_trait style_struct_name="Border" - skip_longhands="${skip_border_longhands} border-image-source - border-image-repeat"> + skip_longhands="${skip_border_longhands} border-image-repeat"> % for side in SIDES: pub fn set_border_${side.ident}_style(&mut self, v: BorderStyle) { self.gecko.mBorderStyle[${side.index}] = v; @@ -848,35 +729,6 @@ fn static_assert() { corner) %> % endfor - pub fn set_border_image_source(&mut self, image: longhands::border_image_source::computed_value::T) { - unsafe { - // Prevent leaking of the last elements we did set - Gecko_SetNullImageValue(&mut self.gecko.mBorderImageSource); - } - - if let ImageLayer::Image(image) = image { - self.gecko.mBorderImageSource.set(image); - } - } - - pub fn copy_border_image_source_from(&mut self, other: &Self) { - unsafe { - Gecko_CopyImageValueFrom(&mut self.gecko.mBorderImageSource, - &other.gecko.mBorderImageSource); - } - } - - pub fn reset_border_image_source(&mut self, other: &Self) { - self.copy_border_image_source_from(other) - } - - pub fn clone_border_image_source(&self) -> longhands::border_image_source::computed_value::T { - match unsafe { self.gecko.mBorderImageSource.into_image() } { - Some(image) => ImageLayer::Image(image), - None => ImageLayer::None, - } - } - <% border_image_repeat_keywords = ["Stretch", "Repeat", "Round", "Space"] %> @@ -950,11 +802,10 @@ fn static_assert() { <% skip_position_longhands = " ".join(x.ident for x in SIDES) %> <%self:impl_trait style_struct_name="Position" - skip_longhands="${skip_position_longhands} grid-auto-flow"> + skip_longhands="${skip_position_longhands}"> % for side in SIDES: <% impl_split_style_coord(side.ident, "mOffset", side.index) %> % endfor - ${impl_simple_type_with_conversion("grid_auto_flow")} pub fn set_computed_justify_items(&mut self, v: values::specified::JustifyItems) { debug_assert_ne!(v.0, crate::values::specified::align::AlignFlags::LEGACY); self.gecko.mJustifyItems.computed = v; @@ -1005,15 +856,13 @@ fn static_assert() { } -<% - skip_font_longhands = """font-family font-size font-size-adjust font-weight - font-style font-stretch -moz-script-level - font-synthesis -x-lang font-variant-alternates - font-variant-east-asian font-variant-ligatures - font-variant-numeric font-language-override - font-feature-settings font-variation-settings - -moz-min-font-size-ratio -x-text-zoom""" -%> +<% skip_font_longhands = """font-family font-size font-size-adjust font-weight + font-style font-stretch font-synthesis -x-lang + font-variant-alternates font-variant-east-asian + font-variant-ligatures font-variant-numeric + font-language-override font-feature-settings + font-variation-settings -moz-min-font-size-ratio + -x-text-zoom""" %> <%self:impl_trait style_struct_name="Font" skip_longhands="${skip_font_longhands}"> @@ -1275,9 +1124,7 @@ fn static_assert() { longhands::_x_text_zoom::computed_value::T(self.gecko.mAllowZoom) } - ${impl_simple("_moz_script_level", "mScriptLevel")} <% impl_simple_type_with_conversion("font_language_override", "mFont.languageOverride") %> - ${impl_simple_type_with_conversion("font_variant_ligatures", "mFont.variantLigatures")} ${impl_simple_type_with_conversion("font_variant_east_asian", "mFont.variantEastAsian")} ${impl_simple_type_with_conversion("font_variant_numeric", "mFont.variantNumeric")} @@ -1401,9 +1248,6 @@ fn static_assert() { ${impl_copy_animation_or_transition_value('animation', ident, gecko_ffi_name)} -<%def name="impl_transition_timing_function()"> - ${impl_animation_or_transition_timing_function('transition')} - <%def name="impl_animation_count(ident, gecko_ffi_name)"> ${impl_animation_or_transition_count('animation', ident, gecko_ffi_name)} @@ -1413,10 +1257,6 @@ fn static_assert() { ${impl_animation_or_transition_time_value('animation', ident, gecko_ffi_name)} -<%def name="impl_animation_timing_function()"> - ${impl_animation_or_transition_timing_function('animation')} - - <%def name="impl_animation_keyword(ident, gecko_ffi_name, keyword, cast_type='u8')"> #[allow(non_snake_case)] pub fn set_animation_${ident}(&mut self, v: I) @@ -1466,7 +1306,7 @@ fn static_assert() { animation-iteration-count animation-timing-function clear transition-duration transition-delay transition-timing-function transition-property - shape-outside -webkit-line-clamp""" %> + -webkit-line-clamp""" %> <%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}"> #[inline] pub fn set_display(&mut self, v: longhands::display::computed_value::T) { @@ -1509,7 +1349,7 @@ fn static_assert() { ${impl_transition_time_value('delay', 'Delay')} ${impl_transition_time_value('duration', 'Duration')} - ${impl_transition_timing_function()} + ${impl_animation_or_transition_timing_function('transition')} pub fn transition_combined_duration_at(&self, index: usize) -> f32 { // https://drafts.csswg.org/css-transitions/#transition-combined-duration @@ -1723,10 +1563,7 @@ fn static_assert() { ${impl_animation_count('iteration_count', 'IterationCount')} ${impl_copy_animation_value('iteration_count', 'IterationCount')} - - ${impl_animation_timing_function()} - - <% impl_shape_source("shape_outside", "mShapeOutside") %> + ${impl_animation_or_transition_timing_function('animation')} #[allow(non_snake_case)] pub fn set__webkit_line_clamp(&mut self, v: longhands::_webkit_line_clamp::computed_value::T) { @@ -2009,7 +1846,7 @@ fn static_assert() { for (layer, other) in self.gecko.${image_layers_field}.mLayers.iter_mut() .zip(other.gecko.${image_layers_field}.mLayers.iter()) .take(count as usize) { - Gecko_CopyImageValueFrom(&mut layer.mImage, &other.mImage); + layer.mImage = other.mImage.clone(); } self.gecko.${image_layers_field}.mImageCount = count; } @@ -2029,22 +1866,17 @@ fn static_assert() { let images = images.into_iter(); unsafe { - // Prevent leaking of the last elements we did set - for image in &mut self.gecko.${image_layers_field}.mLayers { - Gecko_SetNullImageValue(&mut image.mImage) - } - // XXXManishearth clear mSourceURI for masks - Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field}, images.len(), - LayerType::${shorthand.title()}); + Gecko_EnsureImageLayersLength( + &mut self.gecko.${image_layers_field}, + images.len(), + LayerType::${shorthand.title()}, + ); } self.gecko.${image_layers_field}.mImageCount = images.len() as u32; - for (image, geckoimage) in images.zip(self.gecko.${image_layers_field} .mLayers.iter_mut()) { - if let ImageLayer::Image(image) = image { - geckoimage.mImage.set(image) - } + geckoimage.mImage = image; } } @@ -2052,12 +1884,8 @@ fn static_assert() { longhands::${shorthand}_image::computed_value::List( self.gecko.${image_layers_field}.mLayers.iter() .take(self.gecko.${image_layers_field}.mImageCount as usize) - .map(|ref layer| { - match unsafe { layer.mImage.into_image() } { - Some(image) => ImageLayer::Image(image), - None => ImageLayer::None, - } - }).collect() + .map(|layer| layer.mImage.clone()) + .collect() ) } @@ -2189,18 +2017,9 @@ fn static_assert() { <%self:impl_trait style_struct_name="InheritedText" - skip_longhands="text-align -webkit-text-stroke-width text-emphasis-position"> - - <% text_align_keyword = Keyword("text-align", - "start end left right center justify -moz-center -moz-left -moz-right char", - gecko_strip_moz_prefix=False) %> - ${impl_keyword('text_align', 'mTextAlign', text_align_keyword)} - - ${impl_simple_type_with_conversion("text_emphasis_position")} - + skip_longhands="-webkit-text-stroke-width"> ${impl_non_negative_length('_webkit_text_stroke_width', 'mWebkitTextStrokeWidth')} - <%self:impl_trait style_struct_name="Text" skip_longhands="initial-letter"> @@ -2244,204 +2063,21 @@ fn static_assert() { } -// Set SVGPathData to StyleShapeSource. -fn set_style_svg_path( - shape_source: &mut structs::mozilla::StyleShapeSource, - servo_path: values::specified::svg_path::SVGPathData, - fill: values::generics::basic_shape::FillRule, -) { - // Setup path. - unsafe { - bindings::Gecko_SetToSVGPath( - shape_source, - servo_path.0.forget(), - fill, - ); - } -} - -<%def name="impl_shape_source(ident, gecko_ffi_name)"> - pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { - use crate::values::generics::basic_shape::ShapeSource; - use crate::gecko_bindings::structs::StyleShapeSourceType; - use crate::gecko_bindings::structs::StyleGeometryBox; - - let ref mut ${ident} = self.gecko.${gecko_ffi_name}; - - // clean up existing struct. - unsafe { bindings::Gecko_DestroyShapeSource(${ident}) }; - - ${ident}.mType = StyleShapeSourceType::None; - - match v { - ShapeSource::None => {} // don't change the type - ShapeSource::ImageOrUrl(image) => { - % if ident == "clip_path": - use crate::values::generics::image::Image; - - let image = Image::Url(ComputedImageUrl(image)); - % endif - unsafe { - bindings::Gecko_NewShapeImage(${ident}); - let style_image = &mut *${ident}.__bindgen_anon_1.mShapeImage.as_mut().mPtr; - style_image.set(image); - } - } - ShapeSource::Box(reference) => { - ${ident}.mReferenceBox = reference.into(); - ${ident}.mType = StyleShapeSourceType::Box; - } - ShapeSource::Path(p) => set_style_svg_path(${ident}, p.path, p.fill), - ShapeSource::Shape(servo_shape, maybe_box) => { - unsafe { - ${ident}.__bindgen_anon_1.mBasicShape.as_mut().mPtr = - Box::into_raw(servo_shape); - } - ${ident}.mReferenceBox = - maybe_box.map(Into::into).unwrap_or(StyleGeometryBox::NoBox); - ${ident}.mType = StyleShapeSourceType::Shape; - } - } - - } - - pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { - (&self.gecko.${gecko_ffi_name}).into() - } - - pub fn copy_${ident}_from(&mut self, other: &Self) { - use crate::gecko_bindings::bindings::Gecko_CopyShapeSourceFrom; - unsafe { - Gecko_CopyShapeSourceFrom(&mut self.gecko.${gecko_ffi_name}, &other.gecko.${gecko_ffi_name}); - } - } - - pub fn reset_${ident}(&mut self, other: &Self) { - self.copy_${ident}_from(other) - } - - <% skip_svg_longhands = """ mask-mode mask-repeat mask-clip mask-origin mask-composite mask-position-x mask-position-y mask-size mask-image -clip-path """ %> <%self:impl_trait style_struct_name="SVG" skip_longhands="${skip_svg_longhands}"> - <% impl_common_image_layer_properties("mask") %> <% impl_simple_image_array_property("mode", "mask", "mMask", "mMaskMode", "SVG") %> <% impl_simple_image_array_property("composite", "mask", "mMask", "mComposite", "SVG") %> - <% impl_shape_source("clip_path", "mClipPath") %> -<%self:impl_trait style_struct_name="InheritedSVG" - skip_longhands="stroke-dasharray"> - pub fn set_stroke_dasharray(&mut self, v: longhands::stroke_dasharray::computed_value::T) { - use crate::gecko_bindings::structs::nsStyleSVG_STROKE_DASHARRAY_CONTEXT as CONTEXT_VALUE; - use crate::values::generics::svg::SVGStrokeDashArray; - - match v { - SVGStrokeDashArray::Values(v) => { - let v = v.into_iter(); - self.gecko.mContextFlags &= !CONTEXT_VALUE; - unsafe { - bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut *self.gecko, v.len() as u32); - } - for (gecko, servo) in self.gecko.mStrokeDasharray.iter_mut().zip(v) { - *gecko = servo; - } - } - SVGStrokeDashArray::ContextValue => { - self.gecko.mContextFlags |= CONTEXT_VALUE; - unsafe { - bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut *self.gecko, 0); - } - } - } - } - - pub fn copy_stroke_dasharray_from(&mut self, other: &Self) { - use crate::gecko_bindings::structs::nsStyleSVG_STROKE_DASHARRAY_CONTEXT as CONTEXT_VALUE; - unsafe { - bindings::Gecko_nsStyleSVG_CopyDashArray(&mut *self.gecko, &*other.gecko); - } - self.gecko.mContextFlags = - (self.gecko.mContextFlags & !CONTEXT_VALUE) | - (other.gecko.mContextFlags & CONTEXT_VALUE); - } - - pub fn reset_stroke_dasharray(&mut self, other: &Self) { - self.copy_stroke_dasharray_from(other) - } - - pub fn clone_stroke_dasharray(&self) -> longhands::stroke_dasharray::computed_value::T { - use crate::gecko_bindings::structs::nsStyleSVG_STROKE_DASHARRAY_CONTEXT as CONTEXT_VALUE; - use crate::values::generics::svg::SVGStrokeDashArray; - - if self.gecko.mContextFlags & CONTEXT_VALUE != 0 { - debug_assert_eq!(self.gecko.mStrokeDasharray.len(), 0); - return SVGStrokeDashArray::ContextValue; - } - SVGStrokeDashArray::Values(self.gecko.mStrokeDasharray.iter().cloned().collect()) - } +<%self:impl_trait style_struct_name="InheritedSVG"> -<%self:impl_trait style_struct_name="InheritedUI" skip_longhands="cursor"> - pub fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) { - self.gecko.mCursor = v.keyword; - unsafe { - bindings::Gecko_SetCursorArrayCapacity(&mut *self.gecko, v.images.len()); - } - for i in 0..v.images.len() { - unsafe { - bindings::Gecko_AppendCursorImage(&mut *self.gecko, &v.images[i].url); - } - - match v.images[i].hotspot { - Some((x, y)) => { - self.gecko.mCursorImages[i].mHaveHotspot = true; - self.gecko.mCursorImages[i].mHotspotX = x; - self.gecko.mCursorImages[i].mHotspotY = y; - }, - _ => { - self.gecko.mCursorImages[i].mHaveHotspot = false; - } - } - } - } - - pub fn copy_cursor_from(&mut self, other: &Self) { - self.gecko.mCursor = other.gecko.mCursor; - unsafe { - Gecko_CopyCursorArrayFrom(&mut *self.gecko, &*other.gecko); - } - } - - pub fn reset_cursor(&mut self, other: &Self) { - self.copy_cursor_from(other) - } - - pub fn clone_cursor(&self) -> longhands::cursor::computed_value::T { - use crate::values::computed::ui::CursorImage; - - let keyword = self.gecko.mCursor; - - let images = self.gecko.mCursorImages.iter().map(|gecko_cursor_image| { - let url = gecko_cursor_image.mImage.clone(); - - let hotspot = - if gecko_cursor_image.mHaveHotspot { - Some((gecko_cursor_image.mHotspotX, gecko_cursor_image.mHotspotY)) - } else { - None - }; - - CursorImage { url, hotspot } - }).collect::>().into_boxed_slice(); - - longhands::cursor::computed_value::T { images, keyword } - } +<%self:impl_trait style_struct_name="InheritedUI"> <%self:impl_trait style_struct_name="Column" @@ -2483,8 +2119,7 @@ clip-path } -<%self:impl_trait style_struct_name="UI" skip_longhands="-moz-force-broken-image-icon"> - ${impl_simple_type_with_conversion("_moz_force_broken_image_icon", "mForceBrokenImageIcon")} +<%self:impl_trait style_struct_name="UI"> <%self:impl_trait style_struct_name="XUL"> @@ -2494,3 +2129,40 @@ clip-path ${declare_style_struct(style_struct)} ${impl_style_struct(style_struct)} % endfor + +/// Assert that the initial values set in Gecko style struct constructors +/// match the values returned by `get_initial_value()` for each longhand. +#[cfg(feature = "gecko")] +#[inline] +pub fn assert_initial_values_match(data: &PerDocumentStyleData) { + if cfg!(debug_assertions) { + let data = data.borrow(); + let cv = data.stylist.device().default_computed_values(); + <% + # Skip properties with initial values that change at computed value time. + SKIPPED = [ + "border-top-width", + "border-bottom-width", + "border-left-width", + "border-right-width", + "font-family", + "font-size", + "outline-width", + ] + TO_TEST = [p for p in data.longhands if p.enabled_in != "" and not p.logical and not p.name in SKIPPED] + %> + % for property in TO_TEST: + assert_eq!( + cv.clone_${property.ident}(), + longhands::${property.ident}::get_initial_value(), + concat!( + "initial value in Gecko style struct for ", + stringify!(${property.ident}), + " must match longhands::", + stringify!(${property.ident}), + "::get_initial_value()" + ) + ); + % endfor + } +} diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index 7a25b2569ea..9baab22cb45 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -680,7 +680,7 @@ % endfor let mut bits = ${type}::empty(); - % for servo_bit, gecko_bit in bit_map.iteritems(): + % for servo_bit, gecko_bit in bit_map.items(): if kw & (${gecko_bit_prefix}${gecko_bit} as ${kw_type}) != 0 { bits |= ${servo_bit}; } @@ -696,7 +696,7 @@ let mut bits: ${kw_type} = 0; // FIXME: if we ensure that the Servo bitflags storage is the same // as Gecko's one, we can just copy it. - % for servo_bit, gecko_bit in bit_map.iteritems(): + % for servo_bit, gecko_bit in bit_map.items(): if self.contains(${servo_bit}) { bits |= ${gecko_bit_prefix}${gecko_bit} as ${kw_type}; } @@ -707,7 +707,8 @@ <%def name="single_keyword(name, values, vector=False, - extra_specified=None, needs_conversion=False, **kwargs)"> + extra_specified=None, needs_conversion=False, + gecko_pref_controlled_initial_value=None, **kwargs)"> <% keyword_kwargs = {a: kwargs.pop(a, None) for a in [ 'gecko_constant_prefix', @@ -724,18 +725,19 @@ ]} %> - <%def name="inner_body(keyword, extra_specified=None, needs_conversion=False)"> + <%def name="inner_body(keyword, extra_specified=None, needs_conversion=False, + gecko_pref_controlled_initial_value=None)"> <%def name="variants(variants, include_aliases)"> % for variant in variants: % if include_aliases: <% aliases = [] - for alias, v in keyword.aliases_for(engine).iteritems(): + for alias, v in keyword.aliases_for(engine).items(): if variant == v: aliases.append(alias) %> % if aliases: - #[parse(aliases = "${','.join(aliases)}")] + #[parse(aliases = "${','.join(sorted(aliases))}")] % endif % endif ${to_camel_case(variant)}, @@ -773,10 +775,20 @@ } #[inline] pub fn get_initial_value() -> computed_value::T { + % if engine == "gecko" and gecko_pref_controlled_initial_value: + if static_prefs::pref!("${gecko_pref_controlled_initial_value.split('=')[0]}") { + return computed_value::T::${to_camel_case(gecko_pref_controlled_initial_value.split('=')[1])}; + } + % endif computed_value::T::${to_camel_case(values.split()[0])} } #[inline] pub fn get_initial_specified_value() -> SpecifiedValue { + % if engine == "gecko" and gecko_pref_controlled_initial_value: + if static_prefs::pref!("${gecko_pref_controlled_initial_value.split('=')[0]}") { + return SpecifiedValue::${to_camel_case(gecko_pref_controlled_initial_value.split('=')[1])}; + } + % endif SpecifiedValue::${to_camel_case(values.split()[0])} } #[inline] @@ -805,7 +817,8 @@ % else: <%call expr="longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)"> ${inner_body(Keyword(name, values, **keyword_kwargs), - extra_specified=extra_specified, needs_conversion=needs_conversion)} + extra_specified=extra_specified, needs_conversion=needs_conversion, + gecko_pref_controlled_initial_value=gecko_pref_controlled_initial_value)} % if caller: ${caller.body()} % endif diff --git a/components/style/properties/longhands/background.mako.rs b/components/style/properties/longhands/background.mako.rs index e0ef021f32d..1cbf601ad5d 100644 --- a/components/style/properties/longhands/background.mako.rs +++ b/components/style/properties/longhands/background.mako.rs @@ -21,10 +21,10 @@ ${helpers.predefined_type( ${helpers.predefined_type( "background-image", - "ImageLayer", + "Image", engines="gecko servo-2013 servo-2020", - initial_value="computed::ImageLayer::none()", - initial_specified_value="specified::ImageLayer::none()", + initial_value="computed::Image::None", + initial_specified_value="specified::Image::None", spec="https://drafts.csswg.org/css-backgrounds/#the-background-image", vector="True", animation_value_type="discrete", @@ -35,8 +35,8 @@ ${helpers.predefined_type( ${helpers.predefined_type( "background-position-" + axis, "position::" + direction + "Position", + "computed::LengthPercentage::zero_percent()", engines="gecko servo-2013 servo-2020", - initial_value="computed::LengthPercentage::zero()", initial_specified_value="SpecifiedValue::initial_specified_value()", spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-" + axis, animation_value_type="ComputedValue", @@ -107,7 +107,7 @@ ${helpers.single_keyword( """normal multiply screen overlay darken lighten color-dodge color-burn hard-light soft-light difference exclusion hue saturation color luminosity""", - gecko_constant_prefix="NS_STYLE_BLEND", + gecko_enum_prefix="StyleBlend", vector=True, engines="gecko", animation_value_type="discrete", diff --git a/components/style/properties/longhands/border.mako.rs b/components/style/properties/longhands/border.mako.rs index f281fa1a30d..1c4eae16939 100644 --- a/components/style/properties/longhands/border.mako.rs +++ b/components/style/properties/longhands/border.mako.rs @@ -106,10 +106,10 @@ ${helpers.single_keyword( ${helpers.predefined_type( "border-image-source", - "ImageLayer", + "Image", engines="gecko servo-2013 servo-2020", - initial_value="computed::ImageLayer::none()", - initial_specified_value="specified::ImageLayer::none()", + initial_value="computed::Image::None", + initial_specified_value="specified::Image::None", spec="https://drafts.csswg.org/css-backgrounds/#the-background-image", vector=False, animation_value_type="discrete", diff --git a/components/style/properties/longhands/box.mako.rs b/components/style/properties/longhands/box.mako.rs index 8946290918e..a4f2cc670f5 100644 --- a/components/style/properties/longhands/box.mako.rs +++ b/components/style/properties/longhands/box.mako.rs @@ -573,6 +573,7 @@ ${helpers.single_keyword( "backface-visibility", "visible hidden", engines="gecko servo-2013 servo-2020", + gecko_enum_prefix="StyleBackfaceVisibility", spec="https://drafts.csswg.org/css-transforms/#backface-visibility-property", extra_prefixes=transform_extra_prefixes, animation_value_type="discrete", @@ -633,7 +634,7 @@ ${helpers.predefined_type( "Appearance", "computed::Appearance::None", engines="gecko", - alias="-webkit-appearance:layout.css.webkit-appearance.enabled", + alias="-webkit-appearance", spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-appearance)", animation_value_type="discrete", gecko_ffi_name="mAppearance", @@ -679,10 +680,10 @@ ${helpers.predefined_type( ${helpers.predefined_type( "shape-outside", - "basic_shape::FloatAreaShape", - "generics::basic_shape::ShapeSource::None", + "basic_shape::ShapeOutside", + "generics::basic_shape::ShapeOutside::None", engines="gecko", - animation_value_type="basic_shape::FloatAreaShape", + animation_value_type="basic_shape::ShapeOutside", spec="https://drafts.csswg.org/css-shapes/#shape-outside-property", )} diff --git a/components/style/properties/longhands/effects.mako.rs b/components/style/properties/longhands/effects.mako.rs index d34f13a4a76..f9cef1a34e2 100644 --- a/components/style/properties/longhands/effects.mako.rs +++ b/components/style/properties/longhands/effects.mako.rs @@ -83,7 +83,7 @@ ${helpers.single_keyword( color-burn hard-light soft-light difference exclusion hue saturation color luminosity""", engines="gecko servo-2013 servo-2020", - gecko_constant_prefix="NS_STYLE_BLEND", + gecko_enum_prefix="StyleBlend", animation_value_type="discrete", flags="CREATES_STACKING_CONTEXT", spec="https://drafts.fxtf.org/compositing/#propdef-mix-blend-mode", diff --git a/components/style/properties/longhands/font.mako.rs b/components/style/properties/longhands/font.mako.rs index 7e0bff6fbbe..98ed7fb7f9e 100644 --- a/components/style/properties/longhands/font.mako.rs +++ b/components/style/properties/longhands/font.mako.rs @@ -230,7 +230,7 @@ ${helpers.predefined_type( ${helpers.predefined_type( "-moz-script-level", "MozScriptLevel", - 0, + "0", engines="gecko", animation_value_type="none", enabled_in="ua", diff --git a/components/style/properties/longhands/inherited_box.mako.rs b/components/style/properties/longhands/inherited_box.mako.rs index e8f3a0a45d9..fe2cc5ed024 100644 --- a/components/style/properties/longhands/inherited_box.mako.rs +++ b/components/style/properties/longhands/inherited_box.mako.rs @@ -86,6 +86,7 @@ ${helpers.single_keyword( ${helpers.single_keyword( "image-orientation", "none from-image", + gecko_pref_controlled_initial_value="layout.css.image-orientation.initial-from-image=from-image", engines="gecko", gecko_enum_prefix="StyleImageOrientation", animation_value_type="discrete", diff --git a/components/style/properties/longhands/inherited_svg.mako.rs b/components/style/properties/longhands/inherited_svg.mako.rs index 1839f90d6e6..73db38e0042 100644 --- a/components/style/properties/longhands/inherited_svg.mako.rs +++ b/components/style/properties/longhands/inherited_svg.mako.rs @@ -36,15 +36,16 @@ ${helpers.single_keyword( engines="gecko", animation_value_type="discrete", spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty", + gecko_enum_prefix="StyleColorInterpolation", )} ${helpers.single_keyword( "color-interpolation-filters", "linearrgb auto srgb", engines="gecko", - gecko_constant_prefix="NS_STYLE_COLOR_INTERPOLATION", animation_value_type="discrete", spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationFiltersProperty", + gecko_enum_prefix="StyleColorInterpolation", )} ${helpers.predefined_type( diff --git a/components/style/properties/longhands/inherited_text.mako.rs b/components/style/properties/longhands/inherited_text.mako.rs index f01bedb177e..41614a04d92 100644 --- a/components/style/properties/longhands/inherited_text.mako.rs +++ b/components/style/properties/longhands/inherited_text.mako.rs @@ -141,11 +141,12 @@ ${helpers.predefined_type( % endif -${helpers.single_keyword( +${helpers.predefined_type( "text-align-last", - "auto start end left right center justify", + "TextAlignLast", + "computed::text::TextAlignLast::Auto", + needs_context=False, engines="gecko", - gecko_constant_prefix="NS_STYLE_TEXT_ALIGN", animation_value_type="discrete", spec="https://drafts.csswg.org/css-text/#propdef-text-align-last", )} @@ -244,7 +245,7 @@ ${helpers.predefined_type( ${helpers.predefined_type( "text-emphasis-style", "TextEmphasisStyle", - None, + "computed::TextEmphasisStyle::None", engines="gecko", initial_specified_value="SpecifiedValue::None", animation_value_type="discrete", @@ -367,13 +368,12 @@ ${helpers.single_keyword( servo_restyle_damage="rebuild_and_reflow", )} -// FIXME Firefox expects the initial value of this property to change depending -// on the value of the layout.css.control-characters.visible pref. ${helpers.single_keyword( "-moz-control-character-visibility", "hidden visible", engines="gecko", - gecko_constant_prefix="NS_STYLE_CONTROL_CHARACTER_VISIBILITY", + gecko_enum_prefix="StyleControlCharacterVisibility", + gecko_pref_controlled_initial_value="layout.css.control-characters.visible=visible", animation_value_type="none", gecko_ffi_name="mControlCharacterVisibility", spec="Nonstandard", diff --git a/components/style/properties/longhands/position.mako.rs b/components/style/properties/longhands/position.mako.rs index 660da1a5a37..d9403be5864 100644 --- a/components/style/properties/longhands/position.mako.rs +++ b/components/style/properties/longhands/position.mako.rs @@ -333,7 +333,7 @@ ${helpers.single_keyword( ${helpers.predefined_type( "object-position", "Position", - "computed::Position::zero()", + "computed::Position::center()", engines="gecko", boxed=True, spec="https://drafts.csswg.org/css-images-3/#the-object-position", @@ -375,7 +375,7 @@ ${helpers.predefined_type( ${helpers.predefined_type( "grid-auto-flow", "GridAutoFlow", - "computed::GridAutoFlow::row()", + "computed::GridAutoFlow::ROW", engines="gecko", animation_value_type="discrete", spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-flow", diff --git a/components/style/properties/longhands/svg.mako.rs b/components/style/properties/longhands/svg.mako.rs index 724c38b2d1b..a09f3e7b656 100644 --- a/components/style/properties/longhands/svg.mako.rs +++ b/components/style/properties/longhands/svg.mako.rs @@ -10,6 +10,7 @@ ${helpers.single_keyword( "vector-effect", "none non-scaling-stroke", engines="gecko", + gecko_enum_prefix="StyleVectorEffect", animation_value_type="discrete", spec="https://www.w3.org/TR/SVGTiny12/painting.html#VectorEffectProperty", )} @@ -76,10 +77,10 @@ ${helpers.single_keyword( ${helpers.predefined_type( "clip-path", - "basic_shape::ClippingShape", - "generics::basic_shape::ShapeSource::None", + "basic_shape::ClipPath", + "generics::basic_shape::ClipPath::None", engines="gecko", - animation_value_type="basic_shape::ClippingShape", + animation_value_type="basic_shape::ClipPath", flags="CREATES_STACKING_CONTEXT", spec="https://drafts.fxtf.org/css-masking/#propdef-clip-path", )} @@ -110,7 +111,7 @@ ${helpers.predefined_type( ${helpers.predefined_type( "mask-position-" + axis, "position::" + direction + "Position", - "computed::LengthPercentage::zero()", + "computed::LengthPercentage::zero_percent()", engines="gecko", extra_prefixes="webkit", initial_specified_value="specified::PositionComponent::Center", @@ -164,6 +165,7 @@ ${helpers.single_keyword( "mask-composite", "add subtract intersect exclude", engines="gecko", + gecko_enum_prefix="StyleMaskComposite", vector=True, extra_prefixes="webkit", animation_value_type="discrete", @@ -172,10 +174,10 @@ ${helpers.single_keyword( ${helpers.predefined_type( "mask-image", - "ImageLayer", + "Image", engines="gecko", - initial_value="computed::ImageLayer::none()", - initial_specified_value="specified::ImageLayer::none()", + initial_value="computed::Image::None", + initial_specified_value="specified::Image::None", parse_method="parse_with_cors_anonymous", spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image", vector=True, diff --git a/components/style/properties/longhands/ui.mako.rs b/components/style/properties/longhands/ui.mako.rs index 05d22abd9e9..8aaee392662 100644 --- a/components/style/properties/longhands/ui.mako.rs +++ b/components/style/properties/longhands/ui.mako.rs @@ -56,7 +56,7 @@ ${helpers.single_keyword( ${helpers.single_keyword( "-moz-window-shadow", - "none default menu tooltip sheet", + "default none menu tooltip sheet", engines="gecko", gecko_ffi_name="mWindowShadow", gecko_enum_prefix="StyleWindowShadow", diff --git a/components/style/properties/longhands/xul.mako.rs b/components/style/properties/longhands/xul.mako.rs index d5c4011eaf6..a981f5ba795 100644 --- a/components/style/properties/longhands/xul.mako.rs +++ b/components/style/properties/longhands/xul.mako.rs @@ -64,10 +64,12 @@ ${helpers.single_keyword( spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-pack)", )} +// NOTE(heycam): Odd that the initial value is 1 yet 0 is a valid value. There +// are uses of `-moz-box-ordinal-group: 0` in the tree, too. ${helpers.predefined_type( "-moz-box-ordinal-group", "Integer", - "0", + "1", engines="gecko", parse_method="parse_non_negative", alias="-webkit-box-ordinal-group", diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index d3e61867518..5a0b9796c02 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -312,7 +312,7 @@ impl Clone for PropertyDeclaration { trait AssertCopy { fn assert() {} } trait AssertNotCopy { fn assert() {} } impl AssertCopy for Helper {} - % for ty in set(x["type"] for x in others): + % for ty in sorted(set(x["type"] for x in others)): impl AssertNotCopy for Helper<${ty}> {} Helper::<${ty}>::assert(); % endfor @@ -729,10 +729,10 @@ impl NonCustomPropertyIdSet { <%def name="static_non_custom_property_id_set(name, is_member)"> static ${name}: NonCustomPropertyIdSet = NonCustomPropertyIdSet { <% - storage = [0] * ((len(data.longhands) + len(data.shorthands) + len(data.all_aliases()) - 1 + 32) / 32) + storage = [0] * int((len(data.longhands) + len(data.shorthands) + len(data.all_aliases()) - 1 + 32) / 32) for i, property in enumerate(data.longhands + data.shorthands + data.all_aliases()): if is_member(property): - storage[i / 32] |= 1 << (i % 32) + storage[int(i / 32)] |= 1 << (i % 32) %> storage: [${", ".join("0x%x" % word for word in storage)}] }; @@ -741,15 +741,61 @@ static ${name}: NonCustomPropertyIdSet = NonCustomPropertyIdSet { <%def name="static_longhand_id_set(name, is_member)"> static ${name}: LonghandIdSet = LonghandIdSet { <% - storage = [0] * ((len(data.longhands) - 1 + 32) / 32) + storage = [0] * int((len(data.longhands) - 1 + 32) / 32) for i, property in enumerate(data.longhands): if is_member(property): - storage[i / 32] |= 1 << (i % 32) + storage[int(i / 32)] |= 1 << (i % 32) %> storage: [${", ".join("0x%x" % word for word in storage)}] }; +<% + logical_groups = defaultdict(list) + for prop in data.longhands: + if prop.logical_group: + logical_groups[prop.logical_group].append(prop) + + for group, props in logical_groups.items(): + logical_count = sum(1 for p in props if p.logical) + if logical_count * 2 != len(props): + raise RuntimeError("Logical group {} has ".format(group) + + "unbalanced logical / physical properties") + + FIRST_LINE_RESTRICTIONS = PropertyRestrictions.first_line(data) + FIRST_LETTER_RESTRICTIONS = PropertyRestrictions.first_letter(data) + MARKER_RESTRICTIONS = PropertyRestrictions.marker(data) + PLACEHOLDER_RESTRICTIONS = PropertyRestrictions.placeholder(data) + CUE_RESTRICTIONS = PropertyRestrictions.cue(data) + + def restriction_flags(property): + name = property.name + flags = [] + if name in FIRST_LINE_RESTRICTIONS: + flags.append("APPLIES_TO_FIRST_LINE") + if name in FIRST_LETTER_RESTRICTIONS: + flags.append("APPLIES_TO_FIRST_LETTER") + if name in PLACEHOLDER_RESTRICTIONS: + flags.append("APPLIES_TO_PLACEHOLDER") + if name in MARKER_RESTRICTIONS: + flags.append("APPLIES_TO_MARKER") + if name in CUE_RESTRICTIONS: + flags.append("APPLIES_TO_CUE") + return flags + +%> + +/// A group for properties which may override each other +/// via logical resolution. +#[derive(Clone, Copy, Eq, Hash, PartialEq)] +pub enum LogicalGroup { + % for group in sorted(logical_groups.keys()): + /// ${group} + ${to_camel_case(group)}, + % endfor +} + + /// A set of longhand properties #[derive(Clone, Copy, Debug, Default, MallocSizeOf, PartialEq)] pub struct LonghandIdSet { @@ -837,6 +883,30 @@ impl LonghandIdSet { &HAS_NO_EFFECT_ON_SCROLLBARS } + /// Returns the set of padding properties for the purpose of disabling + /// native appearance. + #[inline] + pub fn padding_properties() -> &'static Self { + <% assert "padding" in logical_groups %> + ${static_longhand_id_set( + "PADDING_PROPERTIES", + lambda p: p.logical_group == "padding" + )} + &PADDING_PROPERTIES + } + + /// Returns the set of border properties for the purpose of disabling native + /// appearance. + #[inline] + pub fn border_background_properties() -> &'static Self { + ${static_longhand_id_set( + "BORDER_BACKGROUND_PROPERTIES", + lambda p: (p.logical_group and p.logical_group.startswith("border")) or \ + p.name in ["background-color", "background-image"] + )} + &BORDER_BACKGROUND_PROPERTIES + } + /// Iterate over the current longhand id set. pub fn iter(&self) -> LonghandIdSetIterator { LonghandIdSetIterator { longhands: self, cur: 0, } @@ -998,53 +1068,8 @@ bitflags! { } } -<% - logical_groups = defaultdict(list) - for prop in data.longhands: - if prop.logical_group: - logical_groups[prop.logical_group].append(prop) - - for group, props in logical_groups.iteritems(): - logical_count = sum(1 for p in props if p.logical) - if logical_count * 2 != len(props): - raise RuntimeError("Logical group {} has ".format(group) + - "unbalanced logical / physical properties") - - FIRST_LINE_RESTRICTIONS = PropertyRestrictions.first_line(data) - FIRST_LETTER_RESTRICTIONS = PropertyRestrictions.first_letter(data) - MARKER_RESTRICTIONS = PropertyRestrictions.marker(data) - PLACEHOLDER_RESTRICTIONS = PropertyRestrictions.placeholder(data) - CUE_RESTRICTIONS = PropertyRestrictions.cue(data) - - def restriction_flags(property): - name = property.name - flags = [] - if name in FIRST_LINE_RESTRICTIONS: - flags.append("APPLIES_TO_FIRST_LINE") - if name in FIRST_LETTER_RESTRICTIONS: - flags.append("APPLIES_TO_FIRST_LETTER") - if name in PLACEHOLDER_RESTRICTIONS: - flags.append("APPLIES_TO_PLACEHOLDER") - if name in MARKER_RESTRICTIONS: - flags.append("APPLIES_TO_MARKER") - if name in CUE_RESTRICTIONS: - flags.append("APPLIES_TO_CUE") - return flags - -%> - -/// A group for properties which may override each other -/// via logical resolution. -#[derive(Clone, Copy, Eq, Hash, PartialEq)] -pub enum LogicalGroup { - % for group in logical_groups.iterkeys(): - /// ${group} - ${to_camel_case(group)}, - % endfor -} - /// An identifier for a given longhand property. -#[derive(Clone, Copy, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)] +#[derive(Clone, Copy, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] #[repr(u16)] pub enum LonghandId { % for i, property in enumerate(data.longhands): @@ -1089,6 +1114,7 @@ impl LonghandId { // could potentially do so, which would speed up serialization // algorithms and what not, I guess. <% + from functools import cmp_to_key longhand_to_shorthand_map = {} num_sub_properties = {} for shorthand in data.shorthands: @@ -1099,6 +1125,9 @@ impl LonghandId { longhand_to_shorthand_map[sub_property.ident].append(shorthand.camel_case) + def cmp(a, b): + return (a > b) - (a < b) + def preferred_order(x, y): # Since we want properties in order from most subproperties to least, # reverse the arguments to cmp from the expected order. @@ -1110,8 +1139,8 @@ impl LonghandId { # Sort the lists of shorthand properties according to preferred order: # https://drafts.csswg.org/cssom/#concept-shorthands-preferred-order - for shorthand_list in longhand_to_shorthand_map.itervalues(): - shorthand_list.sort(cmp=preferred_order) + for shorthand_list in longhand_to_shorthand_map.values(): + shorthand_list.sort(key=cmp_to_key(preferred_order)) %> // based on lookup results for each longhand, create result arrays @@ -1353,7 +1382,7 @@ where } /// An identifier for a given shorthand property. -#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)] +#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] #[repr(u16)] pub enum ShorthandId { % for i, property in enumerate(data.shorthands): @@ -1590,10 +1619,7 @@ impl UnparsedValue { } else { CSSWideKeyword::Initial }; - PropertyDeclaration::CSSWideKeyword(WideKeywordDeclaration { - id: longhand_id, - keyword, - }) + PropertyDeclaration::css_wide_keyword(longhand_id, keyword) }; let css = match crate::custom_properties::substitute( @@ -1630,10 +1656,7 @@ impl UnparsedValue { let mut input = Parser::new(&mut input); input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less. if let Ok(keyword) = input.try(CSSWideKeyword::parse) { - return PropertyDeclaration::CSSWideKeyword(WideKeywordDeclaration { - id: longhand_id, - keyword, - }); + return PropertyDeclaration::css_wide_keyword(longhand_id, keyword); } let declaration = input.parse_entirely(|input| { @@ -2239,6 +2262,12 @@ impl PropertyDeclaration { } } + /// Returns a CSS-wide keyword declaration for a given property. + #[inline] + pub fn css_wide_keyword(id: LonghandId, keyword: CSSWideKeyword) -> Self { + Self::CSSWideKeyword(WideKeywordDeclaration { id, keyword }) + } + /// Returns a CSS-wide keyword if the declaration's value is one. #[inline] pub fn get_css_wide_keyword(&self) -> Option { @@ -2367,9 +2396,7 @@ impl PropertyDeclaration { PropertyId::Longhand(id) => { input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less. input.try(CSSWideKeyword::parse).map(|keyword| { - PropertyDeclaration::CSSWideKeyword( - WideKeywordDeclaration { id, keyword }, - ) + PropertyDeclaration::css_wide_keyword(id, keyword) }).or_else(|()| { input.look_for_var_or_env_functions(); input.parse_entirely(|input| id.parse_value(context, input)) @@ -2403,12 +2430,7 @@ impl PropertyDeclaration { declarations.all_shorthand = AllShorthand::CSSWideKeyword(keyword) } else { for longhand in id.longhands() { - declarations.push(PropertyDeclaration::CSSWideKeyword( - WideKeywordDeclaration { - id: longhand, - keyword, - }, - )) + declarations.push(PropertyDeclaration::css_wide_keyword(longhand, keyword)); } } } else { @@ -2550,12 +2572,7 @@ impl<'a> Iterator for AllShorthandDeclarationIterator<'a> { match *self.all_shorthand { AllShorthand::NotSet => None, AllShorthand::CSSWideKeyword(ref keyword) => { - Some(PropertyDeclaration::CSSWideKeyword( - WideKeywordDeclaration { - id: self.longhands.next()?, - keyword: *keyword - } - )) + Some(PropertyDeclaration::css_wide_keyword(self.longhands.next()?, *keyword)) } AllShorthand::WithVariables(ref unparsed) => { Some(PropertyDeclaration::WithVariables( diff --git a/components/style/properties/shorthands/border.mako.rs b/components/style/properties/shorthands/border.mako.rs index 1f77b905021..e5122153db7 100644 --- a/components/style/properties/shorthands/border.mako.rs +++ b/components/style/properties/shorthands/border.mako.rs @@ -70,11 +70,10 @@ pub fn parse_border<'i, 't>( let mut width = None; let mut any = false; loop { - if color.is_none() { - if let Ok(value) = input.try(|i| Color::parse(context, i)) { - color = Some(value); + if width.is_none() { + if let Ok(value) = input.try(|i| BorderSideWidth::parse(context, i)) { + width = Some(value); any = true; - continue } } if style.is_none() { @@ -84,9 +83,9 @@ pub fn parse_border<'i, 't>( continue } } - if width.is_none() { - if let Ok(value) = input.try(|i| BorderSideWidth::parse(context, i)) { - width = Some(value); + if color.is_none() { + if let Ok(value) = input.try(|i| Color::parse(context, i)) { + color = Some(value); any = true; continue } diff --git a/components/style/properties/shorthands/position.mako.rs b/components/style/properties/shorthands/position.mako.rs index d9cb9da3342..48e56e6ef3c 100644 --- a/components/style/properties/shorthands/position.mako.rs +++ b/components/style/properties/shorthands/position.mako.rs @@ -549,7 +549,7 @@ use crate::properties::longhands::{grid_auto_columns, grid_auto_rows, grid_auto_flow}; use crate::values::generics::grid::GridTemplateComponent; use crate::values::specified::{GenericGridTemplateComponent, ImplicitGridTracks}; - use crate::values::specified::position::{AutoFlow, GridAutoFlow, GridTemplateAreas}; + use crate::values::specified::position::{GridAutoFlow, GridTemplateAreas}; pub fn parse_value<'i, 't>( context: &ParserContext, @@ -566,28 +566,28 @@ input: &mut Parser<'i, 't>, is_row: bool, ) -> Result> { - let mut auto_flow = None; - let mut dense = false; + let mut track = None; + let mut dense = GridAutoFlow::empty(); + for _ in 0..2 { if input.try(|i| i.expect_ident_matching("auto-flow")).is_ok() { - auto_flow = if is_row { - Some(AutoFlow::Row) + track = if is_row { + Some(GridAutoFlow::ROW) } else { - Some(AutoFlow::Column) + Some(GridAutoFlow::COLUMN) }; } else if input.try(|i| i.expect_ident_matching("dense")).is_ok() { - dense = true; + dense = GridAutoFlow::DENSE } else { break } } - auto_flow.map(|flow| { - GridAutoFlow { - autoflow: flow, - dense: dense, - } - }).ok_or(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + if track.is_some() { + Ok(track.unwrap() | dense) + } else { + Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + } } if let Ok((rows, cols, areas)) = input.try(|i| super::grid_template::parse_grid_template(context, i)) { @@ -637,7 +637,7 @@ self.grid_template_areas, dest); } - if self.grid_auto_flow.autoflow == AutoFlow::Column { + if self.grid_auto_flow.contains(GridAutoFlow::COLUMN) { // It should fail to serialize if other branch of the if condition's values are set. if !self.grid_auto_rows.is_initial() || !self.grid_template_columns.is_initial() { @@ -653,7 +653,7 @@ self.grid_template_rows.to_css(dest)?; dest.write_str(" / auto-flow")?; - if self.grid_auto_flow.dense { + if self.grid_auto_flow.contains(GridAutoFlow::DENSE) { dest.write_str(" dense")?; } @@ -676,7 +676,7 @@ } dest.write_str("auto-flow")?; - if self.grid_auto_flow.dense { + if self.grid_auto_flow.contains(GridAutoFlow::DENSE) { dest.write_str(" dense")?; } diff --git a/components/style/rule_collector.rs b/components/style/rule_collector.rs index 9841eb9e70f..1550a0368a4 100644 --- a/components/style/rule_collector.rs +++ b/components/style/rule_collector.rs @@ -55,11 +55,6 @@ pub fn containing_shadow_ignoring_svg_use( } } -#[inline] -fn sort_rules_from(rules: &mut ApplicableDeclarationList, start: usize) { - rules[start..].sort_unstable_by_key(|block| (block.specificity, block.source_order())); -} - /// An object that we use with all the intermediate state needed for the /// cascade. /// @@ -82,6 +77,7 @@ where flags_setter: &'a mut F, matches_user_and_author_rules: bool, matches_document_author_rules: bool, + in_sort_scope: bool, } impl<'a, 'b: 'a, E, F: 'a> RuleCollector<'a, 'b, E, F> @@ -134,9 +130,36 @@ where rules, matches_user_and_author_rules, matches_document_author_rules: matches_user_and_author_rules, + in_sort_scope: false, } } + /// Sets up the state necessary to collect rules from a given DOM tree + /// (either the document tree, or a shadow tree). + /// + /// All rules in the same tree need to be matched together, and this + /// function takes care of sorting them by specificity and source order. + #[inline] + fn in_tree(&mut self, host: Option, f: impl FnOnce(&mut Self)) { + debug_assert!(!self.in_sort_scope, "Nested sorting makes no sense"); + let start = self.rules.len(); + self.in_sort_scope = true; + let old_host = self.context.current_host.take(); + self.context.current_host = host.map(|e| e.opaque()); + f(self); + if start != self.rules.len() { + self.rules[start..] + .sort_unstable_by_key(|block| (block.specificity, block.source_order())); + } + self.context.current_host = old_host; + self.in_sort_scope = false; + } + + #[inline] + fn in_shadow_tree(&mut self, host: E, f: impl FnOnce(&mut Self)) { + self.in_tree(Some(host), f); + } + fn collect_stylist_rules(&mut self, origin: Origin) { let cascade_level = match origin { Origin::UserAgent => CascadeLevel::UANormal, @@ -150,7 +173,9 @@ where None => return, }; - self.collect_rules_internal(None, map, cascade_level); + self.in_tree(None, |collector| { + collector.collect_rules_in_map(map, cascade_level); + }); } fn collect_user_agent_rules(&mut self) { @@ -189,39 +214,30 @@ where } } - fn collect_rules_in_shadow_tree( - &mut self, - shadow_host: E, - map: &SelectorMap, - cascade_level: CascadeLevel, - ) { - debug_assert!(shadow_host.shadow_root().is_some()); - self.collect_rules_internal(Some(shadow_host), map, cascade_level); + #[inline] + fn collect_rules_in_list(&mut self, part_rules: &[Rule], cascade_level: CascadeLevel) { + debug_assert!(self.in_sort_scope, "Rules gotta be sorted"); + SelectorMap::get_matching_rules( + self.element, + part_rules, + &mut self.rules, + &mut self.context, + &mut self.flags_setter, + cascade_level, + ); } #[inline] - fn collect_rules_internal( - &mut self, - shadow_host: Option, - map: &SelectorMap, - cascade_level: CascadeLevel, - ) { - 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 start = rules.len(); - self.context.with_shadow_host(shadow_host, |context| { - map.get_all_matching_rules( - element, - rule_hash_target, - rules, - context, - flags_setter, - cascade_level, - ); - }); - sort_rules_from(rules, start); + fn collect_rules_in_map(&mut self, map: &SelectorMap, cascade_level: CascadeLevel) { + debug_assert!(self.in_sort_scope, "Rules gotta be sorted"); + map.get_all_matching_rules( + self.element, + self.rule_hash_target, + &mut self.rules, + &mut self.context, + &mut self.flags_setter, + cascade_level, + ); } /// Collects the rules for the ::slotted pseudo-element and the :host @@ -258,17 +274,16 @@ where None => continue, }; - self.collect_rules_in_shadow_tree( - shadow.host(), - slotted_rules, - CascadeLevel::AuthorNormal { + self.in_shadow_tree(shadow.host(), |collector| { + let cascade_level = CascadeLevel::AuthorNormal { shadow_cascade_order, - }, - ); + }; + collector.collect_rules_in_map(slotted_rules, cascade_level); + }); } } - fn collect_normal_rules_from_containing_shadow_tree(&mut self) { + fn collect_rules_from_containing_shadow_tree(&mut self) { if !self.matches_user_and_author_rules { return; } @@ -281,11 +296,34 @@ where self.matches_document_author_rules = false; - 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::same_tree_author_normal()); - } + let cascade_data = match containing_shadow.style_data() { + Some(c) => c, + None => return, + }; + + let cascade_level = CascadeLevel::same_tree_author_normal(); + self.in_shadow_tree(containing_shadow.host(), |collector| { + if let Some(map) = cascade_data.normal_rules(collector.pseudo_element) { + collector.collect_rules_in_map(map, cascade_level); + } + + // Collect rules from :host::part() and such + let hash_target = collector.rule_hash_target; + if !hash_target.has_part_attr() { + return; + } + + let part_rules = match cascade_data.part_rules(collector.pseudo_element) { + Some(p) => p, + None => return, + }; + + hash_target.each_part(|part| { + if let Some(part_rules) = part_rules.get(part) { + collector.collect_rules_in_list(part_rules, cascade_level); + } + }); + }); } /// Collects the rules for the :host pseudo-class. @@ -311,13 +349,12 @@ where }; let rule_hash_target = self.rule_hash_target; - self.collect_rules_in_shadow_tree( - rule_hash_target, - host_rules, - CascadeLevel::AuthorNormal { + self.in_shadow_tree(rule_hash_target, |collector| { + let cascade_level = CascadeLevel::AuthorNormal { shadow_cascade_order, - }, - ); + }; + collector.collect_rules_in_map(host_rules, cascade_level); + }); } fn collect_document_author_rules(&mut self) { @@ -328,7 +365,7 @@ where self.collect_stylist_rules(Origin::Author); } - fn collect_part_rules(&mut self) { + fn collect_part_rules_from_outer_trees(&mut self) { if !self.rule_hash_target.has_part_attr() { return; } @@ -363,28 +400,16 @@ where if let Some(part_rules) = part_rules { let containing_host = outer_shadow.map(|s| s.host()); - let element = self.element; - let rules = &mut self.rules; - let flags_setter = &mut self.flags_setter; let cascade_level = CascadeLevel::AuthorNormal { shadow_cascade_order, }; - let start = rules.len(); - self.context.with_shadow_host(containing_host, |context| { + self.in_tree(containing_host, |collector| { for p in &parts { if let Some(part_rules) = part_rules.get(p) { - SelectorMap::get_matching_rules( - element, - &part_rules, - rules, - context, - flags_setter, - cascade_level, - ); + collector.collect_rules_in_list(part_rules, cascade_level); } } }); - sort_rules_from(rules, start); shadow_cascade_order.inc(); } @@ -393,14 +418,13 @@ where None => break, // Nowhere to export to. }; - parts.retain(|part| { - let exported_part = match inner_shadow_host.exported_part(part) { - Some(part) => part, - None => return false, - }; - std::mem::replace(part, exported_part); - true - }); + let mut new_parts = SmallVec::new(); + for part in &parts { + inner_shadow_host.each_exported_part(part, |exported_part| { + new_parts.push(exported_part.clone()); + }); + } + parts = new_parts; } } @@ -461,10 +485,10 @@ where return; } self.collect_host_and_slotted_rules(); - self.collect_normal_rules_from_containing_shadow_tree(); + self.collect_rules_from_containing_shadow_tree(); self.collect_document_author_rules(); self.collect_style_attribute(); - self.collect_part_rules(); + self.collect_part_rules_from_outer_trees(); self.collect_animation_rules(); } } diff --git a/components/style/rule_tree/mod.rs b/components/style/rule_tree/mod.rs index 113fa9cb9bb..484cdee5183 100644 --- a/components/style/rule_tree/mod.rs +++ b/components/style/rule_tree/mod.rs @@ -7,8 +7,6 @@ //! The rule tree. use crate::applicable_declarations::ApplicableDeclarationList; -#[cfg(feature = "gecko")] -use crate::gecko::selector_parser::PseudoElement; use crate::hash::{self, FxHashMap}; use crate::properties::{Importance, LonghandIdSet, PropertyDeclarationBlock}; use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards}; @@ -136,29 +134,6 @@ impl StyleSource { let _ = write!(writer, " -> {:?}", self.read(guard).declarations()); } - // This is totally unsafe, should be removed when we figure out the cause of - // bug 1607553. - #[cfg(feature = "gecko")] - unsafe fn dump_unchecked(&self, writer: &mut W) { - if let Some(ref rule) = self.0.as_first() { - let rule = rule.read_unchecked(); - let _ = write!(writer, "{:?}", rule.selectors); - } - let _ = write!(writer, " -> {:?}", self.read_unchecked().declarations()); - } - - // This is totally unsafe, should be removed when we figure out the cause of - // bug 1607553. - #[inline] - #[cfg(feature = "gecko")] - unsafe fn read_unchecked(&self) -> &PropertyDeclarationBlock { - let block: &Locked = match self.0.borrow() { - ArcUnionBorrow::First(ref rule) => &rule.get().read_unchecked().block, - ArcUnionBorrow::Second(ref block) => block.get(), - }; - block.read_unchecked() - } - /// Read the style source guard, and obtain thus read access to the /// underlying property declaration block. #[inline] @@ -1441,198 +1416,6 @@ impl StrongRuleNode { } } - /// Returns true if any properties specified by `rule_type_mask` was set by - /// an author rule. - #[cfg(feature = "gecko")] - pub fn has_author_specified_rules( - &self, - mut element: E, - mut pseudo: Option, - guards: &StylesheetGuards, - rule_type_mask: u32, - author_colors_allowed: bool, - ) -> bool - where - E: crate::dom::TElement, - { - use crate::gecko_bindings::structs::NS_AUTHOR_SPECIFIED_BACKGROUND; - use crate::gecko_bindings::structs::NS_AUTHOR_SPECIFIED_BORDER; - use crate::gecko_bindings::structs::NS_AUTHOR_SPECIFIED_PADDING; - use crate::properties::{CSSWideKeyword, LonghandId}; - use crate::properties::{PropertyDeclaration, PropertyDeclarationId}; - use std::borrow::Cow; - - // Reset properties: - const BACKGROUND_PROPS: &'static [LonghandId] = - &[LonghandId::BackgroundColor, LonghandId::BackgroundImage]; - - const BORDER_PROPS: &'static [LonghandId] = &[ - LonghandId::BorderTopColor, - LonghandId::BorderTopStyle, - LonghandId::BorderTopWidth, - LonghandId::BorderRightColor, - LonghandId::BorderRightStyle, - LonghandId::BorderRightWidth, - LonghandId::BorderBottomColor, - LonghandId::BorderBottomStyle, - LonghandId::BorderBottomWidth, - LonghandId::BorderLeftColor, - LonghandId::BorderLeftStyle, - LonghandId::BorderLeftWidth, - LonghandId::BorderTopLeftRadius, - LonghandId::BorderTopRightRadius, - LonghandId::BorderBottomRightRadius, - LonghandId::BorderBottomLeftRadius, - LonghandId::BorderInlineStartColor, - LonghandId::BorderInlineStartStyle, - LonghandId::BorderInlineStartWidth, - LonghandId::BorderInlineEndColor, - LonghandId::BorderInlineEndStyle, - LonghandId::BorderInlineEndWidth, - LonghandId::BorderBlockStartColor, - LonghandId::BorderBlockStartStyle, - LonghandId::BorderBlockStartWidth, - LonghandId::BorderBlockEndColor, - LonghandId::BorderBlockEndStyle, - LonghandId::BorderBlockEndWidth, - ]; - - const PADDING_PROPS: &'static [LonghandId] = &[ - LonghandId::PaddingTop, - LonghandId::PaddingRight, - LonghandId::PaddingBottom, - LonghandId::PaddingLeft, - LonghandId::PaddingInlineStart, - LonghandId::PaddingInlineEnd, - LonghandId::PaddingBlockStart, - LonghandId::PaddingBlockEnd, - ]; - - // Set of properties that we are currently interested in. - let mut properties = LonghandIdSet::new(); - - if rule_type_mask & NS_AUTHOR_SPECIFIED_BACKGROUND != 0 { - for id in BACKGROUND_PROPS { - properties.insert(*id); - } - } - if rule_type_mask & NS_AUTHOR_SPECIFIED_BORDER != 0 { - for id in BORDER_PROPS { - properties.insert(*id); - } - } - if rule_type_mask & NS_AUTHOR_SPECIFIED_PADDING != 0 { - for id in PADDING_PROPS { - properties.insert(*id); - } - } - - // If author colors are not allowed, don't look at those properties - // (except for background-color which is special and we handle below). - if !author_colors_allowed { - properties.remove_all(LonghandIdSet::ignored_when_colors_disabled()); - if rule_type_mask & NS_AUTHOR_SPECIFIED_BACKGROUND != 0 { - properties.insert(LonghandId::BackgroundColor); - } - } - - let mut element_rule_node = Cow::Borrowed(self); - - loop { - // We need to be careful not to count styles covered up by - // user-important or UA-important declarations. But we do want to - // catch explicit inherit styling in those and check our parent - // element to see whether we have user styling for those properties. - // Note that we don't care here about inheritance due to lack of a - // specified value, since all the properties we care about are reset - // properties. - - let mut inherited_properties = LonghandIdSet::new(); - let mut have_explicit_ua_inherit = false; - - for node in element_rule_node.self_and_ancestors() { - let source = node.style_source(); - let declarations = if source.is_some() { - source - .as_ref() - .unwrap() - .read(node.cascade_level().guard(guards)) - .declaration_importance_iter() - } else { - continue; - }; - - // Iterate over declarations of the longhands we care about. - let node_importance = node.importance(); - let longhands = declarations.rev().filter_map(|(declaration, importance)| { - if importance != node_importance { - return None; - } - match declaration.id() { - PropertyDeclarationId::Longhand(id) => Some((id, declaration)), - _ => None, - } - }); - - let is_author = node.cascade_level().origin() == Origin::Author; - for (id, declaration) in longhands { - if !properties.contains(id) { - continue; - } - - if is_author { - if !author_colors_allowed { - if let PropertyDeclaration::BackgroundColor(ref color) = *declaration { - if color.is_transparent() { - return true; - } - continue; - } - } - return true; - } - - // This property was set by a non-author rule. - // Stop looking for it in this element's rule - // nodes. - properties.remove(id); - - // However, if it is inherited, then it might be - // inherited from an author rule from an - // ancestor element's rule nodes. - if declaration.get_css_wide_keyword() == Some(CSSWideKeyword::Inherit) { - have_explicit_ua_inherit = true; - inherited_properties.insert(id); - } - } - } - - if !have_explicit_ua_inherit { - break; - } - - // Continue to the parent element and search for the inherited properties. - if let Some(pseudo) = pseudo.take() { - if pseudo.inherits_from_default_values() { - break; - } - } else { - element = match element.inheritance_parent() { - Some(parent) => parent, - None => break, - }; - - let parent_data = element.mutate_data().unwrap(); - let parent_rule_node = parent_data.styles.primary().rules().clone(); - element_rule_node = Cow::Owned(parent_rule_node); - } - - properties = inherited_properties; - } - - false - } - /// Returns true if there is either animation or transition level rule. pub fn has_animation_or_transition_rules(&self) -> bool { self.self_and_ancestors() @@ -1742,47 +1525,6 @@ impl Drop for StrongRuleNode { return; } - #[cfg(feature = "gecko")] - #[inline(always)] - fn assert_on_release() -> bool { - crate::gecko_bindings::structs::GECKO_IS_NIGHTLY - } - - #[cfg(feature = "servo")] - fn assert_on_release() -> bool { - false - } - - if cfg!(debug_assertions) || assert_on_release() { - let children = node.children.read(); - if !children.is_empty() { - let mut crash_str = vec![]; - - #[cfg(feature = "gecko")] - unsafe { - // Try to unsafely collect some information of this before - // crashing the process. - if let Some(ref s) = node.source { - s.dump_unchecked(&mut crash_str); - crash_str.push(b'\n'); - } - children.each(|child| { - (*child.ptr()) - .source - .as_ref() - .unwrap() - .dump_unchecked(&mut crash_str); - crash_str.push(b'\n'); - }); - } - - panic!( - "Children left in the rule tree on drop: {}", - String::from_utf8_lossy(&crash_str).trim() - ); - } - } - if node.parent.is_none() { debug!("Dropping root node!"); // The free list should be null by this point diff --git a/components/style/servo/selector_parser.rs b/components/style/servo/selector_parser.rs index 599b603f4ff..2537cae9f83 100644 --- a/components/style/servo/selector_parser.rs +++ b/components/style/servo/selector_parser.rs @@ -709,10 +709,6 @@ impl ElementSnapshot for ServoElementSnapshot { false } - fn exported_part(&self, _: &Atom) -> Option { - None - } - fn imported_part(&self, _: &Atom) -> Option { None } diff --git a/components/style/style_adjuster.rs b/components/style/style_adjuster.rs index a2c6e5a2928..c2a15f7fa0e 100644 --- a/components/style/style_adjuster.rs +++ b/components/style/style_adjuster.rs @@ -227,15 +227,21 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { fn set_bits(&mut self) { let display = self.style.get_box().clone_display(); - if !display.is_contents() && - !self + if !display.is_contents() { + if !self .style .get_text() .clone_text_decoration_line() .is_empty() - { - self.style - .add_flags(ComputedValueFlags::HAS_TEXT_DECORATION_LINES); + { + self.style + .add_flags(ComputedValueFlags::HAS_TEXT_DECORATION_LINES); + } + + if self.style.get_effects().clone_opacity() == 0. { + self.style + .add_flags(ComputedValueFlags::IS_IN_OPACITY_ZERO_SUBTREE); + } } if self.style.is_pseudo_element() { @@ -488,6 +494,35 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { } } + ///