aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/layout/display_list/builder.rs104
-rw-r--r--components/layout/display_list/gradient.rs10
-rw-r--r--components/layout_2020/display_list/gradient.rs56
-rw-r--r--components/layout_2020/display_list/mod.rs149
-rw-r--r--components/layout_2020/flow/inline.rs8
-rw-r--r--components/layout_2020/flow/mod.rs3
-rw-r--r--components/layout_2020/lib.rs2
-rw-r--r--components/layout_2020/positioned.rs6
-rw-r--r--components/layout_thread/dom_wrapper.rs9
-rw-r--r--components/layout_thread_2020/dom_wrapper.rs9
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py9
-rw-r--r--components/script/dom/bindings/root.rs2
-rw-r--r--components/script/dom/cssrulelist.rs5
-rw-r--r--components/script/dom/element.rs9
-rw-r--r--components/script/dom/htmlcanvaselement.rs4
-rw-r--r--components/script/dom/htmlstyleelement.rs3
-rw-r--r--components/script/dom/webgl2renderingcontext.rs23
-rw-r--r--components/script/dom/webidls/WebGL2RenderingContext.webidl2
-rw-r--r--components/script/dom/xrview.rs25
-rw-r--r--components/script/lib.rs3
-rw-r--r--components/script_layout_interface/lib.rs1
-rw-r--r--components/selectors/matching.rs27
-rw-r--r--components/selectors/parser.rs41
-rw-r--r--components/selectors/tree.rs7
-rw-r--r--components/style/animation.rs153
-rw-r--r--components/style/build.rs8
-rw-r--r--components/style/counter_style/mod.rs8
-rw-r--r--components/style/custom_properties.rs37
-rw-r--r--components/style/dom.rs8
-rw-r--r--components/style/driver.rs14
-rw-r--r--components/style/element_state.rs4
-rw-r--r--components/style/encoding_support.rs4
-rw-r--r--components/style/gecko/conversions.rs270
-rw-r--r--components/style/gecko/media_queries.rs13
-rw-r--r--components/style/gecko/non_ts_pseudo_class_list.rs131
-rw-r--r--components/style/gecko/pseudo_element.rs6
-rwxr-xr-xcomponents/style/gecko/regen_atoms.py2
-rw-r--r--components/style/gecko/selector_parser.rs13
-rw-r--r--components/style/gecko/snapshot.rs5
-rw-r--r--components/style/gecko/snapshot_helpers.rs24
-rw-r--r--components/style/gecko/wrapper.rs110
-rw-r--r--components/style/gecko_string_cache/namespace.rs13
-rw-r--r--components/style/invalidation/element/element_wrapper.rs10
-rw-r--r--components/style/properties/Mako-0.9.1.zipbin469500 -> 0 bytes
-rw-r--r--components/style/properties/Mako-1.1.2-py2.py3-none-any.whlbin0 -> 75521 bytes
-rw-r--r--components/style/properties/build.py10
-rw-r--r--components/style/properties/cascade.rs136
-rw-r--r--components/style/properties/computed_value_flags.rs26
-rw-r--r--components/style/properties/data.py11
-rw-r--r--components/style/properties/gecko.mako.rs456
-rw-r--r--components/style/properties/helpers.mako.rs27
-rw-r--r--components/style/properties/helpers/animated_properties.mako.rs65
-rw-r--r--components/style/properties/longhands/background.mako.rs10
-rw-r--r--components/style/properties/longhands/border.mako.rs6
-rw-r--r--components/style/properties/longhands/box.mako.rs9
-rw-r--r--components/style/properties/longhands/effects.mako.rs2
-rw-r--r--components/style/properties/longhands/font.mako.rs2
-rw-r--r--components/style/properties/longhands/inherited_box.mako.rs1
-rw-r--r--components/style/properties/longhands/inherited_svg.mako.rs3
-rw-r--r--components/style/properties/longhands/inherited_text.mako.rs14
-rw-r--r--components/style/properties/longhands/position.mako.rs4
-rw-r--r--components/style/properties/longhands/svg.mako.rs16
-rw-r--r--components/style/properties/longhands/ui.mako.rs2
-rw-r--r--components/style/properties/longhands/xul.mako.rs4
-rw-r--r--components/style/properties/properties.mako.rs178
-rw-r--r--components/style/properties/shorthands/border.mako.rs13
-rw-r--r--components/style/properties/shorthands/position.mako.rs32
-rw-r--r--components/style/rule_collector.rs182
-rw-r--r--components/style/rule_tree/mod.rs258
-rw-r--r--components/style/servo/selector_parser.rs4
-rw-r--r--components/style/style_adjuster.rs55
-rw-r--r--components/style/stylesheet_set.rs4
-rw-r--r--components/style/stylesheets/mod.rs4
-rw-r--r--components/style/stylesheets/rule_list.rs5
-rw-r--r--components/style/stylesheets/rule_parser.rs10
-rw-r--r--components/style/stylesheets/stylesheet.rs18
-rw-r--r--components/style/traversal.rs6
-rw-r--r--components/style/values/animated/length.rs39
-rw-r--r--components/style/values/animated/mod.rs14
-rw-r--r--components/style/values/computed/basic_shape.rs8
-rw-r--r--components/style/values/computed/font.rs67
-rw-r--r--components/style/values/computed/image.rs16
-rw-r--r--components/style/values/computed/length.rs10
-rw-r--r--components/style/values/computed/length_percentage.rs460
-rw-r--r--components/style/values/computed/mod.rs54
-rw-r--r--components/style/values/computed/position.rs10
-rw-r--r--components/style/values/computed/svg.rs4
-rw-r--r--components/style/values/computed/text.rs6
-rw-r--r--components/style/values/computed/ui.rs4
-rw-r--r--components/style/values/distance.rs13
-rw-r--r--components/style/values/generics/basic_shape.rs115
-rw-r--r--components/style/values/generics/calc.rs573
-rw-r--r--components/style/values/generics/grid.rs41
-rw-r--r--components/style/values/generics/image.rs276
-rw-r--r--components/style/values/generics/mod.rs1
-rw-r--r--components/style/values/generics/position.rs18
-rw-r--r--components/style/values/generics/svg.rs5
-rw-r--r--components/style/values/generics/transform.rs2
-rw-r--r--components/style/values/generics/ui.rs28
-rw-r--r--components/style/values/resolved/mod.rs45
-rw-r--r--components/style/values/specified/align.rs2
-rw-r--r--components/style/values/specified/basic_shape.rs130
-rw-r--r--components/style/values/specified/border.rs13
-rw-r--r--components/style/values/specified/box.rs18
-rw-r--r--components/style/values/specified/calc.rs629
-rw-r--r--components/style/values/specified/color.rs25
-rw-r--r--components/style/values/specified/font.rs30
-rw-r--r--components/style/values/specified/grid.rs10
-rw-r--r--components/style/values/specified/image.rs261
-rw-r--r--components/style/values/specified/length.rs55
-rw-r--r--components/style/values/specified/mod.rs5
-rw-r--r--components/style/values/specified/percentage.rs3
-rw-r--r--components/style/values/specified/position.rs188
-rw-r--r--components/style/values/specified/svg.rs6
-rw-r--r--components/style/values/specified/svg_path.rs18
-rw-r--r--components/style/values/specified/text.rs89
-rw-r--r--components/style/values/specified/ui.rs28
-rw-r--r--components/style_derive/animate.rs16
-rw-r--r--components/style_derive/compute_squared_distance.rs16
-rw-r--r--components/style_derive/to_animated_value.rs16
-rw-r--r--components/style_derive/to_computed_value.rs170
-rw-r--r--components/style_derive/to_resolved_value.rs39
-rw-r--r--components/style_traits/arc_slice.rs8
-rw-r--r--components/style_traits/lib.rs3
124 files changed, 3319 insertions, 3191 deletions
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<Color, LengthPercentage>],
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<Au>,
- stops: &[GradientItem],
+ stops: &[GradientItem<Color, LengthPercentage>],
direction: LineDirection,
repeating: bool,
) -> (Gradient, Vec<GradientStop>) {
@@ -303,7 +303,7 @@ pub fn linear(
pub fn radial(
style: &ComputedValues,
size: Size2D<Au>,
- stops: &[GradientItem],
+ stops: &[GradientItem<Color, LengthPercentage>],
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<Color, LengthPercentage>],
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<Color, LengthPercentage>],
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<Color, LengthPercentage>],
gradient_line_length: Length,
) -> Vec<wr::GradientStop> {
// 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,
- )
+ 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(rect) => match **rect {},
+ }
},
+ // Gecko-only value, represented as a (boxed) empty enum on non-Gecko.
+ Image::Rect(ref rect) => match **rect {},
}
}
}
diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs
index 040b4c3f3cf..c129582a358 100644
--- a/components/layout_2020/flow/inline.rs
+++ b/components/layout_2020/flow/inline.rs
@@ -303,7 +303,11 @@ impl InlineFormattingContext {
panic!("display:none does not generate an abspos box")
},
};
- let hoisted_box = box_.clone().to_hoisted(initial_start_corner, tree_rank);
+ let hoisted_box = AbsolutelyPositionedBox::to_hoisted(
+ box_.clone(),
+ initial_start_corner,
+ tree_rank,
+ );
let hoisted_fragment = hoisted_box.fragment.clone();
ifc.push_hoisted_box_to_positioning_context(hoisted_box);
ifc.current_nesting_level.fragments_so_far.push(
@@ -786,7 +790,7 @@ impl TextRun {
glyphs,
text_decoration_line: ifc.current_nesting_level.text_decoration_line,
}));
- if runs.is_empty() {
+ if runs.as_slice().is_empty() {
break;
} else {
// New line
diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs
index 33bba78de96..eb4a03be62e 100644
--- a/components/layout_2020/flow/mod.rs
+++ b/components/layout_2020/flow/mod.rs
@@ -315,7 +315,8 @@ impl BlockLevelBox {
))
},
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
- let hoisted_box = box_.clone().to_hoisted(Vec2::zero(), tree_rank);
+ let hoisted_box =
+ AbsolutelyPositionedBox::to_hoisted(box_.clone(), Vec2::zero(), tree_rank);
let hoisted_fragment = hoisted_box.fragment.clone();
positioning_context.push(hoisted_box);
Fragment::AbsoluteOrFixedPositioned(AbsoluteOrFixedPositionedFragment {
diff --git a/components/layout_2020/lib.rs b/components/layout_2020/lib.rs
index 6b7a08ec29b..be5008035a5 100644
--- a/components/layout_2020/lib.rs
+++ b/components/layout_2020/lib.rs
@@ -3,8 +3,6 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#![deny(unsafe_code)]
-#![feature(arbitrary_self_types)]
-#![feature(exact_size_is_empty)]
#[macro_use]
extern crate serde;
diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs
index 899b2b39e61..cb71ad521c4 100644
--- a/components/layout_2020/positioned.rs
+++ b/components/layout_2020/positioned.rs
@@ -100,7 +100,7 @@ impl AbsolutelyPositionedBox {
}
pub(crate) fn to_hoisted(
- self: Arc<Self>,
+ self_: Arc<Self>,
initial_start_corner: Vec2<Length>,
tree_rank: usize,
) -> HoistedAbsolutelyPositionedBox {
@@ -124,7 +124,7 @@ impl AbsolutelyPositionedBox {
}
}
- let box_offsets = self.contents.style.box_offsets();
+ let box_offsets = self_.contents.style.box_offsets();
HoistedAbsolutelyPositionedBox {
tree_rank,
box_offsets: Vec2 {
@@ -140,7 +140,7 @@ impl AbsolutelyPositionedBox {
),
},
fragment: ArcRefCell::new(None),
- absolutely_positioned_box: self,
+ absolutely_positioned_box: self_,
}
}
}
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<Atom> {
- None
- }
-
fn imported_part(&self, _: &Atom) -> Option<Atom> {
None
}
@@ -1441,11 +1437,6 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
false
}
- fn exported_part(&self, _: &Atom) -> Option<Atom> {
- debug!("ServoThreadSafeLayoutElement::exported_part called");
- None
- }
-
fn imported_part(&self, _: &Atom) -> Option<Atom> {
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<Atom> {
- None
- }
-
fn imported_part(&self, _: &Atom) -> Option<Atom> {
None
}
@@ -1447,11 +1443,6 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
false
}
- fn exported_part(&self, _: &Atom) -> Option<Atom> {
- debug!("ServoThreadSafeLayoutElement::exported_part called");
- None
- }
-
fn imported_part(&self, _: &Atom) -> Option<Atom> {
debug!("ServoThreadSafeLayoutElement::imported_part called");
None
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index 3c9555ba659..021757a4ad1 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -3992,8 +3992,8 @@ class CGMemberJITInfo(CGThing):
protoID: PrototypeList::ID::${name} as u16,
},
__bindgen_anon_3: JSJitInfo__bindgen_ty_3 { depth: ${depth} },
- _bitfield_1: unsafe {
- mem::transmute(new_jsjitinfo_bitfield_1!(
+ _bitfield_1: __BindgenBitfieldUnit::new(
+ new_jsjitinfo_bitfield_1!(
JSJitInfo_OpType::${opType} as u8,
JSJitInfo_AliasSet::${aliasSet} as u8,
JSValueType::${returnType} as u8,
@@ -4004,8 +4004,8 @@ class CGMemberJITInfo(CGThing):
${isLazilyCachedInSlot},
${isTypedMethod},
${slotIndex},
- ))
- },
+ ).to_ne_bytes()
+ ),
}
""",
opName=opName,
@@ -5988,6 +5988,7 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'js::error::throw_type_error',
'js::error::throw_internal_error',
'js::rust::wrappers::Call',
+ 'js::jsapi::__BindgenBitfieldUnit',
'js::jsapi::CallArgs',
'js::jsapi::CurrentGlobalOrNull',
'js::rust::wrappers::GetPropertyKeys',
diff --git a/components/script/dom/bindings/root.rs b/components/script/dom/bindings/root.rs
index 4f4d376e951..59f9b964564 100644
--- a/components/script/dom/bindings/root.rs
+++ b/components/script/dom/bindings/root.rs
@@ -383,7 +383,7 @@ where
#[allow(unrooted_must_root)]
pub unsafe fn from_box(value: Box<T>) -> Self {
Self {
- ptr: Box::into_raw_non_null(value),
+ ptr: Box::leak(value).into(),
}
}
}
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<Element> {
false
}
- fn exported_part(&self, _: &Atom) -> Option<Atom> {
- None
- }
-
fn imported_part(&self, _: &Atom) -> Option<Atom> {
None
}
diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs
index b4118e234c3..9e04585168c 100644
--- a/components/script/dom/htmlcanvaselement.rs
+++ b/components/script/dom/htmlcanvaselement.rs
@@ -41,7 +41,6 @@ use js::error::throw_type_error;
use js::rust::HandleValue;
use profile_traits::ipc;
use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource};
-use servo_config::pref;
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
const DEFAULT_WIDTH: u32 = 300;
@@ -222,7 +221,8 @@ impl HTMLCanvasElement {
cx: JSContext,
options: HandleValue,
) -> Option<DomRoot<WebGL2RenderingContext>> {
- if !pref!(dom.webgl2.enabled) {
+ if !WebGL2RenderingContext::is_webgl2_enabled(cx, self.global().reflector().get_jsobject())
+ {
return None;
}
if let Some(ctx) = self.context() {
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/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs
index 62af18d1002..8e967fbcb86 100644
--- a/components/script/dom/webgl2renderingcontext.rs
+++ b/components/script/dom/webgl2renderingcontext.rs
@@ -16,6 +16,7 @@ use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot, LayoutDom, MutNullableDom};
use crate::dom::bindings::str::DOMString;
+use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlcanvaselement::HTMLCanvasElement;
use crate::dom::htmliframeelement::HTMLIFrameElement;
use crate::dom::webglactiveinfo::WebGLActiveInfo;
@@ -50,12 +51,14 @@ use ipc_channel::ipc;
use js::jsapi::{JSObject, Type};
use js::jsval::{BooleanValue, DoubleValue, Int32Value, UInt32Value};
use js::jsval::{JSVal, NullValue, ObjectValue, UndefinedValue};
-use js::rust::CustomAutoRooterGuard;
+use js::rust::{CustomAutoRooterGuard, HandleObject};
use js::typedarray::{ArrayBufferView, CreateWith, Float32, Int32Array, Uint32, Uint32Array};
use script_layout_interface::HTMLCanvasDataSource;
+use servo_config::pref;
use std::cell::Cell;
use std::cmp;
use std::ptr::{self, NonNull};
+use url::Host;
#[unrooted_must_root_lint::must_root]
#[derive(JSTraceable, MallocSizeOf)]
@@ -178,8 +181,26 @@ impl WebGL2RenderingContext {
WebGL2RenderingContext::new_inherited(window, canvas, size, attrs)
.map(|ctx| reflect_dom_object(Box::new(ctx), window))
}
+
+ #[allow(unsafe_code)]
+ pub fn is_webgl2_enabled(_cx: JSContext, global: HandleObject) -> bool {
+ if pref!(dom.webgl2.enabled) {
+ return true;
+ }
+
+ let global = unsafe { GlobalScope::from_object(global.get()) };
+ let origin = global.origin();
+ let host = origin.host();
+ WEBGL2_ORIGINS
+ .iter()
+ .any(|origin| host == Host::parse(origin).ok().as_ref())
+ }
}
+/// List of domains for which WebGL 2 is enabled automatically, regardless
+/// of the status of the dom.webgl2.enabled preference.
+static WEBGL2_ORIGINS: &[&str] = &["www.servoexperiments.com"];
+
impl WebGL2RenderingContext {
pub fn recreate(&self, size: Size2D<u32>) {
self.base.recreate(size)
diff --git a/components/script/dom/webidls/WebGL2RenderingContext.webidl b/components/script/dom/webidls/WebGL2RenderingContext.webidl
index e7f94cb9a3c..f6278370cce 100644
--- a/components/script/dom/webidls/WebGL2RenderingContext.webidl
+++ b/components/script/dom/webidls/WebGL2RenderingContext.webidl
@@ -542,7 +542,7 @@ interface mixin WebGL2RenderingContextBase
void bindVertexArray(WebGLVertexArrayObject? array);
};
-[Exposed=Window, Pref="dom.webgl2.enabled"]
+[Exposed=Window, Func="WebGL2RenderingContext::is_webgl2_enabled"]
interface WebGL2RenderingContext
{
};
diff --git a/components/script/dom/xrview.rs b/components/script/dom/xrview.rs
index 14309dfc99c..8aa0b0adc58 100644
--- a/components/script/dom/xrview.rs
+++ b/components/script/dom/xrview.rs
@@ -3,6 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::codegen::Bindings::XRViewBinding::{XREye, XRViewMethods};
+use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::utils::create_typed_array;
@@ -24,17 +25,24 @@ pub struct XRView {
proj: Heap<*mut JSObject>,
#[ignore_malloc_size_of = "mozjs"]
view: Heap<*mut JSObject>,
+ proj_array: Vec<f32>,
transform: Dom<XRRigidTransform>,
}
impl XRView {
- fn new_inherited(session: &XRSession, transform: &XRRigidTransform, eye: XREye) -> XRView {
+ fn new_inherited(
+ session: &XRSession,
+ transform: &XRRigidTransform,
+ eye: XREye,
+ proj_array: Vec<f32>,
+ ) -> XRView {
XRView {
reflector_: Reflector::new(),
session: Dom::from_ref(session),
eye,
proj: Heap::default(),
view: Heap::default(),
+ proj_array,
transform: Dom::from_ref(transform),
}
}
@@ -55,13 +63,18 @@ impl XRView {
let transform = pose.pre_transform(&offset);
let transform = XRRigidTransform::new(global, cast_transform(transform));
+ // row_major since euclid uses row vectors
+ let proj = view.projection.to_row_major_array();
let ret = reflect_dom_object(
- Box::new(XRView::new_inherited(session, &transform, eye)),
+ Box::new(XRView::new_inherited(
+ session,
+ &transform,
+ eye,
+ (&proj).to_vec(),
+ )),
global,
);
- // row_major since euclid uses row vectors
- let proj = view.projection.to_row_major_array();
let cx = global.get_cx();
create_typed_array(cx, &proj, &ret.proj);
ret
@@ -80,6 +93,10 @@ impl XRViewMethods for XRView {
/// https://immersive-web.github.io/webxr/#dom-xrview-projectionmatrix
fn ProjectionMatrix(&self, _cx: JSContext) -> NonNull<JSObject> {
+ if self.proj.get().is_null() {
+ let cx = self.global().get_cx();
+ create_typed_array(cx, &self.proj_array, &self.proj);
+ }
NonNull::new(self.proj.get()).unwrap()
}
diff --git a/components/script/lib.rs b/components/script/lib.rs
index 07090f4716b..4eeca229e01 100644
--- a/components/script/lib.rs
+++ b/components/script/lib.rs
@@ -2,12 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-#![feature(box_into_raw_non_null)]
#![feature(const_fn)]
-#![feature(const_transmute)]
#![feature(core_intrinsics)]
#![feature(drain_filter)]
-#![feature(inner_deref)]
#![feature(plugin)]
#![feature(register_tool)]
#![deny(unsafe_code)]
diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs
index 651c0815f9f..374c650986d 100644
--- a/components/script_layout_interface/lib.rs
+++ b/components/script_layout_interface/lib.rs
@@ -7,7 +7,6 @@
//! to depend on script.
#![deny(unsafe_code)]
-#![feature(box_into_raw_non_null)]
#[macro_use]
extern crate html5ever;
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 "<defaultns>|*" 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 "<defaultns>|*" 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: &<Self::Impl as SelectorImpl>::PartName,
- ) -> Option<<Self::Impl as SelectorImpl>::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/animation.rs b/components/style/animation.rs
index d734acd6d7b..402c281a388 100644
--- a/components/style/animation.rs
+++ b/components/style/animation.rs
@@ -12,14 +12,13 @@ use crate::bezier::Bezier;
use crate::context::SharedStyleContext;
use crate::dom::{OpaqueNode, TElement};
use crate::font_metrics::FontMetricsProvider;
-use crate::properties::animated_properties::AnimatedProperty;
+use crate::properties::animated_properties::{AnimatedProperty, TransitionPropertyIteration};
use crate::properties::longhands::animation_direction::computed_value::single_value::T as AnimationDirection;
use crate::properties::longhands::animation_play_state::computed_value::single_value::T as AnimationPlayState;
use crate::properties::{self, CascadeMode, ComputedValues, LonghandId};
use crate::stylesheets::keyframes_rule::{KeyframesAnimation, KeyframesStep, KeyframesStepValue};
use crate::stylesheets::Origin;
use crate::timer::Timer;
-use crate::values::computed::box_::TransitionProperty;
use crate::values::computed::Time;
use crate::values::computed::TimingFunction;
use crate::values::generics::box_::AnimationIterationCount;
@@ -271,52 +270,6 @@ impl PropertyAnimation {
self.property.name()
}
- /// Creates a new property animation for the given transition index and old
- /// and new styles. Any number of animations may be returned, from zero (if
- /// the property did not animate) to one (for a single transition property)
- /// to arbitrarily many (for `all`).
- pub fn from_transition(
- transition_index: usize,
- old_style: &ComputedValues,
- new_style: &mut ComputedValues,
- ) -> Vec<PropertyAnimation> {
- let mut result = vec![];
- let box_style = new_style.get_box();
- let transition_property = box_style.transition_property_at(transition_index);
- let timing_function = box_style.transition_timing_function_mod(transition_index);
- let duration = box_style.transition_duration_mod(transition_index);
-
- match transition_property {
- TransitionProperty::Custom(..) | TransitionProperty::Unsupported(..) => result,
- TransitionProperty::Shorthand(ref shorthand_id) => shorthand_id
- .longhands()
- .filter_map(|longhand| {
- PropertyAnimation::from_longhand(
- longhand,
- timing_function,
- duration,
- old_style,
- new_style,
- )
- })
- .collect(),
- TransitionProperty::Longhand(longhand_id) => {
- let animation = PropertyAnimation::from_longhand(
- longhand_id,
- timing_function,
- duration,
- old_style,
- new_style,
- );
-
- if let Some(animation) = animation {
- result.push(animation);
- }
- result
- },
- }
- }
-
fn from_longhand(
longhand: LonghandId,
timing_function: TimingFunction,
@@ -414,56 +367,70 @@ pub fn start_transitions_if_applicable(
running_and_expired_transitions: &[PropertyAnimation],
) -> bool {
let mut had_animations = false;
- for i in 0..new_style.get_box().transition_property_count() {
- // Create any property animations, if applicable.
- let property_animations =
- PropertyAnimation::from_transition(i, old_style, Arc::make_mut(new_style));
- for property_animation in property_animations {
- // Set the property to the initial value.
- //
- // NB: get_mut is guaranteed to succeed since we called make_mut()
- // above.
- property_animation.update(Arc::get_mut(new_style).unwrap(), 0.0);
+ let transitions: Vec<TransitionPropertyIteration> = new_style.transition_properties().collect();
+ for transition in &transitions {
+ let property_animation = match PropertyAnimation::from_longhand(
+ transition.longhand_id,
+ new_style
+ .get_box()
+ .transition_timing_function_mod(transition.index),
+ new_style
+ .get_box()
+ .transition_duration_mod(transition.index),
+ old_style,
+ Arc::make_mut(new_style),
+ ) {
+ Some(property_animation) => property_animation,
+ None => continue,
+ };
- // Per [1], don't trigger a new transition if the end state for that
- // transition is the same as that of a transition that's already
- // running on the same node.
- //
- // [1]: https://drafts.csswg.org/css-transitions/#starting
+ // Set the property to the initial value.
+ //
+ // NB: get_mut is guaranteed to succeed since we called make_mut()
+ // above.
+ property_animation.update(Arc::get_mut(new_style).unwrap(), 0.0);
+
+ // Per [1], don't trigger a new transition if the end state for that
+ // transition is the same as that of a transition that's already
+ // running on the same node.
+ //
+ // [1]: https://drafts.csswg.org/css-transitions/#starting
+ debug!(
+ "checking {:?} for matching end value",
+ running_and_expired_transitions
+ );
+ if running_and_expired_transitions
+ .iter()
+ .any(|animation| animation.has_the_same_end_value_as(&property_animation))
+ {
debug!(
- "checking {:?} for matching end value",
- running_and_expired_transitions
+ "Not initiating transition for {}, other transition \
+ found with the same end value",
+ property_animation.property_name()
);
- if running_and_expired_transitions
- .iter()
- .any(|animation| animation.has_the_same_end_value_as(&property_animation))
- {
- debug!(
- "Not initiating transition for {}, other transition \
- found with the same end value",
- property_animation.property_name()
- );
- continue;
- }
+ continue;
+ }
- // Kick off the animation.
- debug!("Kicking off transition of {:?}", property_animation);
- let box_style = new_style.get_box();
- let now = timer.seconds();
- let start_time = now + (box_style.transition_delay_mod(i).seconds() as f64);
- new_animations_sender
- .send(Animation::Transition(
- opaque_node,
- start_time,
- AnimationFrame {
- duration: box_style.transition_duration_mod(i).seconds() as f64,
- property_animation,
- },
- ))
- .unwrap();
+ // Kick off the animation.
+ debug!("Kicking off transition of {:?}", property_animation);
+ let box_style = new_style.get_box();
+ let now = timer.seconds();
+ let start_time = now + (box_style.transition_delay_mod(transition.index).seconds() as f64);
+ let duration = box_style
+ .transition_duration_mod(transition.index)
+ .seconds() as f64;
+ new_animations_sender
+ .send(Animation::Transition(
+ opaque_node,
+ start_time,
+ AnimationFrame {
+ duration,
+ property_animation,
+ },
+ ))
+ .unwrap();
- had_animations = true;
- }
+ had_animations = true;
}
had_animations
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 {
}
/// <https://drafts.csswg.org/css-counter-styles/#typedef-symbol>
-#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)]
+#[derive(
+ Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToCss, ToShmem,
+)]
#[repr(u8)]
pub enum Symbol {
/// <string>
@@ -554,7 +556,9 @@ impl Parse for Fallback {
}
/// <https://drafts.csswg.org/css-counter-styles/#descdef-counter-style-symbols>
-#[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<Symbol>);
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<F>(&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<E, D>(
// 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<ScopedTLS<ThreadLocalStyleContext<E>>> = 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<E, D>(
// depth for all the children.
if pool.is_some() && discovered.len() > WORK_UNIT_MAX {
let pool = pool.unwrap();
- maybe_tls = Some(ScopedTLS::<ThreadLocalStyleContext<E>>::new(pool));
+ let tls = ScopedTLS::<ThreadLocalStyleContext<E>>::new(pool);
let root_opaque = root.as_node().opaque();
let drain = discovered.drain(..);
pool.install(|| {
@@ -151,10 +151,12 @@ pub fn traverse_dom<E, D>(
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<E, D>(
// 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<Gradient>) {
- unsafe {
- bindings::Gecko_SetGradientImageValue(self, Box::into_raw(gradient));
- }
- }
-
- /// Converts into Image.
- pub unsafe fn into_image(self: &nsStyleImage) -> Option<Image> {
- 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<ReferenceBox, ImageOrUrl>(
- &self,
- ) -> Option<ShapeSource<BasicShape, ReferenceBox, ImageOrUrl>>
- where
- ReferenceBox: From<StyleGeometryBox>,
- {
- 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<SVGPathData> {
- 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<ShapeBox> 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<GeometryBox> 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<T>,
- // but coherence doesn't like that and TryFrom isn't stable
- impl From<StyleGeometryBox> 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<StyleGeometryBox> 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<RulesMutateError> for nsresult {
fn from(other: RulesMutateError) -> Self {
@@ -260,39 +25,6 @@ impl From<RulesMutateError> 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<f32, CSSPixel> {
- 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<Self> {
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
@@ -194,11 +194,6 @@ impl ElementSnapshot for GeckoElementSnapshot {
}
#[inline]
- fn exported_part(&self, name: &Atom) -> Option<Atom> {
- snapshot_helpers::exported_part(&*self.mAttrs, name)
- }
-
- #[inline]
fn imported_part(&self, name: &Atom) -> Option<Atom> {
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<Atom> {
- 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..a5472fadd66 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<ElementData>> {
+ pub fn get_data(&self) -> Option<&AtomicRefCell<ElementData>> {
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<F>(&self, name: &Atom, callback: F)
+ where
+ F: FnMut(&Atom),
+ {
+ snapshot_helpers::each_exported_part(self.attrs(), name, callback)
+ }
+
fn each_part<F>(&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<AtomicRef<ElementData>> {
- self.get_data().map(|x| x.borrow())
- }
-
- /// Mutably borrows the ElementData.
- fn mutate_data(&self) -> Option<AtomicRefMut<ElementData>> {
- self.get_data().map(|x| x.borrow_mut())
- }
-
unsafe fn ensure_data(&self) -> AtomicRefMut<ElementData> {
if !self.has_data() {
debug!("Creating ElementData for {:?}", self);
@@ -1566,9 +1560,7 @@ impl<'le> TElement for GeckoElement<'le> {
before_change_style: &ComputedValues,
after_change_style: &ComputedValues,
) -> bool {
- use crate::gecko_bindings::structs::nsCSSPropertyID;
use crate::properties::LonghandIdSet;
- use crate::values::computed::TransitionProperty;
debug_assert!(
self.might_need_transitions_update(Some(before_change_style), after_change_style),
@@ -1577,53 +1569,21 @@ impl<'le> TElement for GeckoElement<'le> {
);
let after_change_box_style = after_change_style.get_box();
- let transitions_count = after_change_box_style.transition_property_count();
let existing_transitions = self.css_transitions_info();
-
- // Check if this property is none, custom or unknown.
- let is_none_or_custom_property = |property: nsCSSPropertyID| -> bool {
- return property == nsCSSPropertyID::eCSSPropertyExtra_no_properties ||
- property == nsCSSPropertyID::eCSSPropertyExtra_variable ||
- property == nsCSSPropertyID::eCSSProperty_UNKNOWN;
- };
-
let mut transitions_to_keep = LonghandIdSet::new();
-
- for i in 0..transitions_count {
- let property = after_change_box_style.transition_nscsspropertyid_at(i);
- let combined_duration = after_change_box_style.transition_combined_duration_at(i);
-
- // We don't need to update transition for none/custom properties.
- if is_none_or_custom_property(property) {
- continue;
- }
-
- let transition_property: TransitionProperty = property.into();
-
- let mut property_check_helper = |property: LonghandId| -> bool {
- let property = property.to_physical(after_change_style.writing_mode);
- transitions_to_keep.insert(property);
- self.needs_transitions_update_per_property(
- property,
- combined_duration,
- before_change_style,
- after_change_style,
- &existing_transitions,
- )
- };
-
- match transition_property {
- TransitionProperty::Custom(..) | TransitionProperty::Unsupported(..) => {},
- TransitionProperty::Shorthand(ref shorthand) => {
- if shorthand.longhands().any(property_check_helper) {
- return true;
- }
- },
- TransitionProperty::Longhand(longhand_id) => {
- if property_check_helper(longhand_id) {
- return true;
- }
- },
+ for transition_property in after_change_style.transition_properties() {
+ let physical_longhand = transition_property
+ .longhand_id
+ .to_physical(after_change_style.writing_mode);
+ transitions_to_keep.insert(physical_longhand);
+ if self.needs_transitions_update_per_property(
+ physical_longhand,
+ after_change_box_style.transition_combined_duration_at(transition_property.index),
+ before_change_style,
+ after_change_style,
+ &existing_transitions,
+ ) {
+ return true;
}
}
@@ -1634,6 +1594,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<AtomicRef<ElementData>> {
+ self.get_data().map(|x| x.borrow())
+ }
+
+ /// Mutably borrows the ElementData.
+ fn mutate_data(&self) -> Option<AtomicRefMut<ElementData>> {
+ self.get_data().map(|x| x.borrow_mut())
+ }
+
#[inline]
fn lang_attr(&self) -> Option<AttrValue> {
let ptr = unsafe { bindings::Gecko_LangValue(self.0) };
@@ -2064,6 +2040,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
NonTSPseudoClass::MozReadOnly |
NonTSPseudoClass::MozReadWrite |
NonTSPseudoClass::FocusWithin |
+ NonTSPseudoClass::FocusVisible |
NonTSPseudoClass::MozDragOver |
NonTSPseudoClass::MozDevtoolsHighlighted |
NonTSPseudoClass::MozStyleeditorTransitioning |
@@ -2226,11 +2203,6 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
}
#[inline]
- fn exported_part(&self, name: &Atom) -> Option<Atom> {
- snapshot_helpers::exported_part(self.attrs(), name)
- }
-
- #[inline]
fn imported_part(&self, name: &Atom) -> Option<Atom> {
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<Atom>;
-
/// See Element::imported_part.
fn imported_part(&self, name: &Atom) -> Option<Atom>;
@@ -371,13 +368,6 @@ where
}
}
- fn exported_part(&self, name: &Atom) -> Option<Atom> {
- 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<Atom> {
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
--- a/components/style/properties/Mako-0.9.1.zip
+++ /dev/null
Binary files 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
--- /dev/null
+++ b/components/style/properties/Mako-1.1.2-py2.py3-none-any.whl
Binary files 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<PropertyDeclaration>,
+ 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<LonghandIdSet>,
}
@@ -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>
-<%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>
-
-<%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>
-
<%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>
-<%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() {
}
</%self:impl_trait>
-<%
- 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>
-<%def name="impl_transition_timing_function()">
- ${impl_animation_or_transition_timing_function('transition')}
-</%def>
<%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>
-<%def name="impl_animation_timing_function()">
- ${impl_animation_or_transition_timing_function('animation')}
-</%def>
-
<%def name="impl_animation_keyword(ident, gecko_ffi_name, keyword, cast_type='u8')">
#[allow(non_snake_case)]
pub fn set_animation_${ident}<I>(&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>
<%self:impl_trait style_struct_name="Text" skip_longhands="initial-letter">
@@ -2244,204 +2063,21 @@ fn static_assert() {
}
</%self:impl_trait>
-// 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)
- }
-</%def>
-
<% 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>
-<%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>
-<%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::<Vec<_>>().into_boxed_slice();
-
- longhands::cursor::computed_value::T { images, keyword }
- }
+<%self:impl_trait style_struct_name="InheritedUI">
</%self:impl_trait>
<%self:impl_trait style_struct_name="Column"
@@ -2483,8 +2119,7 @@ clip-path
}
</%self:impl_trait>
-<%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>
<%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>
<%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/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs
index 84f843ec728..2e9a53fc677 100644
--- a/components/style/properties/helpers/animated_properties.mako.rs
+++ b/components/style/properties/helpers/animated_properties.mako.rs
@@ -11,7 +11,7 @@
#[cfg(feature = "gecko")] use crate::gecko_bindings::structs::nsCSSPropertyID;
use itertools::{EitherOrBoth, Itertools};
-use crate::properties::{CSSWideKeyword, PropertyDeclaration};
+use crate::properties::{CSSWideKeyword, PropertyDeclaration, NonCustomPropertyIterator};
use crate::properties::longhands;
use crate::properties::longhands::visibility::computed_value::T as Visibility;
use crate::properties::LonghandId;
@@ -883,3 +883,66 @@ impl ToAnimatedZero for AnimatedFilter {
}
}
}
+
+/// An iterator over all the properties that transition on a given style.
+pub struct TransitionPropertyIterator<'a> {
+ style: &'a ComputedValues,
+ index_range: core::ops::Range<usize>,
+ longhand_iterator: Option<NonCustomPropertyIterator<LonghandId>>,
+}
+
+impl<'a> TransitionPropertyIterator<'a> {
+ /// Create a `TransitionPropertyIterator` for the given style.
+ pub fn from_style(style: &'a ComputedValues) -> Self {
+ Self {
+ style,
+ index_range: 0..style.get_box().transition_property_count(),
+ longhand_iterator: None,
+ }
+ }
+}
+
+/// A single iteration of the TransitionPropertyIterator.
+pub struct TransitionPropertyIteration {
+ /// The id of the longhand for this property.
+ pub longhand_id: LonghandId,
+
+ /// The index of this property in the list of transition properties for this
+ /// iterator's style.
+ pub index: usize,
+}
+
+impl<'a> Iterator for TransitionPropertyIterator<'a> {
+ type Item = TransitionPropertyIteration;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ use crate::values::computed::TransitionProperty;
+ loop {
+ if let Some(ref mut longhand_iterator) = self.longhand_iterator {
+ if let Some(longhand_id) = longhand_iterator.next() {
+ return Some(TransitionPropertyIteration {
+ longhand_id,
+ index: self.index_range.start,
+ });
+ }
+ self.longhand_iterator = None;
+ }
+
+ let index = self.index_range.next()?;
+ match self.style.get_box().transition_property_at(index) {
+ TransitionProperty::Longhand(longhand_id) => {
+ return Some(TransitionPropertyIteration {
+ longhand_id,
+ index,
+ })
+ }
+ // In the other cases, we set up our state so that we are ready to
+ // compute the next value of the iterator and then loop (equivalent
+ // to calling self.next()).
+ TransitionProperty::Shorthand(ref shorthand_id) =>
+ self.longhand_iterator = Some(shorthand_id.longhands()),
+ TransitionProperty::Custom(..) | TransitionProperty::Unsupported(..) => {}
+ }
+ }
+ }
+}
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.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..4bebe0040e7 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<T: Copy> AssertCopy for Helper<T> {}
- % 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)}]
};
</%def>
+<%
+ 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<CSSWideKeyword> {
@@ -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(
@@ -3003,6 +3020,13 @@ impl ComputedValues {
% endfor
set
}
+
+ /// Create a `TransitionPropertyIterator` for this styles transition properties.
+ pub fn transition_properties<'a>(
+ &'a self
+ ) -> animated_properties::TransitionPropertyIterator<'a> {
+ animated_properties::TransitionPropertyIterator::from_style(self)
+ }
}
#[cfg(feature = "servo")]
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<GridAutoFlow, ParseError<'i>> {
- 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<E: TElement>(
}
}
-#[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<E>, 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<Rule>,
- 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<E>,
- map: &SelectorMap<Rule>,
- 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<Rule>, 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<W: Write>(&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<PropertyDeclarationBlock> = 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<E>(
- &self,
- mut element: E,
- mut pseudo: Option<PseudoElement>,
- 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<Atom> {
- None
- }
-
fn imported_part(&self, _: &Atom) -> Option<Atom> {
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> {
}
}
+ /// <textarea>'s editor root needs to inherit the overflow value from its
+ /// parent, but we need to make sure it's still scrollable.
+ #[cfg(feature = "gecko")]
+ fn adjust_for_text_control_editing_root(&mut self) {
+ use crate::selector_parser::PseudoElement;
+
+ if self.style.pseudo != Some(&PseudoElement::MozTextControlEditingRoot) {
+ return;
+ }
+
+ let box_style = self.style.get_box();
+ let overflow_x = box_style.clone_overflow_x();
+ let overflow_y = box_style.clone_overflow_y();
+
+ fn scrollable(v: Overflow) -> bool {
+ v != Overflow::MozHiddenUnscrollable && v != Overflow::Visible
+ }
+
+ // If at least one is scrollable we'll adjust the other one in
+ // adjust_for_overflow if needed.
+ if scrollable(overflow_x) || scrollable(overflow_y) {
+ return;
+ }
+
+ let box_style = self.style.mutate_box();
+ box_style.set_overflow_x(Overflow::Auto);
+ box_style.set_overflow_y(Overflow::Auto);
+ }
+
/// If a <fieldset> has grid/flex display type, we need to inherit
/// this type into its ::-moz-fieldset-content anonymous box.
///
@@ -496,9 +531,10 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
/// normal cascading process.
#[cfg(feature = "gecko")]
fn adjust_for_fieldset_content(&mut self, layout_parent_style: &ComputedValues) {
- match self.style.pseudo {
- Some(ref p) if p.is_fieldset_content() => {},
- _ => return,
+ use crate::selector_parser::PseudoElement;
+
+ if self.style.pseudo != Some(&PseudoElement::FieldsetContent) {
+ return;
}
debug_assert_eq!(self.style.get_box().clone_display(), Display::Block);
@@ -780,6 +816,9 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
{
self.adjust_for_prohibited_display_contents(element);
self.adjust_for_fieldset_content(layout_parent_style);
+ // NOTE: It's important that this happens before
+ // adjust_for_overflow.
+ self.adjust_for_text_control_editing_root();
}
self.adjust_for_top_layer();
self.blockify_if_necessary(layout_parent_style, element);
diff --git a/components/style/stylesheet_set.rs b/components/style/stylesheet_set.rs
index cca08c9d233..a9cd39eef20 100644
--- a/components/style/stylesheet_set.rs
+++ b/components/style/stylesheet_set.rs
@@ -294,7 +294,9 @@ where
// Removing sheets makes us tear down the whole cascade and invalidation
// data, but only if the sheet has been involved in at least one flush.
// Checking whether the sheet has been committed allows us to avoid
- // rebuilding the world when sites quickly append and remove a stylesheet.
+ // rebuilding the world when sites quickly append and remove a
+ // stylesheet.
+ //
// See bug 1434756.
if sheet.committed {
self.set_data_validity_at_least(DataValidity::FullyInvalid);
diff --git a/components/style/stylesheets/mod.rs b/components/style/stylesheets/mod.rs
index c9697ead615..daf97f20e3c 100644
--- a/components/style/stylesheets/mod.rs
+++ b/components/style/stylesheets/mod.rs
@@ -58,8 +58,8 @@ pub use self::rule_parser::{InsertRuleContext, State, TopLevelRuleParser};
pub use self::rules_iterator::{AllRules, EffectiveRules};
pub use self::rules_iterator::{NestedRuleIterationCondition, RulesIterator};
pub use self::style_rule::StyleRule;
+pub use self::stylesheet::{AllowImportRules, SanitizationData, SanitizationKind};
pub use self::stylesheet::{DocumentStyleSheet, Namespaces, Stylesheet};
-pub use self::stylesheet::{SanitizationData, SanitizationKind};
pub use self::stylesheet::{StylesheetContents, StylesheetInDocument, UserAgentStylesheets};
pub use self::supports_rule::SupportsRule;
pub use self::viewport_rule::ViewportRule;
@@ -369,6 +369,7 @@ impl CssRule {
shared_lock: &SharedRwLock,
state: State,
loader: Option<&dyn StylesheetLoader>,
+ allow_import_rules: AllowImportRules,
) -> Result<Self, RulesMutateError> {
let url_data = parent_stylesheet_contents.url_data.read();
let context = ParserContext::new(
@@ -395,6 +396,7 @@ impl CssRule {
dom_error: None,
namespaces: &mut *guard,
insert_rule_context: Some(insert_rule_context),
+ allow_import_rules,
};
parse_one_rule(&mut input, &mut rule_parser)
diff --git a/components/style/stylesheets/rule_list.rs b/components/style/stylesheets/rule_list.rs
index 05f93eca489..d84a738bca0 100644
--- a/components/style/stylesheets/rule_list.rs
+++ b/components/style/stylesheets/rule_list.rs
@@ -10,7 +10,7 @@ use crate::str::CssStringWriter;
use crate::stylesheets::loader::StylesheetLoader;
use crate::stylesheets::rule_parser::{InsertRuleContext, State};
use crate::stylesheets::stylesheet::StylesheetContents;
-use crate::stylesheets::{CssRule, RulesMutateError};
+use crate::stylesheets::{AllowImportRules, CssRule, RulesMutateError};
#[cfg(feature = "gecko")]
use malloc_size_of::{MallocShallowSizeOf, MallocSizeOfOps};
use servo_arc::{Arc, RawOffsetArc};
@@ -128,6 +128,7 @@ pub trait CssRulesHelpers {
index: usize,
nested: bool,
loader: Option<&dyn StylesheetLoader>,
+ allow_import_rules: AllowImportRules,
) -> Result<CssRule, RulesMutateError>;
}
@@ -140,6 +141,7 @@ impl CssRulesHelpers for RawOffsetArc<Locked<CssRules>> {
index: usize,
nested: bool,
loader: Option<&dyn StylesheetLoader>,
+ allow_import_rules: AllowImportRules,
) -> Result<CssRule, RulesMutateError> {
let new_rule = {
let read_guard = lock.read();
@@ -176,6 +178,7 @@ impl CssRulesHelpers for RawOffsetArc<Locked<CssRules>> {
lock,
state,
loader,
+ allow_import_rules,
)?
};
diff --git a/components/style/stylesheets/rule_parser.rs b/components/style/stylesheets/rule_parser.rs
index aefea6c504d..74425afafcd 100644
--- a/components/style/stylesheets/rule_parser.rs
+++ b/components/style/stylesheets/rule_parser.rs
@@ -19,6 +19,7 @@ use crate::stylesheets::keyframes_rule::parse_keyframe_list;
use crate::stylesheets::stylesheet::Namespaces;
use crate::stylesheets::supports_rule::SupportsCondition;
use crate::stylesheets::viewport_rule;
+use crate::stylesheets::AllowImportRules;
use crate::stylesheets::{CorsMode, DocumentRule, FontFeatureValuesRule, KeyframesRule, MediaRule};
use crate::stylesheets::{CssRule, CssRuleType, CssRules, RulesMutateError, StylesheetLoader};
use crate::stylesheets::{NamespaceRule, PageRule, StyleRule, SupportsRule, ViewportRule};
@@ -50,7 +51,7 @@ pub struct TopLevelRuleParser<'a> {
/// This won't contain any namespaces, and only nested parsers created with
/// `ParserContext::new_with_rule_type` will.
pub context: ParserContext<'a>,
- /// The current state of the parser.
+ /// The current stajkj/te of the parser.
pub state: State,
/// Whether we have tried to parse was invalid due to being in the wrong
/// place (e.g. an @import rule was found while in the `Body` state). Reset
@@ -62,6 +63,8 @@ pub struct TopLevelRuleParser<'a> {
pub namespaces: &'a mut Namespaces,
/// The info we need insert a rule in a list.
pub insert_rule_context: Option<InsertRuleContext<'a>>,
+ /// Whether @import rules will be allowed.
+ pub allow_import_rules: AllowImportRules,
}
impl<'b> TopLevelRuleParser<'b> {
@@ -189,6 +192,10 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedImportRule))
}
+ if let AllowImportRules::No = self.allow_import_rules {
+ return Err(input.new_custom_error(StyleParseErrorKind::DisallowedImportRule))
+ }
+
// FIXME(emilio): We should always be able to have a loader
// around! See bug 1533783.
if self.loader.is_none() {
@@ -203,6 +210,7 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
let media = Arc::new(self.shared_lock.wrap(media));
let prelude = AtRuleNonBlockPrelude::Import(url, media);
+
return Ok(AtRuleType::WithoutBlock(prelude));
},
"namespace" => {
diff --git a/components/style/stylesheets/stylesheet.rs b/components/style/stylesheets/stylesheet.rs
index 068bfb6502a..6679f587a41 100644
--- a/components/style/stylesheets/stylesheet.rs
+++ b/components/style/stylesheets/stylesheet.rs
@@ -81,6 +81,7 @@ impl StylesheetContents {
quirks_mode: QuirksMode,
line_number_offset: u32,
use_counters: Option<&UseCounters>,
+ allow_import_rules: AllowImportRules,
sanitization_data: Option<&mut SanitizationData>,
) -> Self {
let namespaces = RwLock::new(Namespaces::default());
@@ -95,6 +96,7 @@ impl StylesheetContents {
quirks_mode,
line_number_offset,
use_counters,
+ allow_import_rules,
sanitization_data,
);
@@ -355,6 +357,16 @@ pub enum SanitizationKind {
NoConditionalRules,
}
+/// Whether @import rules are allowed.
+#[repr(u8)]
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum AllowImportRules {
+ /// @import rules will be parsed.
+ Yes,
+ /// @import rules will not be parsed.
+ No,
+}
+
impl SanitizationKind {
fn allows(self, rule: &CssRule) -> bool {
debug_assert_ne!(self, SanitizationKind::None);
@@ -415,6 +427,7 @@ impl Stylesheet {
stylesheet_loader: Option<&dyn StylesheetLoader>,
error_reporter: Option<&dyn ParseErrorReporter>,
line_number_offset: u32,
+ allow_import_rules: AllowImportRules,
) {
let namespaces = RwLock::new(Namespaces::default());
@@ -430,6 +443,7 @@ impl Stylesheet {
existing.contents.quirks_mode,
line_number_offset,
/* use_counters = */ None,
+ allow_import_rules,
/* sanitization_data = */ None,
);
@@ -457,6 +471,7 @@ impl Stylesheet {
quirks_mode: QuirksMode,
line_number_offset: u32,
use_counters: Option<&UseCounters>,
+ allow_import_rules: AllowImportRules,
mut sanitization_data: Option<&mut SanitizationData>,
) -> (Vec<CssRule>, Option<String>, Option<String>) {
let mut rules = Vec::new();
@@ -481,6 +496,7 @@ impl Stylesheet {
dom_error: None,
insert_rule_context: None,
namespaces,
+ allow_import_rules,
};
{
@@ -537,6 +553,7 @@ impl Stylesheet {
error_reporter: Option<&dyn ParseErrorReporter>,
quirks_mode: QuirksMode,
line_number_offset: u32,
+ allow_import_rules: AllowImportRules,
) -> Self {
// FIXME: Consider adding use counters to Servo?
let contents = StylesheetContents::from_str(
@@ -549,6 +566,7 @@ impl Stylesheet {
quirks_mode,
line_number_offset,
/* use_counters = */ None,
+ allow_import_rules,
/* sanitized_output = */ None,
);
diff --git a/components/style/traversal.rs b/components/style/traversal.rs
index a6aa220ccfa..48e42656e86 100644
--- a/components/style/traversal.rs
+++ b/components/style/traversal.rs
@@ -684,7 +684,7 @@ fn notify_paint_worklet<E>(context: &StyleContext<E>, data: &ElementData)
where
E: TElement,
{
- use crate::values::generics::image::{GenericImageLayer, Image};
+ use crate::values::generics::image::Image;
use style_traits::ToCss;
// We speculatively evaluate any paint worklets during styling.
@@ -694,9 +694,7 @@ where
if let Some(ref values) = data.styles.primary {
for image in &values.get_background().background_image.0 {
let (name, arguments) = match *image {
- GenericImageLayer::Image(Image::PaintWorklet(ref worklet)) => {
- (&worklet.name, &worklet.arguments)
- },
+ Image::PaintWorklet(ref worklet) => (&worklet.name, &worklet.arguments),
_ => continue,
};
let painter = match context.shared.registered_speculative_painters.get(name) {
diff --git a/components/style/values/animated/length.rs b/components/style/values/animated/length.rs
deleted file mode 100644
index 04690446e64..00000000000
--- a/components/style/values/animated/length.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-//! Animation implementation for various length-related types.
-
-use super::{Animate, Procedure};
-use crate::values::computed::length::LengthPercentage;
-use crate::values::computed::Percentage;
-use style_traits::values::specified::AllowedNumericType;
-
-/// <https://drafts.csswg.org/css-transitions/#animtype-lpcalc>
-impl Animate for LengthPercentage {
- #[inline]
- fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
- let animate_percentage_half = |this: Option<Percentage>, other: Option<Percentage>| {
- if this.is_none() && other.is_none() {
- return Ok(None);
- }
- let this = this.unwrap_or_default();
- let other = other.unwrap_or_default();
- Ok(Some(this.animate(&other, procedure)?))
- };
-
- let length = self
- .unclamped_length()
- .animate(&other.unclamped_length(), procedure)?;
- let percentage =
- animate_percentage_half(self.specified_percentage(), other.specified_percentage())?;
-
- // Gets clamped as needed after the animation if needed, so no need to
- // specify any particular AllowedNumericType.
- Ok(LengthPercentage::new_calc(
- length,
- percentage,
- AllowedNumericType::All,
- ))
- }
-}
diff --git a/components/style/values/animated/mod.rs b/components/style/values/animated/mod.rs
index 7e699542fd4..226c01a9a49 100644
--- a/components/style/values/animated/mod.rs
+++ b/components/style/values/animated/mod.rs
@@ -23,7 +23,6 @@ pub mod color;
pub mod effects;
mod font;
mod grid;
-mod length;
mod svg;
pub mod transform;
@@ -109,9 +108,6 @@ pub fn animate_multiplicative_factor(
/// If a variant is annotated with `#[animation(error)]`, the corresponding
/// `match` arm returns an error.
///
-/// If the two values are not similar, an error is returned unless a fallback
-/// function has been specified through `#[animate(fallback)]`.
-///
/// Trait bounds for type parameter `Foo` can be opted out of with
/// `#[animation(no_bound(Foo))]` on the type definition, trait bounds for
/// fields can be opted into with `#[animation(field_bound)]` on the field.
@@ -457,6 +453,16 @@ where
}
}
+impl<T> ToAnimatedZero for Box<[T]>
+where
+ T: ToAnimatedZero,
+{
+ #[inline]
+ fn to_animated_zero(&self) -> Result<Self, ()> {
+ self.iter().map(|v| v.to_animated_zero()).collect()
+ }
+}
+
impl<T> ToAnimatedZero for crate::OwnedSlice<T>
where
T: ToAnimatedZero,
diff --git a/components/style/values/computed/basic_shape.rs b/components/style/values/computed/basic_shape.rs
index 27a091a1115..fa30220157b 100644
--- a/components/style/values/computed/basic_shape.rs
+++ b/components/style/values/computed/basic_shape.rs
@@ -14,11 +14,11 @@ use crate::values::generics::basic_shape as generic;
/// A computed alias for FillRule.
pub use crate::values::generics::basic_shape::FillRule;
-/// A computed clipping shape.
-pub type ClippingShape = generic::ClippingShape<BasicShape, ComputedUrl>;
+/// A computed `clip-path` value.
+pub type ClipPath = generic::GenericClipPath<BasicShape, ComputedUrl>;
-/// A computed float area shape.
-pub type FloatAreaShape = generic::FloatAreaShape<BasicShape, Image>;
+/// A computed `shape-outside` value.
+pub type ShapeOutside = generic::GenericShapeOutside<BasicShape, Image>;
/// A computed basic shape.
pub type BasicShape = generic::GenericBasicShape<
diff --git a/components/style/values/computed/font.rs b/components/style/values/computed/font.rs
index 6867f582d7d..0f821123c20 100644
--- a/components/style/values/computed/font.rs
+++ b/components/style/values/computed/font.rs
@@ -178,7 +178,7 @@ impl ToAnimatedValue for FontSize {
}
}
-#[derive(Clone, Debug, Eq, PartialEq, ToResolvedValue)]
+#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToResolvedValue)]
#[cfg_attr(feature = "servo", derive(Hash, MallocSizeOf))]
/// Specifies a prioritized list of font family names or generic family names.
pub struct FontFamily {
@@ -227,7 +227,9 @@ impl ToCss for FontFamily {
}
}
-#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToResolvedValue, ToShmem)]
+#[derive(
+ Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem,
+)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
/// The name of a font family of choice
pub struct FamilyName {
@@ -270,7 +272,9 @@ impl ToCss for FamilyName {
}
}
-#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToResolvedValue, ToShmem)]
+#[derive(
+ Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem,
+)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
/// Font family names must either be given quoted as strings,
/// or unquoted as a sequence of one or more identifiers.
@@ -285,7 +289,9 @@ pub enum FontFamilyNameSyntax {
Identifiers,
}
-#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToResolvedValue, ToShmem)]
+#[derive(
+ Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToComputedValue, ToResolvedValue, ToShmem,
+)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize, Hash))]
/// A set of faces that vary in weight, width or slope.
pub enum SingleFontFamily {
@@ -301,15 +307,28 @@ pub enum SingleFontFamily {
/// `gfxPlatformFontList.h`s ranged array and `gfxFontFamilyList`'s
/// sSingleGenerics are updated as well.
#[derive(
- Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, Parse, ToCss, ToResolvedValue, ToShmem,
+ Clone,
+ Copy,
+ Debug,
+ Eq,
+ Hash,
+ MallocSizeOf,
+ PartialEq,
+ Parse,
+ ToCss,
+ ToComputedValue,
+ ToResolvedValue,
+ ToShmem,
)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[repr(u8)]
#[allow(missing_docs)]
pub enum GenericFontFamily {
/// No generic family specified, only for internal usage.
+ ///
+ /// NOTE(emilio): Gecko code relies on this variant being zero.
#[css(skip)]
- None,
+ None = 0,
Serif,
SansSerif,
#[parse(aliases = "-moz-fixed")]
@@ -350,19 +369,22 @@ impl SingleFontFamily {
};
let mut value = first_ident.as_ref().to_owned();
+ let mut serialize_quoted = value.contains(' ');
// These keywords are not allowed by themselves.
// The only way this value can be valid with with another keyword.
if reserved {
let ident = input.expect_ident()?;
+ serialize_quoted = serialize_quoted || ident.contains(' ');
value.push(' ');
value.push_str(&ident);
}
while let Ok(ident) = input.try(|i| i.expect_ident_cloned()) {
+ serialize_quoted = serialize_quoted || ident.contains(' ');
value.push(' ');
value.push_str(&ident);
}
- let syntax = if value.starts_with(' ') || value.ends_with(' ') || value.contains(" ") {
+ let syntax = if serialize_quoted {
// For font family names which contains special white spaces, e.g.
// `font-family: \ a\ \ b\ \ c\ ;`, it is tricky to serialize them
// as identifiers correctly. Just mark them quoted so we don't need
@@ -422,16 +444,22 @@ impl SingleFontFamily {
}
#[cfg(feature = "servo")]
-#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToResolvedValue, ToShmem)]
+#[derive(
+ Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem,
+)]
/// A list of SingleFontFamily
pub struct FontFamilyList(Box<[SingleFontFamily]>);
#[cfg(feature = "gecko")]
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, ToComputedValue, ToResolvedValue)]
/// A list of SingleFontFamily
pub enum FontFamilyList {
/// A strong reference to a Gecko SharedFontList object.
- SharedFontList(RefPtr<structs::SharedFontList>),
+ SharedFontList(
+ #[compute(no_field_bound)]
+ #[resolve(no_field_bound)]
+ RefPtr<structs::SharedFontList>,
+ ),
/// A font-family generic ID.
Generic(GenericFontFamily),
}
@@ -675,7 +703,7 @@ pub type FontVariationSettings = FontSettings<VariationValue<Number>>;
/// (see http://www.microsoft.com/typography/otspec/languagetags.htm).
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToResolvedValue)]
#[repr(C)]
-pub struct FontLanguageOverride(u32);
+pub struct FontLanguageOverride(pub u32);
impl FontLanguageOverride {
#[inline]
@@ -686,10 +714,7 @@ impl FontLanguageOverride {
/// Returns this value as a `&str`, backed by `storage`.
#[inline]
- pub fn to_str(self, storage: &mut [u8; 4]) -> &str {
- if self.0 == 0 {
- return "normal";
- }
+ pub(crate) fn to_str(self, storage: &mut [u8; 4]) -> &str {
*storage = u32::to_be_bytes(self.0);
// Safe because we ensure it's ASCII during computing
let slice = if cfg!(debug_assertions) {
@@ -730,10 +755,22 @@ impl ToCss for FontLanguageOverride {
where
W: fmt::Write,
{
+ if self.0 == 0 {
+ return dest.write_str("normal");
+ }
self.to_str(&mut [0; 4]).to_css(dest)
}
}
+// FIXME(emilio): Make Gecko use the cbindgen'd fontLanguageOverride, then
+// remove this.
+#[cfg(feature = "gecko")]
+impl From<u32> for FontLanguageOverride {
+ fn from(v: u32) -> Self {
+ unsafe { Self::from_u32(v) }
+ }
+}
+
#[cfg(feature = "gecko")]
impl From<FontLanguageOverride> for u32 {
fn from(v: FontLanguageOverride) -> u32 {
diff --git a/components/style/values/computed/image.rs b/components/style/values/computed/image.rs
index bd59acac547..a2b59809021 100644
--- a/components/style/values/computed/image.rs
+++ b/components/style/values/computed/image.rs
@@ -13,7 +13,8 @@ use crate::values::computed::url::ComputedImageUrl;
use crate::values::computed::NumberOrPercentage;
use crate::values::computed::{Angle, Color, Context};
use crate::values::computed::{
- LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage, ToComputedValue,
+ AngleOrPercentage, LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage,
+ ToComputedValue,
};
use crate::values::generics::image::{self as generic, GradientCompatMode};
use crate::values::specified::image::LineDirection as SpecifiedLineDirection;
@@ -22,9 +23,6 @@ use std::f32::consts::PI;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
-/// A computed image layer.
-pub type ImageLayer = generic::GenericImageLayer<Image>;
-
/// Computed values for an image according to CSS-IMAGES.
/// <https://drafts.csswg.org/css-images/#image-values>
pub type Image = generic::GenericImage<Gradient, MozImageRect, ComputedImageUrl>;
@@ -37,6 +35,8 @@ pub type Gradient = generic::GenericGradient<
NonNegativeLength,
NonNegativeLengthPercentage,
Position,
+ Angle,
+ AngleOrPercentage,
Color,
>;
@@ -57,15 +57,9 @@ pub enum LineDirection {
Corner(HorizontalPositionKeyword, VerticalPositionKeyword),
}
-/// A computed gradient item.
-pub type GradientItem = generic::GenericGradientItem<Color, LengthPercentage>;
-
-/// A computed color stop.
-pub type ColorStop = generic::ColorStop<Color, LengthPercentage>;
-
/// Computed values for `-moz-image-rect(...)`.
#[cfg(feature = "gecko")]
-pub type MozImageRect = generic::MozImageRect<NumberOrPercentage, ComputedImageUrl>;
+pub type MozImageRect = generic::GenericMozImageRect<NumberOrPercentage, ComputedImageUrl>;
/// Empty enum on non-gecko
#[cfg(not(feature = "gecko"))]
diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs
index 32b0946493c..8c6dde8c738 100644
--- a/components/style/values/computed/length.rs
+++ b/components/style/values/computed/length.rs
@@ -17,7 +17,7 @@ use crate::values::{specified, CSSFloat};
use crate::Zero;
use app_units::Au;
use std::fmt::{self, Write};
-use std::ops::{Add, AddAssign, Div, Mul, Neg, Sub};
+use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub};
use style_traits::{CSSPixel, CssWriter, ToCss};
pub use super::image::Image;
@@ -203,6 +203,7 @@ impl Size {
Serialize,
ToAnimatedValue,
ToAnimatedZero,
+ ToComputedValue,
ToResolvedValue,
ToShmem,
)]
@@ -331,6 +332,13 @@ impl Div<CSSFloat> for CSSPixelLength {
}
}
+impl MulAssign<CSSFloat> for CSSPixelLength {
+ #[inline]
+ fn mul_assign(&mut self, other: CSSFloat) {
+ self.0 *= other;
+ }
+}
+
impl Mul<CSSFloat> for CSSPixelLength {
type Output = Self;
diff --git a/components/style/values/computed/length_percentage.rs b/components/style/values/computed/length_percentage.rs
index 96bf76c98d4..1889481ad84 100644
--- a/components/style/values/computed/length_percentage.rs
+++ b/components/style/values/computed/length_percentage.rs
@@ -25,15 +25,16 @@
//! our expectations.
use super::{Context, Length, Percentage, ToComputedValue};
-use crate::values::animated::{ToAnimatedValue, ToAnimatedZero};
+use crate::values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
-use crate::values::generics::NonNegative;
+use crate::values::generics::{calc, NonNegative};
use crate::values::specified::length::FontBaseSize;
use crate::values::{specified, CSSFloat};
use crate::Zero;
use app_units::Au;
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use serde::{Deserialize, Serialize};
+use std::borrow::Cow;
use std::fmt::{self, Write};
use style_traits::values::specified::AllowedNumericType;
use style_traits::{CssWriter, ToCss};
@@ -162,13 +163,20 @@ impl MallocSizeOf for LengthPercentage {
}
/// An unpacked `<length-percentage>` that borrows the `calc()` variant.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, ToCss)]
enum Unpacked<'a> {
Calc(&'a CalcLengthPercentage),
Length(Length),
Percentage(Percentage),
}
+/// An unpacked `<length-percentage>` that mutably borrows the `calc()` variant.
+enum UnpackedMut<'a> {
+ Calc(&'a mut CalcLengthPercentage),
+ Length(Length),
+ Percentage(Percentage),
+}
+
/// An unpacked `<length-percentage>` that owns the `calc()` variant, for
/// serialization purposes.
#[derive(Deserialize, PartialEq, Serialize)]
@@ -185,6 +193,22 @@ impl LengthPercentage {
Self::new_length(Length::new(1.))
}
+ /// 0%
+ #[inline]
+ pub fn zero_percent() -> Self {
+ Self::new_percent(Percentage::zero())
+ }
+
+ fn to_calc_node(&self) -> Cow<CalcNode> {
+ match self.unpack() {
+ Unpacked::Length(l) => Cow::Owned(CalcNode::Leaf(CalcLengthPercentageLeaf::Length(l))),
+ Unpacked::Percentage(p) => {
+ Cow::Owned(CalcNode::Leaf(CalcLengthPercentageLeaf::Percentage(p)))
+ },
+ Unpacked::Calc(p) => Cow::Borrowed(&p.node),
+ }
+ }
+
/// Constructs a length value.
#[inline]
pub fn new_length(length: Length) -> Self {
@@ -211,25 +235,46 @@ impl LengthPercentage {
percent
}
+ /// Given a `LengthPercentage` value `v`, construct the value representing
+ /// `calc(100% - v)`.
+ pub fn hundred_percent_minus(v: Self, clamping_mode: AllowedNumericType) -> Self {
+ // TODO: This could in theory take ownership of the calc node in `v` if
+ // possible instead of cloning.
+ let mut node = v.to_calc_node().into_owned();
+ node.negate();
+
+ let new_node = CalcNode::Sum(
+ vec![
+ CalcNode::Leaf(CalcLengthPercentageLeaf::Percentage(Percentage::hundred())),
+ node,
+ ]
+ .into(),
+ );
+
+ Self::new_calc(new_node, clamping_mode)
+ }
+
/// Constructs a `calc()` value.
#[inline]
- pub fn new_calc(
- length: Length,
- percentage: Option<Percentage>,
- clamping_mode: AllowedNumericType,
- ) -> Self {
- let percentage = match percentage {
- Some(p) => p,
- None => return Self::new_length(Length::new(clamping_mode.clamp(length.px()))),
- };
- if length.is_zero() {
- return Self::new_percent(Percentage(clamping_mode.clamp(percentage.0)));
+ pub fn new_calc(mut node: CalcNode, clamping_mode: AllowedNumericType) -> Self {
+ node.simplify_and_sort();
+
+ match node {
+ CalcNode::Leaf(l) => {
+ return match l {
+ CalcLengthPercentageLeaf::Length(l) => {
+ Self::new_length(Length::new(clamping_mode.clamp(l.px())))
+ },
+ CalcLengthPercentageLeaf::Percentage(p) => {
+ Self::new_percent(Percentage(clamping_mode.clamp(p.0)))
+ },
+ }
+ },
+ _ => Self::new_calc_unchecked(Box::new(CalcLengthPercentage {
+ clamping_mode,
+ node,
+ })),
}
- Self::new_calc_unchecked(Box::new(CalcLengthPercentage {
- length,
- percentage,
- clamping_mode,
- }))
}
/// Private version of new_calc() that constructs a calc() variant without
@@ -262,7 +307,18 @@ impl LengthPercentage {
LengthPercentageUnion::TAG_CALC => Tag::Calc,
LengthPercentageUnion::TAG_LENGTH => Tag::Length,
LengthPercentageUnion::TAG_PERCENTAGE => Tag::Percentage,
- _ => unreachable!("Bogus tag?"),
+ _ => unsafe { debug_unreachable!("Bogus tag?") },
+ }
+ }
+
+ #[inline]
+ fn unpack_mut<'a>(&'a mut self) -> UnpackedMut<'a> {
+ unsafe {
+ match self.tag() {
+ Tag::Calc => UnpackedMut::Calc(&mut *self.calc_ptr()),
+ Tag::Length => UnpackedMut::Length(self.0.length.length),
+ Tag::Percentage => UnpackedMut::Percentage(self.0.percentage.percentage),
+ }
}
}
@@ -313,57 +369,7 @@ impl LengthPercentage {
match self.unpack() {
Unpacked::Length(l) => l.px() == 0.0,
Unpacked::Percentage(p) => p.0 == 0.0,
- Unpacked::Calc(ref c) => {
- debug_assert_ne!(
- c.length.px(),
- 0.0,
- "Should've been simplified to a percentage"
- );
- false
- },
- }
- }
-
- /// Returns the `<length>` component of this `calc()`, unclamped.
- #[inline]
- pub fn unclamped_length(&self) -> Length {
- match self.unpack() {
- Unpacked::Length(l) => l,
- Unpacked::Percentage(..) => Zero::zero(),
- Unpacked::Calc(c) => c.unclamped_length(),
- }
- }
-
- /// Returns this `calc()` as a `<length>`.
- ///
- /// Panics in debug mode if a percentage is present in the expression.
- #[inline]
- fn length(&self) -> Length {
- debug_assert!(!self.has_percentage());
- self.length_component()
- }
-
- /// Returns the `<length>` component of this `calc()`, clamped.
- #[inline]
- pub fn length_component(&self) -> Length {
- match self.unpack() {
- Unpacked::Length(l) => l,
- Unpacked::Percentage(..) => Zero::zero(),
- Unpacked::Calc(c) => c.length_component(),
- }
- }
-
- /// Returns the `<percentage>` component of this `calc()`, unclamped, as a
- /// float.
- ///
- /// FIXME: This are very different semantics from length(), we should
- /// probably rename this.
- #[inline]
- pub fn percentage(&self) -> CSSFloat {
- match self.unpack() {
- Unpacked::Length(..) => 0.,
- Unpacked::Percentage(p) => p.0,
- Unpacked::Calc(c) => c.percentage.0,
+ Unpacked::Calc(..) => false,
}
}
@@ -407,25 +413,8 @@ impl LengthPercentage {
#[inline]
pub fn to_percentage(&self) -> Option<Percentage> {
match self.unpack() {
- Unpacked::Length(..) => None,
Unpacked::Percentage(p) => Some(p),
- Unpacked::Calc(ref c) => {
- debug_assert!(!c.length.is_zero());
- None
- },
- }
- }
-
- /// Return the specified percentage if any.
- #[inline]
- pub fn specified_percentage(&self) -> Option<Percentage> {
- match self.unpack() {
- Unpacked::Length(..) => None,
- Unpacked::Percentage(p) => Some(p),
- Unpacked::Calc(ref c) => {
- debug_assert!(self.has_percentage());
- Some(c.percentage)
- },
+ Unpacked::Length(..) | Unpacked::Calc(..) => None,
}
}
@@ -452,19 +441,22 @@ impl LengthPercentage {
/// the height property), they apply whenever a calc() expression contains
/// percentages.
pub fn maybe_percentage_relative_to(&self, container_len: Option<Length>) -> Option<Length> {
- if self.has_percentage() {
- return Some(self.resolve(container_len?));
+ if let Unpacked::Length(l) = self.unpack() {
+ return Some(l);
}
- Some(self.length())
+ Some(self.resolve(container_len?))
}
/// Returns the clamped non-negative values.
#[inline]
- pub fn clamp_to_non_negative(&self) -> Self {
- match self.unpack() {
- Unpacked::Length(l) => Self::new_length(l.clamp_to_non_negative()),
- Unpacked::Percentage(p) => Self::new_percent(p.clamp_to_non_negative()),
- Unpacked::Calc(c) => c.clamp_to_non_negative(),
+ pub fn clamp_to_non_negative(mut self) -> Self {
+ match self.unpack_mut() {
+ UnpackedMut::Length(l) => Self::new_length(l.clamp_to_non_negative()),
+ UnpackedMut::Percentage(p) => Self::new_percent(p.clamp_to_non_negative()),
+ UnpackedMut::Calc(ref mut c) => {
+ c.clamping_mode = AllowedNumericType::NonNegative;
+ self
+ },
}
}
}
@@ -549,7 +541,7 @@ impl ToCss for LengthPercentage {
where
W: Write,
{
- specified::LengthPercentage::from_computed_value(self).to_css(dest)
+ self.unpack().to_css(dest)
}
}
@@ -584,46 +576,138 @@ impl<'de> Deserialize<'de> for LengthPercentage {
}
}
-/// The representation of a calc() function with mixed lengths and percentages.
-#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize, ToAnimatedZero, ToResolvedValue)]
-#[repr(C)]
-pub struct CalcLengthPercentage {
- length: Length,
+/// The leaves of a `<length-percentage>` calc expression.
+#[derive(
+ Clone,
+ Debug,
+ Deserialize,
+ MallocSizeOf,
+ PartialEq,
+ Serialize,
+ ToAnimatedZero,
+ ToCss,
+ ToResolvedValue,
+)]
+#[allow(missing_docs)]
+#[repr(u8)]
+pub enum CalcLengthPercentageLeaf {
+ Length(Length),
+ Percentage(Percentage),
+}
- percentage: Percentage,
+impl CalcLengthPercentageLeaf {
+ fn is_zero_length(&self) -> bool {
+ match *self {
+ Self::Length(ref l) => l.is_zero(),
+ Self::Percentage(..) => false,
+ }
+ }
+}
- #[animation(constant)]
- clamping_mode: AllowedNumericType,
+impl PartialOrd for CalcLengthPercentageLeaf {
+ fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+ use self::CalcLengthPercentageLeaf::*;
+
+ if std::mem::discriminant(self) != std::mem::discriminant(other) {
+ return None;
+ }
+
+ match (self, other) {
+ (&Length(ref one), &Length(ref other)) => one.partial_cmp(other),
+ (&Percentage(ref one), &Percentage(ref other)) => one.partial_cmp(other),
+ _ => {
+ match *self {
+ Length(..) | Percentage(..) => {},
+ }
+ unsafe {
+ debug_unreachable!("Forgot a branch?");
+ }
+ },
+ }
+ }
}
-impl CalcLengthPercentage {
- /// Returns the length component of this `calc()`, clamped.
- #[inline]
- fn length_component(&self) -> Length {
- Length::new(self.clamping_mode.clamp(self.length.px()))
+impl calc::CalcNodeLeaf for CalcLengthPercentageLeaf {
+ fn is_negative(&self) -> bool {
+ match *self {
+ Self::Length(ref l) => l.px() < 0.,
+ Self::Percentage(ref p) => p.0 < 0.,
+ }
}
- /// Resolves the percentage.
- #[inline]
- pub fn resolve(&self, basis: Length) -> Length {
- let length = self.length.px() + basis.px() * self.percentage.0;
- Length::new(self.clamping_mode.clamp(length))
+ fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()> {
+ use self::CalcLengthPercentageLeaf::*;
+
+ // 0px plus anything else is equal to the right hand side.
+ if self.is_zero_length() {
+ *self = other.clone();
+ return Ok(());
+ }
+
+ if other.is_zero_length() {
+ return Ok(());
+ }
+
+ match (self, other) {
+ (&mut Length(ref mut one), &Length(ref other)) => {
+ *one += *other;
+ },
+ (&mut Percentage(ref mut one), &Percentage(ref other)) => {
+ one.0 += other.0;
+ },
+ _ => return Err(()),
+ }
+
+ Ok(())
}
- /// Returns the length, without clamping.
- #[inline]
- fn unclamped_length(&self) -> Length {
- self.length
+ fn mul_by(&mut self, scalar: f32) {
+ match *self {
+ Self::Length(ref mut l) => *l = *l * scalar,
+ Self::Percentage(ref mut p) => p.0 *= scalar,
+ }
}
- /// Returns the clamped non-negative values.
+ fn simplify(&mut self) {}
+
+ fn sort_key(&self) -> calc::SortKey {
+ match *self {
+ Self::Length(..) => calc::SortKey::Px,
+ Self::Percentage(..) => calc::SortKey::Percentage,
+ }
+ }
+}
+
+/// The computed version of a calc() node for `<length-percentage>` values.
+pub type CalcNode = calc::GenericCalcNode<CalcLengthPercentageLeaf>;
+
+/// The representation of a calc() function with mixed lengths and percentages.
+#[derive(
+ Clone, Debug, Deserialize, MallocSizeOf, Serialize, ToAnimatedZero, ToResolvedValue, ToCss,
+)]
+#[repr(C)]
+pub struct CalcLengthPercentage {
+ #[animation(constant)]
+ #[css(skip)]
+ clamping_mode: AllowedNumericType,
+ node: CalcNode,
+}
+
+impl CalcLengthPercentage {
+ /// Resolves the percentage.
#[inline]
- fn clamp_to_non_negative(&self) -> LengthPercentage {
- LengthPercentage::new_calc(
- self.length,
- Some(self.percentage),
- AllowedNumericType::NonNegative,
- )
+ fn resolve(&self, basis: Length) -> Length {
+ // unwrap() is fine because the conversion below is infallible.
+ let px = self
+ .node
+ .resolve(|l| {
+ Ok(match *l {
+ CalcLengthPercentageLeaf::Length(l) => l.px(),
+ CalcLengthPercentageLeaf::Percentage(ref p) => basis.px() * p.0,
+ })
+ })
+ .unwrap();
+ Length::new(self.clamping_mode.clamp(px))
}
}
@@ -641,7 +725,7 @@ impl CalcLengthPercentage {
// maybe.
impl PartialEq for CalcLengthPercentage {
fn eq(&self, other: &Self) -> bool {
- self.length == other.length && self.percentage == other.percentage
+ self.node == other.node
}
}
@@ -656,43 +740,22 @@ impl specified::CalcLengthPercentage {
where
F: Fn(Length) -> Length,
{
- use crate::values::specified::length::{FontRelativeLength, ViewportPercentageLength};
- use std::f32;
-
- let mut length = 0.;
-
- if let Some(absolute) = self.absolute {
- length += zoom_fn(absolute.to_computed_value(context)).px();
- }
-
- for val in &[
- self.vw.map(ViewportPercentageLength::Vw),
- self.vh.map(ViewportPercentageLength::Vh),
- self.vmin.map(ViewportPercentageLength::Vmin),
- self.vmax.map(ViewportPercentageLength::Vmax),
- ] {
- if let Some(val) = *val {
- let viewport_size = context.viewport_size_for_viewport_unit_resolution();
- length += val.to_computed_value(viewport_size).px();
- }
- }
-
- for val in &[
- self.ch.map(FontRelativeLength::Ch),
- self.em.map(FontRelativeLength::Em),
- self.ex.map(FontRelativeLength::Ex),
- self.rem.map(FontRelativeLength::Rem),
- ] {
- if let Some(val) = *val {
- length += val.to_computed_value(context, base_size).px();
- }
- }
+ use crate::values::specified::calc::Leaf;
+ use crate::values::specified::length::NoCalcLength;
+
+ let node = self.node.map_leaves(|leaf| match *leaf {
+ Leaf::Percentage(p) => CalcLengthPercentageLeaf::Percentage(Percentage(p)),
+ Leaf::Length(l) => CalcLengthPercentageLeaf::Length(match l {
+ NoCalcLength::Absolute(ref abs) => zoom_fn(abs.to_computed_value(context)),
+ NoCalcLength::FontRelative(ref fr) => fr.to_computed_value(context, base_size),
+ other => other.to_computed_value(context),
+ }),
+ Leaf::Number(..) | Leaf::Angle(..) | Leaf::Time(..) => {
+ unreachable!("Shouldn't have parsed")
+ },
+ });
- LengthPercentage::new_calc(
- Length::new(length.min(f32::MAX).max(f32::MIN)),
- self.percentage,
- self.clamping_mode,
- )
+ LengthPercentage::new_calc(node, self.clamping_mode)
}
/// Compute font-size or line-height taking into account text-zoom if necessary.
@@ -711,25 +774,14 @@ impl specified::CalcLengthPercentage {
/// Compute the value into pixel length as CSSFloat without context,
/// so it returns Err(()) if there is any non-absolute unit.
pub fn to_computed_pixel_length_without_context(&self) -> Result<CSSFloat, ()> {
- if self.vw.is_some() ||
- self.vh.is_some() ||
- self.vmin.is_some() ||
- self.vmax.is_some() ||
- self.em.is_some() ||
- self.ex.is_some() ||
- self.ch.is_some() ||
- self.rem.is_some() ||
- self.percentage.is_some()
- {
- return Err(());
- }
-
- match self.absolute {
- Some(abs) => Ok(abs.to_px()),
- None => {
- debug_assert!(false, "Someone forgot to handle an unit here: {:?}", self);
- Err(())
- },
+ use crate::values::specified::calc::Leaf;
+ use crate::values::specified::length::NoCalcLength;
+
+ // Simplification should've turned this into an absolute length,
+ // otherwise it wouldn't have been able to.
+ match self.node {
+ calc::CalcNode::Leaf(Leaf::Length(NoCalcLength::Absolute(ref l))) => Ok(l.to_px()),
+ _ => Err(()),
}
}
@@ -740,17 +792,51 @@ impl specified::CalcLengthPercentage {
#[inline]
fn from_computed_value(computed: &CalcLengthPercentage) -> Self {
- use crate::values::specified::length::AbsoluteLength;
+ use crate::values::specified::calc::Leaf;
+ use crate::values::specified::length::NoCalcLength;
specified::CalcLengthPercentage {
clamping_mode: computed.clamping_mode,
- absolute: Some(AbsoluteLength::from_computed_value(&computed.length)),
- percentage: Some(computed.percentage),
- ..Default::default()
+ node: computed.node.map_leaves(|l| match l {
+ CalcLengthPercentageLeaf::Length(ref l) => {
+ Leaf::Length(NoCalcLength::from_px(l.px()))
+ },
+ CalcLengthPercentageLeaf::Percentage(ref p) => Leaf::Percentage(p.0),
+ }),
}
}
}
+/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
+/// https://drafts.csswg.org/css-values-4/#combine-math
+/// https://drafts.csswg.org/css-values-4/#combine-mixed
+impl Animate for LengthPercentage {
+ #[inline]
+ fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+ Ok(match (self.unpack(), other.unpack()) {
+ (Unpacked::Length(one), Unpacked::Length(other)) => {
+ Self::new_length(one.animate(&other, procedure)?)
+ },
+ (Unpacked::Percentage(one), Unpacked::Percentage(other)) => {
+ Self::new_percent(one.animate(&other, procedure)?)
+ },
+ _ => {
+ let mut one = self.to_calc_node().into_owned();
+ let mut other = other.to_calc_node().into_owned();
+ let (l, r) = procedure.weights();
+
+ one.mul_by(l as f32);
+ other.mul_by(r as f32);
+
+ Self::new_calc(
+ CalcNode::Sum(vec![one, other].into()),
+ AllowedNumericType::All,
+ )
+ },
+ })
+ }
+}
+
/// A wrapper of LengthPercentage, whose value must be >= 0.
pub type NonNegativeLengthPercentage = NonNegative<LengthPercentage>;
diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs
index 7cfd1e20abe..841cc3df22a 100644
--- a/components/style/values/computed/mod.rs
+++ b/components/style/values/computed/mod.rs
@@ -21,10 +21,9 @@ use crate::media_queries::Device;
use crate::properties;
use crate::properties::{ComputedValues, LonghandId, StyleBuilder};
use crate::rule_cache::RuleCacheConditions;
-use crate::Atom;
-#[cfg(feature = "servo")]
-use crate::Prefix;
+use crate::{ArcSlice, Atom};
use euclid::default::Size2D;
+use servo_arc::Arc;
use std::cell::RefCell;
use std::cmp;
use std::f32;
@@ -57,7 +56,7 @@ pub use self::font::{FontSize, FontSizeAdjust, FontStretch, FontSynthesis};
pub use self::font::{FontVariantAlternates, FontWeight};
pub use self::font::{FontVariantEastAsian, FontVariationSettings};
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom};
-pub use self::image::{Gradient, GradientItem, Image, ImageLayer, LineDirection, MozImageRect};
+pub use self::image::{Gradient, Image, LineDirection, MozImageRect};
pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength};
pub use self::length::{Length, LengthOrNumber, LengthPercentage, NonNegativeLengthOrNumber};
pub use self::length::{LengthOrAuto, LengthPercentageOrAuto, MaxSize, Size};
@@ -78,7 +77,7 @@ pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
pub use self::text::TextUnderlinePosition;
pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight};
pub use self::text::{OverflowWrap, TextOverflow, WordBreak, WordSpacing};
-pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle};
+pub use self::text::{TextAlign, TextAlignLast, TextEmphasisPosition, TextEmphasisStyle};
pub use self::text::{TextDecorationLength, TextDecorationSkipInk};
pub use self::time::Time;
pub use self::transform::{Rotate, Scale, Transform, TransformOperation};
@@ -450,6 +449,46 @@ where
}
}
+// NOTE(emilio): This is implementable more generically, but it's unlikely
+// what you want there, as it forces you to have an extra allocation.
+//
+// We could do that if needed, ideally with specialization for the case where
+// ComputedValue = T. But we don't need it for now.
+impl<T> ToComputedValue for Arc<T>
+where
+ T: ToComputedValue<ComputedValue = T>,
+{
+ type ComputedValue = Self;
+
+ #[inline]
+ fn to_computed_value(&self, _: &Context) -> Self {
+ self.clone()
+ }
+
+ #[inline]
+ fn from_computed_value(computed: &Self) -> Self {
+ computed.clone()
+ }
+}
+
+// Same caveat as above applies.
+impl<T> ToComputedValue for ArcSlice<T>
+where
+ T: ToComputedValue<ComputedValue = T>,
+{
+ type ComputedValue = Self;
+
+ #[inline]
+ fn to_computed_value(&self, _: &Context) -> Self {
+ self.clone()
+ }
+
+ #[inline]
+ fn from_computed_value(computed: &Self) -> Self {
+ computed.clone()
+ }
+}
+
trivial_to_computed_value!(());
trivial_to_computed_value!(bool);
trivial_to_computed_value!(f32);
@@ -460,10 +499,13 @@ trivial_to_computed_value!(u32);
trivial_to_computed_value!(usize);
trivial_to_computed_value!(Atom);
#[cfg(feature = "servo")]
-trivial_to_computed_value!(Prefix);
+trivial_to_computed_value!(html5ever::Namespace);
+#[cfg(feature = "servo")]
+trivial_to_computed_value!(html5ever::Prefix);
trivial_to_computed_value!(String);
trivial_to_computed_value!(Box<str>);
trivial_to_computed_value!(crate::OwnedStr);
+trivial_to_computed_value!(style_traits::values::specified::AllowedNumericType);
#[allow(missing_docs)]
#[derive(
diff --git a/components/style/values/computed/position.rs b/components/style/values/computed/position.rs
index 7b22c37f73f..3eff231de88 100644
--- a/components/style/values/computed/position.rs
+++ b/components/style/values/computed/position.rs
@@ -9,6 +9,7 @@
use crate::values::computed::{Integer, LengthPercentage, Percentage};
use crate::values::generics::position::Position as GenericPosition;
+use crate::values::generics::position::PositionComponent as GenericPositionComponent;
use crate::values::generics::position::PositionOrAuto as GenericPositionOrAuto;
use crate::values::generics::position::ZIndex as GenericZIndex;
pub use crate::values::specified::position::{GridAutoFlow, GridTemplateAreas};
@@ -56,5 +57,14 @@ impl ToCss for Position {
}
}
+impl GenericPositionComponent for LengthPercentage {
+ fn is_center(&self) -> bool {
+ match self.to_percentage() {
+ Some(Percentage(per)) => per == 0.5,
+ _ => false,
+ }
+ }
+}
+
/// A computed value for the `z-index` property.
pub type ZIndex = GenericZIndex<Integer>;
diff --git a/components/style/values/computed/svg.rs b/components/style/values/computed/svg.rs
index 54648572f86..a348d071ab9 100644
--- a/components/style/values/computed/svg.rs
+++ b/components/style/values/computed/svg.rs
@@ -31,7 +31,7 @@ impl SVGPaint {
}
/// <length> | <percentage> | <number> | context-value
-pub type SVGLength = generic::SVGLength<LengthPercentage>;
+pub type SVGLength = generic::GenericSVGLength<LengthPercentage>;
impl SVGLength {
/// `0px`
@@ -41,7 +41,7 @@ impl SVGLength {
}
/// An non-negative wrapper of SVGLength.
-pub type SVGWidth = generic::SVGLength<NonNegativeLengthPercentage>;
+pub type SVGWidth = generic::GenericSVGLength<NonNegativeLengthPercentage>;
impl SVGWidth {
/// `1px`.
diff --git a/components/style/values/computed/text.rs b/components/style/values/computed/text.rs
index 0ca2e6044ed..b77695e06c0 100644
--- a/components/style/values/computed/text.rs
+++ b/components/style/values/computed/text.rs
@@ -18,8 +18,7 @@ use crate::Zero;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
-pub use crate::values::specified::TextAlignKeyword as TextAlign;
-pub use crate::values::specified::TextUnderlinePosition;
+pub use crate::values::specified::text::{TextAlignLast, TextUnderlinePosition};
pub use crate::values::specified::{LineBreak, OverflowWrap, WordBreak};
pub use crate::values::specified::{TextDecorationLine, TextEmphasisPosition};
pub use crate::values::specified::{TextDecorationSkipInk, TextTransform};
@@ -30,6 +29,9 @@ pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;
/// Implements type for `text-decoration-thickness` property.
pub type TextDecorationLength = GenericTextDecorationLength<LengthPercentage>;
+/// The computed value of `text-align`.
+pub type TextAlign = specified::TextAlignKeyword;
+
/// A computed value for the `letter-spacing` property.
#[repr(transparent)]
#[derive(
diff --git a/components/style/values/computed/ui.rs b/components/style/values/computed/ui.rs
index 21914995951..ae12dfcdae0 100644
--- a/components/style/values/computed/ui.rs
+++ b/components/style/values/computed/ui.rs
@@ -13,10 +13,10 @@ pub use crate::values::specified::ui::CursorKind;
pub use crate::values::specified::ui::{MozForceBrokenImageIcon, UserSelect};
/// A computed value for the `cursor` property.
-pub type Cursor = generics::Cursor<CursorImage>;
+pub type Cursor = generics::GenericCursor<CursorImage>;
/// A computed value for item of `image cursors`.
-pub type CursorImage = generics::CursorImage<ComputedImageUrl, Number>;
+pub type CursorImage = generics::GenericCursorImage<ComputedImageUrl, Number>;
/// A computed value for `scrollbar-color` property.
pub type ScrollbarColor = generics::GenericScrollbarColor<Color>;
diff --git a/components/style/values/distance.rs b/components/style/values/distance.rs
index 67c735676b5..a4259ce8c6b 100644
--- a/components/style/values/distance.rs
+++ b/components/style/values/distance.rs
@@ -19,9 +19,6 @@ use std::ops::Add;
/// If a variant is annotated with `#[animation(error)]`, the corresponding
/// `match` arm returns an error.
///
-/// If the two values are not similar, an error is returned unless a fallback
-/// function has been specified through `#[distance(fallback)]`.
-///
/// Trait bounds for type parameter `Foo` can be opted out of with
/// `#[animation(no_bound(Foo))]` on the type definition, trait bounds for
/// fields can be opted into with `#[distance(field_bound)]` on the field.
@@ -81,6 +78,16 @@ impl ComputeSquaredDistance for Au {
}
}
+impl<T> ComputeSquaredDistance for Box<T>
+where
+ T: ComputeSquaredDistance,
+{
+ #[inline]
+ fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+ (**self).compute_squared_distance(&**other)
+ }
+}
+
impl<T> ComputeSquaredDistance for Option<T>
where
T: ComputeSquaredDistance,
diff --git a/components/style/values/generics/basic_shape.rs b/components/style/values/generics/basic_shape.rs
index d91fa58eb0d..745d6e07bbf 100644
--- a/components/style/values/generics/basic_shape.rs
+++ b/components/style/values/generics/basic_shape.rs
@@ -15,18 +15,17 @@ use crate::Zero;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
-/// A clipping shape, for `clip-path`.
-pub type ClippingShape<BasicShape, Url> = ShapeSource<BasicShape, GeometryBox, Url>;
-
/// <https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box>
#[allow(missing_docs)]
#[derive(
Animate,
Clone,
+ ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
PartialEq,
+ Parse,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
@@ -34,15 +33,27 @@ pub type ClippingShape<BasicShape, Url> = ShapeSource<BasicShape, GeometryBox, U
ToResolvedValue,
ToShmem,
)]
-pub enum GeometryBox {
+#[repr(u8)]
+pub enum ShapeGeometryBox {
+ /// Depending on which kind of element this style value applied on, the
+ /// default value of the reference-box can be different. For an HTML
+ /// element, the default value of reference-box is border-box; for an SVG
+ /// element, the default value is fill-box. Since we can not determine the
+ /// default value at parsing time, we keep this value to make a decision on
+ /// it.
+ #[css(skip)]
+ ElementDependent,
FillBox,
StrokeBox,
ViewBox,
ShapeBox(ShapeBox),
}
-/// A float area shape, for `shape-outside`.
-pub type FloatAreaShape<BasicShape, Image> = ShapeSource<BasicShape, ShapeBox, Image>;
+impl Default for ShapeGeometryBox {
+ fn default() -> Self {
+ Self::ElementDependent
+ }
+}
/// https://drafts.csswg.org/css-shapes-1/#typedef-shape-box
#[allow(missing_docs)]
@@ -51,6 +62,7 @@ pub type FloatAreaShape<BasicShape, Image> = ShapeSource<BasicShape, ShapeBox, I
Animate,
Clone,
Copy,
+ ComputeSquaredDistance,
Debug,
Eq,
MallocSizeOf,
@@ -63,6 +75,7 @@ pub type FloatAreaShape<BasicShape, Image> = ShapeSource<BasicShape, ShapeBox, I
ToResolvedValue,
ToShmem,
)]
+#[repr(u8)]
pub enum ShapeBox {
MarginBox,
BorderBox,
@@ -70,12 +83,19 @@ pub enum ShapeBox {
ContentBox,
}
-/// A shape source, for some reference box.
+impl Default for ShapeBox {
+ fn default() -> Self {
+ ShapeBox::MarginBox
+ }
+}
+
+/// A value for the `clip-path` property.
#[allow(missing_docs)]
-#[animation(no_bound(ImageOrUrl))]
+#[animation(no_bound(U))]
#[derive(
Animate,
Clone,
+ ComputeSquaredDistance,
Debug,
MallocSizeOf,
PartialEq,
@@ -86,18 +106,54 @@ pub enum ShapeBox {
ToResolvedValue,
ToShmem,
)]
-pub enum ShapeSource<BasicShape, ReferenceBox, ImageOrUrl> {
+#[repr(u8)]
+pub enum GenericClipPath<BasicShape, U> {
#[animation(error)]
- ImageOrUrl(ImageOrUrl),
- Shape(Box<BasicShape>, Option<ReferenceBox>),
+ None,
#[animation(error)]
- Box(ReferenceBox),
+ Url(U),
#[css(function)]
Path(Path),
+ Shape(
+ Box<BasicShape>,
+ #[css(skip_if = "is_default")] ShapeGeometryBox,
+ ),
+ #[animation(error)]
+ Box(ShapeGeometryBox),
+}
+
+pub use self::GenericClipPath as ClipPath;
+
+/// A value for the `shape-outside` property.
+#[allow(missing_docs)]
+#[animation(no_bound(I))]
+#[derive(
+ Animate,
+ Clone,
+ ComputeSquaredDistance,
+ Debug,
+ MallocSizeOf,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToAnimatedValue,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+ ToShmem,
+)]
+#[repr(u8)]
+pub enum GenericShapeOutside<BasicShape, I> {
#[animation(error)]
None,
+ #[animation(error)]
+ Image(I),
+ Shape(Box<BasicShape>, #[css(skip_if = "is_default")] ShapeBox),
+ #[animation(error)]
+ Box(ShapeBox),
}
+pub use self::GenericShapeOutside as ShapeOutside;
+
#[allow(missing_docs)]
#[derive(
Animate,
@@ -252,7 +308,7 @@ pub use self::GenericShapeRadius as ShapeRadius;
#[repr(C)]
pub struct GenericPolygon<LengthPercentage> {
/// The filling rule for a polygon.
- #[css(skip_if = "fill_is_default")]
+ #[css(skip_if = "is_default")]
pub fill: FillRule,
/// A collection of (x, y) coordinates to draw the polygon.
#[css(iterable)]
@@ -311,6 +367,7 @@ pub enum FillRule {
#[derive(
Animate,
Clone,
+ ComputeSquaredDistance,
Debug,
MallocSizeOf,
PartialEq,
@@ -321,39 +378,23 @@ pub enum FillRule {
ToResolvedValue,
ToShmem,
)]
+#[repr(C)]
pub struct Path {
/// The filling rule for the svg path.
- #[css(skip_if = "fill_is_default")]
+ #[css(skip_if = "is_default")]
#[animation(constant)]
pub fill: FillRule,
/// The svg path data.
pub path: SVGPathData,
}
-// FIXME(nox): Implement ComputeSquaredDistance for T types and stop
-// using PartialEq here, this will let us derive this impl.
-impl<B, T, U> ComputeSquaredDistance for ShapeSource<B, T, U>
-where
- B: ComputeSquaredDistance,
- T: PartialEq,
-{
- fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
- match (self, other) {
- (
- &ShapeSource::Shape(ref this, ref this_box),
- &ShapeSource::Shape(ref other, ref other_box),
- ) if this_box == other_box => this.compute_squared_distance(other),
- (&ShapeSource::Path(ref this), &ShapeSource::Path(ref other))
- if this.fill == other.fill =>
- {
- this.path.compute_squared_distance(&other.path)
- },
- _ => Err(()),
- }
+impl<B, U> ToAnimatedZero for ClipPath<B, U> {
+ fn to_animated_zero(&self) -> Result<Self, ()> {
+ Err(())
}
}
-impl<B, T, U> ToAnimatedZero for ShapeSource<B, T, U> {
+impl<B, U> ToAnimatedZero for ShapeOutside<B, U> {
fn to_animated_zero(&self) -> Result<Self, ()> {
Err(())
}
@@ -488,6 +529,6 @@ impl Default for FillRule {
}
#[inline]
-fn fill_is_default(fill: &FillRule) -> bool {
- *fill == FillRule::default()
+fn is_default<T: Default + PartialEq>(fill: &T) -> bool {
+ *fill == Default::default()
}
diff --git a/components/style/values/generics/calc.rs b/components/style/values/generics/calc.rs
new file mode 100644
index 00000000000..074dd97f4d0
--- /dev/null
+++ b/components/style/values/generics/calc.rs
@@ -0,0 +1,573 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+//! [Calc expressions][calc].
+//!
+//! [calc]: https://drafts.csswg.org/css-values/#calc-notation
+
+use crate::Zero;
+use smallvec::SmallVec;
+use std::fmt::{self, Write};
+use std::ops::Add;
+use std::{cmp, mem};
+use style_traits::{CssWriter, ToCss};
+
+/// Whether we're a `min` or `max` function.
+#[derive(
+ Clone,
+ Copy,
+ Debug,
+ Deserialize,
+ MallocSizeOf,
+ PartialEq,
+ Serialize,
+ ToAnimatedZero,
+ ToResolvedValue,
+ ToShmem,
+)]
+#[repr(u8)]
+pub enum MinMaxOp {
+ /// `min()`
+ Min,
+ /// `max()`
+ Max,
+}
+
+/// This determines the order in which we serialize members of a calc() sum.
+///
+/// See https://drafts.csswg.org/css-values-4/#sort-a-calculations-children
+#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
+#[allow(missing_docs)]
+pub enum SortKey {
+ Number,
+ Percentage,
+ Ch,
+ Deg,
+ Em,
+ Ex,
+ Px,
+ Rem,
+ Sec,
+ Vh,
+ Vmax,
+ Vmin,
+ Vw,
+ Other,
+}
+
+/// A generic node in a calc expression.
+///
+/// FIXME: This would be much more elegant if we used `Self` in the types below,
+/// but we can't because of https://github.com/serde-rs/serde/issues/1565.
+#[repr(u8)]
+#[derive(
+ Clone,
+ Debug,
+ Deserialize,
+ MallocSizeOf,
+ PartialEq,
+ Serialize,
+ ToAnimatedZero,
+ ToResolvedValue,
+ ToShmem,
+)]
+pub enum GenericCalcNode<L> {
+ /// A leaf node.
+ Leaf(L),
+ /// A sum node, representing `a + b + c` where a, b, and c are the
+ /// arguments.
+ Sum(crate::OwnedSlice<GenericCalcNode<L>>),
+ /// A `min` or `max` function.
+ MinMax(crate::OwnedSlice<GenericCalcNode<L>>, MinMaxOp),
+ /// A `clamp()` function.
+ Clamp {
+ /// The minimum value.
+ min: Box<GenericCalcNode<L>>,
+ /// The central value.
+ center: Box<GenericCalcNode<L>>,
+ /// The maximum value.
+ max: Box<GenericCalcNode<L>>,
+ },
+}
+
+pub use self::GenericCalcNode as CalcNode;
+
+/// A trait that represents all the stuff a valid leaf of a calc expression.
+pub trait CalcNodeLeaf: Clone + Sized + PartialOrd + PartialEq + ToCss {
+ /// Whether this value is known-negative.
+ fn is_negative(&self) -> bool;
+
+ /// Tries to merge one sum to another, that is, perform `x` + `y`.
+ fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()>;
+
+ /// Multiplies the leaf by a given scalar number.
+ fn mul_by(&mut self, scalar: f32);
+
+ /// Negates the leaf.
+ fn negate(&mut self) {
+ self.mul_by(-1.);
+ }
+
+ /// Canonicalizes the expression if necessary.
+ fn simplify(&mut self);
+
+ /// Returns the sort key for simplification.
+ fn sort_key(&self) -> SortKey;
+}
+
+impl<L: CalcNodeLeaf> CalcNode<L> {
+ /// Negates the node.
+ pub fn negate(&mut self) {
+ self.mul_by(-1.);
+ }
+
+ fn sort_key(&self) -> SortKey {
+ match *self {
+ Self::Leaf(ref l) => l.sort_key(),
+ _ => SortKey::Other,
+ }
+ }
+
+ /// Tries to merge one sum to another, that is, perform `x` + `y`.
+ fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()> {
+ match (self, other) {
+ (&mut CalcNode::Leaf(ref mut one), &CalcNode::Leaf(ref other)) => {
+ one.try_sum_in_place(other)
+ },
+ _ => Err(()),
+ }
+ }
+
+ /// Convert this `CalcNode` into a `CalcNode` with a different leaf kind.
+ pub fn map_leaves<O, F>(&self, mut map: F) -> CalcNode<O>
+ where
+ O: CalcNodeLeaf,
+ F: FnMut(&L) -> O,
+ {
+ self.map_leaves_internal(&mut map)
+ }
+
+ fn map_leaves_internal<O, F>(&self, map: &mut F) -> CalcNode<O>
+ where
+ O: CalcNodeLeaf,
+ F: FnMut(&L) -> O,
+ {
+ fn map_children<L, O, F>(
+ children: &[CalcNode<L>],
+ map: &mut F,
+ ) -> crate::OwnedSlice<CalcNode<O>>
+ where
+ L: CalcNodeLeaf,
+ O: CalcNodeLeaf,
+ F: FnMut(&L) -> O,
+ {
+ children
+ .iter()
+ .map(|c| c.map_leaves_internal(map))
+ .collect()
+ }
+
+ match *self {
+ Self::Leaf(ref l) => CalcNode::Leaf(map(l)),
+ Self::Sum(ref c) => CalcNode::Sum(map_children(c, map)),
+ Self::MinMax(ref c, op) => CalcNode::MinMax(map_children(c, map), op),
+ Self::Clamp {
+ ref min,
+ ref center,
+ ref max,
+ } => {
+ let min = Box::new(min.map_leaves_internal(map));
+ let center = Box::new(center.map_leaves_internal(map));
+ let max = Box::new(max.map_leaves_internal(map));
+ CalcNode::Clamp { min, center, max }
+ },
+ }
+ }
+
+ /// Resolves the expression returning a value of `O`, given a function to
+ /// turn a leaf into the relevant value.
+ pub fn resolve<O>(
+ &self,
+ mut leaf_to_output_fn: impl FnMut(&L) -> Result<O, ()>,
+ ) -> Result<O, ()>
+ where
+ O: PartialOrd + PartialEq + Add<Output = O> + Zero,
+ {
+ self.resolve_internal(&mut leaf_to_output_fn)
+ }
+
+ fn resolve_internal<O, F>(&self, leaf_to_output_fn: &mut F) -> Result<O, ()>
+ where
+ O: PartialOrd + PartialEq + Add<Output = O> + Zero,
+ F: FnMut(&L) -> Result<O, ()>,
+ {
+ Ok(match *self {
+ Self::Leaf(ref l) => return leaf_to_output_fn(l),
+ Self::Sum(ref c) => {
+ let mut result = Zero::zero();
+ for child in &**c {
+ result = result + child.resolve_internal(leaf_to_output_fn)?;
+ }
+ result
+ },
+ Self::MinMax(ref nodes, op) => {
+ let mut result = nodes[0].resolve_internal(leaf_to_output_fn)?;
+ for node in nodes.iter().skip(1) {
+ let candidate = node.resolve_internal(leaf_to_output_fn)?;
+ let candidate_wins = match op {
+ MinMaxOp::Min => candidate < result,
+ MinMaxOp::Max => candidate > result,
+ };
+ if candidate_wins {
+ result = candidate;
+ }
+ }
+ result
+ },
+ Self::Clamp {
+ ref min,
+ ref center,
+ ref max,
+ } => {
+ let min = min.resolve_internal(leaf_to_output_fn)?;
+ let center = center.resolve_internal(leaf_to_output_fn)?;
+ let max = max.resolve_internal(leaf_to_output_fn)?;
+
+ let mut result = center;
+ if result > max {
+ result = max;
+ }
+ if result < min {
+ result = min
+ }
+ result
+ },
+ })
+ }
+
+ fn is_negative_leaf(&self) -> bool {
+ match *self {
+ Self::Leaf(ref l) => l.is_negative(),
+ _ => false,
+ }
+ }
+
+ /// Multiplies the node by a scalar.
+ pub fn mul_by(&mut self, scalar: f32) {
+ match *self {
+ Self::Leaf(ref mut l) => l.mul_by(scalar),
+ // Multiplication is distributive across this.
+ Self::Sum(ref mut children) => {
+ for node in &mut **children {
+ node.mul_by(scalar);
+ }
+ },
+ // This one is a bit trickier.
+ Self::MinMax(ref mut children, ref mut op) => {
+ for node in &mut **children {
+ node.mul_by(scalar);
+ }
+
+ // For negatives we need to invert the operation.
+ if scalar < 0. {
+ *op = match *op {
+ MinMaxOp::Min => MinMaxOp::Max,
+ MinMaxOp::Max => MinMaxOp::Min,
+ }
+ }
+ },
+ // This one is slightly tricky too.
+ Self::Clamp {
+ ref mut min,
+ ref mut center,
+ ref mut max,
+ } => {
+ min.mul_by(scalar);
+ center.mul_by(scalar);
+ max.mul_by(scalar);
+ // For negatives we need to swap min / max.
+ if scalar < 0. {
+ mem::swap(min, max);
+ }
+ },
+ }
+ }
+
+ /// Visits all the nodes in this calculation tree recursively, starting by
+ /// the leaves and bubbling all the way up.
+ ///
+ /// This is useful for simplification, but can also be used for validation
+ /// and such.
+ pub fn visit_depth_first(&mut self, mut f: impl FnMut(&mut Self)) {
+ self.visit_depth_first_internal(&mut f);
+ }
+
+ fn visit_depth_first_internal(&mut self, f: &mut impl FnMut(&mut Self)) {
+ match *self {
+ Self::Clamp {
+ ref mut min,
+ ref mut center,
+ ref mut max,
+ } => {
+ min.visit_depth_first_internal(f);
+ center.visit_depth_first_internal(f);
+ max.visit_depth_first_internal(f);
+ },
+ Self::Sum(ref mut children) | Self::MinMax(ref mut children, _) => {
+ for child in &mut **children {
+ child.visit_depth_first_internal(f);
+ }
+ },
+ Self::Leaf(..) => {},
+ }
+ f(self);
+ }
+
+ /// Simplifies and sorts the calculation of a given node. All the nodes
+ /// below it should be simplified already, this only takes care of
+ /// simplifying directly nested nodes. So, probably should always be used in
+ /// combination with `visit_depth_first()`.
+ ///
+ /// This is only needed if it's going to be preserved after parsing (so, for
+ /// `<length-percentage>`). Otherwise we can just evaluate it using
+ /// `resolve()`, and we'll come up with a simplified value anyways.
+ pub fn simplify_and_sort_direct_children(&mut self) {
+ macro_rules! replace_self_with {
+ ($slot:expr) => {{
+ let dummy = Self::MinMax(Default::default(), MinMaxOp::Max);
+ let result = mem::replace($slot, dummy);
+ mem::replace(self, result);
+ }};
+ }
+ match *self {
+ Self::Clamp {
+ ref mut min,
+ ref mut center,
+ ref mut max,
+ } => {
+ // NOTE: clamp() is max(min, min(center, max))
+ let min_cmp_center = match min.partial_cmp(&center) {
+ Some(o) => o,
+ None => return,
+ };
+
+ // So if we can prove that min is more than center, then we won,
+ // as that's what we should always return.
+ if matches!(min_cmp_center, cmp::Ordering::Greater) {
+ return replace_self_with!(&mut **min);
+ }
+
+ // Otherwise try with max.
+ let max_cmp_center = match max.partial_cmp(&center) {
+ Some(o) => o,
+ None => return,
+ };
+
+ if matches!(max_cmp_center, cmp::Ordering::Less) {
+ // max is less than center, so we need to return effectively
+ // `max(min, max)`.
+ let max_cmp_min = match max.partial_cmp(&min) {
+ Some(o) => o,
+ None => {
+ debug_assert!(
+ false,
+ "We compared center with min and max, how are \
+ min / max not comparable with each other?"
+ );
+ return;
+ },
+ };
+
+ if matches!(max_cmp_min, cmp::Ordering::Less) {
+ return replace_self_with!(&mut **min);
+ }
+
+ return replace_self_with!(&mut **max);
+ }
+
+ // Otherwise we're the center node.
+ return replace_self_with!(&mut **center);
+ },
+ Self::MinMax(ref mut children, op) => {
+ let winning_order = match op {
+ MinMaxOp::Min => cmp::Ordering::Less,
+ MinMaxOp::Max => cmp::Ordering::Greater,
+ };
+
+ let mut result = 0;
+ for i in 1..children.len() {
+ let o = match children[i].partial_cmp(&children[result]) {
+ // We can't compare all the children, so we can't
+ // know which one will actually win. Bail out and
+ // keep ourselves as a min / max function.
+ //
+ // TODO: Maybe we could simplify compatible children,
+ // see https://github.com/w3c/csswg-drafts/issues/4756
+ None => return,
+ Some(o) => o,
+ };
+
+ if o == winning_order {
+ result = i;
+ }
+ }
+
+ replace_self_with!(&mut children[result]);
+ },
+ Self::Sum(ref mut children_slot) => {
+ let mut sums_to_merge = SmallVec::<[_; 3]>::new();
+ let mut extra_kids = 0;
+ for (i, child) in children_slot.iter().enumerate() {
+ if let Self::Sum(ref children) = *child {
+ extra_kids += children.len();
+ sums_to_merge.push(i);
+ }
+ }
+
+ // If we only have one kid, we've already simplified it, and it
+ // doesn't really matter whether it's a sum already or not, so
+ // lift it up and continue.
+ if children_slot.len() == 1 {
+ return replace_self_with!(&mut children_slot[0]);
+ }
+
+ let mut children = mem::replace(children_slot, Default::default()).into_vec();
+
+ if !sums_to_merge.is_empty() {
+ children.reserve(extra_kids - sums_to_merge.len());
+ // Merge all our nested sums, in reverse order so that the
+ // list indices are not invalidated.
+ for i in sums_to_merge.drain(..).rev() {
+ let kid_children = match children.swap_remove(i) {
+ Self::Sum(c) => c,
+ _ => unreachable!(),
+ };
+
+ // This would be nicer with
+ // https://github.com/rust-lang/rust/issues/59878 fixed.
+ children.extend(kid_children.into_vec());
+ }
+ }
+
+ debug_assert!(children.len() >= 2, "Should still have multiple kids!");
+
+ // Sort by spec order.
+ children.sort_unstable_by_key(|c| c.sort_key());
+
+ // NOTE: if the function returns true, by the docs of dedup_by,
+ // a is removed.
+ children.dedup_by(|a, b| b.try_sum_in_place(a).is_ok());
+
+ if children.len() == 1 {
+ // If only one children remains, lift it up, and carry on.
+ replace_self_with!(&mut children[0]);
+ } else {
+ // Else put our simplified children back.
+ mem::replace(children_slot, children.into_boxed_slice().into());
+ }
+ },
+ Self::Leaf(ref mut l) => {
+ l.simplify();
+ },
+ }
+ }
+
+ /// Simplifies and sorts the kids in the whole calculation subtree.
+ pub fn simplify_and_sort(&mut self) {
+ self.visit_depth_first(|node| node.simplify_and_sort_direct_children())
+ }
+
+ fn to_css_impl<W>(&self, dest: &mut CssWriter<W>, is_outermost: bool) -> fmt::Result
+ where
+ W: Write,
+ {
+ let write_closing_paren = match *self {
+ Self::MinMax(_, op) => {
+ dest.write_str(match op {
+ MinMaxOp::Max => "max(",
+ MinMaxOp::Min => "min(",
+ })?;
+ true
+ },
+ Self::Clamp { .. } => {
+ dest.write_str("clamp(")?;
+ true
+ },
+ _ => {
+ if is_outermost {
+ dest.write_str("calc(")?;
+ }
+ is_outermost
+ },
+ };
+
+ match *self {
+ Self::MinMax(ref children, _) => {
+ let mut first = true;
+ for child in &**children {
+ if !first {
+ dest.write_str(", ")?;
+ }
+ first = false;
+ child.to_css_impl(dest, false)?;
+ }
+ },
+ Self::Sum(ref children) => {
+ let mut first = true;
+ for child in &**children {
+ if !first {
+ if child.is_negative_leaf() {
+ dest.write_str(" - ")?;
+ let mut c = child.clone();
+ c.negate();
+ c.to_css_impl(dest, false)?;
+ } else {
+ dest.write_str(" + ")?;
+ child.to_css_impl(dest, false)?;
+ }
+ } else {
+ first = false;
+ child.to_css_impl(dest, false)?;
+ }
+ }
+ },
+ Self::Clamp {
+ ref min,
+ ref center,
+ ref max,
+ } => {
+ min.to_css_impl(dest, false)?;
+ dest.write_str(", ")?;
+ center.to_css_impl(dest, false)?;
+ dest.write_str(", ")?;
+ max.to_css_impl(dest, false)?;
+ },
+ Self::Leaf(ref l) => l.to_css(dest)?,
+ }
+
+ if write_closing_paren {
+ dest.write_str(")")?;
+ }
+ Ok(())
+ }
+}
+
+impl<L: CalcNodeLeaf> PartialOrd for CalcNode<L> {
+ fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
+ match (self, other) {
+ (&CalcNode::Leaf(ref one), &CalcNode::Leaf(ref other)) => one.partial_cmp(other),
+ _ => None,
+ }
+ }
+}
+
+impl<L: CalcNodeLeaf> ToCss for CalcNode<L> {
+ /// <https://drafts.csswg.org/css-values/#calc-serialize>
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+ where
+ W: Write,
+ {
+ self.to_css_impl(dest, /* is_outermost = */ true)
+ }
+}
diff --git a/components/style/values/generics/grid.rs b/components/style/values/generics/grid.rs
index 5666e2c5818..6f0f155912d 100644
--- a/components/style/values/generics/grid.rs
+++ b/components/style/values/generics/grid.rs
@@ -655,8 +655,10 @@ impl<L: ToCss, I: ToCss> ToCss for TrackList<L, I> {
pub struct LineNameList {
/// The optional `<line-name-list>`
pub names: crate::OwnedSlice<crate::OwnedSlice<CustomIdent>>,
- /// Indicates the line name that requires `auto-fill`, if in bounds.
- pub fill_idx: usize,
+ /// Indicates the starting line names that requires `auto-fill`, if in bounds.
+ pub fill_start: usize,
+ /// Indicates the number of line names in the auto-fill
+ pub fill_len: usize,
}
impl Parse for LineNameList {
@@ -666,7 +668,7 @@ impl Parse for LineNameList {
) -> Result<Self, ParseError<'i>> {
input.expect_ident_matching("subgrid")?;
let mut line_names = vec![];
- let mut fill_idx = None;
+ let mut fill_data = None;
loop {
let repeat_parse_result = input.try(|input| {
@@ -682,8 +684,7 @@ impl Parse for LineNameList {
Ok((names_list, count))
})
});
-
- if let Ok((mut names_list, count)) = repeat_parse_result {
+ if let Ok((names_list, count)) = repeat_parse_result {
match count {
// FIXME(emilio): we shouldn't expand repeat() at
// parse time for subgrid. (bug 1583429)
@@ -694,19 +695,11 @@ impl Parse for LineNameList {
.cycle()
.take(num.value() as usize * names_list.len()),
),
- RepeatCount::AutoFill if fill_idx.is_none() => {
- // `repeat(autof-fill, ..)` should have just one line name.
- // FIXME(bug 1341507) the above comment is wrong per:
- // https://drafts.csswg.org/css-grid-2/#typedef-name-repeat
- if names_list.len() != 1 {
- return Err(
- input.new_custom_error(StyleParseErrorKind::UnspecifiedError)
- );
- }
- let names = names_list.pop().unwrap();
-
- line_names.push(names);
- fill_idx = Some(line_names.len() - 1);
+ RepeatCount::AutoFill if fill_data.is_none() => {
+ let fill_idx = line_names.len();
+ let fill_len = names_list.len();
+ fill_data = Some((fill_idx, fill_len));
+ line_names.extend(names_list.into_iter());
},
_ => return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
}
@@ -721,9 +714,12 @@ impl Parse for LineNameList {
line_names.truncate(MAX_GRID_LINE as usize);
}
+ let (fill_start, fill_len) = fill_data.unwrap_or((usize::MAX, 0));
+
Ok(LineNameList {
names: line_names.into(),
- fill_idx: fill_idx.unwrap_or(usize::MAX),
+ fill_start: fill_start,
+ fill_len: fill_len,
})
}
}
@@ -734,9 +730,10 @@ impl ToCss for LineNameList {
W: Write,
{
dest.write_str("subgrid")?;
- let fill_idx = self.fill_idx;
+ let fill_start = self.fill_start;
+ let fill_len = self.fill_len;
for (i, names) in self.names.iter().enumerate() {
- if i == fill_idx {
+ if i == fill_start {
dest.write_str(" repeat(auto-fill,")?;
}
@@ -751,7 +748,7 @@ impl ToCss for LineNameList {
}
dest.write_str("]")?;
- if i == fill_idx {
+ if i == fill_start + fill_len - 1 {
dest.write_str(")")?;
}
}
diff --git a/components/style/values/generics/image.rs b/components/style/values/generics/image.rs
index a6b45bc82ad..42d541dc6f2 100644
--- a/components/style/values/generics/image.rs
+++ b/components/style/values/generics/image.rs
@@ -9,55 +9,28 @@
use crate::custom_properties;
use crate::values::serialize_atom_identifier;
use crate::Atom;
+use crate::Zero;
use servo_arc::Arc;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
+use values::generics::position::PositionComponent;
-/// An <image> | <none> (for background-image, for example).
-#[derive(
- Clone,
- Debug,
- MallocSizeOf,
- Parse,
- PartialEq,
- SpecifiedValueInfo,
- ToComputedValue,
- ToCss,
- ToResolvedValue,
- ToShmem,
-)]
-pub enum GenericImageLayer<Image> {
- /// The `none` value.
- None,
- /// The `<image>` value.
- Image(Image),
-}
-
-pub use self::GenericImageLayer as ImageLayer;
-
-impl<I> ImageLayer<I> {
- /// Returns `none`.
- #[inline]
- pub fn none() -> Self {
- ImageLayer::None
- }
-}
-
-/// An [image].
+/// An `<image> | none` value.
///
-/// [image]: https://drafts.csswg.org/css-images/#image-values
+/// https://drafts.csswg.org/css-images/#image-values
#[derive(
Clone, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem,
)]
#[repr(C, u8)]
-pub enum GenericImage<Gradient, MozImageRect, ImageUrl> {
+pub enum GenericImage<G, MozImageRect, ImageUrl> {
+ /// `none` variant.
+ None,
/// A `<url()>` image.
Url(ImageUrl),
/// A `<gradient>` image. Gradients are rather large, and not nearly as
/// common as urls, so we box them here to keep the size of this enum sane.
- Gradient(Box<Gradient>),
-
+ Gradient(Box<G>),
/// A `-moz-image-rect` image. Also fairly large and rare.
// not cfg’ed out on non-Gecko to avoid `error[E0392]: parameter `MozImageRect` is never used`
// Instead we make MozImageRect an empty enum
@@ -80,27 +53,51 @@ pub use self::GenericImage as Image;
/// <https://drafts.csswg.org/css-images/#gradients>
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)]
#[repr(C)]
-pub struct GenericGradient<
+pub enum GenericGradient<
LineDirection,
LengthPercentage,
NonNegativeLength,
NonNegativeLengthPercentage,
Position,
+ Angle,
+ AngleOrPercentage,
Color,
> {
- /// Gradients can be linear or radial.
- pub kind: GenericGradientKind<
- LineDirection,
- NonNegativeLength,
- NonNegativeLengthPercentage,
- Position,
- >,
- /// The color stops and interpolation hints.
- pub items: crate::OwnedSlice<GenericGradientItem<Color, LengthPercentage>>,
- /// True if this is a repeating gradient.
- pub repeating: bool,
- /// Compatibility mode.
- pub compat_mode: GradientCompatMode,
+ /// A linear gradient.
+ Linear {
+ /// Line direction
+ direction: LineDirection,
+ /// The color stops and interpolation hints.
+ items: crate::OwnedSlice<GenericGradientItem<Color, LengthPercentage>>,
+ /// True if this is a repeating gradient.
+ repeating: bool,
+ /// Compatibility mode.
+ compat_mode: GradientCompatMode,
+ },
+ /// A radial gradient.
+ Radial {
+ /// Shape of gradient
+ shape: GenericEndingShape<NonNegativeLength, NonNegativeLengthPercentage>,
+ /// Center of gradient
+ position: Position,
+ /// The color stops and interpolation hints.
+ items: crate::OwnedSlice<GenericGradientItem<Color, LengthPercentage>>,
+ /// True if this is a repeating gradient.
+ repeating: bool,
+ /// Compatibility mode.
+ compat_mode: GradientCompatMode,
+ },
+ /// A conic gradient.
+ Conic {
+ /// Start angle of gradient
+ angle: Angle,
+ /// Center of gradient
+ position: Position,
+ /// The color stops and interpolation hints.
+ items: crate::OwnedSlice<GenericGradientItem<Color, AngleOrPercentage>>,
+ /// True if this is a repeating gradient.
+ repeating: bool,
+ },
}
pub use self::GenericGradient as Gradient;
@@ -117,26 +114,6 @@ pub enum GradientCompatMode {
Moz,
}
-/// A gradient kind.
-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)]
-#[repr(C, u8)]
-pub enum GenericGradientKind<
- LineDirection,
- NonNegativeLength,
- NonNegativeLengthPercentage,
- Position,
-> {
- /// A linear gradient.
- Linear(LineDirection),
- /// A radial gradient.
- Radial(
- GenericEndingShape<NonNegativeLength, NonNegativeLengthPercentage>,
- Position,
- ),
-}
-
-pub use self::GenericGradientKind as GradientKind;
-
/// A radial gradient's ending shape.
#[derive(
Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem,
@@ -209,7 +186,7 @@ pub enum ShapeExtent {
Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem,
)]
#[repr(C, u8)]
-pub enum GenericGradientItem<Color, LengthPercentage> {
+pub enum GenericGradientItem<Color, T> {
/// A simple color stop, without position.
SimpleColorStop(Color),
/// A complex color stop, with a position.
@@ -217,10 +194,10 @@ pub enum GenericGradientItem<Color, LengthPercentage> {
/// The color for the stop.
color: Color,
/// The position for the stop.
- position: LengthPercentage,
+ position: T,
},
/// An interpolation hint.
- InterpolationHint(LengthPercentage),
+ InterpolationHint(T),
}
pub use self::GenericGradientItem as GradientItem;
@@ -230,17 +207,17 @@ pub use self::GenericGradientItem as GradientItem;
#[derive(
Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem,
)]
-pub struct ColorStop<Color, LengthPercentage> {
+pub struct ColorStop<Color, T> {
/// The color of this stop.
pub color: Color,
/// The position of this stop.
- pub position: Option<LengthPercentage>,
+ pub position: Option<T>,
}
-impl<Color, LengthPercentage> ColorStop<Color, LengthPercentage> {
+impl<Color, T> ColorStop<Color, T> {
/// Convert the color stop into an appropriate `GradientItem`.
#[inline]
- pub fn into_item(self) -> GradientItem<Color, LengthPercentage> {
+ pub fn into_item(self) -> GradientItem<Color, T> {
match self.position {
Some(position) => GradientItem::ComplexColorStop {
color: self.color,
@@ -261,6 +238,8 @@ pub struct PaintWorklet {
/// The arguments for the worklet.
/// TODO: store a parsed representation of the arguments.
#[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
+ #[compute(no_field_bound)]
+ #[resolve(no_field_bound)]
pub arguments: Vec<Arc<custom_properties::SpecifiedValue>>,
}
@@ -285,7 +264,7 @@ impl ToCss for PaintWorklet {
///
/// `-moz-image-rect(<uri>, top, right, bottom, left);`
#[allow(missing_docs)]
-#[css(comma, function)]
+#[css(comma, function = "-moz-image-rect")]
#[derive(
Clone,
Debug,
@@ -297,7 +276,8 @@ impl ToCss for PaintWorklet {
ToResolvedValue,
ToShmem,
)]
-pub struct MozImageRect<NumberOrPercentage, MozImageRectUrl> {
+#[repr(C)]
+pub struct GenericMozImageRect<NumberOrPercentage, MozImageRectUrl> {
pub url: MozImageRectUrl,
pub top: NumberOrPercentage,
pub right: NumberOrPercentage,
@@ -305,6 +285,8 @@ pub struct MozImageRect<NumberOrPercentage, MozImageRectUrl> {
pub left: NumberOrPercentage,
}
+pub use self::GenericMozImageRect as MozImageRect;
+
impl<G, R, U> fmt::Debug for Image<G, R, U>
where
G: ToCss,
@@ -327,6 +309,7 @@ where
W: Write,
{
match *self {
+ Image::None => dest.write_str("none"),
Image::Url(ref url) => url.to_css(dest),
Image::Gradient(ref gradient) => gradient.to_css(dest),
Image::Rect(ref rect) => rect.to_css(dest),
@@ -342,81 +325,146 @@ where
}
}
-impl<D, LP, NL, NLP, P, C> ToCss for Gradient<D, LP, NL, NLP, P, C>
+impl<D, LP, NL, NLP, P, A: Zero, AoP, C> ToCss for Gradient<D, LP, NL, NLP, P, A, AoP, C>
where
D: LineDirection,
LP: ToCss,
NL: ToCss,
NLP: ToCss,
- P: ToCss,
+ P: PositionComponent + ToCss,
+ A: ToCss,
+ AoP: ToCss,
C: ToCss,
{
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
- match self.compat_mode {
+ let (compat_mode, repeating) = match *self {
+ Gradient::Linear {
+ compat_mode,
+ repeating,
+ ..
+ } => (compat_mode, repeating),
+ Gradient::Radial {
+ compat_mode,
+ repeating,
+ ..
+ } => (compat_mode, repeating),
+ Gradient::Conic { repeating, .. } => (GradientCompatMode::Modern, repeating),
+ };
+
+ match compat_mode {
GradientCompatMode::WebKit => dest.write_str("-webkit-")?,
GradientCompatMode::Moz => dest.write_str("-moz-")?,
_ => {},
}
- if self.repeating {
+ if repeating {
dest.write_str("repeating-")?;
}
- dest.write_str(self.kind.label())?;
- dest.write_str("-gradient(")?;
- let mut skip_comma = match self.kind {
- GradientKind::Linear(ref direction) if direction.points_downwards(self.compat_mode) => {
- true
- },
- GradientKind::Linear(ref direction) => {
- direction.to_css(dest, self.compat_mode)?;
- false
+
+ match *self {
+ Gradient::Linear {
+ ref direction,
+ ref items,
+ compat_mode,
+ ..
+ } => {
+ dest.write_str("linear-gradient(")?;
+ let mut skip_comma = if !direction.points_downwards(compat_mode) {
+ direction.to_css(dest, compat_mode)?;
+ false
+ } else {
+ true
+ };
+ for item in &**items {
+ if !skip_comma {
+ dest.write_str(", ")?;
+ }
+ skip_comma = false;
+ item.to_css(dest)?;
+ }
},
- GradientKind::Radial(ref shape, ref position) => {
+ Gradient::Radial {
+ ref shape,
+ ref position,
+ ref items,
+ compat_mode,
+ ..
+ } => {
+ dest.write_str("radial-gradient(")?;
let omit_shape = match *shape {
EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::Cover)) |
EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::FarthestCorner)) => true,
_ => false,
};
- if self.compat_mode == GradientCompatMode::Modern {
+ let omit_position = position.is_center();
+ if compat_mode == GradientCompatMode::Modern {
+ if !omit_shape {
+ shape.to_css(dest)?;
+ if !omit_position {
+ dest.write_str(" ")?;
+ }
+ }
+ if !omit_position {
+ dest.write_str("at ")?;
+ position.to_css(dest)?;
+ }
+ } else {
+ if !omit_position {
+ position.to_css(dest)?;
+ if !omit_shape {
+ dest.write_str(", ")?;
+ }
+ }
if !omit_shape {
shape.to_css(dest)?;
+ }
+ }
+ let mut skip_comma = omit_shape && omit_position;
+ for item in &**items {
+ if !skip_comma {
+ dest.write_str(", ")?;
+ }
+ skip_comma = false;
+ item.to_css(dest)?;
+ }
+ },
+ Gradient::Conic {
+ ref angle,
+ ref position,
+ ref items,
+ ..
+ } => {
+ dest.write_str("conic-gradient(")?;
+ let omit_angle = angle.is_zero();
+ let omit_position = position.is_center();
+ if !omit_angle {
+ dest.write_str("from ")?;
+ angle.to_css(dest)?;
+ if !omit_position {
dest.write_str(" ")?;
}
+ }
+ if !omit_position {
dest.write_str("at ")?;
position.to_css(dest)?;
- } else {
- position.to_css(dest)?;
- if !omit_shape {
+ }
+ let mut skip_comma = omit_angle && omit_position;
+ for item in &**items {
+ if !skip_comma {
dest.write_str(", ")?;
- shape.to_css(dest)?;
}
+ skip_comma = false;
+ item.to_css(dest)?;
}
- false
},
- };
- for item in &*self.items {
- if !skip_comma {
- dest.write_str(", ")?;
- }
- skip_comma = false;
- item.to_css(dest)?;
}
dest.write_str(")")
}
}
-impl<D, L, LoP, P> GradientKind<D, L, LoP, P> {
- fn label(&self) -> &str {
- match *self {
- GradientKind::Linear(..) => "linear",
- GradientKind::Radial(..) => "radial",
- }
- }
-}
-
/// The direction of a linear gradient.
pub trait LineDirection {
/// Whether this direction points towards, and thus can be omitted.
diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs
index a97d9e1018a..6689405b2b1 100644
--- a/components/style/values/generics/mod.rs
+++ b/components/style/values/generics/mod.rs
@@ -19,6 +19,7 @@ pub mod basic_shape;
pub mod border;
#[path = "box.rs"]
pub mod box_;
+pub mod calc;
pub mod color;
pub mod column;
pub mod counters;
diff --git a/components/style/values/generics/position.rs b/components/style/values/generics/position.rs
index a3552ea3eab..00a9a219df4 100644
--- a/components/style/values/generics/position.rs
+++ b/components/style/values/generics/position.rs
@@ -31,6 +31,17 @@ pub struct GenericPosition<H, V> {
pub vertical: V,
}
+impl<H, V> PositionComponent for Position<H, V>
+where
+ H: PositionComponent,
+ V: PositionComponent,
+{
+ #[inline]
+ fn is_center(&self) -> bool {
+ self.horizontal.is_center() && self.vertical.is_center()
+ }
+}
+
pub use self::GenericPosition as Position;
impl<H, V> Position<H, V> {
@@ -43,6 +54,13 @@ impl<H, V> Position<H, V> {
}
}
+/// Implements a method that checks if the position is centered.
+pub trait PositionComponent {
+ /// Returns if the position component is 50% or center.
+ /// For pixel lengths, it always returns false.
+ fn is_center(&self) -> bool;
+}
+
/// A generic type for representing an `Auto | <position>`.
/// This is used by <offset-anchor> for now.
/// https://drafts.fxtf.org/motion-1/#offset-anchor-property
diff --git a/components/style/values/generics/svg.rs b/components/style/values/generics/svg.rs
index 82183c30564..2b04d36db78 100644
--- a/components/style/values/generics/svg.rs
+++ b/components/style/values/generics/svg.rs
@@ -152,7 +152,8 @@ impl<C: Parse, U: Parse> Parse for SVGPaint<C, U> {
ToResolvedValue,
ToShmem,
)]
-pub enum SVGLength<L> {
+#[repr(C, u8)]
+pub enum GenericSVGLength<L> {
/// `<length> | <percentage> | <number>`
LengthPercentage(L),
/// `context-value`
@@ -160,6 +161,8 @@ pub enum SVGLength<L> {
ContextValue,
}
+pub use self::GenericSVGLength as SVGLength;
+
/// Generic value for stroke-dasharray.
#[derive(
Clone,
diff --git a/components/style/values/generics/transform.rs b/components/style/values/generics/transform.rs
index b77bba40b82..ef414c1f9a0 100644
--- a/components/style/values/generics/transform.rs
+++ b/components/style/values/generics/transform.rs
@@ -354,7 +354,7 @@ impl ToAbsoluteLength for SpecifiedLengthPercentage {
match *self {
Length(len) => len.to_computed_pixel_length_without_context(),
Calc(ref calc) => calc.to_computed_pixel_length_without_context(),
- _ => Err(()),
+ Percentage(..) => Err(()),
}
}
}
diff --git a/components/style/values/generics/ui.rs b/components/style/values/generics/ui.rs
index 945f60fb5dd..6dfbb4a9c94 100644
--- a/components/style/values/generics/ui.rs
+++ b/components/style/values/generics/ui.rs
@@ -21,19 +21,22 @@ use values::specified::ui::CursorKind;
ToResolvedValue,
ToShmem,
)]
-pub struct Cursor<Image> {
+#[repr(C)]
+pub struct GenericCursor<Image> {
/// The parsed images for the cursor.
- pub images: Box<[Image]>,
+ pub images: crate::OwnedSlice<Image>,
/// The kind of the cursor [default | help | ...].
pub keyword: CursorKind,
}
+pub use self::GenericCursor as Cursor;
+
impl<Image> Cursor<Image> {
/// Set `cursor` to `auto`
#[inline]
pub fn auto() -> Self {
Self {
- images: vec![].into_boxed_slice(),
+ images: Default::default(),
keyword: CursorKind::Auto,
}
}
@@ -63,24 +66,31 @@ impl<Image: ToCss> ToCss for Cursor<Image> {
ToResolvedValue,
ToShmem,
)]
-pub struct CursorImage<ImageUrl, Number> {
+#[repr(C)]
+pub struct GenericCursorImage<ImageUrl, Number> {
/// The url to parse images from.
pub url: ImageUrl,
- /// The <x> and <y> coordinates.
- pub hotspot: Option<(Number, Number)>,
+ /// Whether the image has a hotspot or not.
+ pub has_hotspot: bool,
+ /// The x coordinate.
+ pub hotspot_x: Number,
+ /// The y coordinate.
+ pub hotspot_y: Number,
}
+pub use self::GenericCursorImage as CursorImage;
+
impl<ImageUrl: ToCss, Number: ToCss> ToCss for CursorImage<ImageUrl, Number> {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
self.url.to_css(dest)?;
- if let Some((ref x, ref y)) = self.hotspot {
+ if self.has_hotspot {
dest.write_str(" ")?;
- x.to_css(dest)?;
+ self.hotspot_x.to_css(dest)?;
dest.write_str(" ")?;
- y.to_css(dest)?;
+ self.hotspot_y.to_css(dest)?;
}
Ok(())
}
diff --git a/components/style/values/resolved/mod.rs b/components/style/values/resolved/mod.rs
index 022cb7893c6..45cc5cbd8cf 100644
--- a/components/style/values/resolved/mod.rs
+++ b/components/style/values/resolved/mod.rs
@@ -6,7 +6,9 @@
//! there are used values.
use crate::properties::ComputedValues;
+use crate::ArcSlice;
use cssparser;
+use servo_arc::Arc;
use smallvec::SmallVec;
mod color;
@@ -77,8 +79,11 @@ trivial_to_resolved_value!(computed::url::ComputedUrl);
#[cfg(feature = "gecko")]
trivial_to_resolved_value!(computed::url::ComputedImageUrl);
#[cfg(feature = "servo")]
+trivial_to_resolved_value!(html5ever::Namespace);
+#[cfg(feature = "servo")]
trivial_to_resolved_value!(html5ever::Prefix);
trivial_to_resolved_value!(computed::LengthPercentage);
+trivial_to_resolved_value!(style_traits::values::specified::AllowedNumericType);
impl<A, B> ToResolvedValue for (A, B)
where
@@ -214,3 +219,43 @@ where
Self::from(Box::from_resolved_value(resolved.into_box()))
}
}
+
+// NOTE(emilio): This is implementable more generically, but it's unlikely what
+// you want there, as it forces you to have an extra allocation.
+//
+// We could do that if needed, ideally with specialization for the case where
+// ResolvedValue = T. But we don't need it for now.
+impl<T> ToResolvedValue for Arc<T>
+where
+ T: ToResolvedValue<ResolvedValue = T>,
+{
+ type ResolvedValue = Self;
+
+ #[inline]
+ fn to_resolved_value(self, _: &Context) -> Self {
+ self
+ }
+
+ #[inline]
+ fn from_resolved_value(resolved: Self) -> Self {
+ resolved
+ }
+}
+
+// Same caveat as above applies.
+impl<T> ToResolvedValue for ArcSlice<T>
+where
+ T: ToResolvedValue<ResolvedValue = T>,
+{
+ type ResolvedValue = Self;
+
+ #[inline]
+ fn to_resolved_value(self, _: &Context) -> Self {
+ self
+ }
+
+ #[inline]
+ fn from_resolved_value(resolved: Self) -> Self {
+ resolved
+ }
+}
diff --git a/components/style/values/specified/align.rs b/components/style/values/specified/align.rs
index d0160a32ae6..10f7f3efbfc 100644
--- a/components/style/values/specified/align.rs
+++ b/components/style/values/specified/align.rs
@@ -556,7 +556,7 @@ impl SpecifiedValueInfo for AlignItems {
/// Value of the `justify-items` property
///
/// <https://drafts.csswg.org/css-align/#justify-items-property>
-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToShmem)]
+#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToResolvedValue, ToShmem)]
#[repr(C)]
pub struct JustifyItems(pub AlignFlags);
diff --git a/components/style/values/specified/basic_shape.rs b/components/style/values/specified/basic_shape.rs
index 3c32144e71c..b1782c5b294 100644
--- a/components/style/values/specified/basic_shape.rs
+++ b/components/style/values/specified/basic_shape.rs
@@ -9,8 +9,7 @@
use crate::parser::{Parse, ParserContext};
use crate::values::generics::basic_shape as generic;
-use crate::values::generics::basic_shape::{GeometryBox, Path, PolygonCoord};
-use crate::values::generics::basic_shape::{ShapeBox, ShapeSource};
+use crate::values::generics::basic_shape::{Path, PolygonCoord};
use crate::values::generics::rect::Rect;
use crate::values::specified::border::BorderRadius;
use crate::values::specified::image::Image;
@@ -25,14 +24,14 @@ use style_traits::{ParseError, StyleParseErrorKind};
/// A specified alias for FillRule.
pub use crate::values::generics::basic_shape::FillRule;
-/// A specified clipping shape.
-pub type ClippingShape = generic::ClippingShape<BasicShape, SpecifiedUrl>;
+/// A specified `clip-path` value.
+pub type ClipPath = generic::GenericClipPath<BasicShape, SpecifiedUrl>;
-/// A specified float area shape.
-pub type FloatAreaShape = generic::FloatAreaShape<BasicShape, Image>;
+/// A specified `shape-outside` value.
+pub type ShapeOutside = generic::GenericShapeOutside<BasicShape, Image>;
/// A specified basic shape.
-pub type BasicShape = generic::BasicShape<
+pub type BasicShape = generic::GenericBasicShape<
HorizontalPosition,
VerticalPosition,
LengthPercentage,
@@ -65,99 +64,90 @@ fn is_clip_path_path_enabled(_: &ParserContext) -> bool {
false
}
-impl Parse for ClippingShape {
- #[inline]
- fn parse<'i, 't>(
+/// A helper for both clip-path and shape-outside parsing of shapes.
+fn parse_shape_or_box<'i, 't, R, ReferenceBox>(
+ context: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ to_shape: impl FnOnce(Box<BasicShape>, ReferenceBox) -> R,
+ to_reference_box: impl FnOnce(ReferenceBox) -> R,
+) -> Result<R, ParseError<'i>>
+where
+ ReferenceBox: Default + Parse,
+{
+ fn parse_component<U: Parse>(
context: &ParserContext,
- input: &mut Parser<'i, 't>,
- ) -> Result<Self, ParseError<'i>> {
- if is_clip_path_path_enabled(context) {
- if let Ok(p) = input.try(|i| Path::parse(context, i)) {
- return Ok(ShapeSource::Path(p));
- }
+ input: &mut Parser,
+ component: &mut Option<U>,
+ ) -> bool {
+ if component.is_some() {
+ return false; // already parsed this component
}
- if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
- return Ok(ShapeSource::ImageOrUrl(url));
- }
+ *component = input.try(|i| U::parse(context, i)).ok();
+ component.is_some()
+ }
+
+ let mut shape = None;
+ let mut ref_box = None;
- Self::parse_common(context, input)
+ while parse_component(context, input, &mut shape) ||
+ parse_component(context, input, &mut ref_box)
+ {
+ //
}
-}
-impl Parse for FloatAreaShape {
- #[inline]
- fn parse<'i, 't>(
- context: &ParserContext,
- input: &mut Parser<'i, 't>,
- ) -> Result<Self, ParseError<'i>> {
- if let Ok(image) = input.try(|i| Image::parse_with_cors_anonymous(context, i)) {
- return Ok(ShapeSource::ImageOrUrl(image));
- }
+ if let Some(shp) = shape {
+ return Ok(to_shape(Box::new(shp), ref_box.unwrap_or_default()));
+ }
- Self::parse_common(context, input)
+ match ref_box {
+ Some(r) => Ok(to_reference_box(r)),
+ None => Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
}
}
-impl<ReferenceBox, ImageOrUrl> ShapeSource<BasicShape, ReferenceBox, ImageOrUrl>
-where
- ReferenceBox: Parse,
-{
- /// The internal parser for ShapeSource.
- fn parse_common<'i, 't>(
+impl Parse for ClipPath {
+ #[inline]
+ fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
- return Ok(ShapeSource::None);
+ return Ok(ClipPath::None);
}
- fn parse_component<U: Parse>(
- context: &ParserContext,
- input: &mut Parser,
- component: &mut Option<U>,
- ) -> bool {
- if component.is_some() {
- return false; // already parsed this component
+ if is_clip_path_path_enabled(context) {
+ if let Ok(p) = input.try(|i| Path::parse(context, i)) {
+ return Ok(ClipPath::Path(p));
}
-
- *component = input.try(|i| U::parse(context, i)).ok();
- component.is_some()
}
- let mut shape = None;
- let mut ref_box = None;
-
- while parse_component(context, input, &mut shape) ||
- parse_component(context, input, &mut ref_box)
- {
- //
- }
-
- if let Some(shp) = shape {
- return Ok(ShapeSource::Shape(Box::new(shp), ref_box));
+ if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
+ return Ok(ClipPath::Url(url));
}
- ref_box
- .map(ShapeSource::Box)
- .ok_or(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
+ parse_shape_or_box(context, input, ClipPath::Shape, ClipPath::Box)
}
}
-impl Parse for GeometryBox {
+impl Parse for ShapeOutside {
+ #[inline]
fn parse<'i, 't>(
- _context: &ParserContext,
+ context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
- if let Ok(shape_box) = input.try(ShapeBox::parse) {
- return Ok(GeometryBox::ShapeBox(shape_box));
+ // Need to parse this here so that `Image::parse_with_cors_anonymous`
+ // doesn't parse it.
+ if input.try(|i| i.expect_ident_matching("none")).is_ok() {
+ return Ok(ShapeOutside::None);
}
- try_match_ident_ignore_ascii_case! { input,
- "fill-box" => Ok(GeometryBox::FillBox),
- "stroke-box" => Ok(GeometryBox::StrokeBox),
- "view-box" => Ok(GeometryBox::ViewBox),
+ if let Ok(image) = input.try(|i| Image::parse_with_cors_anonymous(context, i)) {
+ debug_assert_ne!(image, Image::None);
+ return Ok(ShapeOutside::Image(image));
}
+
+ parse_shape_or_box(context, input, ShapeOutside::Shape, ShapeOutside::Box)
}
}
diff --git a/components/style/values/specified/border.rs b/components/style/values/specified/border.rs
index 1b1ed74d568..28be8177cf4 100644
--- a/components/style/values/specified/border.rs
+++ b/components/style/values/specified/border.rs
@@ -234,7 +234,18 @@ impl Parse for BorderSpacing {
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(
- Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem,
+ Clone,
+ Copy,
+ Debug,
+ Eq,
+ MallocSizeOf,
+ Parse,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+ ToShmem,
)]
pub enum BorderImageRepeatKeyword {
Stretch,
diff --git a/components/style/values/specified/box.rs b/components/style/values/specified/box.rs
index fa5d5a2d43a..987a0567432 100644
--- a/components/style/values/specified/box.rs
+++ b/components/style/values/specified/box.rs
@@ -104,6 +104,8 @@ pub enum DisplayInside {
#[cfg(feature = "gecko")]
MozGridLine,
#[cfg(feature = "gecko")]
+ MozStack,
+ #[cfg(feature = "gecko")]
MozDeck,
#[cfg(feature = "gecko")]
MozPopup,
@@ -227,6 +229,8 @@ impl Display {
#[cfg(feature = "gecko")]
pub const MozGridLine: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGridLine);
#[cfg(feature = "gecko")]
+ pub const MozStack: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozStack);
+ #[cfg(feature = "gecko")]
pub const MozDeck: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozDeck);
#[cfg(feature = "gecko")]
pub const MozPopup: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozPopup);
@@ -616,6 +620,8 @@ impl Parse for Display {
#[cfg(feature = "gecko")]
"-moz-grid-line" if moz_display_values_enabled(context) => Display::MozGridLine,
#[cfg(feature = "gecko")]
+ "-moz-stack" if moz_display_values_enabled(context) => Display::MozStack,
+ #[cfg(feature = "gecko")]
"-moz-deck" if moz_display_values_enabled(context) => Display::MozDeck,
#[cfg(feature = "gecko")]
"-moz-popup" if moz_display_values_enabled(context) => Display::MozPopup,
@@ -1595,7 +1601,7 @@ pub enum Appearance {
Meterchunk,
/// The "arrowed" part of the dropdown button that open up a dropdown list.
#[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
- MozMenulistButton,
+ MozMenulistArrowButton,
/// For HTML's <input type=number>
NumberInput,
/// A horizontal progress bar.
@@ -1624,7 +1630,7 @@ pub enum Appearance {
RadioLabel,
/// nsRangeFrame and its subparts
Range,
- RangeThumb,
+ RangeThumb, // FIXME: This should not be exposed to content.
/// The resizer background area in a status bar for the resizer widget in
/// the corner of a window.
#[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
@@ -1850,6 +1856,14 @@ pub enum Appearance {
Count,
}
+impl Appearance {
+ /// Returns whether we're the `none` value.
+ #[inline]
+ pub fn is_none(self) -> bool {
+ self == Appearance::None
+ }
+}
+
/// A kind of break between two boxes.
///
/// https://drafts.csswg.org/css-break/#break-between
diff --git a/components/style/values/specified/calc.rs b/components/style/values/specified/calc.rs
index 9736491adce..9947fc7a8cc 100644
--- a/components/style/values/specified/calc.rs
+++ b/components/style/values/specified/calc.rs
@@ -7,15 +7,16 @@
//! [calc]: https://drafts.csswg.org/css-values/#calc-notation
use crate::parser::ParserContext;
-use crate::values::computed;
+use crate::values::generics::calc as generic;
+use crate::values::generics::calc::{MinMaxOp, SortKey};
use crate::values::specified::length::ViewportPercentageLength;
use crate::values::specified::length::{AbsoluteLength, FontRelativeLength, NoCalcLength};
use crate::values::specified::{self, Angle, Time};
use crate::values::{CSSFloat, CSSInteger};
use cssparser::{AngleOrNumber, CowRcStr, NumberOrPercentage, Parser, Token};
use smallvec::SmallVec;
+use std::cmp;
use std::fmt::{self, Write};
-use std::{cmp, mem};
use style_traits::values::specified::AllowedNumericType;
use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss};
@@ -32,40 +33,9 @@ pub enum MathFunction {
Clamp,
}
-/// This determines the order in which we serialize members of a calc()
-/// sum.
-///
-/// See https://drafts.csswg.org/css-values-4/#sort-a-calculations-children
-#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
-enum SortKey {
- Number,
- Percentage,
- Ch,
- Deg,
- Em,
- Ex,
- Px,
- Rem,
- Sec,
- Vh,
- Vmax,
- Vmin,
- Vw,
- Other,
-}
-
-/// Whether we're a `min` or `max` function.
-#[derive(Clone, Copy, Debug, PartialEq)]
-pub enum MinMaxOp {
- /// `min()`
- Min,
- /// `max()`
- Max,
-}
-
-/// A node inside a `Calc` expression's AST.
-#[derive(Clone, Debug, PartialEq)]
-pub enum CalcNode {
+/// A leaf node inside a `Calc` expression's AST.
+#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
+pub enum Leaf {
/// `<length>`
Length(NoCalcLength),
/// `<angle>`
@@ -76,27 +46,28 @@ pub enum CalcNode {
Percentage(CSSFloat),
/// `<number>`
Number(CSSFloat),
- /// An expression of the form `x + y + ...`. Subtraction is represented by
- /// the negated expression of the right hand side.
- Sum(Box<[CalcNode]>),
- /// A `min()` / `max()` function.
- MinMax(Box<[CalcNode]>, MinMaxOp),
- /// A `clamp()` function.
- Clamp {
- /// The minimum value.
- min: Box<CalcNode>,
- /// The central value.
- center: Box<CalcNode>,
- /// The maximum value.
- max: Box<CalcNode>,
- },
+}
+
+impl ToCss for Leaf {
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+ where
+ W: Write,
+ {
+ match *self {
+ Self::Length(ref l) => l.to_css(dest),
+ Self::Number(ref n) => n.to_css(dest),
+ Self::Percentage(p) => crate::values::serialize_percentage(p, dest),
+ Self::Angle(ref a) => a.to_css(dest),
+ Self::Time(ref t) => t.to_css(dest),
+ }
+ }
}
/// An expected unit we intend to parse within a `calc()` expression.
///
/// This is used as a hint for the parser to fast-reject invalid expressions.
#[derive(Clone, Copy, PartialEq)]
-pub enum CalcUnit {
+enum CalcUnit {
/// `<number>`
Number,
/// `<length>`
@@ -117,178 +88,50 @@ pub enum CalcUnit {
/// relative lengths, and to_computed_pixel_length_without_context() handles
/// this case. Therefore, if you want to add a new field, please make sure this
/// function work properly.
-#[derive(Clone, Copy, Debug, Default, MallocSizeOf, PartialEq, ToShmem)]
+#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
#[allow(missing_docs)]
pub struct CalcLengthPercentage {
+ #[css(skip)]
pub clamping_mode: AllowedNumericType,
- pub absolute: Option<AbsoluteLength>,
- pub vw: Option<CSSFloat>,
- pub vh: Option<CSSFloat>,
- pub vmin: Option<CSSFloat>,
- pub vmax: Option<CSSFloat>,
- pub em: Option<CSSFloat>,
- pub ex: Option<CSSFloat>,
- pub ch: Option<CSSFloat>,
- pub rem: Option<CSSFloat>,
- pub percentage: Option<computed::Percentage>,
-}
-
-impl ToCss for CalcLengthPercentage {
- /// <https://drafts.csswg.org/css-values/#calc-serialize>
- ///
- /// FIXME(emilio): Should this simplify away zeros?
- #[allow(unused_assignments)]
- fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
- where
- W: Write,
- {
- use num_traits::Zero;
-
- let mut first_value = true;
- macro_rules! first_value_check {
- ($val:expr) => {
- if !first_value {
- dest.write_str(if $val < Zero::zero() { " - " } else { " + " })?;
- } else if $val < Zero::zero() {
- dest.write_str("-")?;
- }
- first_value = false;
- };
- }
-
- macro_rules! serialize {
- ( $( $val:ident ),* ) => {
- $(
- if let Some(val) = self.$val {
- first_value_check!(val);
- val.abs().to_css(dest)?;
- dest.write_str(stringify!($val))?;
- }
- )*
- };
- }
-
- macro_rules! serialize_abs {
- ( $( $val:ident ),+ ) => {
- $(
- if let Some(AbsoluteLength::$val(v)) = self.absolute {
- first_value_check!(v);
- AbsoluteLength::$val(v.abs()).to_css(dest)?;
- }
- )+
- };
- }
-
- dest.write_str("calc(")?;
-
- // NOTE(emilio): Percentages first because of web-compat problems, see:
- // https://github.com/w3c/csswg-drafts/issues/1731
- if let Some(val) = self.percentage {
- first_value_check!(val.0);
- val.abs().to_css(dest)?;
- }
-
- // NOTE(emilio): The order here it's very intentional, and alphabetic
- // per the spec linked above.
- serialize!(ch);
- serialize_abs!(Cm);
- serialize!(em, ex);
- serialize_abs!(In, Mm, Pc, Pt, Px, Q);
- serialize!(rem, vh, vmax, vmin, vw);
-
- dest.write_str(")")
- }
+ pub node: CalcNode,
}
impl SpecifiedValueInfo for CalcLengthPercentage {}
-macro_rules! impl_generic_to_type {
- ($self:ident, $self_variant:ident, $to_self:ident, $to_float:ident, $from_float:path) => {{
- if let Self::$self_variant(ref v) = *$self {
- return Ok(v.clone());
- }
-
- Ok(match *$self {
- Self::Sum(ref expressions) => {
- let mut sum = 0.;
- for sub in &**expressions {
- sum += sub.$to_self()?.$to_float();
- }
- $from_float(sum)
- },
- Self::Clamp {
- ref min,
- ref center,
- ref max,
- } => {
- let min = min.$to_self()?;
- let center = center.$to_self()?;
- let max = max.$to_self()?;
-
- // Equivalent to cmp::max(min, cmp::min(center, max))
- //
- // But preserving units when appropriate.
- let center_float = center.$to_float();
- let min_float = min.$to_float();
- let max_float = max.$to_float();
-
- let mut result = center;
- let mut result_float = center_float;
-
- if result_float > max_float {
- result = max;
- result_float = max_float;
- }
+impl PartialOrd for Leaf {
+ fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
+ use self::Leaf::*;
- if result_float < min_float {
- min
- } else {
- result
- }
- },
- Self::MinMax(ref nodes, op) => {
- let mut result = nodes[0].$to_self()?;
- let mut result_float = result.$to_float();
- for node in nodes.iter().skip(1) {
- let candidate = node.$to_self()?;
- let candidate_float = candidate.$to_float();
- let candidate_wins = match op {
- MinMaxOp::Min => candidate_float < result_float,
- MinMaxOp::Max => candidate_float > result_float,
- };
- if candidate_wins {
- result = candidate;
- result_float = candidate_float;
- }
- }
- result
- },
- Self::Length(..) |
- Self::Angle(..) |
- Self::Time(..) |
- Self::Percentage(..) |
- Self::Number(..) => return Err(()),
- })
- }};
-}
+ if std::mem::discriminant(self) != std::mem::discriminant(other) {
+ return None;
+ }
-impl PartialOrd for CalcNode {
- fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
- use self::CalcNode::*;
match (self, other) {
(&Length(ref one), &Length(ref other)) => one.partial_cmp(other),
(&Percentage(ref one), &Percentage(ref other)) => one.partial_cmp(other),
(&Angle(ref one), &Angle(ref other)) => one.degrees().partial_cmp(&other.degrees()),
(&Time(ref one), &Time(ref other)) => one.seconds().partial_cmp(&other.seconds()),
(&Number(ref one), &Number(ref other)) => one.partial_cmp(other),
- _ => None,
+ _ => {
+ match *self {
+ Length(..) | Percentage(..) | Angle(..) | Time(..) | Number(..) => {},
+ }
+ unsafe {
+ debug_unreachable!("Forgot a branch?");
+ }
+ },
}
}
}
-impl CalcNode {
- fn negate(&mut self) {
- self.mul_by(-1.);
+impl generic::CalcNodeLeaf for Leaf {
+ fn is_negative(&self) -> bool {
+ match *self {
+ Self::Length(ref l) => l.is_negative(),
+ Self::Percentage(n) | Self::Number(n) => n < 0.,
+ Self::Angle(ref a) => a.degrees() < 0.,
+ Self::Time(ref t) => t.seconds() < 0.,
+ }
}
fn mul_by(&mut self, scalar: f32) {
@@ -310,44 +153,10 @@ impl CalcNode {
Self::Percentage(ref mut p) => {
*p *= scalar;
},
- // Multiplication is distributive across this.
- Self::Sum(ref mut children) => {
- for node in &mut **children {
- node.mul_by(scalar);
- }
- },
- // This one is a bit trickier.
- Self::MinMax(ref mut children, ref mut op) => {
- for node in &mut **children {
- node.mul_by(scalar);
- }
-
- // For negatives we need to invert the operation.
- if scalar < 0. {
- *op = match *op {
- MinMaxOp::Min => MinMaxOp::Max,
- MinMaxOp::Max => MinMaxOp::Min,
- }
- }
- },
- // Multiplication is distributive across these.
- Self::Clamp {
- ref mut min,
- ref mut center,
- ref mut max,
- } => {
- min.mul_by(scalar);
- center.mul_by(scalar);
- max.mul_by(scalar);
- // For negatives we need to swap min / max.
- if scalar < 0. {
- mem::swap(min, max);
- }
- },
}
}
- fn calc_node_sort_key(&self) -> SortKey {
+ fn sort_key(&self) -> SortKey {
match *self {
Self::Number(..) => SortKey::Number,
Self::Percentage(..) => SortKey::Percentage,
@@ -369,7 +178,12 @@ impl CalcNode {
},
NoCalcLength::ServoCharacterWidth(..) => unreachable!(),
},
- Self::Sum(..) | Self::MinMax(..) | Self::Clamp { .. } => SortKey::Other,
+ }
+ }
+
+ fn simplify(&mut self) {
+ if let Self::Length(NoCalcLength::Absolute(ref mut abs)) = *self {
+ *abs = AbsoluteLength::Px(abs.to_px());
}
}
@@ -378,7 +192,11 @@ impl CalcNode {
/// Only handles leaf nodes, it's the caller's responsibility to simplify
/// them before calling this if needed.
fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()> {
- use self::CalcNode::*;
+ use self::Leaf::*;
+
+ if std::mem::discriminant(self) != std::mem::discriminant(other) {
+ return Err(());
+ }
match (self, other) {
(&mut Number(ref mut one), &Number(ref other)) |
@@ -394,170 +212,24 @@ impl CalcNode {
(&mut Length(ref mut one), &Length(ref other)) => {
*one = one.try_sum(other)?;
},
- _ => return Err(()),
- }
-
- Ok(())
- }
-
- /// Simplifies and sorts the calculation. This is only needed if it's going
- /// to be preserved after parsing (so, for `<length-percentage>`). Otherwise
- /// we can just evaluate it and we'll come up with a simplified value
- /// anyways.
- fn simplify_and_sort_children(&mut self) {
- macro_rules! replace_self_with {
- ($slot:expr) => {{
- let result = mem::replace($slot, Self::Number(0.));
- mem::replace(self, result);
- }};
- }
- match *self {
- Self::Clamp {
- ref mut min,
- ref mut center,
- ref mut max,
- } => {
- min.simplify_and_sort_children();
- center.simplify_and_sort_children();
- max.simplify_and_sort_children();
-
- // NOTE: clamp() is max(min, min(center, max))
- let min_cmp_center = match min.partial_cmp(&center) {
- Some(o) => o,
- None => return,
- };
-
- // So if we can prove that min is more than center, then we won,
- // as that's what we should always return.
- if matches!(min_cmp_center, cmp::Ordering::Greater) {
- return replace_self_with!(&mut **min);
- }
-
- // Otherwise try with max.
- let max_cmp_center = match max.partial_cmp(&center) {
- Some(o) => o,
- None => return,
- };
-
- if matches!(max_cmp_center, cmp::Ordering::Less) {
- // max is less than center, so we need to return effectively
- // `max(min, max)`.
- let max_cmp_min = match max.partial_cmp(&min) {
- Some(o) => o,
- None => {
- debug_assert!(
- false,
- "We compared center with min and max, how are \
- min / max not comparable with each other?"
- );
- return;
- },
- };
-
- if matches!(max_cmp_min, cmp::Ordering::Less) {
- return replace_self_with!(&mut **min);
- }
-
- return replace_self_with!(&mut **max);
- }
-
- // Otherwise we're the center node.
- return replace_self_with!(&mut **center);
- },
- Self::MinMax(ref mut children, op) => {
- for child in &mut **children {
- child.simplify_and_sort_children();
- }
-
- let winning_order = match op {
- MinMaxOp::Min => cmp::Ordering::Less,
- MinMaxOp::Max => cmp::Ordering::Greater,
- };
-
- let mut result = 0;
- for i in 1..children.len() {
- let o = match children[i].partial_cmp(&children[result]) {
- // We can't compare all the children, so we can't
- // know which one will actually win. Bail out and
- // keep ourselves as a min / max function.
- //
- // TODO: Maybe we could simplify compatible children,
- // see https://github.com/w3c/csswg-drafts/issues/4756
- None => return,
- Some(o) => o,
- };
-
- if o == winning_order {
- result = i;
- }
- }
-
- replace_self_with!(&mut children[result]);
- },
- Self::Sum(ref mut children_slot) => {
- let mut sums_to_merge = SmallVec::<[_; 3]>::new();
- let mut extra_kids = 0;
- for (i, child) in children_slot.iter_mut().enumerate() {
- child.simplify_and_sort_children();
- if let Self::Sum(ref mut children) = *child {
- extra_kids += children.len();
- sums_to_merge.push(i);
- }
- }
-
- // If we only have one kid, we've already simplified it, and it
- // doesn't really matter whether it's a sum already or not, so
- // lift it up and continue.
- if children_slot.len() == 1 {
- return replace_self_with!(&mut children_slot[0]);
- }
-
- let mut children = mem::replace(children_slot, Box::new([])).into_vec();
-
- if !sums_to_merge.is_empty() {
- children.reserve(extra_kids - sums_to_merge.len());
- // Merge all our nested sums, in reverse order so that the
- // list indices are not invalidated.
- for i in sums_to_merge.drain(..).rev() {
- let kid_children = match children.swap_remove(i) {
- Self::Sum(c) => c,
- _ => unreachable!(),
- };
-
- // This would be nicer with
- // https://github.com/rust-lang/rust/issues/59878 fixed.
- children.extend(kid_children.into_vec());
- }
- }
-
- debug_assert!(children.len() >= 2, "Should still have multiple kids!");
-
- // Sort by spec order.
- children.sort_unstable_by_key(|c| c.calc_node_sort_key());
-
- // NOTE: if the function returns true, by the docs of dedup_by,
- // a is removed.
- children.dedup_by(|a, b| b.try_sum_in_place(a).is_ok());
-
- if children.len() == 1 {
- // If only one children remains, lift it up, and carry on.
- replace_self_with!(&mut children[0]);
- } else {
- // Else put our simplified children back.
- mem::replace(children_slot, children.into_boxed_slice());
+ _ => {
+ match *other {
+ Number(..) | Percentage(..) | Angle(..) | Time(..) | Length(..) => {},
}
- },
- Self::Length(ref mut len) => {
- if let NoCalcLength::Absolute(ref mut absolute_length) = *len {
- *absolute_length = AbsoluteLength::Px(absolute_length.to_px());
+ unsafe {
+ debug_unreachable!();
}
},
- Self::Percentage(..) | Self::Angle(..) | Self::Time(..) | Self::Number(..) => {
- // These are leaves already, nothing to do.
- },
}
+
+ Ok(())
}
+}
+
+/// A calc node representation for specified values.
+pub type CalcNode = generic::GenericCalcNode<Leaf>;
+impl CalcNode {
/// Tries to parse a single element in the expression, that is, a
/// `<length>`, `<angle>`, `<time>`, `<percentage>`, according to
/// `expected_unit`.
@@ -571,7 +243,7 @@ impl CalcNode {
) -> Result<Self, ParseError<'i>> {
let location = input.current_source_location();
match (input.next()?, expected_unit) {
- (&Token::Number { value, .. }, _) => Ok(CalcNode::Number(value)),
+ (&Token::Number { value, .. }, _) => Ok(CalcNode::Leaf(Leaf::Number(value))),
(
&Token::Dimension {
value, ref unit, ..
@@ -583,18 +255,22 @@ impl CalcNode {
value, ref unit, ..
},
CalcUnit::LengthPercentage,
- ) => NoCalcLength::parse_dimension(context, value, unit)
- .map(CalcNode::Length)
- .map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
+ ) => match NoCalcLength::parse_dimension(context, value, unit) {
+ Ok(l) => Ok(CalcNode::Leaf(Leaf::Length(l))),
+ Err(()) => Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
+ },
(
&Token::Dimension {
value, ref unit, ..
},
CalcUnit::Angle,
) => {
- Angle::parse_dimension(value, unit, /* from_calc = */ true)
- .map(CalcNode::Angle)
- .map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
+ match Angle::parse_dimension(value, unit, /* from_calc = */ true) {
+ Ok(a) => Ok(CalcNode::Leaf(Leaf::Angle(a))),
+ Err(()) => {
+ Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
+ },
+ }
},
(
&Token::Dimension {
@@ -602,13 +278,16 @@ impl CalcNode {
},
CalcUnit::Time,
) => {
- Time::parse_dimension(value, unit, /* from_calc = */ true)
- .map(CalcNode::Time)
- .map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
+ match Time::parse_dimension(value, unit, /* from_calc = */ true) {
+ Ok(t) => Ok(CalcNode::Leaf(Leaf::Time(t))),
+ Err(()) => {
+ Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
+ },
+ }
},
(&Token::Percentage { unit_value, .. }, CalcUnit::LengthPercentage) |
(&Token::Percentage { unit_value, .. }, CalcUnit::Percentage) => {
- Ok(CalcNode::Percentage(unit_value))
+ Ok(CalcNode::Leaf(Leaf::Percentage(unit_value)))
},
(&Token::ParenthesisBlock, _) => input.parse_nested_block(|input| {
CalcNode::parse_argument(context, input, expected_unit)
@@ -654,11 +333,9 @@ impl CalcNode {
//
// Consider adding an API to cssparser to specify the
// initial vector capacity?
- let arguments = input
- .parse_comma_separated(|input| {
- Self::parse_argument(context, input, expected_unit)
- })?
- .into_boxed_slice();
+ let arguments = input.parse_comma_separated(|input| {
+ Self::parse_argument(context, input, expected_unit)
+ })?;
let op = match function {
MathFunction::Min => MinMaxOp::Min,
@@ -666,7 +343,7 @@ impl CalcNode {
_ => unreachable!(),
};
- Ok(Self::MinMax(arguments, op))
+ Ok(Self::MinMax(arguments.into(), op))
},
}
})
@@ -712,7 +389,7 @@ impl CalcNode {
Ok(if sum.len() == 1 {
sum.drain(..).next().unwrap()
} else {
- Self::Sum(sum.into_boxed_slice())
+ Self::Sum(sum.into_boxed_slice().into())
})
}
@@ -773,106 +450,64 @@ impl CalcNode {
Ok(node)
}
- /// Tries to simplify this expression into a `<length>` or `<percentage`>
+ /// Tries to simplify this expression into a `<length>` or `<percentage>`
/// value.
- fn to_length_or_percentage(
- &mut self,
+ fn into_length_or_percentage(
+ mut self,
clamping_mode: AllowedNumericType,
) -> Result<CalcLengthPercentage, ()> {
- let mut ret = CalcLengthPercentage {
- clamping_mode,
- ..Default::default()
- };
- self.simplify_and_sort_children();
- self.add_length_or_percentage_to(&mut ret, 1.0)?;
- Ok(ret)
- }
+ // Keep track of whether there's any invalid member of the calculation,
+ // so as to reject the calculation properly at parse-time.
+ let mut any_invalid = false;
+ self.visit_depth_first(|node| {
+ if let CalcNode::Leaf(ref l) = *node {
+ any_invalid |= !matches!(*l, Leaf::Percentage(..) | Leaf::Length(..));
+ }
+ node.simplify_and_sort_direct_children();
+ });
- /// Puts this `<length>` or `<percentage>` into `ret`, or error.
- ///
- /// `factor` is the sign or multiplicative factor to account for the sign
- /// (this allows adding and substracting into the return value).
- fn add_length_or_percentage_to(
- &self,
- ret: &mut CalcLengthPercentage,
- factor: CSSFloat,
- ) -> Result<(), ()> {
- match *self {
- CalcNode::Percentage(pct) => {
- ret.percentage = Some(computed::Percentage(
- ret.percentage.map_or(0., |p| p.0) + pct * factor,
- ));
- },
- CalcNode::Length(ref l) => match *l {
- NoCalcLength::Absolute(abs) => {
- ret.absolute = Some(match ret.absolute {
- Some(value) => value + abs * factor,
- None => abs * factor,
- });
- },
- NoCalcLength::FontRelative(rel) => match rel {
- FontRelativeLength::Em(em) => {
- ret.em = Some(ret.em.unwrap_or(0.) + em * factor);
- },
- FontRelativeLength::Ex(ex) => {
- ret.ex = Some(ret.ex.unwrap_or(0.) + ex * factor);
- },
- FontRelativeLength::Ch(ch) => {
- ret.ch = Some(ret.ch.unwrap_or(0.) + ch * factor);
- },
- FontRelativeLength::Rem(rem) => {
- ret.rem = Some(ret.rem.unwrap_or(0.) + rem * factor);
- },
- },
- NoCalcLength::ViewportPercentage(rel) => match rel {
- ViewportPercentageLength::Vh(vh) => {
- ret.vh = Some(ret.vh.unwrap_or(0.) + vh * factor)
- },
- ViewportPercentageLength::Vw(vw) => {
- ret.vw = Some(ret.vw.unwrap_or(0.) + vw * factor)
- },
- ViewportPercentageLength::Vmax(vmax) => {
- ret.vmax = Some(ret.vmax.unwrap_or(0.) + vmax * factor)
- },
- ViewportPercentageLength::Vmin(vmin) => {
- ret.vmin = Some(ret.vmin.unwrap_or(0.) + vmin * factor)
- },
- },
- NoCalcLength::ServoCharacterWidth(..) => unreachable!(),
- },
- CalcNode::Sum(ref children) => {
- for child in &**children {
- child.add_length_or_percentage_to(ret, factor)?;
- }
- },
- CalcNode::MinMax(..) | CalcNode::Clamp { .. } => {
- // FIXME(emilio): Implement min/max/clamp for length-percentage.
- return Err(());
- },
- CalcNode::Angle(..) | CalcNode::Time(..) | CalcNode::Number(..) => return Err(()),
+ if any_invalid {
+ return Err(());
}
- Ok(())
+ Ok(CalcLengthPercentage {
+ clamping_mode,
+ node: self,
+ })
}
/// Tries to simplify this expression into a `<time>` value.
fn to_time(&self) -> Result<Time, ()> {
- impl_generic_to_type!(self, Time, to_time, seconds, Time::from_calc)
+ let seconds = self.resolve(|leaf| match *leaf {
+ Leaf::Time(ref t) => Ok(t.seconds()),
+ _ => Err(()),
+ })?;
+ Ok(Time::from_calc(seconds))
}
/// Tries to simplify this expression into an `Angle` value.
fn to_angle(&self) -> Result<Angle, ()> {
- impl_generic_to_type!(self, Angle, to_angle, degrees, Angle::from_calc)
+ let degrees = self.resolve(|leaf| match *leaf {
+ Leaf::Angle(ref angle) => Ok(angle.degrees()),
+ _ => Err(()),
+ })?;
+ Ok(Angle::from_calc(degrees))
}
/// Tries to simplify this expression into a `<number>` value.
fn to_number(&self) -> Result<CSSFloat, ()> {
- impl_generic_to_type!(self, Number, to_number, clone, From::from)
+ self.resolve(|leaf| match *leaf {
+ Leaf::Number(n) => Ok(n),
+ _ => Err(()),
+ })
}
/// Tries to simplify this expression into a `<percentage>` value.
fn to_percentage(&self) -> Result<CSSFloat, ()> {
- impl_generic_to_type!(self, Percentage, to_percentage, clone, From::from)
+ self.resolve(|leaf| match *leaf {
+ Leaf::Percentage(p) => Ok(p),
+ _ => Err(()),
+ })
}
/// Given a function name, and the location from where the token came from,
@@ -926,7 +561,7 @@ impl CalcNode {
function: MathFunction,
) -> Result<CalcLengthPercentage, ParseError<'i>> {
Self::parse(context, input, function, CalcUnit::LengthPercentage)?
- .to_length_or_percentage(clamping_mode)
+ .into_length_or_percentage(clamping_mode)
.map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
@@ -949,7 +584,7 @@ impl CalcNode {
function: MathFunction,
) -> Result<CalcLengthPercentage, ParseError<'i>> {
Self::parse(context, input, function, CalcUnit::Length)?
- .to_length_or_percentage(clamping_mode)
+ .into_length_or_percentage(clamping_mode)
.map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
diff --git a/components/style/values/specified/color.rs b/components/style/values/specified/color.rs
index be969f27cd4..e697f2523c9 100644
--- a/components/style/values/specified/color.rs
+++ b/components/style/values/specified/color.rs
@@ -140,8 +140,10 @@ pub enum SystemColor {
Windowframe,
Windowtext,
MozButtondefault,
- MozDefaultColor,
- MozDefaultBackgroundColor,
+ #[parse(aliases = "-moz-default-color")]
+ Canvastext,
+ #[parse(aliases = "-moz-default-background-color")]
+ Canvas,
MozDialog,
MozDialogtext,
/// Used to highlight valid regions to drop something onto.
@@ -230,9 +232,12 @@ pub enum SystemColor {
/// colors.
MozNativehyperlinktext,
- MozHyperlinktext,
- MozActivehyperlinktext,
- MozVisitedhyperlinktext,
+ #[parse(aliases = "-moz-hyperlinktext")]
+ Linktext,
+ #[parse(aliases = "-moz-activehyperlinktext")]
+ Activetext,
+ #[parse(aliases = "-moz-visitedhyperlinktext")]
+ Visitedtext,
/// Combobox widgets
MozComboboxtext,
@@ -253,11 +258,11 @@ impl SystemColor {
let prefs = cx.device().pref_sheet_prefs();
convert_nscolor_to_computedcolor(match *self {
- SystemColor::MozDefaultColor => prefs.mDefaultColor,
- SystemColor::MozDefaultBackgroundColor => prefs.mDefaultBackgroundColor,
- SystemColor::MozHyperlinktext => prefs.mLinkColor,
- SystemColor::MozActivehyperlinktext => prefs.mActiveLinkColor,
- SystemColor::MozVisitedhyperlinktext => prefs.mVisitedLinkColor,
+ SystemColor::Canvastext => prefs.mDefaultColor,
+ SystemColor::Canvas => prefs.mDefaultBackgroundColor,
+ SystemColor::Linktext => prefs.mLinkColor,
+ SystemColor::Activetext => prefs.mActiveLinkColor,
+ SystemColor::Visitedtext => prefs.mVisitedLinkColor,
_ => unsafe {
bindings::Gecko_GetLookAndFeelSystemColor(*self as i32, cx.device().document())
diff --git a/components/style/values/specified/font.rs b/components/style/values/specified/font.rs
index 94c28d068f9..dd9f9d3b86d 100644
--- a/components/style/values/specified/font.rs
+++ b/components/style/values/specified/font.rs
@@ -492,7 +492,9 @@ impl ToComputedValue for FontStretch {
SpecifiedValueInfo,
ToAnimatedValue,
ToAnimatedZero,
+ ToComputedValue,
ToCss,
+ ToResolvedValue,
ToShmem,
)]
#[allow(missing_docs)]
@@ -534,7 +536,9 @@ impl Default for KeywordSize {
PartialEq,
ToAnimatedValue,
ToAnimatedZero,
+ ToComputedValue,
ToCss,
+ ToResolvedValue,
ToShmem,
)]
/// Additional information for keyword-derived font sizes.
@@ -567,7 +571,7 @@ impl KeywordInfo {
/// Computes the final size for this font-size keyword, accounting for
/// text-zoom.
fn to_computed_value(&self, context: &Context) -> CSSPixelLength {
- let base = context.maybe_zoom_text(self.kw.to_computed_value(context).0);
+ let base = context.maybe_zoom_text(self.kw.to_length(context).0);
base * self.factor + context.maybe_zoom_text(self.offset)
}
@@ -760,11 +764,10 @@ const LARGER_FONT_SIZE_RATIO: f32 = 1.2;
/// The default font size.
pub const FONT_MEDIUM_PX: i32 = 16;
-#[cfg(feature = "servo")]
-impl ToComputedValue for KeywordSize {
- type ComputedValue = NonNegativeLength;
+impl KeywordSize {
#[inline]
- fn to_computed_value(&self, _: &Context) -> NonNegativeLength {
+ #[cfg(feature = "servo")]
+ fn to_length(&self, _: &Context) -> NonNegativeLength {
let medium = Length::new(FONT_MEDIUM_PX as f32);
// https://drafts.csswg.org/css-fonts-3/#font-size-prop
NonNegative(match *self {
@@ -779,17 +782,9 @@ impl ToComputedValue for KeywordSize {
})
}
+ #[cfg(feature = "gecko")]
#[inline]
- fn from_computed_value(_: &NonNegativeLength) -> Self {
- unreachable!()
- }
-}
-
-#[cfg(feature = "gecko")]
-impl ToComputedValue for KeywordSize {
- type ComputedValue = NonNegativeLength;
- #[inline]
- fn to_computed_value(&self, cx: &Context) -> NonNegativeLength {
+ fn to_length(&self, cx: &Context) -> NonNegativeLength {
use crate::context::QuirksMode;
// The tables in this function are originally from
@@ -857,11 +852,6 @@ impl ToComputedValue for KeywordSize {
base_size * FONT_SIZE_FACTORS[html_size] as f32 / 100.0
})
}
-
- #[inline]
- fn from_computed_value(_: &NonNegativeLength) -> Self {
- unreachable!()
- }
}
impl FontSize {
diff --git a/components/style/values/specified/grid.rs b/components/style/values/specified/grid.rs
index 4830aea24d6..54d31d5826d 100644
--- a/components/style/values/specified/grid.rs
+++ b/components/style/values/specified/grid.rs
@@ -185,16 +185,6 @@ impl TrackRepeat<LengthPercentage, Integer> {
values.push(track_size);
names.push(current_names);
- if is_auto {
- // FIXME: In the older version of the spec
- // (https://www.w3.org/TR/2015/WD-css-grid-1-20150917/#typedef-auto-repeat),
- // if the repeat type is `<auto-repeat>` we shouldn't try to parse more than
- // one `TrackSize`. But in current version of the spec, this is deprecated
- // but we are adding this for gecko parity. We should remove this when
- // gecko implements new spec.
- names.push(input.try(parse_line_names).unwrap_or_default());
- break;
- }
} else {
if values.is_empty() {
// expecting at least one <track-size>
diff --git a/components/style/values/specified/image.rs b/components/style/values/specified/image.rs
index 14a2a9ad9c8..59250c45a6f 100644
--- a/components/style/values/specified/image.rs
+++ b/components/style/values/specified/image.rs
@@ -19,7 +19,8 @@ use crate::values::specified::position::{HorizontalPositionKeyword, VerticalPosi
use crate::values::specified::position::{Position, PositionComponent, Side};
use crate::values::specified::url::SpecifiedImageUrl;
use crate::values::specified::{
- Angle, Color, Length, LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage,
+ Angle, AngleOrPercentage, Color, Length, LengthPercentage, NonNegativeLength,
+ NonNegativeLengthPercentage,
};
use crate::values::specified::{Number, NumberOrPercentage, Percentage};
use crate::Atom;
@@ -32,24 +33,6 @@ use std::fmt::{self, Write};
use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError};
use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
-/// A specified image layer.
-pub type ImageLayer = generic::GenericImageLayer<Image>;
-
-impl ImageLayer {
- /// This is a specialization of Either with an alternative parse
- /// method to provide anonymous CORS headers for the Image url fetch.
- pub fn parse_with_cors_anonymous<'i, 't>(
- context: &ParserContext,
- input: &mut Parser<'i, 't>,
- ) -> Result<Self, ParseError<'i>> {
- if let Ok(v) = input.try(|i| Image::parse_with_cors_anonymous(context, i)) {
- return Ok(generic::GenericImageLayer::Image(v));
- }
- input.expect_ident_matching("none")?;
- Ok(generic::GenericImageLayer::None)
- }
-}
-
/// Specified values for an image according to CSS-IMAGES.
/// <https://drafts.csswg.org/css-images/#image-values>
pub type Image = generic::Image<Gradient, MozImageRect, SpecifiedImageUrl>;
@@ -62,9 +45,23 @@ pub type Gradient = generic::Gradient<
NonNegativeLength,
NonNegativeLengthPercentage,
Position,
+ Angle,
+ AngleOrPercentage,
Color,
>;
+type LengthPercentageItemList = crate::OwnedSlice<generic::GradientItem<Color, LengthPercentage>>;
+
+#[cfg(feature = "gecko")]
+fn conic_gradients_enabled() -> bool {
+ static_prefs::pref!("layout.css.conic-gradient.enabled")
+}
+
+#[cfg(feature = "servo")]
+fn conic_gradients_enabled() -> bool {
+ false
+}
+
impl SpecifiedValueInfo for Gradient {
const SUPPORTED_TYPES: u8 = CssType::GRADIENT;
@@ -85,13 +82,13 @@ impl SpecifiedValueInfo for Gradient {
"-moz-repeating-radial-gradient",
"-webkit-gradient",
]);
+
+ if conic_gradients_enabled() {
+ f(&["conic-gradient", "repeating-conic-gradient"]);
+ }
}
}
-/// A specified gradient kind.
-pub type GradientKind =
- generic::GradientKind<LineDirection, NonNegativeLength, NonNegativeLengthPercentage, Position>;
-
/// A specified gradient line direction.
///
/// FIXME(emilio): This should be generic over Angle.
@@ -110,16 +107,10 @@ pub enum LineDirection {
/// A specified ending shape.
pub type EndingShape = generic::EndingShape<NonNegativeLength, NonNegativeLengthPercentage>;
-/// A specified gradient item.
-pub type GradientItem = generic::GradientItem<Color, LengthPercentage>;
-
-/// A computed color stop.
-pub type ColorStop = generic::ColorStop<Color, LengthPercentage>;
-
/// Specified values for `moz-image-rect`
/// -moz-image-rect(<uri>, top, right, bottom, left);
-#[cfg(feature = "gecko")]
-pub type MozImageRect = generic::MozImageRect<NumberOrPercentage, SpecifiedImageUrl>;
+#[cfg(all(feature = "gecko", not(feature = "cbindgen")))]
+pub type MozImageRect = generic::GenericMozImageRect<NumberOrPercentage, SpecifiedImageUrl>;
#[cfg(not(feature = "gecko"))]
#[derive(
@@ -141,6 +132,9 @@ impl Parse for Image {
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Image, ParseError<'i>> {
+ if input.try(|i| i.expect_ident_matching("none")).is_ok() {
+ return Ok(generic::Image::None);
+ }
if let Ok(url) = input.try(|input| SpecifiedImageUrl::parse(context, input)) {
return Ok(generic::Image::Url(url));
}
@@ -211,10 +205,11 @@ impl Parse for Gradient {
enum Shape {
Linear,
Radial,
+ Conic,
}
let func = input.expect_function()?;
- let (shape, repeating, mut compat_mode) = match_ignore_ascii_case! { &func,
+ let (shape, repeating, compat_mode) = match_ignore_ascii_case! { &func,
"linear-gradient" => {
(Shape::Linear, false, GradientCompatMode::Modern)
},
@@ -255,6 +250,12 @@ impl Parse for Gradient {
"-moz-repeating-radial-gradient" => {
(Shape::Radial, true, GradientCompatMode::Moz)
},
+ "conic-gradient" if conic_gradients_enabled() => {
+ (Shape::Conic, false, GradientCompatMode::Modern)
+ },
+ "repeating-conic-gradient" if conic_gradients_enabled() => {
+ (Shape::Conic, true, GradientCompatMode::Modern)
+ },
"-webkit-gradient" => {
return input.parse_nested_block(|i| {
Self::parse_webkit_gradient_argument(context, i)
@@ -266,25 +267,13 @@ impl Parse for Gradient {
}
};
- let (kind, items) = input.parse_nested_block(|i| {
- let shape = match shape {
- Shape::Linear => GradientKind::parse_linear(context, i, &mut compat_mode)?,
- Shape::Radial => GradientKind::parse_radial(context, i, &mut compat_mode)?,
- };
- let items = GradientItem::parse_comma_separated(context, i)?;
- Ok((shape, items))
- })?;
-
- if items.len() < 2 {
- return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
- }
-
- Ok(Gradient {
- items,
- repeating,
- kind,
- compat_mode,
- })
+ Ok(input.parse_nested_block(|i| {
+ Ok(match shape {
+ Shape::Linear => Self::parse_linear(context, i, repeating, compat_mode)?,
+ Shape::Radial => Self::parse_radial(context, i, repeating, compat_mode)?,
+ Shape::Conic => Self::parse_conic(context, i, repeating)?,
+ })
+ })?)
}
}
@@ -404,16 +393,21 @@ impl Gradient {
let ident = input.expect_ident_cloned()?;
input.expect_comma()?;
- let (kind, reverse_stops) = match_ignore_ascii_case! { &ident,
+ Ok(match_ignore_ascii_case! { &ident,
"linear" => {
let first = Point::parse(context, input)?;
input.expect_comma()?;
let second = Point::parse(context, input)?;
let direction = LineDirection::from_points(first, second);
- let kind = generic::GradientKind::Linear(direction);
+ let items = Gradient::parse_webkit_gradient_stops(context, input, false)?;
- (kind, false)
+ generic::Gradient::Linear {
+ direction,
+ items,
+ repeating: false,
+ compat_mode: GradientCompatMode::Modern,
+ }
},
"radial" => {
let first_point = Point::parse(context, input)?;
@@ -433,16 +427,28 @@ impl Gradient {
let rad = Circle::Radius(NonNegative(Length::from_px(radius.value)));
let shape = generic::EndingShape::Circle(rad);
let position: Position = point.into();
-
- let kind = generic::GradientKind::Radial(shape, position);
- (kind, reverse_stops)
+ let items = Gradient::parse_webkit_gradient_stops(context, input, reverse_stops)?;
+
+ generic::Gradient::Radial {
+ shape,
+ position,
+ items,
+ repeating: false,
+ compat_mode: GradientCompatMode::Modern,
+ }
},
_ => {
let e = SelectorParseErrorKind::UnexpectedIdent(ident.clone());
return Err(input.new_custom_error(e));
},
- };
+ })
+ }
+ fn parse_webkit_gradient_stops<'i, 't>(
+ context: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ reverse_stops: bool,
+ ) -> Result<LengthPercentageItemList, ParseError<'i>> {
let mut items = input
.try(|i| {
i.expect_comma()?;
@@ -521,46 +527,62 @@ impl Gradient {
}
})
}
+ Ok(items.into())
+ }
- Ok(generic::Gradient {
- kind,
- items: items.into(),
- repeating: false,
- compat_mode: GradientCompatMode::Modern,
- })
+ /// Not used for -webkit-gradient syntax and conic-gradient
+ fn parse_stops<'i, 't>(
+ context: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ ) -> Result<LengthPercentageItemList, ParseError<'i>> {
+ let items =
+ generic::GradientItem::parse_comma_separated(context, input, LengthPercentage::parse)?;
+ if items.len() < 2 {
+ return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
+ }
+ Ok(items)
}
-}
-impl GradientKind {
/// Parses a linear gradient.
/// GradientCompatMode can change during `-moz-` prefixed gradient parsing if it come across a `to` keyword.
fn parse_linear<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
- compat_mode: &mut GradientCompatMode,
+ repeating: bool,
+ mut compat_mode: GradientCompatMode,
) -> Result<Self, ParseError<'i>> {
- let direction = if let Ok(d) = input.try(|i| LineDirection::parse(context, i, compat_mode))
- {
- input.expect_comma()?;
- d
- } else {
- match *compat_mode {
- GradientCompatMode::Modern => {
- LineDirection::Vertical(VerticalPositionKeyword::Bottom)
- },
- _ => LineDirection::Vertical(VerticalPositionKeyword::Top),
- }
- };
- Ok(generic::GradientKind::Linear(direction))
+ let direction =
+ if let Ok(d) = input.try(|i| LineDirection::parse(context, i, &mut compat_mode)) {
+ input.expect_comma()?;
+ d
+ } else {
+ match compat_mode {
+ GradientCompatMode::Modern => {
+ LineDirection::Vertical(VerticalPositionKeyword::Bottom)
+ },
+ _ => LineDirection::Vertical(VerticalPositionKeyword::Top),
+ }
+ };
+ let items = Gradient::parse_stops(context, input)?;
+
+ Ok(Gradient::Linear {
+ direction,
+ items,
+ repeating,
+ compat_mode,
+ })
}
+
+ /// Parses a radial gradient.
fn parse_radial<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
- compat_mode: &mut GradientCompatMode,
+ repeating: bool,
+ compat_mode: GradientCompatMode,
) -> Result<Self, ParseError<'i>> {
- let (shape, position) = match *compat_mode {
+ let (shape, position) = match compat_mode {
GradientCompatMode::Modern => {
- let shape = input.try(|i| EndingShape::parse(context, i, *compat_mode));
+ let shape = input.try(|i| EndingShape::parse(context, i, compat_mode));
let position = input.try(|i| {
i.expect_ident_matching("at")?;
Position::parse(context, i)
@@ -573,7 +595,7 @@ impl GradientKind {
if position.is_ok() {
i.expect_comma()?;
}
- EndingShape::parse(context, i, *compat_mode)
+ EndingShape::parse(context, i, compat_mode)
});
(shape, position.ok())
},
@@ -588,7 +610,54 @@ impl GradientKind {
});
let position = position.unwrap_or(Position::center());
- Ok(generic::GradientKind::Radial(shape, position))
+
+ let items = Gradient::parse_stops(context, input)?;
+
+ Ok(Gradient::Radial {
+ shape,
+ position,
+ items,
+ repeating,
+ compat_mode,
+ })
+ }
+ fn parse_conic<'i, 't>(
+ context: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ repeating: bool,
+ ) -> Result<Self, ParseError<'i>> {
+ let angle = input.try(|i| {
+ i.expect_ident_matching("from")?;
+ // Spec allows unitless zero start angles
+ // https://drafts.csswg.org/css-images-4/#valdef-conic-gradient-angle
+ Angle::parse_with_unitless(context, i)
+ });
+ let position = input.try(|i| {
+ i.expect_ident_matching("at")?;
+ Position::parse(context, i)
+ });
+ if angle.is_ok() || position.is_ok() {
+ input.expect_comma()?;
+ }
+
+ let angle = angle.unwrap_or(Angle::zero());
+ let position = position.unwrap_or(Position::center());
+ let items = generic::GradientItem::parse_comma_separated(
+ context,
+ input,
+ AngleOrPercentage::parse_with_unitless,
+ )?;
+
+ if items.len() < 2 {
+ return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
+ }
+
+ Ok(Gradient::Conic {
+ angle,
+ position,
+ items,
+ repeating,
+ })
}
}
@@ -793,10 +862,12 @@ impl ShapeExtent {
}
}
-impl GradientItem {
+impl<T> generic::GradientItem<Color, T> {
fn parse_comma_separated<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
+ parse_position: impl for<'i1, 't1> Fn(&ParserContext, &mut Parser<'i1, 't1>) -> Result<T, ParseError<'i1>>
+ + Copy,
) -> Result<crate::OwnedSlice<Self>, ParseError<'i>> {
let mut items = Vec::new();
let mut seen_stop = false;
@@ -804,20 +875,20 @@ impl GradientItem {
loop {
input.parse_until_before(Delimiter::Comma, |input| {
if seen_stop {
- if let Ok(hint) = input.try(|i| LengthPercentage::parse(context, i)) {
+ if let Ok(hint) = input.try(|i| parse_position(context, i)) {
seen_stop = false;
items.push(generic::GradientItem::InterpolationHint(hint));
return Ok(());
}
}
- let stop = ColorStop::parse(context, input)?;
+ let stop = generic::ColorStop::parse(context, input, parse_position)?;
- if let Ok(multi_position) = input.try(|i| LengthPercentage::parse(context, i)) {
+ if let Ok(multi_position) = input.try(|i| parse_position(context, i)) {
let stop_color = stop.color.clone();
items.push(stop.into_item());
items.push(
- ColorStop {
+ generic::ColorStop {
color: stop_color,
position: Some(multi_position),
}
@@ -845,14 +916,18 @@ impl GradientItem {
}
}
-impl Parse for ColorStop {
+impl<T> generic::ColorStop<Color, T> {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
+ parse_position: impl for<'i1, 't1> Fn(
+ &ParserContext,
+ &mut Parser<'i1, 't1>,
+ ) -> Result<T, ParseError<'i1>>,
) -> Result<Self, ParseError<'i>> {
- Ok(ColorStop {
+ Ok(generic::ColorStop {
color: Color::parse(context, input)?,
- position: input.try(|i| LengthPercentage::parse(context, i)).ok(),
+ position: input.try(|i| parse_position(context, i)).ok(),
})
}
}
diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs
index ff24404c09a..0b1bf0b68a7 100644
--- a/components/style/values/specified/length.rs
+++ b/components/style/values/specified/length.rs
@@ -16,7 +16,7 @@ use crate::values::generics::length::{
GenericLengthOrNumber, GenericLengthPercentageOrNormal, GenericMaxSize, GenericSize,
};
use crate::values::generics::NonNegative;
-use crate::values::specified::calc::CalcNode;
+use crate::values::specified::calc::{self, CalcNode};
use crate::values::specified::NonNegativeNumber;
use crate::values::CSSFloat;
use crate::Zero;
@@ -28,8 +28,8 @@ use std::ops::{Add, Mul};
use style_traits::values::specified::AllowedNumericType;
use style_traits::{ParseError, SpecifiedValueInfo, StyleParseErrorKind};
-pub use super::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
-pub use super::image::{GradientKind, Image};
+pub use super::image::Image;
+pub use super::image::{EndingShape as GradientEndingShape, Gradient};
pub use crate::values::specified::calc::CalcLengthPercentage;
/// Number of app units per pixel
@@ -92,7 +92,16 @@ impl FontRelativeLength {
FontRelativeLength::Em(v) |
FontRelativeLength::Ex(v) |
FontRelativeLength::Ch(v) |
- FontRelativeLength::Rem(v) => v == 0.0,
+ FontRelativeLength::Rem(v) => v == 0.,
+ }
+ }
+
+ fn is_negative(&self) -> bool {
+ match *self {
+ FontRelativeLength::Em(v) |
+ FontRelativeLength::Ex(v) |
+ FontRelativeLength::Ch(v) |
+ FontRelativeLength::Rem(v) => v < 0.,
}
}
@@ -266,7 +275,16 @@ impl ViewportPercentageLength {
ViewportPercentageLength::Vw(v) |
ViewportPercentageLength::Vh(v) |
ViewportPercentageLength::Vmin(v) |
- ViewportPercentageLength::Vmax(v) => v == 0.0,
+ ViewportPercentageLength::Vmax(v) => v == 0.,
+ }
+ }
+
+ fn is_negative(&self) -> bool {
+ match *self {
+ ViewportPercentageLength::Vw(v) |
+ ViewportPercentageLength::Vh(v) |
+ ViewportPercentageLength::Vmin(v) |
+ ViewportPercentageLength::Vmax(v) => v < 0.,
}
}
@@ -370,6 +388,18 @@ impl AbsoluteLength {
}
}
+ fn is_negative(&self) -> bool {
+ match *self {
+ AbsoluteLength::Px(v) |
+ AbsoluteLength::In(v) |
+ AbsoluteLength::Cm(v) |
+ AbsoluteLength::Mm(v) |
+ AbsoluteLength::Q(v) |
+ AbsoluteLength::Pt(v) |
+ AbsoluteLength::Pc(v) => v < 0.,
+ }
+ }
+
/// Convert this into a pixel value.
#[inline]
pub fn to_px(&self) -> CSSFloat {
@@ -484,6 +514,16 @@ impl Mul<CSSFloat> for NoCalcLength {
}
impl NoCalcLength {
+ /// Returns whether the value of this length without unit is less than zero.
+ pub fn is_negative(&self) -> bool {
+ match *self {
+ NoCalcLength::Absolute(v) => v.is_negative(),
+ NoCalcLength::FontRelative(v) => v.is_negative(),
+ NoCalcLength::ViewportPercentage(v) => v.is_negative(),
+ NoCalcLength::ServoCharacterWidth(c) => c.0 < 0,
+ }
+ }
+
/// Parse a given absolute or relative dimension.
pub fn parse_dimension(
context: &ParserContext,
@@ -912,9 +952,10 @@ impl From<Percentage> for LengthPercentage {
#[inline]
fn from(pc: Percentage) -> Self {
if pc.is_calc() {
+ // FIXME(emilio): Hard-coding the clamping mode is suspect.
LengthPercentage::Calc(Box::new(CalcLengthPercentage {
- percentage: Some(computed::Percentage(pc.get())),
- ..Default::default()
+ clamping_mode: AllowedNumericType::All,
+ node: CalcNode::Leaf(calc::Leaf::Percentage(pc.get())),
}))
} else {
LengthPercentage::Percentage(computed::Percentage(pc.get()))
diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs
index 54401045809..63af3015386 100644
--- a/components/style/values/specified/mod.rs
+++ b/components/style/values/specified/mod.rs
@@ -55,8 +55,8 @@ pub use self::font::{FontSize, FontSizeAdjust, FontStretch, FontSynthesis};
pub use self::font::{FontVariantAlternates, FontWeight};
pub use self::font::{FontVariantEastAsian, FontVariationSettings};
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom};
-pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
-pub use self::image::{GradientItem, GradientKind, Image, ImageLayer, MozImageRect};
+pub use self::image::{EndingShape as GradientEndingShape, Gradient};
+pub use self::image::{Image, MozImageRect};
pub use self::length::{AbsoluteLength, CalcLengthPercentage, CharacterWidth};
pub use self::length::{FontRelativeLength, Length, LengthOrNumber, NonNegativeLengthOrNumber};
pub use self::length::{LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
@@ -80,6 +80,7 @@ pub use self::svg::MozContextProperties;
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint};
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
pub use self::svg_path::SVGPathData;
+pub use self::text::TextAlignLast;
pub use self::text::TextUnderlinePosition;
pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight, TextAlign};
pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle, WordBreak};
diff --git a/components/style/values/specified/percentage.rs b/components/style/values/specified/percentage.rs
index 75549dca3be..eac4d91cf8f 100644
--- a/components/style/values/specified/percentage.rs
+++ b/components/style/values/specified/percentage.rs
@@ -120,9 +120,6 @@ impl Percentage {
Token::Function(ref name) => {
let function = CalcNode::math_function(name, location)?;
let value = CalcNode::parse_percentage(context, input, function)?;
-
- // TODO(emilio): -moz-image-rect is the only thing that uses
- // the clamping mode... I guess we could disallow it...
Ok(Percentage {
value,
calc_clamping_mode: Some(num_context),
diff --git a/components/style/values/specified/position.rs b/components/style/values/specified/position.rs
index 3f01988e49d..b843de29a41 100644
--- a/components/style/values/specified/position.rs
+++ b/components/style/values/specified/position.rs
@@ -13,6 +13,7 @@ use crate::str::HTML_SPACE_CHARACTERS;
use crate::values::computed::LengthPercentage as ComputedLengthPercentage;
use crate::values::computed::{Context, Percentage, ToComputedValue};
use crate::values::generics::position::Position as GenericPosition;
+use crate::values::generics::position::PositionComponent as GenericPositionComponent;
use crate::values::generics::position::PositionOrAuto as GenericPositionOrAuto;
use crate::values::generics::position::ZIndex as GenericZIndex;
use crate::values::specified::{AllowQuirks, Integer, LengthPercentage};
@@ -262,6 +263,18 @@ impl<S: Parse> PositionComponent<S> {
}
}
+impl<S> GenericPositionComponent for PositionComponent<S> {
+ fn is_center(&self) -> bool {
+ match *self {
+ PositionComponent::Center => true,
+ PositionComponent::Length(LengthPercentage::Percentage(ref per)) => per.0 == 0.5,
+ // 50% from any side is still the center.
+ PositionComponent::Side(_, Some(LengthPercentage::Percentage(ref per))) => per.0 == 0.5,
+ _ => false,
+ }
+ }
+}
+
impl<S> PositionComponent<S> {
/// `0%`
pub fn zero() -> Self {
@@ -295,10 +308,8 @@ impl<S: Side> ToComputedValue for PositionComponent<S> {
},
PositionComponent::Side(ref keyword, Some(ref length)) if !keyword.is_start() => {
let length = length.to_computed_value(context);
- let p = Percentage(1. - length.percentage());
- let l = -length.unclamped_length();
// We represent `<end-side> <length>` as `calc(100% - <length>)`.
- ComputedLengthPercentage::new_calc(l, Some(p), AllowedNumericType::All)
+ ComputedLengthPercentage::hundred_percent_minus(length, AllowedNumericType::All)
},
PositionComponent::Side(_, Some(ref length)) |
PositionComponent::Length(ref length) => length.to_computed_value(context),
@@ -350,66 +361,25 @@ impl Side for VerticalPositionKeyword {
}
}
-#[derive(
- Clone,
- Copy,
- Debug,
- Eq,
- MallocSizeOf,
- PartialEq,
- SpecifiedValueInfo,
- ToComputedValue,
- ToCss,
- ToResolvedValue,
- ToShmem,
-)]
-/// Auto-placement algorithm Option
-pub enum AutoFlow {
- /// The auto-placement algorithm places items by filling each row in turn,
- /// adding new rows as necessary.
- Row,
- /// The auto-placement algorithm places items by filling each column in turn,
- /// adding new columns as necessary.
- Column,
-}
-
-/// If `dense` is specified, `row` is implied.
-fn is_row_dense(autoflow: &AutoFlow, dense: &bool) -> bool {
- *autoflow == AutoFlow::Row && *dense
-}
-
-#[derive(
- Clone,
- Copy,
- Debug,
- Eq,
- MallocSizeOf,
- PartialEq,
- SpecifiedValueInfo,
- ToComputedValue,
- ToCss,
- ToResolvedValue,
- ToShmem,
-)]
-/// Controls how the auto-placement algorithm works
-/// specifying exactly how auto-placed items get flowed into the grid
-pub struct GridAutoFlow {
- /// Specifiy how auto-placement algorithm fills each `row` or `column` in turn
- #[css(contextual_skip_if = "is_row_dense")]
- pub autoflow: AutoFlow,
- /// Specify use `dense` packing algorithm or not
- #[css(represents_keyword)]
- pub dense: bool,
-}
-
-impl GridAutoFlow {
- #[inline]
- /// Get default `grid-auto-flow` as `row`
- pub fn row() -> GridAutoFlow {
- GridAutoFlow {
- autoflow: AutoFlow::Row,
- dense: false,
- }
+bitflags! {
+ /// Controls how the auto-placement algorithm works
+ /// specifying exactly how auto-placed items get flowed into the grid
+ #[derive(
+ MallocSizeOf,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToResolvedValue,
+ ToShmem
+ )]
+ #[value_info(other_values = "row,column,dense")]
+ #[repr(C)]
+ pub struct GridAutoFlow: u8 {
+ /// 'row' - mutually exclusive with 'column'
+ const ROW = 1 << 0;
+ /// 'column' - mutually exclusive with 'row'
+ const COLUMN = 1 << 1;
+ /// 'dense'
+ const DENSE = 1 << 2;
}
}
@@ -419,26 +389,26 @@ impl Parse for GridAutoFlow {
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<GridAutoFlow, ParseError<'i>> {
- let mut value = None;
- let mut dense = false;
+ let mut track = None;
+ let mut dense = GridAutoFlow::empty();
while !input.is_exhausted() {
let location = input.current_source_location();
let ident = input.expect_ident()?;
let success = match_ignore_ascii_case! { &ident,
- "row" if value.is_none() => {
- value = Some(AutoFlow::Row);
+ "row" if track.is_none() => {
+ track = Some(GridAutoFlow::ROW);
true
},
- "column" if value.is_none() => {
- value = Some(AutoFlow::Column);
+ "column" if track.is_none() => {
+ track = Some(GridAutoFlow::COLUMN);
true
},
- "dense" if !dense => {
- dense = true;
+ "dense" if dense.is_empty() => {
+ dense = GridAutoFlow::DENSE;
true
},
- _ => false
+ _ => false,
};
if !success {
return Err(location
@@ -446,47 +416,37 @@ impl Parse for GridAutoFlow {
}
}
- if value.is_some() || dense {
- Ok(GridAutoFlow {
- autoflow: value.unwrap_or(AutoFlow::Row),
- dense: dense,
- })
+ if track.is_some() || !dense.is_empty() {
+ Ok(track.unwrap_or(GridAutoFlow::ROW) | dense)
} else {
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
}
}
-#[cfg(feature = "gecko")]
-impl From<u8> for GridAutoFlow {
- fn from(bits: u8) -> GridAutoFlow {
- use crate::gecko_bindings::structs;
-
- GridAutoFlow {
- autoflow: if bits & structs::NS_STYLE_GRID_AUTO_FLOW_ROW as u8 != 0 {
- AutoFlow::Row
- } else {
- AutoFlow::Column
- },
- dense: bits & structs::NS_STYLE_GRID_AUTO_FLOW_DENSE as u8 != 0,
+impl ToCss for GridAutoFlow {
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+ where
+ W: Write,
+ {
+ if *self == GridAutoFlow::ROW {
+ return dest.write_str("row");
}
- }
-}
-#[cfg(feature = "gecko")]
-impl From<GridAutoFlow> for u8 {
- fn from(v: GridAutoFlow) -> u8 {
- use crate::gecko_bindings::structs;
+ if *self == GridAutoFlow::COLUMN {
+ return dest.write_str("column");
+ }
- let mut result: u8 = match v.autoflow {
- AutoFlow::Row => structs::NS_STYLE_GRID_AUTO_FLOW_ROW as u8,
- AutoFlow::Column => structs::NS_STYLE_GRID_AUTO_FLOW_COLUMN as u8,
- };
+ if *self == GridAutoFlow::ROW | GridAutoFlow::DENSE {
+ return dest.write_str("dense");
+ }
- if v.dense {
- result |= structs::NS_STYLE_GRID_AUTO_FLOW_DENSE as u8;
+ if *self == GridAutoFlow::COLUMN | GridAutoFlow::DENSE {
+ return dest.write_str("column dense");
}
- result
+
+ debug_assert!(false, "Unknown or invalid grid-autoflow value");
+ Ok(())
}
}
@@ -592,7 +552,7 @@ impl TemplateAreas {
Ok(TemplateAreas {
areas: areas.into(),
strings: strings.into(),
- width: width,
+ width,
})
}
}
@@ -642,7 +602,16 @@ impl Parse for TemplateAreasArc {
/// A range of rows or columns. Using this instead of std::ops::Range for FFI
/// purposes.
#[repr(C)]
-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToShmem)]
+#[derive(
+ Clone,
+ Debug,
+ MallocSizeOf,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToResolvedValue,
+ ToShmem,
+)]
pub struct UnsignedRange {
/// The start of the range.
pub start: u32,
@@ -650,7 +619,16 @@ pub struct UnsignedRange {
pub end: u32,
}
-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToShmem)]
+#[derive(
+ Clone,
+ Debug,
+ MallocSizeOf,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToResolvedValue,
+ ToShmem,
+)]
#[repr(C)]
/// Not associated with any particular grid item, but can be referenced from the
/// grid-placement properties.
diff --git a/components/style/values/specified/svg.rs b/components/style/values/specified/svg.rs
index e603ddfda07..cff899fce35 100644
--- a/components/style/values/specified/svg.rs
+++ b/components/style/values/specified/svg.rs
@@ -21,13 +21,13 @@ use style_traits::{StyleParseErrorKind, ToCss};
pub type SVGPaint = generic::GenericSVGPaint<Color, SpecifiedUrl>;
/// <length> | <percentage> | <number> | context-value
-pub type SVGLength = generic::SVGLength<LengthPercentage>;
+pub type SVGLength = generic::GenericSVGLength<LengthPercentage>;
/// A non-negative version of SVGLength.
-pub type SVGWidth = generic::SVGLength<NonNegativeLengthPercentage>;
+pub type SVGWidth = generic::GenericSVGLength<NonNegativeLengthPercentage>;
/// [ <length> | <percentage> | <number> ]# | context-value
-pub type SVGStrokeDashArray = generic::SVGStrokeDashArray<NonNegativeLengthPercentage>;
+pub type SVGStrokeDashArray = generic::GenericSVGStrokeDashArray<NonNegativeLengthPercentage>;
/// Whether the `context-value` value is enabled.
#[cfg(feature = "gecko")]
diff --git a/components/style/values/specified/svg_path.rs b/components/style/values/specified/svg_path.rs
index 288f396b73c..9f1c5c5e32c 100644
--- a/components/style/values/specified/svg_path.rs
+++ b/components/style/values/specified/svg_path.rs
@@ -159,6 +159,8 @@ impl ComputeSquaredDistance for SVGPathData {
Serialize,
SpecifiedValueInfo,
ToAnimatedZero,
+ ToComputedValue,
+ ToResolvedValue,
ToShmem,
)]
#[allow(missing_docs)]
@@ -488,6 +490,8 @@ impl ToCss for PathCommand {
Serialize,
SpecifiedValueInfo,
ToAnimatedZero,
+ ToComputedValue,
+ ToResolvedValue,
ToShmem,
)]
#[repr(u8)]
@@ -518,7 +522,9 @@ impl IsAbsolute {
Serialize,
SpecifiedValueInfo,
ToAnimatedZero,
+ ToComputedValue,
ToCss,
+ ToResolvedValue,
ToShmem,
)]
#[repr(C)]
@@ -534,7 +540,17 @@ impl CoordPair {
/// The EllipticalArc flag type.
#[derive(
- Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, SpecifiedValueInfo, ToShmem,
+ Clone,
+ Copy,
+ Debug,
+ Deserialize,
+ MallocSizeOf,
+ PartialEq,
+ Serialize,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToResolvedValue,
+ ToShmem,
)]
#[repr(C)]
pub struct ArcFlag(bool);
diff --git a/components/style/values/specified/text.rs b/components/style/values/specified/text.rs
index 0228d5123ce..703e51a5248 100644
--- a/components/style/values/specified/text.rs
+++ b/components/style/values/specified/text.rs
@@ -122,7 +122,18 @@ impl ToComputedValue for LineHeight {
}
/// A generic value for the `text-overflow` property.
-#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
+#[derive(
+ Clone,
+ Debug,
+ Eq,
+ MallocSizeOf,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+ ToShmem,
+)]
#[repr(C, u8)]
pub enum TextOverflowSide {
/// Clip inline content.
@@ -517,6 +528,35 @@ impl ToCss for TextTransformOther {
}
}
+/// Specified and computed value of text-align-last.
+#[derive(
+ Clone,
+ Copy,
+ Debug,
+ Eq,
+ FromPrimitive,
+ Hash,
+ MallocSizeOf,
+ Parse,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+ ToShmem,
+)]
+#[allow(missing_docs)]
+#[repr(u8)]
+pub enum TextAlignLast {
+ Auto,
+ Start,
+ End,
+ Left,
+ Right,
+ Center,
+ Justify,
+}
+
/// Specified value of text-align keyword value.
#[derive(
Clone,
@@ -535,14 +575,18 @@ impl ToCss for TextTransformOther {
ToShmem,
)]
#[allow(missing_docs)]
+#[repr(u8)]
pub enum TextAlignKeyword {
Start,
- End,
Left,
Right,
Center,
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
Justify,
+ #[css(skip)]
+ #[cfg(feature = "gecko")]
+ Char,
+ End,
#[cfg(feature = "gecko")]
MozCenter,
#[cfg(feature = "gecko")]
@@ -555,9 +599,6 @@ pub enum TextAlignKeyword {
ServoLeft,
#[cfg(feature = "servo-layout-2013")]
ServoRight,
- #[css(skip)]
- #[cfg(feature = "gecko")]
- Char,
}
/// Specified value of text-align property.
@@ -579,14 +620,6 @@ pub enum TextAlign {
MozCenterOrInherit,
}
-impl TextAlign {
- /// Convert an enumerated value coming from Gecko to a `TextAlign`.
- #[cfg(feature = "gecko")]
- pub fn from_gecko_keyword(kw: u32) -> Self {
- TextAlign::Keyword(TextAlignKeyword::from_gecko_keyword(kw))
- }
-}
-
impl ToComputedValue for TextAlign {
type ComputedValue = TextAlignKeyword;
@@ -665,7 +698,19 @@ pub enum TextEmphasisStyle {
}
/// Fill mode for the text-emphasis-style property
-#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
+#[derive(
+ Clone,
+ Copy,
+ Debug,
+ MallocSizeOf,
+ Parse,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToCss,
+ ToComputedValue,
+ ToResolvedValue,
+ ToShmem,
+)]
#[repr(u8)]
pub enum TextEmphasisFillMode {
/// `filled`
@@ -684,7 +729,18 @@ impl TextEmphasisFillMode {
/// Shape keyword for the text-emphasis-style property
#[derive(
- Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem,
+ Clone,
+ Copy,
+ Debug,
+ Eq,
+ MallocSizeOf,
+ Parse,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToCss,
+ ToComputedValue,
+ ToResolvedValue,
+ ToShmem,
)]
#[repr(u8)]
pub enum TextEmphasisShapeKeyword {
@@ -1010,7 +1066,7 @@ pub enum OverflowWrap {
Anywhere,
}
-/// Implements text-decoration-skip-ink which takes the keywords auto | none
+/// Implements text-decoration-skip-ink which takes the keywords auto | none | all
///
/// https://drafts.csswg.org/css-text-decor-4/#text-decoration-skip-ink-property
#[repr(u8)]
@@ -1033,6 +1089,7 @@ pub enum OverflowWrap {
pub enum TextDecorationSkipInk {
Auto,
None,
+ All,
}
/// Implements type for `text-decoration-thickness` property
diff --git a/components/style/values/specified/ui.rs b/components/style/values/specified/ui.rs
index 46272b2ae85..b94267162c9 100644
--- a/components/style/values/specified/ui.rs
+++ b/components/style/values/specified/ui.rs
@@ -14,10 +14,10 @@ use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
/// A specified value for the `cursor` property.
-pub type Cursor = generics::Cursor<CursorImage>;
+pub type Cursor = generics::GenericCursor<CursorImage>;
/// A specified value for item of `image cursors`.
-pub type CursorImage = generics::CursorImage<SpecifiedImageUrl, Number>;
+pub type CursorImage = generics::GenericCursorImage<SpecifiedImageUrl, Number>;
impl Parse for Cursor {
/// cursor: [<url> [<number> <number>]?]# [auto | default | ...]
@@ -34,7 +34,7 @@ impl Parse for Cursor {
input.expect_comma()?;
}
Ok(Self {
- images: images.into_boxed_slice(),
+ images: images.into(),
keyword: CursorKind::parse(input)?,
})
}
@@ -45,12 +45,24 @@ impl Parse for CursorImage {
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
+ use crate::Zero;
+
+ let url = SpecifiedImageUrl::parse(context, input)?;
+ let mut has_hotspot = false;
+ let mut hotspot_x = Number::zero();
+ let mut hotspot_y = Number::zero();
+
+ if let Ok(x) = input.try(|input| Number::parse(context, input)) {
+ has_hotspot = true;
+ hotspot_x = x;
+ hotspot_y = Number::parse(context, input)?;
+ }
+
Ok(Self {
- url: SpecifiedImageUrl::parse(context, input)?,
- hotspot: match input.try(|input| Number::parse(context, input)) {
- Ok(number) => Some((number, Number::parse(context, input)?)),
- Err(_) => None,
- },
+ url,
+ has_hotspot,
+ hotspot_x,
+ hotspot_y,
})
}
}
diff --git a/components/style_derive/animate.rs b/components/style_derive/animate.rs
index 190568514fc..59b19214971 100644
--- a/components/style_derive/animate.rs
+++ b/components/style_derive/animate.rs
@@ -6,12 +6,11 @@ use darling::util::PathList;
use derive_common::cg;
use proc_macro2::TokenStream;
use quote::TokenStreamExt;
-use syn::{DeriveInput, Path, WhereClause};
+use syn::{DeriveInput, WhereClause};
use synstructure::{Structure, VariantInfo};
pub fn derive(mut input: DeriveInput) -> TokenStream {
let animation_input_attrs = cg::parse_input_attrs::<AnimationInputAttrs>(&input);
- let input_attrs = cg::parse_input_attrs::<AnimateInputAttrs>(&input);
let no_bound = animation_input_attrs.no_bound.unwrap_or_default();
let mut where_clause = input.generics.where_clause.take();
@@ -44,11 +43,6 @@ pub fn derive(mut input: DeriveInput) -> TokenStream {
let name = &input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
- let fallback = match input_attrs.fallback {
- Some(fallback) => quote! { #fallback(self, other, procedure) },
- None => quote! { Err(()) },
- };
-
quote! {
impl #impl_generics crate::values::animated::Animate for #name #ty_generics #where_clause {
#[allow(unused_variables, unused_imports)]
@@ -59,7 +53,7 @@ pub fn derive(mut input: DeriveInput) -> TokenStream {
procedure: crate::values::animated::Procedure,
) -> Result<Self, ()> {
if std::mem::discriminant(self) != std::mem::discriminant(other) {
- return #fallback;
+ return Err(());
}
match (self, other) {
#match_body
@@ -118,12 +112,6 @@ fn derive_variant_arm(
}
}
-#[darling(attributes(animate), default)]
-#[derive(Default, FromDeriveInput)]
-struct AnimateInputAttrs {
- fallback: Option<Path>,
-}
-
#[darling(attributes(animation), default)]
#[derive(Default, FromDeriveInput)]
pub struct AnimationInputAttrs {
diff --git a/components/style_derive/compute_squared_distance.rs b/components/style_derive/compute_squared_distance.rs
index 5e130e75b06..b4e67f6c984 100644
--- a/components/style_derive/compute_squared_distance.rs
+++ b/components/style_derive/compute_squared_distance.rs
@@ -6,12 +6,11 @@ use crate::animate::{AnimationFieldAttrs, AnimationInputAttrs, AnimationVariantA
use derive_common::cg;
use proc_macro2::TokenStream;
use quote::TokenStreamExt;
-use syn::{DeriveInput, Path, WhereClause};
+use syn::{DeriveInput, WhereClause};
use synstructure;
pub fn derive(mut input: DeriveInput) -> TokenStream {
let animation_input_attrs = cg::parse_input_attrs::<AnimationInputAttrs>(&input);
- let input_attrs = cg::parse_input_attrs::<DistanceInputAttrs>(&input);
let no_bound = animation_input_attrs.no_bound.unwrap_or_default();
let mut where_clause = input.generics.where_clause.take();
for param in input.generics.type_params() {
@@ -43,11 +42,6 @@ pub fn derive(mut input: DeriveInput) -> TokenStream {
match_body.append_all(quote! { _ => unsafe { debug_unreachable!() } });
}
- let fallback = match input_attrs.fallback {
- Some(fallback) => quote! { #fallback(self, other) },
- None => quote! { Err(()) },
- };
-
let name = &input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
@@ -60,7 +54,7 @@ pub fn derive(mut input: DeriveInput) -> TokenStream {
other: &Self,
) -> Result<crate::values::distance::SquaredDistance, ()> {
if std::mem::discriminant(self) != std::mem::discriminant(other) {
- return #fallback;
+ return Err(());
}
match (self, other) {
#match_body
@@ -125,12 +119,6 @@ fn derive_variant_arm(
}
#[darling(attributes(distance), default)]
-#[derive(Default, FromDeriveInput)]
-struct DistanceInputAttrs {
- fallback: Option<Path>,
-}
-
-#[darling(attributes(distance), default)]
#[derive(Default, FromField)]
struct DistanceFieldAttrs {
field_bound: bool,
diff --git a/components/style_derive/to_animated_value.rs b/components/style_derive/to_animated_value.rs
index 51a73cbf4e1..45282f0c448 100644
--- a/components/style_derive/to_animated_value.rs
+++ b/components/style_derive/to_animated_value.rs
@@ -11,33 +11,25 @@ pub fn derive(input: DeriveInput) -> TokenStream {
let trait_impl = |from_body, to_body| {
quote! {
#[inline]
- fn from_animated_value(animated: Self::AnimatedValue) -> Self {
- match animated {
- #from_body
- }
+ fn from_animated_value(from: Self::AnimatedValue) -> Self {
+ #from_body
}
#[inline]
fn to_animated_value(self) -> Self::AnimatedValue {
- match self {
- #to_body
- }
+ #to_body
}
}
};
- // TODO(emilio): Consider optimizing away non-generic cases as well?
- let non_generic_implementation = || None;
-
to_computed_value::derive_to_value(
input,
parse_quote!(crate::values::animated::ToAnimatedValue),
parse_quote!(AnimatedValue),
BindStyle::Move,
- |_| false,
+ |_| Default::default(),
|binding| quote!(crate::values::animated::ToAnimatedValue::from_animated_value(#binding)),
|binding| quote!(crate::values::animated::ToAnimatedValue::to_animated_value(#binding)),
trait_impl,
- non_generic_implementation,
)
}
diff --git a/components/style_derive/to_computed_value.rs b/components/style_derive/to_computed_value.rs
index ed6e07a2f5a..fe6bddb7ed2 100644
--- a/components/style_derive/to_computed_value.rs
+++ b/components/style_derive/to_computed_value.rs
@@ -13,7 +13,7 @@ pub fn derive_to_value(
output_type_name: Ident,
bind_style: BindStyle,
// Returns whether to apply the field bound for a given item.
- mut field_bound: impl FnMut(&BindingInfo) -> bool,
+ mut binding_attrs: impl FnMut(&BindingInfo) -> ToValueAttrs,
// Returns a token stream of the form: trait_path::from_foo(#binding)
mut call_from: impl FnMut(&BindingInfo) -> TokenStream,
mut call_to: impl FnMut(&BindingInfo) -> TokenStream,
@@ -26,25 +26,9 @@ pub fn derive_to_value(
// #second_arg
// }
mut trait_impl: impl FnMut(TokenStream, TokenStream) -> TokenStream,
- // if this is provided, the derive for non-generic types will be simplified
- // to this token stream, which should be the body of the impl block.
- non_generic_implementation: impl FnOnce() -> Option<TokenStream>,
) -> TokenStream {
let name = &input.ident;
- if input.generics.type_params().next().is_none() {
- if let Some(non_generic_implementation) = non_generic_implementation() {
- let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
- return quote! {
- impl #impl_generics #trait_path for #name #ty_generics
- #where_clause
- {
- #non_generic_implementation
- }
- };
- }
- }
-
let mut where_clause = input.generics.where_clause.take();
cg::propagate_clauses_to_output_type(
&mut where_clause,
@@ -52,33 +36,107 @@ pub fn derive_to_value(
&trait_path,
&output_type_name,
);
- let (to_body, from_body) = {
- let params = input.generics.type_params().collect::<Vec<_>>();
- for param in &params {
- cg::add_predicate(&mut where_clause, parse_quote!(#param: #trait_path));
- }
- let to_body = cg::fmap_match(&input, bind_style, |binding| {
- if field_bound(&binding) {
- let ty = &binding.ast().ty;
+ let moves = match bind_style {
+ BindStyle::Move | BindStyle::MoveMut => true,
+ BindStyle::Ref | BindStyle::RefMut => false,
+ };
- let output_type = cg::map_type_params(
- ty,
- &params,
- &mut |ident| parse_quote!(<#ident as #trait_path>::#output_type_name),
- );
+ let params = input.generics.type_params().collect::<Vec<_>>();
+ for param in &params {
+ cg::add_predicate(&mut where_clause, parse_quote!(#param: #trait_path));
+ }
- cg::add_predicate(
- &mut where_clause,
- parse_quote!(
- #ty: #trait_path<#output_type_name = #output_type>
- ),
+ let mut add_field_bound = |binding: &BindingInfo| {
+ let ty = &binding.ast().ty;
+
+ let output_type = cg::map_type_params(
+ ty,
+ &params,
+ &mut |ident| parse_quote!(<#ident as #trait_path>::#output_type_name),
+ );
+
+ cg::add_predicate(
+ &mut where_clause,
+ parse_quote!(
+ #ty: #trait_path<#output_type_name = #output_type>
+ ),
+ );
+ };
+
+ let (to_body, from_body) = if params.is_empty() {
+ let mut s = synstructure::Structure::new(&input);
+ s.variants_mut().iter_mut().for_each(|v| {
+ v.bind_with(|_| bind_style);
+ });
+
+ for variant in s.variants() {
+ for binding in variant.bindings() {
+ let attrs = binding_attrs(&binding);
+ assert!(
+ !attrs.field_bound,
+ "It is default on a non-generic implementation",
);
+ if !attrs.no_field_bound {
+ // Add field bounds to all bindings except the manually
+ // excluded. This ensures the correctness of the clone() /
+ // move based implementation.
+ add_field_bound(binding);
+ }
+ }
+ }
+
+ let to_body = if moves {
+ quote! { self }
+ } else {
+ quote! { std::clone::Clone::clone(self) }
+ };
+
+ let from_body = if moves {
+ quote! { from }
+ } else {
+ quote! { std::clone::Clone::clone(from) }
+ };
+
+ (to_body, from_body)
+ } else {
+ let to_body = cg::fmap_match(&input, bind_style, |binding| {
+ let attrs = binding_attrs(&binding);
+ assert!(
+ !attrs.no_field_bound,
+ "It doesn't make sense on a generic implementation"
+ );
+ if attrs.field_bound {
+ add_field_bound(&binding);
}
call_to(&binding)
});
+
let from_body = cg::fmap_match(&input, bind_style, |binding| call_from(&binding));
+ let self_ = if moves {
+ quote! { self }
+ } else {
+ quote! { *self }
+ };
+ let from_ = if moves {
+ quote! { from }
+ } else {
+ quote! { *from }
+ };
+
+ let to_body = quote! {
+ match #self_ {
+ #to_body
+ }
+ };
+
+ let from_body = quote! {
+ match #from_ {
+ #from_body
+ }
+ };
+
(to_body, from_body)
};
@@ -101,53 +159,45 @@ pub fn derive(input: DeriveInput) -> TokenStream {
let trait_impl = |from_body, to_body| {
quote! {
#[inline]
- fn from_computed_value(computed: &Self::ComputedValue) -> Self {
- match *computed {
- #from_body
- }
+ fn from_computed_value(from: &Self::ComputedValue) -> Self {
+ #from_body
}
#[allow(unused_variables)]
#[inline]
fn to_computed_value(&self, context: &crate::values::computed::Context) -> Self::ComputedValue {
- match *self {
- #to_body
- }
+ #to_body
}
}
};
- let non_generic_implementation = || {
- Some(quote! {
- type ComputedValue = Self;
-
- #[inline]
- fn to_computed_value(&self, _: &crate::values::computed::Context) -> Self::ComputedValue {
- std::clone::Clone::clone(self)
- }
-
- #[inline]
- fn from_computed_value(computed: &Self::ComputedValue) -> Self {
- std::clone::Clone::clone(computed)
- }
- })
- };
-
derive_to_value(
input,
parse_quote!(crate::values::computed::ToComputedValue),
parse_quote!(ComputedValue),
BindStyle::Ref,
- |binding| cg::parse_field_attrs::<ComputedValueAttrs>(&binding.ast()).field_bound,
+ |binding| {
+ let attrs = cg::parse_field_attrs::<ComputedValueAttrs>(&binding.ast());
+ ToValueAttrs {
+ field_bound: attrs.field_bound,
+ no_field_bound: attrs.no_field_bound,
+ }
+ },
|binding| quote!(crate::values::computed::ToComputedValue::from_computed_value(#binding)),
|binding| quote!(crate::values::computed::ToComputedValue::to_computed_value(#binding, context)),
trait_impl,
- non_generic_implementation,
)
}
+#[derive(Default)]
+pub struct ToValueAttrs {
+ pub field_bound: bool,
+ pub no_field_bound: bool,
+}
+
#[darling(attributes(compute), default)]
#[derive(Default, FromField)]
struct ComputedValueAttrs {
field_bound: bool,
+ no_field_bound: bool,
}
diff --git a/components/style_derive/to_resolved_value.rs b/components/style_derive/to_resolved_value.rs
index 040cda954a8..f7ba2645e89 100644
--- a/components/style_derive/to_resolved_value.rs
+++ b/components/style_derive/to_resolved_value.rs
@@ -12,10 +12,8 @@ pub fn derive(input: DeriveInput) -> TokenStream {
let trait_impl = |from_body, to_body| {
quote! {
#[inline]
- fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
- match resolved {
- #from_body
- }
+ fn from_resolved_value(from: Self::ResolvedValue) -> Self {
+ #from_body
}
#[inline]
@@ -23,42 +21,26 @@ pub fn derive(input: DeriveInput) -> TokenStream {
self,
context: &crate::values::resolved::Context,
) -> Self::ResolvedValue {
- match self {
- #to_body
- }
+ #to_body
}
}
};
- let non_generic_implementation = || {
- Some(quote! {
- type ResolvedValue = Self;
-
- #[inline]
- fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
- resolved
- }
-
- #[inline]
- fn to_resolved_value(
- self,
- context: &crate::values::resolved::Context,
- ) -> Self {
- self
- }
- })
- };
-
to_computed_value::derive_to_value(
input,
parse_quote!(crate::values::resolved::ToResolvedValue),
parse_quote!(ResolvedValue),
BindStyle::Move,
- |binding| cg::parse_field_attrs::<ResolvedValueAttrs>(&binding.ast()).field_bound,
+ |binding| {
+ let attrs = cg::parse_field_attrs::<ResolvedValueAttrs>(&binding.ast());
+ to_computed_value::ToValueAttrs {
+ field_bound: attrs.field_bound,
+ no_field_bound: attrs.no_field_bound,
+ }
+ },
|binding| quote!(crate::values::resolved::ToResolvedValue::from_resolved_value(#binding)),
|binding| quote!(crate::values::resolved::ToResolvedValue::to_resolved_value(#binding, context)),
trait_impl,
- non_generic_implementation,
)
}
@@ -66,4 +48,5 @@ pub fn derive(input: DeriveInput) -> TokenStream {
#[derive(Default, FromField)]
struct ResolvedValueAttrs {
field_bound: bool,
+ no_field_bound: bool,
}
diff --git a/components/style_traits/arc_slice.rs b/components/style_traits/arc_slice.rs
index f5d0c56e7fc..8d55beff3c5 100644
--- a/components/style_traits/arc_slice.rs
+++ b/components/style_traits/arc_slice.rs
@@ -26,7 +26,7 @@ const ARC_SLICE_CANARY: u64 = 0xf3f3f3f3f3f3f3f3;
/// cbindgen:derive-eq=false
/// cbindgen:derive-neq=false
#[repr(C)]
-#[derive(Clone, Debug, Eq, PartialEq, ToShmem)]
+#[derive(Debug, Eq, PartialEq, ToShmem)]
pub struct ArcSlice<T>(#[shmem(field_bound)] ThinArc<u64, T>);
impl<T> Deref for ArcSlice<T> {
@@ -39,6 +39,12 @@ impl<T> Deref for ArcSlice<T> {
}
}
+impl<T> Clone for ArcSlice<T> {
+ fn clone(&self) -> Self {
+ ArcSlice(self.0.clone())
+ }
+}
+
lazy_static! {
// ThinArc doesn't support alignments greater than align_of::<u64>.
static ref EMPTY_ARC_SLICE: ArcSlice<u64> = {
diff --git a/components/style_traits/lib.rs b/components/style_traits/lib.rs
index 516e7b6efba..be2d275b654 100644
--- a/components/style_traits/lib.rs
+++ b/components/style_traits/lib.rs
@@ -137,6 +137,8 @@ pub enum StyleParseErrorKind<'i> {
UnexpectedNamespaceRule,
/// @import must be before any rule but @charset
UnexpectedImportRule,
+ /// @import rules are disallowed in the parser.
+ DisallowedImportRule,
/// Unexpected @charset rule encountered.
UnexpectedCharsetRule,
/// Unsupported @ rule
@@ -149,7 +151,6 @@ pub enum StyleParseErrorKind<'i> {
ValueError(ValueParseErrorKind<'i>),
/// An error was encountered while parsing a selector
SelectorError(SelectorParseErrorKind<'i>),
-
/// The property declaration was for an unknown property.
UnknownProperty(CowRcStr<'i>),
/// The property declaration was for a disabled experimental property.