Auto merge of #25299 - emilio:gecko-sync, r=emilio,nox

style: Sync changes from mozilla-central.

See individual commits for details.
This commit is contained in:
bors-servo 2019-12-16 23:51:18 -05:00 committed by GitHub
commit a8b8f46476
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
80 changed files with 770 additions and 450 deletions

69
Cargo.lock generated
View file

@ -887,7 +887,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" checksum = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b"
dependencies = [ dependencies = [
"crossbeam-utils", "crossbeam-utils",
"smallvec", "smallvec 0.6.10",
] ]
[[package]] [[package]]
@ -947,7 +947,7 @@ dependencies = [
"proc-macro2 1.0.1", "proc-macro2 1.0.1",
"quote 1.0.2", "quote 1.0.2",
"serde", "serde",
"smallvec", "smallvec 0.6.10",
"syn 1.0.3", "syn 1.0.3",
] ]
@ -1102,6 +1102,17 @@ dependencies = [
"syn 0.15.39", "syn 0.15.39",
] ]
[[package]]
name = "derive_more"
version = "0.99.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2159be042979966de68315bce7034bb000c775f22e3e834e1c52ff78f041cae8"
dependencies = [
"proc-macro2 1.0.1",
"quote 1.0.2",
"syn 1.0.3",
]
[[package]] [[package]]
name = "device" name = "device"
version = "0.0.1" version = "0.0.1"
@ -1387,7 +1398,7 @@ name = "fallible"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"hashglobe", "hashglobe",
"smallvec", "smallvec 1.0.0",
] ]
[[package]] [[package]]
@ -1609,7 +1620,7 @@ dependencies = [
"servo_arc", "servo_arc",
"servo_atoms", "servo_atoms",
"servo_url", "servo_url",
"smallvec", "smallvec 0.6.10",
"style", "style",
"time", "time",
"truetype", "truetype",
@ -1646,7 +1657,7 @@ dependencies = [
"parking_lot", "parking_lot",
"range-alloc", "range-alloc",
"raw-window-handle", "raw-window-handle",
"smallvec", "smallvec 0.6.10",
"spirv_cross", "spirv_cross",
"winapi", "winapi",
"wio", "wio",
@ -1665,7 +1676,7 @@ dependencies = [
"log", "log",
"range-alloc", "range-alloc",
"raw-window-handle", "raw-window-handle",
"smallvec", "smallvec 0.6.10",
"spirv_cross", "spirv_cross",
"winapi", "winapi",
] ]
@ -1702,7 +1713,7 @@ dependencies = [
"parking_lot", "parking_lot",
"range-alloc", "range-alloc",
"raw-window-handle", "raw-window-handle",
"smallvec", "smallvec 0.6.10",
"spirv_cross", "spirv_cross",
"storage-map", "storage-map",
] ]
@ -1722,7 +1733,7 @@ dependencies = [
"log", "log",
"objc", "objc",
"raw-window-handle", "raw-window-handle",
"smallvec", "smallvec 0.6.10",
"winapi", "winapi",
"x11", "x11",
] ]
@ -1735,7 +1746,7 @@ checksum = "7c88981665c780447bb08eb099e1ded330754a7246719bab927ee4a949c0ba7f"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"raw-window-handle", "raw-window-handle",
"smallvec", "smallvec 0.6.10",
] ]
[[package]] [[package]]
@ -2706,7 +2717,7 @@ dependencies = [
"servo_geometry", "servo_geometry",
"servo_url", "servo_url",
"size_of_test", "size_of_test",
"smallvec", "smallvec 0.6.10",
"style", "style",
"style_traits", "style_traits",
"unicode-bidi", "unicode-bidi",
@ -2938,7 +2949,7 @@ dependencies = [
"rust-webvr", "rust-webvr",
"servo-egl", "servo-egl",
"simpleservo", "simpleservo",
"smallvec", "smallvec 0.6.10",
"webxr", "webxr",
"webxr-api", "webxr-api",
] ]
@ -3137,7 +3148,7 @@ dependencies = [
"serde_bytes", "serde_bytes",
"servo_arc", "servo_arc",
"smallbitvec", "smallbitvec",
"smallvec", "smallvec 1.0.0",
"string_cache", "string_cache",
"thin-slice", "thin-slice",
"time", "time",
@ -3812,7 +3823,7 @@ dependencies = [
"libc", "libc",
"redox_syscall", "redox_syscall",
"rustc_version", "rustc_version",
"smallvec", "smallvec 0.6.10",
"winapi", "winapi",
] ]
@ -4307,7 +4318,7 @@ dependencies = [
"gfx-hal", "gfx-hal",
"log", "log",
"relevant", "relevant",
"smallvec", "smallvec 0.6.10",
] ]
[[package]] [[package]]
@ -4322,7 +4333,7 @@ dependencies = [
"log", "log",
"relevant", "relevant",
"slab", "slab",
"smallvec", "smallvec 0.6.10",
] ]
[[package]] [[package]]
@ -4514,7 +4525,7 @@ dependencies = [
"servo_geometry", "servo_geometry",
"servo_rand", "servo_rand",
"servo_url", "servo_url",
"smallvec", "smallvec 0.6.10",
"sparkle", "sparkle",
"style", "style",
"style_traits", "style_traits",
@ -4633,7 +4644,7 @@ version = "0.21.0"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cssparser", "cssparser",
"derive_more", "derive_more 0.99.2",
"fxhash", "fxhash",
"log", "log",
"matches", "matches",
@ -4641,7 +4652,7 @@ dependencies = [
"phf_codegen", "phf_codegen",
"precomputed-hash", "precomputed-hash",
"servo_arc", "servo_arc",
"smallvec", "smallvec 1.0.0",
"thin-slice", "thin-slice",
"to_shmem", "to_shmem",
"to_shmem_derive", "to_shmem_derive",
@ -4836,7 +4847,7 @@ dependencies = [
"servo-media-player", "servo-media-player",
"servo-media-traits", "servo-media-traits",
"servo_media_derive", "servo_media_derive",
"smallvec", "smallvec 0.6.10",
] ]
[[package]] [[package]]
@ -5223,6 +5234,12 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "smallvec"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ecf3b85f68e8abaa7555aa5abdb1153079387e60b718283d732f03897fcfc86"
[[package]] [[package]]
name = "smithay-client-toolkit" name = "smithay-client-toolkit"
version = "0.4.6" version = "0.4.6"
@ -5351,7 +5368,7 @@ dependencies = [
"byteorder", "byteorder",
"crossbeam-channel", "crossbeam-channel",
"cssparser", "cssparser",
"derive_more", "derive_more 0.99.2",
"encoding_rs", "encoding_rs",
"euclid", "euclid",
"fallible", "fallible",
@ -5384,7 +5401,7 @@ dependencies = [
"servo_config", "servo_config",
"servo_url", "servo_url",
"smallbitvec", "smallbitvec",
"smallvec", "smallvec 1.0.0",
"string_cache", "string_cache",
"style_derive", "style_derive",
"style_traits", "style_traits",
@ -5689,7 +5706,7 @@ dependencies = [
"cssparser", "cssparser",
"servo_arc", "servo_arc",
"smallbitvec", "smallbitvec",
"smallvec", "smallvec 1.0.0",
"string_cache", "string_cache",
"thin-slice", "thin-slice",
] ]
@ -6279,7 +6296,7 @@ dependencies = [
"malloc_size_of", "malloc_size_of",
"serde", "serde",
"servo_config", "servo_config",
"smallvec", "smallvec 0.6.10",
"wgpu-core", "wgpu-core",
] ]
@ -6314,7 +6331,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"sha2", "sha2",
"smallvec", "smallvec 0.6.10",
"svg_fmt", "svg_fmt",
"thread_profiler", "thread_profiler",
"time", "time",
@ -6334,7 +6351,7 @@ dependencies = [
"byteorder", "byteorder",
"core-foundation", "core-foundation",
"core-graphics", "core-graphics",
"derive_more", "derive_more 0.13.0",
"euclid", "euclid",
"malloc_size_of_derive", "malloc_size_of_derive",
"peek-poke", "peek-poke",
@ -6443,7 +6460,7 @@ dependencies = [
"rendy-descriptor", "rendy-descriptor",
"rendy-memory", "rendy-memory",
"serde", "serde",
"smallvec", "smallvec 0.6.10",
"vec_map", "vec_map",
] ]

View file

@ -10,7 +10,7 @@ name = "fallible"
path = "lib.rs" path = "lib.rs"
[dependencies] [dependencies]
smallvec = "0.6" smallvec = "1.0"
hashglobe = { path = "../hashglobe" } hashglobe = { path = "../hashglobe" }
# This crate effectively does nothing except if the `known_system_malloc` # This crate effectively does nothing except if the `known_system_malloc`

View file

@ -131,7 +131,7 @@ impl<'a> From<&'a FontStyleStruct> for FontDescriptor {
FontDescriptor { FontDescriptor {
template_descriptor: FontTemplateDescriptor::from(style), template_descriptor: FontTemplateDescriptor::from(style),
variant: style.font_variant_caps, variant: style.font_variant_caps,
pt_size: style.font_size.size(), pt_size: Au::from_f32_px(style.font_size.size().px()),
} }
} }
} }

View file

@ -95,7 +95,7 @@ impl<S: FontSource> FontContext<S> {
self.expire_font_caches_if_necessary(); self.expire_font_caches_if_necessary();
let cache_key = FontGroupCacheKey { let cache_key = FontGroupCacheKey {
size: style.font_size.size(), size: Au::from_f32_px(style.font_size.size().px()),
style, style,
}; };

View file

@ -2029,7 +2029,7 @@ impl BlockFlow {
// If `max-width` is set, then don't perform this speculation. We guess that the // If `max-width` is set, then don't perform this speculation. We guess that the
// page set `max-width` in order to avoid hitting floats. The search box on Google // page set `max-width` in order to avoid hitting floats. The search box on Google
// SERPs falls into this category. // SERPs falls into this category.
if self.fragment.style.max_inline_size() != MaxSize::None { if !matches!(self.fragment.style.max_inline_size(), MaxSize::None) {
return; return;
} }
@ -2548,8 +2548,16 @@ impl Flow for BlockFlow {
.base .base
.flags .flags
.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) && .contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) &&
self.fragment.style().logical_position().inline_start == LengthPercentageOrAuto::Auto && self.fragment
self.fragment.style().logical_position().inline_end == LengthPercentageOrAuto::Auto .style()
.logical_position()
.inline_start
.is_auto() &&
self.fragment
.style()
.logical_position()
.inline_end
.is_auto()
{ {
self.base.position.start.i = inline_position self.base.position.start.i = inline_position
} }
@ -2560,8 +2568,12 @@ impl Flow for BlockFlow {
.base .base
.flags .flags
.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) && .contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) &&
self.fragment.style().logical_position().block_start == LengthPercentageOrAuto::Auto && self.fragment
self.fragment.style().logical_position().block_end == LengthPercentageOrAuto::Auto .style()
.logical_position()
.block_start
.is_auto() &&
self.fragment.style().logical_position().block_end.is_auto()
{ {
self.base.position.start.b = block_position self.base.position.start.b = block_position
} }
@ -2848,16 +2860,15 @@ pub trait ISizeAndMarginsComputer {
parent_flow_inline_size: Au, parent_flow_inline_size: Au,
shared_context: &SharedStyleContext, shared_context: &SharedStyleContext,
) -> MaybeAuto { ) -> MaybeAuto {
let inline_size =
self.containing_block_inline_size(block, parent_flow_inline_size, shared_context);
MaybeAuto::from_option( MaybeAuto::from_option(
block block
.fragment() .fragment()
.style() .style()
.content_inline_size() .content_inline_size()
.to_used_value(self.containing_block_inline_size( .to_used_value(inline_size),
block,
parent_flow_inline_size,
shared_context,
)),
) )
} }

View file

@ -47,7 +47,7 @@ pub fn get_cyclic<T>(arr: &[T], index: usize) -> &T {
/// For a given area and an image compute how big the /// For a given area and an image compute how big the
/// image should be displayed on the background. /// image should be displayed on the background.
fn compute_background_image_size( fn compute_background_image_size(
bg_size: BackgroundSize, bg_size: &BackgroundSize,
bounds_size: Size2D<Au>, bounds_size: Size2D<Au>,
intrinsic_size: Option<Size2D<Au>>, intrinsic_size: Option<Size2D<Au>>,
) -> Size2D<Au> { ) -> Size2D<Au> {
@ -156,7 +156,7 @@ pub fn placement(
let bg_position_x = get_cyclic(&bg.background_position_x.0, index); let bg_position_x = get_cyclic(&bg.background_position_x.0, index);
let bg_position_y = get_cyclic(&bg.background_position_y.0, index); let bg_position_y = get_cyclic(&bg.background_position_y.0, index);
let bg_repeat = get_cyclic(&bg.background_repeat.0, index); let bg_repeat = get_cyclic(&bg.background_repeat.0, index);
let bg_size = *get_cyclic(&bg.background_size.0, index); let bg_size = get_cyclic(&bg.background_size.0, index);
let (clip_rect, clip_radii) = clip( let (clip_rect, clip_radii) = clip(
bg_clip, bg_clip,

View file

@ -25,7 +25,7 @@ use webrender_api::{BorderRadius, BorderSide, BorderStyle, ColorF, NormalBorder}
/// ///
/// [1]: https://drafts.csswg.org/css-backgrounds-3/#border-radius /// [1]: https://drafts.csswg.org/css-backgrounds-3/#border-radius
fn corner_radius( fn corner_radius(
radius: BorderCornerRadius, radius: &BorderCornerRadius,
containing_size: UntypedSize2D<Au>, containing_size: UntypedSize2D<Au>,
) -> UntypedSize2D<Au> { ) -> UntypedSize2D<Au> {
let w = radius.0.width().to_used_value(containing_size.width); let w = radius.0.width().to_used_value(containing_size.width);
@ -91,13 +91,13 @@ pub fn radii(abs_bounds: Rect<Au>, border_style: &Border) -> BorderRadius {
overlapping_radii( overlapping_radii(
abs_bounds.size.to_layout(), abs_bounds.size.to_layout(),
BorderRadius { BorderRadius {
top_left: corner_radius(border_style.border_top_left_radius, abs_bounds.size) top_left: corner_radius(&border_style.border_top_left_radius, abs_bounds.size)
.to_layout(), .to_layout(),
top_right: corner_radius(border_style.border_top_right_radius, abs_bounds.size) top_right: corner_radius(&border_style.border_top_right_radius, abs_bounds.size)
.to_layout(), .to_layout(),
bottom_right: corner_radius(border_style.border_bottom_right_radius, abs_bounds.size) bottom_right: corner_radius(&border_style.border_bottom_right_radius, abs_bounds.size)
.to_layout(), .to_layout(),
bottom_left: corner_radius(border_style.border_bottom_left_radius, abs_bounds.size) bottom_left: corner_radius(&border_style.border_bottom_left_radius, abs_bounds.size)
.to_layout(), .to_layout(),
}, },
) )
@ -161,7 +161,7 @@ pub fn image_outset(
} }
fn side_image_width( fn side_image_width(
border_image_width: BorderImageSideWidth, border_image_width: &BorderImageSideWidth,
border_width: f32, border_width: f32,
total_length: Au, total_length: Au,
) -> f32 { ) -> f32 {
@ -178,10 +178,10 @@ pub fn image_width(
border_area: UntypedSize2D<Au>, border_area: UntypedSize2D<Au>,
) -> LayoutSideOffsets { ) -> LayoutSideOffsets {
LayoutSideOffsets::new( LayoutSideOffsets::new(
side_image_width(width.0, border.top, border_area.height), side_image_width(&width.0, border.top, border_area.height),
side_image_width(width.1, border.right, border_area.width), side_image_width(&width.1, border.right, border_area.width),
side_image_width(width.2, border.bottom, border_area.height), side_image_width(&width.2, border.bottom, border_area.height),
side_image_width(width.3, border.left, border_area.width), side_image_width(&width.3, border.left, border_area.width),
) )
} }

View file

@ -995,7 +995,7 @@ impl Fragment {
}; };
DisplayItem::Gradient(CommonDisplayItem::with_data(base, item, stops)) DisplayItem::Gradient(CommonDisplayItem::with_data(base, item, stops))
}, },
GradientKind::Radial(shape, center) => { GradientKind::Radial(ref shape, ref center) => {
let (gradient, stops) = gradient::radial( let (gradient, stops) = gradient::radial(
style, style,
placement.tile_size, placement.tile_size,
@ -1238,7 +1238,7 @@ impl Fragment {
stops = linear_stops; stops = linear_stops;
NinePatchBorderSource::Gradient(wr_gradient) NinePatchBorderSource::Gradient(wr_gradient)
}, },
GradientKind::Radial(shape, center) => { GradientKind::Radial(ref shape, ref center) => {
let (wr_gradient, radial_stops) = gradient::radial( let (wr_gradient, radial_stops) = gradient::radial(
style, style,
border_image_area, border_image_area,

View file

@ -91,9 +91,12 @@ fn convert_gradient_stops(
color, color,
position: None, position: None,
}), }),
GradientItem::ComplexColorStop { color, position } => Some(ColorStop { GradientItem::ComplexColorStop {
color, color,
position: Some(position), ref position,
} => Some(ColorStop {
color,
position: Some(position.clone()),
}), }),
_ => None, _ => None,
}) })
@ -122,15 +125,24 @@ fn convert_gradient_stops(
// Step 2: Move any stops placed before earlier stops to the // Step 2: Move any stops placed before earlier stops to the
// same position as the preceding stop. // same position as the preceding stop.
let mut last_stop_position = stop_items.first().unwrap().position.unwrap(); //
// FIXME(emilio): Once we know the offsets, it seems like converting the
// positions to absolute at once then process that would be cheaper.
let mut last_stop_position = stop_items
.first()
.unwrap()
.position
.as_ref()
.unwrap()
.clone();
for stop in stop_items.iter_mut().skip(1) { for stop in stop_items.iter_mut().skip(1) {
if let Some(pos) = stop.position { if let Some(ref pos) = stop.position {
if position_to_offset(last_stop_position, total_length) > if position_to_offset(&last_stop_position, total_length) >
position_to_offset(pos, total_length) position_to_offset(pos, total_length)
{ {
stop.position = Some(last_stop_position); stop.position = Some(last_stop_position);
} }
last_stop_position = stop.position.unwrap(); last_stop_position = stop.position.as_ref().unwrap().clone();
} }
} }
@ -144,8 +156,10 @@ fn convert_gradient_stops(
// Initialize a new stop run. // Initialize a new stop run.
// `unwrap()` here should never fail because this is the beginning of // `unwrap()` here should never fail because this is the beginning of
// a stop run, which is always bounded by a length or percentage. // a stop run, which is always bounded by a length or percentage.
let start_offset = let start_offset = position_to_offset(
position_to_offset(stop_items[i - 1].position.unwrap(), total_length); stop_items[i - 1].position.as_ref().unwrap(),
total_length,
);
// `unwrap()` here should never fail because this is the end of // `unwrap()` here should never fail because this is the end of
// a stop run, which is always bounded by a length or percentage. // a stop run, which is always bounded by a length or percentage.
let (end_index, end_stop) = stop_items[(i + 1)..] let (end_index, end_stop) = stop_items[(i + 1)..]
@ -153,7 +167,8 @@ fn convert_gradient_stops(
.enumerate() .enumerate()
.find(|&(_, ref stop)| stop.position.is_some()) .find(|&(_, ref stop)| stop.position.is_some())
.unwrap(); .unwrap();
let end_offset = position_to_offset(end_stop.position.unwrap(), total_length); let end_offset =
position_to_offset(end_stop.position.as_ref().unwrap(), total_length);
stop_run = Some(StopRun { stop_run = Some(StopRun {
start_offset, start_offset,
end_offset, end_offset,
@ -168,7 +183,7 @@ fn convert_gradient_stops(
stop_run_length * (i - stop_run.start_index) as f32 / stop_run_length * (i - stop_run.start_index) as f32 /
((2 + stop_run.stop_count) as f32) ((2 + stop_run.stop_count) as f32)
}, },
Some(position) => { Some(ref position) => {
stop_run = None; stop_run = None;
position_to_offset(position, total_length) position_to_offset(position, total_length)
}, },
@ -212,7 +227,7 @@ where
Size2D::new(cmp(left_side, right_side), cmp(top_side, bottom_side)) Size2D::new(cmp(left_side, right_side), cmp(top_side, bottom_side))
} }
fn position_to_offset(position: LengthPercentage, total_length: Au) -> f32 { fn position_to_offset(position: &LengthPercentage, total_length: Au) -> f32 {
if total_length == Au(0) { if total_length == Au(0) {
return 0.0; return 0.0;
} }
@ -289,8 +304,8 @@ pub fn radial(
style: &ComputedValues, style: &ComputedValues,
size: Size2D<Au>, size: Size2D<Au>,
stops: &[GradientItem], stops: &[GradientItem],
shape: EndingShape, shape: &EndingShape,
center: Position, center: &Position,
repeating: bool, repeating: bool,
) -> (RadialGradient, Vec<GradientStop>) { ) -> (RadialGradient, Vec<GradientStop>) {
let center = Point2D::new( let center = Point2D::new(
@ -299,15 +314,15 @@ pub fn radial(
); );
let radius = match shape { let radius = match shape {
EndingShape::Circle(Circle::Radius(length)) => { EndingShape::Circle(Circle::Radius(length)) => {
let length = Au::from(length); let length = Au::from(*length);
Size2D::new(length, length) Size2D::new(length, length)
}, },
EndingShape::Circle(Circle::Extent(extent)) => circle_size_keyword(extent, &size, &center), EndingShape::Circle(Circle::Extent(extent)) => circle_size_keyword(*extent, &size, &center),
EndingShape::Ellipse(Ellipse::Radii(x, y)) => { EndingShape::Ellipse(Ellipse::Radii(x, y)) => {
Size2D::new(x.to_used_value(size.width), y.to_used_value(size.height)) Size2D::new(x.to_used_value(size.width), y.to_used_value(size.height))
}, },
EndingShape::Ellipse(Ellipse::Extent(extent)) => { EndingShape::Ellipse(Ellipse::Extent(extent)) => {
ellipse_size_keyword(extent, &size, &center) ellipse_size_keyword(*extent, &size, &center)
}, },
}; };

View file

@ -43,7 +43,7 @@ enum AxisSize {
impl AxisSize { impl AxisSize {
/// Generate a new available cross or main axis size from the specified size of the container, /// Generate a new available cross or main axis size from the specified size of the container,
/// containing block size, min constraint, and max constraint /// containing block size, min constraint, and max constraint
pub fn new(size: Size, content_size: Option<Au>, min: Size, max: MaxSize) -> AxisSize { pub fn new(size: &Size, content_size: Option<Au>, min: &Size, max: &MaxSize) -> AxisSize {
match size { match size {
Size::Auto => AxisSize::MinMax(SizeConstraint::new(content_size, min, max, None)), Size::Auto => AxisSize::MinMax(SizeConstraint::new(content_size, min, max, None)),
Size::LengthPercentage(ref lp) => match lp.maybe_to_used_value(content_size) { Size::LengthPercentage(ref lp) => match lp.maybe_to_used_value(content_size) {
@ -58,10 +58,10 @@ impl AxisSize {
/// and the container size, then return the used value of flex basis. it can be used to help /// and the container size, then return the used value of flex basis. it can be used to help
/// determining the flex base size and to indicate whether the main size of the item /// determining the flex base size and to indicate whether the main size of the item
/// is definite after flex size resolving. /// is definite after flex size resolving.
fn from_flex_basis(flex_basis: FlexBasis, main_length: Size, containing_length: Au) -> MaybeAuto { fn from_flex_basis(flex_basis: &FlexBasis, main_length: &Size, containing_length: Au) -> MaybeAuto {
let width = match flex_basis { let width = match flex_basis {
FlexBasis::Content => return MaybeAuto::Auto, FlexBasis::Content => return MaybeAuto::Auto,
FlexBasis::Size(width) => width, FlexBasis::Size(ref width) => width,
}; };
let width = match width { let width = match width {
@ -135,7 +135,7 @@ impl FlexItem {
// https://drafts.csswg.org/css-flexbox-1/#min-size-auto // https://drafts.csswg.org/css-flexbox-1/#min-size-auto
Direction::Inline => { Direction::Inline => {
let basis = from_flex_basis( let basis = from_flex_basis(
block.fragment.style.get_position().flex_basis, &block.fragment.style.get_position().flex_basis,
block.fragment.style.content_inline_size(), block.fragment.style.content_inline_size(),
containing_length, containing_length,
); );
@ -170,7 +170,7 @@ impl FlexItem {
}, },
Direction::Block => { Direction::Block => {
let basis = from_flex_basis( let basis = from_flex_basis(
block.fragment.style.get_position().flex_basis, &block.fragment.style.get_position().flex_basis,
block.fragment.style.content_block_size(), block.fragment.style.content_block_size(),
containing_length, containing_length,
); );
@ -452,7 +452,7 @@ impl FlexFlow {
fn inline_mode_bubble_inline_sizes(&mut self) { fn inline_mode_bubble_inline_sizes(&mut self) {
// FIXME(emilio): This doesn't handle at all writing-modes. // FIXME(emilio): This doesn't handle at all writing-modes.
let fixed_width = let fixed_width =
!model::style_length(self.block_flow.fragment.style().get_position().width, None) !model::style_length(&self.block_flow.fragment.style().get_position().width, None)
.is_auto(); .is_auto();
let mut computation = self.block_flow.fragment.compute_intrinsic_inline_sizes(); let mut computation = self.block_flow.fragment.compute_intrinsic_inline_sizes();
@ -478,7 +478,7 @@ impl FlexFlow {
// stripped out. // stripped out.
fn block_mode_bubble_inline_sizes(&mut self) { fn block_mode_bubble_inline_sizes(&mut self) {
let fixed_width = let fixed_width =
!model::style_length(self.block_flow.fragment.style().get_position().width, None) !model::style_length(&self.block_flow.fragment.style().get_position().width, None)
.is_auto(); .is_auto();
let mut computation = self.block_flow.fragment.compute_intrinsic_inline_sizes(); let mut computation = self.block_flow.fragment.compute_intrinsic_inline_sizes();
@ -960,9 +960,9 @@ impl Flow for FlexFlow {
let style = &self.block_flow.fragment.style; let style = &self.block_flow.fragment.style;
let (specified_block_size, specified_inline_size) = if style.writing_mode.is_vertical() let (specified_block_size, specified_inline_size) = if style.writing_mode.is_vertical()
{ {
(style.get_position().width, style.get_position().height) (&style.get_position().width, &style.get_position().height)
} else { } else {
(style.get_position().height, style.get_position().width) (&style.get_position().height, &style.get_position().width)
}; };
let available_inline_size = AxisSize::new( let available_inline_size = AxisSize::new(

View file

@ -64,7 +64,6 @@ use style::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::selector_parser::RestyleDamage; use style::selector_parser::RestyleDamage;
use style::servo::restyle_damage::ServoRestyleDamage; use style::servo::restyle_damage::ServoRestyleDamage;
use style::values::computed::LengthPercentageOrAuto;
use webrender_api::units::LayoutTransform; use webrender_api::units::LayoutTransform;
/// This marker trait indicates that a type is a struct with `#[repr(C)]` whose first field /// This marker trait indicates that a type is a struct with `#[repr(C)]` whose first field
@ -1020,13 +1019,13 @@ impl BaseFlow {
flags.insert(FlowFlags::IS_ABSOLUTELY_POSITIONED); flags.insert(FlowFlags::IS_ABSOLUTELY_POSITIONED);
let logical_position = style.logical_position(); let logical_position = style.logical_position();
if logical_position.inline_start == LengthPercentageOrAuto::Auto && if logical_position.inline_start.is_auto() &&
logical_position.inline_end == LengthPercentageOrAuto::Auto logical_position.inline_end.is_auto()
{ {
flags.insert(FlowFlags::INLINE_POSITION_IS_STATIC); flags.insert(FlowFlags::INLINE_POSITION_IS_STATIC);
} }
if logical_position.block_start == LengthPercentageOrAuto::Auto && if logical_position.block_start.is_auto() &&
logical_position.block_end == LengthPercentageOrAuto::Auto logical_position.block_end.is_auto()
{ {
flags.insert(FlowFlags::BLOCK_POSITION_IS_STATIC); flags.insert(FlowFlags::BLOCK_POSITION_IS_STATIC);
} }
@ -1113,13 +1112,12 @@ impl BaseFlow {
let logical_position = style.logical_position(); let logical_position = style.logical_position();
self.flags.set( self.flags.set(
FlowFlags::INLINE_POSITION_IS_STATIC, FlowFlags::INLINE_POSITION_IS_STATIC,
logical_position.inline_start == LengthPercentageOrAuto::Auto && logical_position.inline_start.is_auto() &&
logical_position.inline_end == LengthPercentageOrAuto::Auto, logical_position.inline_end.is_auto(),
); );
self.flags.set( self.flags.set(
FlowFlags::BLOCK_POSITION_IS_STATIC, FlowFlags::BLOCK_POSITION_IS_STATIC,
logical_position.block_start == LengthPercentageOrAuto::Auto && logical_position.block_start.is_auto() && logical_position.block_end.is_auto(),
logical_position.block_end == LengthPercentageOrAuto::Auto,
); );
} }
} }

View file

@ -61,10 +61,9 @@ use style::selector_parser::RestyleDamage;
use style::servo::restyle_damage::ServoRestyleDamage; use style::servo::restyle_damage::ServoRestyleDamage;
use style::str::char_is_whitespace; use style::str::char_is_whitespace;
use style::values::computed::counters::ContentItem; use style::values::computed::counters::ContentItem;
use style::values::computed::{LengthPercentage, LengthPercentageOrAuto, Size, VerticalAlign}; use style::values::computed::{Size, VerticalAlign};
use style::values::generics::box_::{Perspective, VerticalAlignKeyword}; use style::values::generics::box_::{Perspective, VerticalAlignKeyword};
use style::values::generics::transform; use style::values::generics::transform;
use style::Zero;
use webrender_api; use webrender_api;
use webrender_api::units::LayoutTransform; use webrender_api::units::LayoutTransform;
@ -1329,13 +1328,17 @@ impl Fragment {
return; return;
}, },
_ => { _ => {
let (inline_start, inline_end) = {
let margin = self.style().logical_margin(); let margin = self.style().logical_margin();
self.margin.inline_start = (
MaybeAuto::from_style(margin.inline_start, containing_block_inline_size) MaybeAuto::from_style(margin.inline_start, containing_block_inline_size)
.specified_or_zero(); .specified_or_zero(),
self.margin.inline_end =
MaybeAuto::from_style(margin.inline_end, containing_block_inline_size) MaybeAuto::from_style(margin.inline_end, containing_block_inline_size)
.specified_or_zero(); .specified_or_zero(),
)
};
self.margin.inline_start = inline_start;
self.margin.inline_end = inline_end;
}, },
} }
@ -1384,13 +1387,17 @@ impl Fragment {
_ => { _ => {
// NB: Percentages are relative to containing block inline-size (not block-size) // NB: Percentages are relative to containing block inline-size (not block-size)
// per CSS 2.1. // per CSS 2.1.
let (block_start, block_end) = {
let margin = self.style().logical_margin(); let margin = self.style().logical_margin();
self.margin.block_start = (
MaybeAuto::from_style(margin.block_start, containing_block_inline_size) MaybeAuto::from_style(margin.block_start, containing_block_inline_size)
.specified_or_zero(); .specified_or_zero(),
self.margin.block_end =
MaybeAuto::from_style(margin.block_end, containing_block_inline_size) MaybeAuto::from_style(margin.block_end, containing_block_inline_size)
.specified_or_zero(); .specified_or_zero(),
)
};
self.margin.block_start = block_start;
self.margin.block_end = block_end;
}, },
} }
} }
@ -1458,14 +1465,14 @@ impl Fragment {
pub fn relative_position(&self, containing_block_size: &LogicalSize<Au>) -> LogicalSize<Au> { pub fn relative_position(&self, containing_block_size: &LogicalSize<Au>) -> LogicalSize<Au> {
fn from_style(style: &ComputedValues, container_size: &LogicalSize<Au>) -> LogicalSize<Au> { fn from_style(style: &ComputedValues, container_size: &LogicalSize<Au>) -> LogicalSize<Au> {
let offsets = style.logical_position(); let offsets = style.logical_position();
let offset_i = if offsets.inline_start != LengthPercentageOrAuto::Auto { let offset_i = if !offsets.inline_start.is_auto() {
MaybeAuto::from_style(offsets.inline_start, container_size.inline) MaybeAuto::from_style(offsets.inline_start, container_size.inline)
.specified_or_zero() .specified_or_zero()
} else { } else {
-MaybeAuto::from_style(offsets.inline_end, container_size.inline) -MaybeAuto::from_style(offsets.inline_end, container_size.inline)
.specified_or_zero() .specified_or_zero()
}; };
let offset_b = if offsets.block_start != LengthPercentageOrAuto::Auto { let offset_b = if !offsets.block_start.is_auto() {
MaybeAuto::from_style(offsets.block_start, container_size.block).specified_or_zero() MaybeAuto::from_style(offsets.block_start, container_size.block).specified_or_zero()
} else { } else {
-MaybeAuto::from_style(offsets.block_end, container_size.block).specified_or_zero() -MaybeAuto::from_style(offsets.block_end, container_size.block).specified_or_zero()
@ -2520,13 +2527,19 @@ impl Fragment {
{ {
continue; continue;
} }
if inline_context_node.style.logical_margin().inline_end != if !inline_context_node
LengthPercentageOrAuto::zero() .style
.logical_margin()
.inline_end
.is_definitely_zero()
{ {
return false; return false;
} }
if inline_context_node.style.logical_padding().inline_end != if !inline_context_node
LengthPercentage::zero() .style
.logical_padding()
.inline_end
.is_definitely_zero()
{ {
return false; return false;
} }
@ -2546,13 +2559,19 @@ impl Fragment {
{ {
continue; continue;
} }
if inline_context_node.style.logical_margin().inline_start != if !inline_context_node
LengthPercentageOrAuto::zero() .style
.logical_margin()
.inline_start
.is_definitely_zero()
{ {
return false; return false;
} }
if inline_context_node.style.logical_padding().inline_start != if !inline_context_node
LengthPercentage::zero() .style
.logical_padding()
.inline_start
.is_definitely_zero()
{ {
return false; return false;
} }
@ -3193,7 +3212,7 @@ impl Fragment {
) -> Option<LayoutTransform> { ) -> Option<LayoutTransform> {
match self.style().get_box().perspective { match self.style().get_box().perspective {
Perspective::Length(length) => { Perspective::Length(length) => {
let perspective_origin = self.style().get_box().perspective_origin; let perspective_origin = &self.style().get_box().perspective_origin;
let perspective_origin = Point2D::new( let perspective_origin = Point2D::new(
perspective_origin perspective_origin
.horizontal .horizontal

View file

@ -1275,7 +1275,7 @@ impl InlineFlow {
&mut line_metrics, &mut line_metrics,
&inline_metrics, &inline_metrics,
style.get_box().display, style.get_box().display,
VerticalAlign::baseline(), &VerticalAlign::baseline(),
&mut largest_block_size_for_top_fragments, &mut largest_block_size_for_top_fragments,
&mut largest_block_size_for_bottom_fragments, &mut largest_block_size_for_bottom_fragments,
); );
@ -1296,7 +1296,7 @@ impl InlineFlow {
&mut line_metrics, &mut line_metrics,
&inline_metrics, &inline_metrics,
node.style.get_box().display, node.style.get_box().display,
node.style.get_box().vertical_align, &node.style.get_box().vertical_align,
&mut largest_block_size_for_top_fragments, &mut largest_block_size_for_top_fragments,
&mut largest_block_size_for_bottom_fragments, &mut largest_block_size_for_bottom_fragments,
); );
@ -1318,7 +1318,7 @@ impl InlineFlow {
line_metrics: &mut LineMetrics, line_metrics: &mut LineMetrics,
inline_metrics: &InlineMetrics, inline_metrics: &InlineMetrics,
display_value: Display, display_value: Display,
vertical_align_value: VerticalAlign, vertical_align_value: &VerticalAlign,
largest_block_size_for_top_fragments: &mut Au, largest_block_size_for_top_fragments: &mut Au,
largest_block_size_for_bottom_fragments: &mut Au, largest_block_size_for_bottom_fragments: &mut Au,
) { ) {

View file

@ -3,6 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#![deny(unsafe_code)] #![deny(unsafe_code)]
#![feature(matches_macro)]
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;

View file

@ -437,7 +437,7 @@ pub enum MaybeAuto {
impl MaybeAuto { impl MaybeAuto {
#[inline] #[inline]
pub fn from_style(length: LengthPercentageOrAuto, containing_length: Au) -> MaybeAuto { pub fn from_style(length: &LengthPercentageOrAuto, containing_length: Au) -> MaybeAuto {
match length { match length {
LengthPercentageOrAuto::Auto => MaybeAuto::Auto, LengthPercentageOrAuto::Auto => MaybeAuto::Auto,
LengthPercentageOrAuto::LengthPercentage(ref lp) => { LengthPercentageOrAuto::LengthPercentage(ref lp) => {
@ -498,7 +498,7 @@ impl MaybeAuto {
/// Receive an optional container size and return used value for width or height. /// Receive an optional container size and return used value for width or height.
/// ///
/// `style_length`: content size as given in the CSS. /// `style_length`: content size as given in the CSS.
pub fn style_length(style_length: Size, container_size: Option<Au>) -> MaybeAuto { pub fn style_length(style_length: &Size, container_size: Option<Au>) -> MaybeAuto {
match style_length { match style_length {
Size::Auto => MaybeAuto::Auto, Size::Auto => MaybeAuto::Auto,
Size::LengthPercentage(ref lp) => { Size::LengthPercentage(ref lp) => {
@ -546,10 +546,10 @@ pub fn specified_margin_from_style(
LogicalMargin::from_physical( LogicalMargin::from_physical(
writing_mode, writing_mode,
SideOffsets2D::new( SideOffsets2D::new(
MaybeAuto::from_style(margin_style.margin_top, Au(0)).specified_or_zero(), MaybeAuto::from_style(&margin_style.margin_top, Au(0)).specified_or_zero(),
MaybeAuto::from_style(margin_style.margin_right, Au(0)).specified_or_zero(), MaybeAuto::from_style(&margin_style.margin_right, Au(0)).specified_or_zero(),
MaybeAuto::from_style(margin_style.margin_bottom, Au(0)).specified_or_zero(), MaybeAuto::from_style(&margin_style.margin_bottom, Au(0)).specified_or_zero(),
MaybeAuto::from_style(margin_style.margin_left, Au(0)).specified_or_zero(), MaybeAuto::from_style(&margin_style.margin_left, Au(0)).specified_or_zero(),
), ),
) )
} }
@ -568,8 +568,8 @@ impl SizeConstraint {
/// Create a `SizeConstraint` for an axis. /// Create a `SizeConstraint` for an axis.
pub fn new( pub fn new(
container_size: Option<Au>, container_size: Option<Au>,
min_size: Size, min_size: &Size,
max_size: MaxSize, max_size: &MaxSize,
border: Option<Au>, border: Option<Au>,
) -> SizeConstraint { ) -> SizeConstraint {
let mut min_size = match min_size { let mut min_size = match min_size {

View file

@ -102,14 +102,14 @@ impl Flow for MulticolFlow {
let column_width; let column_width;
{ {
let style = &self.block_flow.fragment.style; let style = &self.block_flow.fragment.style;
let column_gap = match style.get_position().column_gap { let column_gap = Au::from(match style.get_position().column_gap {
NonNegativeLengthPercentageOrNormal::LengthPercentage(len) => { NonNegativeLengthPercentageOrNormal::LengthPercentage(ref len) => {
len.0.to_pixel_length(content_inline_size).into() len.0.to_pixel_length(content_inline_size)
}, },
NonNegativeLengthPercentageOrNormal::Normal => { NonNegativeLengthPercentageOrNormal::Normal => {
self.block_flow.fragment.style.get_font().font_size.size() self.block_flow.fragment.style.get_font().font_size.size()
}, },
}; });
let column_style = style.get_column(); let column_style = style.get_column();
let mut column_count; let mut column_count;

View file

@ -76,7 +76,7 @@ impl Flow for TableColGroupFlow {
// Retrieve the specified value from the appropriate CSS property. // Retrieve the specified value from the appropriate CSS property.
let inline_size = fragment.style().content_inline_size(); let inline_size = fragment.style().content_inline_size();
for _ in 0..fragment.column_span() { for _ in 0..fragment.column_span() {
self.inline_sizes.push(inline_size) self.inline_sizes.push(inline_size.clone())
} }
} }
} }

View file

@ -403,11 +403,6 @@ impl Flow for TableRowFlow {
let child_row_span; let child_row_span;
{ {
let child_table_cell = kid.as_mut_table_cell(); let child_table_cell = kid.as_mut_table_cell();
child_specified_inline_size = child_table_cell
.block_flow
.fragment
.style
.content_inline_size();
child_column_span = child_table_cell.column_span; child_column_span = child_table_cell.column_span;
child_row_span = child_table_cell.row_span; child_row_span = child_table_cell.row_span;
@ -422,6 +417,13 @@ impl Flow for TableRowFlow {
&mut self.preliminary_collapsed_borders, &mut self.preliminary_collapsed_borders,
) )
} }
child_specified_inline_size = child_table_cell
.block_flow
.fragment
.style
.content_inline_size()
.clone();
} }
// Collect minimum and preferred inline-sizes of the cell for automatic table layout // Collect minimum and preferred inline-sizes of the cell for automatic table layout

View file

@ -519,7 +519,7 @@ pub fn line_height_from_style(style: &ComputedValues, metrics: &FontMetrics) ->
let font_size = style.get_font().font_size.size(); let font_size = style.get_font().font_size.size();
match style.get_inherited_text().line_height { match style.get_inherited_text().line_height {
LineHeight::Normal => Au::from(metrics.line_gap), LineHeight::Normal => Au::from(metrics.line_gap),
LineHeight::Number(l) => font_size.scale_by(l.0), LineHeight::Number(l) => Au::from(font_size * l.0),
LineHeight::Length(l) => Au::from(l), LineHeight::Length(l) => Au::from(l),
} }
} }

View file

@ -175,13 +175,18 @@ impl flow_relative::Vec2<MaxSize<LengthPercentage>> {
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
) -> flow_relative::Vec2<Option<Length>> { ) -> flow_relative::Vec2<Option<Length>> {
flow_relative::Vec2 { flow_relative::Vec2 {
inline: self inline: match self.inline {
.inline MaxSize::None => None,
.to_option() MaxSize::LengthPercentage(ref lp) => {
.map(|lp| lp.percentage_relative_to(containing_block.inline_size)), Some(lp.percentage_relative_to(containing_block.inline_size))
block: self.block.to_option().and_then(|olp| { },
olp.maybe_percentage_relative_to(containing_block.block_size.non_auto()) },
}), block: match self.block {
MaxSize::None => None,
MaxSize::LengthPercentage(ref lp) => {
lp.maybe_percentage_relative_to(containing_block.block_size.non_auto())
},
},
} }
} }
} }

View file

@ -40,7 +40,7 @@ pub(crate) struct HoistedAbsolutelyPositionedBox<'box_tree> {
box_offsets: Vec2<AbsoluteBoxOffsets>, box_offsets: Vec2<AbsoluteBoxOffsets>,
} }
#[derive(Clone, Copy, Debug)] #[derive(Clone, Debug)]
pub(crate) enum AbsoluteBoxOffsets { pub(crate) enum AbsoluteBoxOffsets {
StaticStart { StaticStart {
start: Length, start: Length,
@ -113,13 +113,13 @@ impl AbsolutelyPositionedBox {
box_offsets: Vec2 { box_offsets: Vec2 {
inline: absolute_box_offsets( inline: absolute_box_offsets(
initial_start_corner.inline, initial_start_corner.inline,
box_offsets.inline_start, box_offsets.inline_start.clone(),
box_offsets.inline_end, box_offsets.inline_end.clone(),
), ),
block: absolute_box_offsets( block: absolute_box_offsets(
initial_start_corner.block, initial_start_corner.block,
box_offsets.block_start, box_offsets.block_start.clone(),
box_offsets.block_end, box_offsets.block_end.clone(),
), ),
}, },
} }
@ -372,20 +372,20 @@ impl<'box_tree> HoistedAbsolutelyPositionedBox<'box_tree> {
let inline_axis = solve_axis( let inline_axis = solve_axis(
cbis, cbis,
pb.inline_sum(), pb.inline_sum(),
computed_margin.inline_start, computed_margin.inline_start.clone(),
computed_margin.inline_end, computed_margin.inline_end.clone(),
/* avoid_negative_margin_start */ true, /* avoid_negative_margin_start */ true,
self.box_offsets.inline, self.box_offsets.inline.clone(),
size.inline, size.inline,
); );
let block_axis = solve_axis( let block_axis = solve_axis(
cbis, cbis,
pb.block_sum(), pb.block_sum(),
computed_margin.block_start, computed_margin.block_start.clone(),
computed_margin.block_end, computed_margin.block_end.clone(),
/* avoid_negative_margin_start */ false, /* avoid_negative_margin_start */ false,
self.box_offsets.block, self.box_offsets.block.clone(),
size.block, size.block,
); );

View file

@ -7,6 +7,7 @@
use crate::style_ext::ComputedValuesExt; use crate::style_ext::ComputedValuesExt;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::{Length, LengthPercentage, Percentage}; use style::values::computed::{Length, LengthPercentage, Percentage};
use style::values::generics::length::MaxSize;
use style::Zero; use style::Zero;
/// Which min/max-content values should be computed during box construction /// Which min/max-content values should be computed during box construction
@ -114,11 +115,10 @@ impl BoxContentSizes {
.inline .inline
.percentage_relative_to(Length::zero()) .percentage_relative_to(Length::zero())
.auto_is(Length::zero); .auto_is(Length::zero);
let max_inline_size = style let max_inline_size = match style.max_box_size().inline {
.max_box_size() MaxSize::None => None,
.inline MaxSize::LengthPercentage(ref lp) => lp.as_length(),
.to_option() };
.and_then(|lp| lp.as_length());
let clamp = |l: Length| l.clamp_between_extremums(min_inline_size, max_inline_size); let clamp = |l: Length| l.clamp_between_extremums(min_inline_size, max_inline_size);
// Percentages for 'width' are treated as 'auto' // Percentages for 'width' are treated as 'auto'

View file

@ -55,9 +55,9 @@ impl ComputedValuesExt for ComputedValues {
fn inline_size_is_length(&self) -> bool { fn inline_size_is_length(&self) -> bool {
let position = self.get_position(); let position = self.get_position();
let size = if self.writing_mode.is_horizontal() { let size = if self.writing_mode.is_horizontal() {
position.width &position.width
} else { } else {
position.height &position.height
}; };
matches!(size, Size::LengthPercentage(lp) if lp.0.as_length().is_some()) matches!(size, Size::LengthPercentage(lp) if lp.0.as_length().is_some())
} }
@ -65,21 +65,21 @@ impl ComputedValuesExt for ComputedValues {
fn inline_box_offsets_are_both_non_auto(&self) -> bool { fn inline_box_offsets_are_both_non_auto(&self) -> bool {
let position = self.get_position(); let position = self.get_position();
let (a, b) = if self.writing_mode.is_horizontal() { let (a, b) = if self.writing_mode.is_horizontal() {
(position.left, position.right) (&position.left, &position.right)
} else { } else {
(position.top, position.bottom) (&position.top, &position.bottom)
}; };
a != LengthPercentageOrAuto::Auto && b != LengthPercentageOrAuto::Auto !a.is_auto() && !b.is_auto()
} }
#[inline] #[inline]
fn box_offsets(&self) -> flow_relative::Sides<LengthPercentageOrAuto> { fn box_offsets(&self) -> flow_relative::Sides<LengthPercentageOrAuto> {
let position = self.get_position(); let position = self.get_position();
physical::Sides { physical::Sides {
top: position.top, top: position.top.clone(),
left: position.left, left: position.left.clone(),
bottom: position.bottom, bottom: position.bottom.clone(),
right: position.right, right: position.right.clone(),
} }
.to_flow_relative(self.writing_mode) .to_flow_relative(self.writing_mode)
} }
@ -88,8 +88,8 @@ impl ComputedValuesExt for ComputedValues {
fn box_size(&self) -> flow_relative::Vec2<LengthPercentageOrAuto> { fn box_size(&self) -> flow_relative::Vec2<LengthPercentageOrAuto> {
let position = self.get_position(); let position = self.get_position();
physical::Vec2 { physical::Vec2 {
x: size_to_length(position.width), x: size_to_length(position.width.clone()),
y: size_to_length(position.height), y: size_to_length(position.height.clone()),
} }
.size_to_flow_relative(self.writing_mode) .size_to_flow_relative(self.writing_mode)
} }
@ -98,8 +98,8 @@ impl ComputedValuesExt for ComputedValues {
fn min_box_size(&self) -> flow_relative::Vec2<LengthPercentageOrAuto> { fn min_box_size(&self) -> flow_relative::Vec2<LengthPercentageOrAuto> {
let position = self.get_position(); let position = self.get_position();
physical::Vec2 { physical::Vec2 {
x: size_to_length(position.min_width), x: size_to_length(position.min_width.clone()),
y: size_to_length(position.min_height), y: size_to_length(position.min_height.clone()),
} }
.size_to_flow_relative(self.writing_mode) .size_to_flow_relative(self.writing_mode)
} }
@ -112,8 +112,8 @@ impl ComputedValuesExt for ComputedValues {
}; };
let position = self.get_position(); let position = self.get_position();
physical::Vec2 { physical::Vec2 {
x: unwrap(position.max_width), x: unwrap(position.max_width.clone()),
y: unwrap(position.max_height), y: unwrap(position.max_height.clone()),
} }
.size_to_flow_relative(self.writing_mode) .size_to_flow_relative(self.writing_mode)
} }
@ -122,10 +122,10 @@ impl ComputedValuesExt for ComputedValues {
fn padding(&self) -> flow_relative::Sides<LengthPercentage> { fn padding(&self) -> flow_relative::Sides<LengthPercentage> {
let padding = self.get_padding(); let padding = self.get_padding();
physical::Sides { physical::Sides {
top: padding.padding_top.0, top: padding.padding_top.0.clone(),
left: padding.padding_left.0, left: padding.padding_left.0.clone(),
bottom: padding.padding_bottom.0, bottom: padding.padding_bottom.0.clone(),
right: padding.padding_right.0, right: padding.padding_right.0.clone(),
} }
.to_flow_relative(self.writing_mode) .to_flow_relative(self.writing_mode)
} }
@ -144,10 +144,10 @@ impl ComputedValuesExt for ComputedValues {
fn margin(&self) -> flow_relative::Sides<LengthPercentageOrAuto> { fn margin(&self) -> flow_relative::Sides<LengthPercentageOrAuto> {
let margin = self.get_margin(); let margin = self.get_margin();
physical::Sides { physical::Sides {
top: margin.margin_top, top: margin.margin_top.clone(),
left: margin.margin_left, left: margin.margin_left.clone(),
bottom: margin.margin_bottom, bottom: margin.margin_bottom.clone(),
right: margin.margin_right, right: margin.margin_right.clone(),
} }
.to_flow_relative(self.writing_mode) .to_flow_relative(self.writing_mode)
} }
@ -180,7 +180,9 @@ impl From<stylo::Display> for Display {
fn size_to_length(size: Size) -> LengthPercentageOrAuto { fn size_to_length(size: Size) -> LengthPercentageOrAuto {
match size { match size {
Size::LengthPercentage(length) => LengthPercentageOrAuto::LengthPercentage(length.0), Size::LengthPercentage(length) => {
LengthPercentageOrAuto::LengthPercentage(length.0.clone())
},
Size::Auto => LengthPercentageOrAuto::Auto, Size::Auto => LengthPercentageOrAuto::Auto,
} }
} }

View file

@ -40,7 +40,7 @@ serde = { version = "1.0.27", optional = true }
serde_bytes = { version = "0.11", optional = true } serde_bytes = { version = "0.11", optional = true }
servo_arc = { path = "../servo_arc" } servo_arc = { path = "../servo_arc" }
smallbitvec = "2.3.0" smallbitvec = "2.3.0"
smallvec = "0.6" smallvec = "1.0"
string_cache = { version = "0.8", optional = true } string_cache = { version = "0.8", optional = true }
thin-slice = "0.1.0" thin-slice = "0.1.0"
time = { version = "0.1.17", optional = true } time = { version = "0.1.17", optional = true }

View file

@ -23,13 +23,13 @@ bench = []
bitflags = "1.0" bitflags = "1.0"
matches = "0.1" matches = "0.1"
cssparser = "0.27" cssparser = "0.27"
derive_more = "0.13" derive_more = "0.99"
log = "0.4" log = "0.4"
fxhash = "0.2" fxhash = "0.2"
phf = "0.8" phf = "0.8"
precomputed-hash = "0.1" precomputed-hash = "0.1"
servo_arc = { version = "0.1", path = "../servo_arc" } servo_arc = { version = "0.1", path = "../servo_arc" }
smallvec = "0.6" smallvec = "1.0"
thin-slice = "0.1.0" thin-slice = "0.1.0"
to_shmem = { path = "../to_shmem" } to_shmem = { path = "../to_shmem" }
to_shmem_derive = { path = "../to_shmem_derive" } to_shmem_derive = { path = "../to_shmem_derive" }

View file

@ -17,7 +17,7 @@
//! is non-trivial. This module encapsulates those details and presents an //! is non-trivial. This module encapsulates those details and presents an
//! easy-to-use API for the parser. //! easy-to-use API for the parser.
use crate::parser::{Combinator, Component, SelectorImpl}; use crate::parser::{Combinator, Component, NonTSPseudoClass, SelectorImpl};
use crate::sink::Push; use crate::sink::Push;
use servo_arc::{Arc, HeaderWithLength, ThinArc}; use servo_arc::{Arc, HeaderWithLength, ThinArc};
use smallvec::{self, SmallVec}; use smallvec::{self, SmallVec};
@ -142,7 +142,7 @@ impl<Impl: SelectorImpl> SelectorBuilder<Impl> {
let iter = SelectorBuilderIter { let iter = SelectorBuilderIter {
current_simple_selectors: current.iter(), current_simple_selectors: current.iter(),
rest_of_simple_selectors: rest, rest_of_simple_selectors: rest,
combinators: self.combinators.drain().rev(), combinators: self.combinators.drain(..).rev(),
}; };
Arc::into_thin(Arc::from_header_and_iter(header, iter)) Arc::into_thin(Arc::from_header_and_iter(header, iter))
@ -152,7 +152,7 @@ impl<Impl: SelectorImpl> SelectorBuilder<Impl> {
struct SelectorBuilderIter<'a, Impl: SelectorImpl> { struct SelectorBuilderIter<'a, Impl: SelectorImpl> {
current_simple_selectors: slice::Iter<'a, Component<Impl>>, current_simple_selectors: slice::Iter<'a, Component<Impl>>,
rest_of_simple_selectors: &'a [Component<Impl>], rest_of_simple_selectors: &'a [Component<Impl>],
combinators: iter::Rev<smallvec::Drain<'a, (Combinator, usize)>>, combinators: iter::Rev<smallvec::Drain<'a, [(Combinator, usize); 16]>>,
} }
impl<'a, Impl: SelectorImpl> ExactSizeIterator for SelectorBuilderIter<'a, Impl> { impl<'a, Impl: SelectorImpl> ExactSizeIterator for SelectorBuilderIter<'a, Impl> {
@ -322,10 +322,14 @@ where
Component::NthLastOfType(..) | Component::NthLastOfType(..) |
Component::FirstOfType | Component::FirstOfType |
Component::LastOfType | Component::LastOfType |
Component::OnlyOfType | Component::OnlyOfType => {
Component::NonTSPseudoClass(..) => {
specificity.class_like_selectors += 1; specificity.class_like_selectors += 1;
}, },
Component::NonTSPseudoClass(ref pseudo) => {
if !pseudo.has_zero_specificity() {
specificity.class_like_selectors += 1;
}
},
Component::ExplicitUniversalType | Component::ExplicitUniversalType |
Component::ExplicitAnyNamespace | Component::ExplicitAnyNamespace |
Component::ExplicitNoNamespace | Component::ExplicitNoNamespace |

View file

@ -52,6 +52,9 @@ pub trait NonTSPseudoClass: Sized + ToCss {
/// ///
/// https://drafts.csswg.org/selectors-4/#useraction-pseudos /// https://drafts.csswg.org/selectors-4/#useraction-pseudos
fn is_user_action_state(&self) -> bool; fn is_user_action_state(&self) -> bool;
/// Whether this pseudo-class has zero specificity.
fn has_zero_specificity(&self) -> bool;
} }
/// Returns a Cow::Borrowed if `s` is already ASCII lowercase, and a /// Returns a Cow::Borrowed if `s` is already ASCII lowercase, and a
@ -2336,6 +2339,11 @@ pub mod tests {
fn is_user_action_state(&self) -> bool { fn is_user_action_state(&self) -> bool {
self.is_active_or_hover() self.is_active_or_hover()
} }
#[inline]
fn has_zero_specificity(&self) -> bool {
false
}
} }
impl ToCss for PseudoClass { impl ToCss for PseudoClass {

View file

@ -35,7 +35,7 @@ bitflags = "1.0"
byteorder = "1.0" byteorder = "1.0"
cssparser = "0.27" cssparser = "0.27"
crossbeam-channel = { version = "0.3", optional = true } crossbeam-channel = { version = "0.3", optional = true }
derive_more = "0.13" derive_more = "0.99"
new_debug_unreachable = "1.0" new_debug_unreachable = "1.0"
encoding_rs = {version = "0.8", optional = true} encoding_rs = {version = "0.8", optional = true}
euclid = "0.20" euclid = "0.20"
@ -66,7 +66,7 @@ servo_arc = { path = "../servo_arc" }
servo_atoms = {path = "../atoms", optional = true} servo_atoms = {path = "../atoms", optional = true}
servo_config = {path = "../config", optional = true} servo_config = {path = "../config", optional = true}
smallbitvec = "2.3.0" smallbitvec = "2.3.0"
smallvec = "0.6.6" smallvec = "1.0"
string_cache = { version = "0.8", optional = true } string_cache = { version = "0.8", optional = true }
style_derive = {path = "../style_derive"} style_derive = {path = "../style_derive"}
style_traits = {path = "../style_traits"} style_traits = {path = "../style_traits"}

View file

@ -216,7 +216,7 @@ impl<E: TElement> StyleBloom<E> {
self.filter.clear(); self.filter.clear();
self.pushed_hashes.clear(); self.pushed_hashes.clear();
} else { } else {
for hash in self.pushed_hashes.drain() { for hash in self.pushed_hashes.drain(..) {
self.filter.remove_hash(hash); self.filter.remove_hash(hash);
} }
debug_assert!(self.filter.is_zeroed()); debug_assert!(self.filter.is_zeroed());
@ -233,7 +233,7 @@ impl<E: TElement> StyleBloom<E> {
element = parent; element = parent;
} }
for parent in parents_to_insert.drain().rev() { for parent in parents_to_insert.drain(..).rev() {
self.push(parent); self.push(parent);
} }
} }
@ -374,7 +374,7 @@ impl<E: TElement> StyleBloom<E> {
// Now the parents match, so insert the stack of elements we have been // Now the parents match, so insert the stack of elements we have been
// collecting so far. // collecting so far.
for parent in parents_to_insert.drain().rev() { for parent in parents_to_insert.drain(..).rev() {
self.push(parent); self.push(parent);
} }

View file

@ -807,6 +807,9 @@ pub trait TElement:
/// data if it comes from Shadow DOM. /// data if it comes from Shadow DOM.
/// ///
/// Returns whether normal document author rules should apply. /// Returns whether normal document author rules should apply.
///
/// TODO(emilio): We could separate the invalidation data for elements
/// matching in other scopes to avoid over-invalidation.
fn each_applicable_non_document_style_rule_data<'a, F>(&self, mut f: F) -> bool fn each_applicable_non_document_style_rule_data<'a, F>(&self, mut f: F) -> bool
where where
Self: 'a, Self: 'a,
@ -841,11 +844,42 @@ pub trait TElement:
// Slots can only have assigned nodes when in a shadow tree. // Slots can only have assigned nodes when in a shadow tree.
let shadow = slot.containing_shadow().unwrap(); let shadow = slot.containing_shadow().unwrap();
if let Some(data) = shadow.style_data() { if let Some(data) = shadow.style_data() {
if data.any_slotted_rule() {
f(data, shadow.host()); f(data, shadow.host());
} }
}
current = slot.assigned_slot(); current = slot.assigned_slot();
} }
if target.has_part_attr() {
if let Some(mut inner_shadow) = target.containing_shadow() {
loop {
let inner_shadow_host = inner_shadow.host();
match inner_shadow_host.containing_shadow() {
Some(shadow) => {
if let Some(data) = shadow.style_data() {
if data.any_part_rule() {
f(data, shadow.host())
}
}
// TODO: Could be more granular.
if !shadow.host().exports_any_part() {
break;
}
inner_shadow = shadow;
},
None => {
// TODO(emilio): Should probably distinguish with
// MatchesDocumentRules::{No,Yes,IfPart} or
// something so that we could skip some work.
doc_rules_apply = true;
break;
},
}
}
}
}
doc_rules_apply doc_rules_apply
} }

View file

@ -7,17 +7,17 @@
#![deny(missing_docs)] #![deny(missing_docs)]
use crate::context::SharedStyleContext; use crate::context::SharedStyleContext;
use crate::values::computed::Length;
use crate::Atom; use crate::Atom;
use app_units::Au;
/// Represents the font metrics that style needs from a font to compute the /// Represents the font metrics that style needs from a font to compute the
/// value of certain CSS units like `ex`. /// value of certain CSS units like `ex`.
#[derive(Clone, Debug, Default, PartialEq)] #[derive(Clone, Debug, Default, PartialEq)]
pub struct FontMetrics { pub struct FontMetrics {
/// The x-height of the font. /// The x-height of the font.
pub x_height: Option<Au>, pub x_height: Option<Length>,
/// The zero advance. This is usually writing mode dependent /// The zero advance. This is usually writing mode dependent
pub zero_advance_measure: Option<Au>, pub zero_advance_measure: Option<Length>,
} }
/// Type of font metrics to retrieve. /// Type of font metrics to retrieve.
@ -47,7 +47,7 @@ pub trait FontMetricsProvider {
&self, &self,
font_name: &Atom, font_name: &Atom,
font_family: crate::values::computed::font::GenericFontFamily, font_family: crate::values::computed::font::GenericFontFamily,
) -> Au; ) -> Length;
/// Construct from a shared style context /// Construct from a shared style context
fn create_from(context: &SharedStyleContext) -> Self fn create_from(context: &SharedStyleContext) -> Self
@ -70,7 +70,7 @@ impl FontMetricsProvider for ServoMetricsProvider {
ServoMetricsProvider ServoMetricsProvider
} }
fn get_size(&self, _: &Atom, _: crate::values::computed::font::GenericFontFamily) -> Au { fn get_size(&self, _: &Atom, _: crate::values::computed::font::GenericFontFamily) -> Length {
unreachable!("Dummy provider should never be used to compute font size") unreachable!("Dummy provider should never be used to compute font size")
} }
} }

View file

@ -11,10 +11,9 @@ use crate::gecko_bindings::structs;
use crate::media_queries::MediaType; use crate::media_queries::MediaType;
use crate::properties::ComputedValues; use crate::properties::ComputedValues;
use crate::string_cache::Atom; use crate::string_cache::Atom;
use crate::values::computed::font::FontSize; use crate::values::specified::font::FONT_MEDIUM_PX;
use crate::values::{CustomIdent, KeyframesName}; use crate::values::{CustomIdent, KeyframesName};
use app_units::Au; use app_units::{Au, AU_PER_PX};
use app_units::AU_PER_PX;
use cssparser::RGBA; use cssparser::RGBA;
use euclid::default::Size2D; use euclid::default::Size2D;
use euclid::Scale; use euclid::Scale;
@ -87,7 +86,7 @@ impl Device {
document, document,
default_values: ComputedValues::default_values(doc), default_values: ComputedValues::default_values(doc),
// FIXME(bz): Seems dubious? // FIXME(bz): Seems dubious?
root_font_size: AtomicIsize::new(FontSize::medium().size().0 as isize), root_font_size: AtomicIsize::new(Au::from_px(FONT_MEDIUM_PX as i32).0 as isize),
body_text_color: AtomicUsize::new(prefs.mDefaultColor as usize), body_text_color: AtomicUsize::new(prefs.mDefaultColor as usize),
used_root_font_size: AtomicBool::new(false), used_root_font_size: AtomicBool::new(false),
used_viewport_size: AtomicBool::new(false), used_viewport_size: AtomicBool::new(false),

View file

@ -48,8 +48,7 @@ macro_rules! apply_non_ts_list {
("indeterminate", Indeterminate, indeterminate, IN_INDETERMINATE_STATE, _), ("indeterminate", Indeterminate, indeterminate, IN_INDETERMINATE_STATE, _),
("-moz-devtools-highlighted", MozDevtoolsHighlighted, mozDevtoolsHighlighted, IN_DEVTOOLS_HIGHLIGHTED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), ("-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), ("-moz-styleeditor-transitioning", MozStyleeditorTransitioning, mozStyleeditorTransitioning, IN_STYLEEDITOR_TRANSITIONING_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS),
("fullscreen", Fullscreen, fullscreen, IN_FULLSCREEN_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), ("fullscreen", Fullscreen, fullscreen, IN_FULLSCREEN_STATE, _),
("-moz-full-screen", MozFullScreen, mozFullScreen, IN_FULLSCREEN_STATE, _),
// TODO(emilio): This is inconsistently named (the capital R). // TODO(emilio): This is inconsistently named (the capital R).
("-moz-focusring", MozFocusRing, mozFocusRing, IN_FOCUSRING_STATE, _), ("-moz-focusring", MozFocusRing, mozFocusRing, IN_FOCUSRING_STATE, _),
("-moz-broken", MozBroken, mozBroken, IN_BROKEN_STATE, _), ("-moz-broken", MozBroken, mozBroken, IN_BROKEN_STATE, _),
@ -94,6 +93,7 @@ macro_rules! apply_non_ts_list {
("-moz-last-node", MozLastNode, lastNode, _, _), ("-moz-last-node", MozLastNode, lastNode, _, _),
("-moz-only-whitespace", MozOnlyWhitespace, mozOnlyWhitespace, _, _), ("-moz-only-whitespace", MozOnlyWhitespace, mozOnlyWhitespace, _, _),
("-moz-native-anonymous", MozNativeAnonymous, mozNativeAnonymous, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS), ("-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-use-shadow-tree-root", MozUseShadowTreeRoot, mozUseShadowTreeRoot, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS),
("-moz-is-html", MozIsHTML, mozIsHTML, _, _), ("-moz-is-html", MozIsHTML, mozIsHTML, _, _),
("-moz-placeholder", MozPlaceholder, mozPlaceholder, _, _), ("-moz-placeholder", MozPlaceholder, mozPlaceholder, _, _),

View file

@ -193,18 +193,18 @@ impl PseudoElement {
% for pseudo in SIMPLE_PSEUDOS: % for pseudo in SIMPLE_PSEUDOS:
"${pseudo.value[1:]}" => { "${pseudo.value[1:]}" => {
return Some(${pseudo_element_variant(pseudo)}) return Some(${pseudo_element_variant(pseudo)})
} },
% endfor % endfor
// Alias some legacy prefixed pseudos to their standardized name at parse time: // Alias some legacy prefixed pseudos to their standardized name at parse time:
"-moz-selection" => { "-moz-selection" => {
return Some(PseudoElement::Selection); return Some(PseudoElement::Selection);
} },
"-moz-placeholder" => { "-moz-placeholder" => {
return Some(PseudoElement::Placeholder); return Some(PseudoElement::Placeholder);
} },
"-moz-list-bullet" | "-moz-list-number" => { "-moz-list-bullet" | "-moz-list-number" => {
return Some(PseudoElement::Marker); return Some(PseudoElement::Marker);
} },
_ => { _ => {
if starts_with_ignore_ascii_case(name, "-moz-tree-") { if starts_with_ignore_ascii_case(name, "-moz-tree-") {
return PseudoElement::tree_pseudo_element(name, Box::new([])) return PseudoElement::tree_pseudo_element(name, Box::new([]))

View file

@ -137,6 +137,7 @@ impl NonTSPseudoClass {
([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => { ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => {
match_ignore_ascii_case! { &name, match_ignore_ascii_case! { &name,
$($css => Some(NonTSPseudoClass::$name),)* $($css => Some(NonTSPseudoClass::$name),)*
"-moz-full-screen" => Some(NonTSPseudoClass::Fullscreen),
_ => None, _ => None,
} }
} }
@ -169,16 +170,9 @@ impl NonTSPseudoClass {
} }
/// Returns whether the pseudo-class is enabled in content sheets. /// Returns whether the pseudo-class is enabled in content sheets.
#[inline]
fn is_enabled_in_content(&self) -> bool { fn is_enabled_in_content(&self) -> bool {
match *self { !self.has_any_flag(NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME)
// For pseudo-classes with pref, the availability in content
// depends on the pref.
NonTSPseudoClass::Fullscreen => static_prefs::pref!("full-screen-api.unprefix.enabled"),
// Otherwise, a pseudo-class is enabled in content when it
// doesn't have any enabled flag.
_ => !self
.has_any_flag(NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME),
}
} }
/// Get the state flag associated with a pseudo-class, if any. /// Get the state flag associated with a pseudo-class, if any.
@ -233,6 +227,9 @@ impl NonTSPseudoClass {
// across all the elements involved and the latter is already // across all the elements involved and the latter is already
// checked for by our caching precondtions. // checked for by our caching precondtions.
NonTSPseudoClass::MozIsHTML | NonTSPseudoClass::MozIsHTML |
// We prevent style sharing for NAC.
NonTSPseudoClass::MozNativeAnonymous |
NonTSPseudoClass::MozNativeAnonymousNoSpecificity |
// :-moz-placeholder is parsed but never matches. // :-moz-placeholder is parsed but never matches.
NonTSPseudoClass::MozPlaceholder | NonTSPseudoClass::MozPlaceholder |
// :-moz-locale-dir and :-moz-window-inactive depend only on // :-moz-locale-dir and :-moz-window-inactive depend only on
@ -275,6 +272,11 @@ impl ::selectors::parser::NonTSPseudoClass for NonTSPseudoClass {
NonTSPseudoClass::Hover | NonTSPseudoClass::Active | NonTSPseudoClass::Focus NonTSPseudoClass::Hover | NonTSPseudoClass::Active | NonTSPseudoClass::Focus
) )
} }
#[inline]
fn has_zero_specificity(&self) -> bool {
matches!(*self, NonTSPseudoClass::MozNativeAnonymousNoSpecificity)
}
} }
/// The dummy struct we use to implement our selector parsing. /// The dummy struct we use to implement our selector parsing.
@ -394,7 +396,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
parser, parser,
)?.into() )?.into()
) )
} },
_ => return Err(parser.new_custom_error( _ => return Err(parser.new_custom_error(
SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone()) SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone())
)) ))

View file

@ -71,7 +71,7 @@ impl GeckoElementSnapshot {
} }
/// Returns true if the snapshot recorded an attribute change which isn't a /// Returns true if the snapshot recorded an attribute change which isn't a
/// class or id change. /// class / id
#[inline] #[inline]
pub fn other_attr_changed(&self) -> bool { pub fn other_attr_changed(&self) -> bool {
self.mOtherAttributeChanged() self.mOtherAttributeChanged()

View file

@ -68,6 +68,7 @@ use crate::shared_lock::Locked;
use crate::string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; use crate::string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
use crate::stylist::CascadeData; use crate::stylist::CascadeData;
use crate::values::computed::font::GenericFontFamily; use crate::values::computed::font::GenericFontFamily;
use crate::values::computed::Length;
use crate::values::specified::length::FontBaseSize; use crate::values::specified::length::FontBaseSize;
use crate::CaseSensitivityExt; use crate::CaseSensitivityExt;
use app_units::Au; use app_units::Au;
@ -929,7 +930,7 @@ impl FontMetricsProvider for GeckoFontMetricsProvider {
GeckoFontMetricsProvider::new() GeckoFontMetricsProvider::new()
} }
fn get_size(&self, font_name: &Atom, font_family: GenericFontFamily) -> Au { fn get_size(&self, font_name: &Atom, font_family: GenericFontFamily) -> Length {
let mut cache = self.font_size_cache.borrow_mut(); let mut cache = self.font_size_cache.borrow_mut();
if let Some(sizes) = cache.iter().find(|el| el.0 == *font_name) { if let Some(sizes) = cache.iter().find(|el| el.0 == *font_name) {
return sizes.1.size_for_generic(font_family); return sizes.1.size_for_generic(font_family);
@ -950,7 +951,7 @@ impl FontMetricsProvider for GeckoFontMetricsProvider {
None => return Default::default(), None => return Default::default(),
}; };
let size = base_size.resolve(context); let size = Au::from(base_size.resolve(context));
let style = context.style(); let style = context.style();
let (wm, font) = match base_size { let (wm, font) = match base_size {
@ -977,9 +978,9 @@ impl FontMetricsProvider for GeckoFontMetricsProvider {
) )
}; };
FontMetrics { FontMetrics {
x_height: Some(Au(gecko_metrics.mXSize)), x_height: Some(Au(gecko_metrics.mXSize).into()),
zero_advance_measure: if gecko_metrics.mChSize >= 0 { zero_advance_measure: if gecko_metrics.mChSize >= 0 {
Some(Au(gecko_metrics.mChSize)) Some(Au(gecko_metrics.mChSize).into())
} else { } else {
None None
}, },
@ -988,7 +989,7 @@ impl FontMetricsProvider for GeckoFontMetricsProvider {
} }
impl structs::FontSizePrefs { impl structs::FontSizePrefs {
fn size_for_generic(&self, font_family: GenericFontFamily) -> Au { fn size_for_generic(&self, font_family: GenericFontFamily) -> Length {
Au(match font_family { Au(match font_family {
GenericFontFamily::None => self.mDefaultVariableSize, GenericFontFamily::None => self.mDefaultVariableSize,
GenericFontFamily::Serif => self.mDefaultSerifSize, GenericFontFamily::Serif => self.mDefaultSerifSize,
@ -1000,6 +1001,7 @@ impl structs::FontSizePrefs {
"Should never get here, since this doesn't (yet) appear on font family" "Should never get here, since this doesn't (yet) appear on font family"
), ),
}) })
.into()
} }
} }
@ -2045,7 +2047,6 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
NonTSPseudoClass::Disabled | NonTSPseudoClass::Disabled |
NonTSPseudoClass::Checked | NonTSPseudoClass::Checked |
NonTSPseudoClass::Fullscreen | NonTSPseudoClass::Fullscreen |
NonTSPseudoClass::MozFullScreen |
NonTSPseudoClass::Indeterminate | NonTSPseudoClass::Indeterminate |
NonTSPseudoClass::PlaceholderShown | NonTSPseudoClass::PlaceholderShown |
NonTSPseudoClass::Target | NonTSPseudoClass::Target |
@ -2130,7 +2131,10 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
} }
true true
}, },
NonTSPseudoClass::MozNativeAnonymous => self.is_in_native_anonymous_subtree(), NonTSPseudoClass::MozNativeAnonymous |
NonTSPseudoClass::MozNativeAnonymousNoSpecificity => {
self.is_in_native_anonymous_subtree()
},
NonTSPseudoClass::MozUseShadowTreeRoot => self.is_root_of_use_element_shadow_tree(), NonTSPseudoClass::MozUseShadowTreeRoot => self.is_root_of_use_element_shadow_tree(),
NonTSPseudoClass::MozTableBorderNonzero => unsafe { NonTSPseudoClass::MozTableBorderNonzero => unsafe {
bindings::Gecko_IsTableBorderNonzero(self.0) bindings::Gecko_IsTableBorderNonzero(self.0)

View file

@ -89,9 +89,11 @@ impl<T> nsTArray<T> {
pub unsafe fn set_len(&mut self, len: u32) { pub unsafe fn set_len(&mut self, len: u32) {
// this can leak // this can leak
debug_assert!(len >= self.len() as u32); debug_assert!(len >= self.len() as u32);
if self.len() == len as usize {
return;
}
self.ensure_capacity(len as usize); self.ensure_capacity(len as usize);
let header = self.header_mut(); self.header_mut().mLength = len;
header.mLength = len;
} }
/// Resizes an array containing only POD elements /// Resizes an array containing only POD elements
@ -103,6 +105,9 @@ impl<T> nsTArray<T> {
where where
T: Copy, T: Copy,
{ {
if self.len() == len as usize {
return;
}
self.ensure_capacity(len as usize); self.ensure_capacity(len as usize);
let header = self.header_mut(); let header = self.header_mut();
header.mLength = len; header.mLength = len;

View file

@ -142,6 +142,19 @@ pub struct DocumentStateDependency {
pub state: DocumentState, pub state: DocumentState,
} }
bitflags! {
/// A set of flags that denote whether any invalidations have occurred
/// for a particular attribute selector.
#[derive(MallocSizeOf)]
#[repr(C)]
pub struct InvalidationMapFlags : u8 {
/// Whether [class] or such is used.
const HAS_CLASS_ATTR_SELECTOR = 1 << 0;
/// Whether [id] or such is used.
const HAS_ID_ATTR_SELECTOR = 1 << 1;
}
}
/// A map where we store invalidations. /// A map where we store invalidations.
/// ///
/// This is slightly different to a SelectorMap, in the sense of that the same /// This is slightly different to a SelectorMap, in the sense of that the same
@ -164,16 +177,9 @@ pub struct InvalidationMap {
pub document_state_selectors: Vec<DocumentStateDependency>, pub document_state_selectors: Vec<DocumentStateDependency>,
/// A map of other attribute affecting selectors. /// A map of other attribute affecting selectors.
pub other_attribute_affecting_selectors: SelectorMap<Dependency>, pub other_attribute_affecting_selectors: SelectorMap<Dependency>,
/// Whether there are attribute rules of the form `[class~="foo"]` that may /// A set of flags that contain whether various special attributes are used
/// match. In that case, we need to look at /// in this invalidation map.
/// `other_attribute_affecting_selectors` too even if only the `class` has pub flags: InvalidationMapFlags,
/// changed.
pub has_class_attribute_selectors: bool,
/// Whether there are attribute rules of the form `[id|="foo"]` that may
/// match. In that case, we need to look at
/// `other_attribute_affecting_selectors` too even if only the `id` has
/// changed.
pub has_id_attribute_selectors: bool,
} }
impl InvalidationMap { impl InvalidationMap {
@ -185,8 +191,7 @@ impl InvalidationMap {
state_affecting_selectors: SelectorMap::new(), state_affecting_selectors: SelectorMap::new(),
document_state_selectors: Vec::new(), document_state_selectors: Vec::new(),
other_attribute_affecting_selectors: SelectorMap::new(), other_attribute_affecting_selectors: SelectorMap::new(),
has_class_attribute_selectors: false, flags: InvalidationMapFlags::empty(),
has_id_attribute_selectors: false,
} }
} }
@ -210,8 +215,7 @@ impl InvalidationMap {
self.state_affecting_selectors.clear(); self.state_affecting_selectors.clear();
self.document_state_selectors.clear(); self.document_state_selectors.clear();
self.other_attribute_affecting_selectors.clear(); self.other_attribute_affecting_selectors.clear();
self.has_id_attribute_selectors = false; self.flags = InvalidationMapFlags::empty();
self.has_class_attribute_selectors = false;
} }
/// Adds a selector to this `InvalidationMap`. Returns Err(..) to /// Adds a selector to this `InvalidationMap`. Returns Err(..) to
@ -238,8 +242,7 @@ impl InvalidationMap {
state: ElementState::empty(), state: ElementState::empty(),
document_state: &mut document_state, document_state: &mut document_state,
other_attributes: false, other_attributes: false,
has_id_attribute_selectors: false, flags: &mut self.flags,
has_class_attribute_selectors: false,
}; };
// Visit all the simple selectors in this sequence. // Visit all the simple selectors in this sequence.
@ -255,9 +258,6 @@ impl InvalidationMap {
index += 1; // Account for the simple selector. index += 1; // Account for the simple selector.
} }
self.has_id_attribute_selectors |= compound_visitor.has_id_attribute_selectors;
self.has_class_attribute_selectors |= compound_visitor.has_class_attribute_selectors;
for class in compound_visitor.classes { for class in compound_visitor.classes {
self.class_to_selector self.class_to_selector
.try_entry(class, quirks_mode)? .try_entry(class, quirks_mode)?
@ -349,11 +349,8 @@ struct CompoundSelectorDependencyCollector<'a> {
/// [id] attribute selectors). /// [id] attribute selectors).
other_attributes: bool, other_attributes: bool,
/// Whether there were attribute selectors with the id attribute. /// The invalidation map flags, that we set when some attribute selectors are present.
has_id_attribute_selectors: bool, flags: &'a mut InvalidationMapFlags,
/// Whether there were attribute selectors with the class attribute.
has_class_attribute_selectors: bool,
} }
impl<'a> SelectorVisitor for CompoundSelectorDependencyCollector<'a> { impl<'a> SelectorVisitor for CompoundSelectorDependencyCollector<'a> {
@ -398,8 +395,13 @@ impl<'a> SelectorVisitor for CompoundSelectorDependencyCollector<'a> {
}; };
if may_match_in_no_namespace { if may_match_in_no_namespace {
self.has_id_attribute_selectors |= *local_name_lower == local_name!("id"); if *local_name_lower == local_name!("id") {
self.has_class_attribute_selectors |= *local_name_lower == local_name!("class"); self.flags
.insert(InvalidationMapFlags::HAS_ID_ATTR_SELECTOR)
} else if *local_name_lower == local_name!("class") {
self.flags
.insert(InvalidationMapFlags::HAS_CLASS_ATTR_SELECTOR)
}
} }
true true

View file

@ -698,7 +698,7 @@ where
} }
} }
sibling_invalidations.extend(new_sibling_invalidations.drain()); sibling_invalidations.extend(new_sibling_invalidations.drain(..));
invalidated_self invalidated_self
} }

View file

@ -42,6 +42,7 @@ where
descendant_invalidations: &'a mut DescendantInvalidationLists<'selectors>, descendant_invalidations: &'a mut DescendantInvalidationLists<'selectors>,
sibling_invalidations: &'a mut InvalidationVector<'selectors>, sibling_invalidations: &'a mut InvalidationVector<'selectors>,
invalidates_self: bool, invalidates_self: bool,
attr_selector_flags: InvalidationMapFlags,
} }
/// An invalidation processor for style changes due to state and attribute /// An invalidation processor for style changes due to state and attribute
@ -155,6 +156,8 @@ where
return false; return false;
} }
let mut attr_selector_flags = InvalidationMapFlags::empty();
// If we the visited state changed, we force a restyle here. Matching // If we the visited state changed, we force a restyle here. Matching
// doesn't depend on the actual visited state at all, so we can't look // doesn't depend on the actual visited state at all, so we can't look
// at matching results to decide what to do for this case. // at matching results to decide what to do for this case.
@ -172,6 +175,7 @@ where
let mut classes_removed = SmallVec::<[Atom; 8]>::new(); let mut classes_removed = SmallVec::<[Atom; 8]>::new();
let mut classes_added = SmallVec::<[Atom; 8]>::new(); let mut classes_added = SmallVec::<[Atom; 8]>::new();
if snapshot.class_changed() { if snapshot.class_changed() {
attr_selector_flags.insert(InvalidationMapFlags::HAS_CLASS_ATTR_SELECTOR);
// TODO(emilio): Do this more efficiently! // TODO(emilio): Do this more efficiently!
snapshot.each_class(|c| { snapshot.each_class(|c| {
if !element.has_class(c, CaseSensitivity::CaseSensitive) { if !element.has_class(c, CaseSensitivity::CaseSensitive) {
@ -189,6 +193,7 @@ where
let mut id_removed = None; let mut id_removed = None;
let mut id_added = None; let mut id_added = None;
if snapshot.id_changed() { if snapshot.id_changed() {
attr_selector_flags.insert(InvalidationMapFlags::HAS_ID_ATTR_SELECTOR);
let old_id = snapshot.id_attr(); let old_id = snapshot.id_attr();
let current_id = element.id(); let current_id = element.id();
@ -199,7 +204,10 @@ where
} }
if log_enabled!(::log::Level::Debug) { if log_enabled!(::log::Level::Debug) {
debug!("Collecting changes for: {:?}", element); debug!(
"Collecting changes for: {:?}, flags {:?}",
element, attr_selector_flags
);
if !state_changes.is_empty() { if !state_changes.is_empty() {
debug!(" > state: {:?}", state_changes); debug!(" > state: {:?}", state_changes);
} }
@ -247,6 +255,7 @@ where
descendant_invalidations, descendant_invalidations,
sibling_invalidations, sibling_invalidations,
invalidates_self: false, invalidates_self: false,
attr_selector_flags,
}; };
let document_origins = if !matches_document_author_rules { let document_origins = if !matches_document_author_rules {
@ -356,9 +365,8 @@ where
} }
} }
let should_examine_attribute_selector_map = self.snapshot.other_attr_changed() || let should_examine_attribute_selector_map =
(self.snapshot.class_changed() && map.has_class_attribute_selectors) || self.snapshot.other_attr_changed() || map.flags.intersects(self.attr_selector_flags);
(self.snapshot.id_changed() && map.has_id_attribute_selectors);
if should_examine_attribute_selector_map { if should_examine_attribute_selector_map {
self.collect_dependencies_in_map(&map.other_attribute_affecting_selectors) self.collect_dependencies_in_map(&map.other_attribute_affecting_selectors)

View file

@ -468,7 +468,7 @@ impl<T: Zero> LogicalSize<T> {
} }
} }
impl<T: Copy> LogicalSize<T> { impl<T> LogicalSize<T> {
#[inline] #[inline]
pub fn new(mode: WritingMode, inline: T, block: T) -> LogicalSize<T> { pub fn new(mode: WritingMode, inline: T, block: T) -> LogicalSize<T> {
LogicalSize { LogicalSize {
@ -486,7 +486,9 @@ impl<T: Copy> LogicalSize<T> {
LogicalSize::new(mode, size.width, size.height) LogicalSize::new(mode, size.width, size.height)
} }
} }
}
impl<T: Copy> LogicalSize<T> {
#[inline] #[inline]
pub fn width(&self, mode: WritingMode) -> T { pub fn width(&self, mode: WritingMode) -> T {
self.debug_writing_mode.check(mode); self.debug_writing_mode.check(mode);
@ -860,7 +862,7 @@ impl<T: Zero> LogicalMargin<T> {
} }
} }
impl<T: Copy> LogicalMargin<T> { impl<T> LogicalMargin<T> {
#[inline] #[inline]
pub fn new( pub fn new(
mode: WritingMode, mode: WritingMode,
@ -878,11 +880,6 @@ impl<T: Copy> LogicalMargin<T> {
} }
} }
#[inline]
pub fn new_all_same(mode: WritingMode, value: T) -> LogicalMargin<T> {
LogicalMargin::new(mode, value, value, value, value)
}
#[inline] #[inline]
pub fn from_physical(mode: WritingMode, offsets: SideOffsets2D<T>) -> LogicalMargin<T> { pub fn from_physical(mode: WritingMode, offsets: SideOffsets2D<T>) -> LogicalMargin<T> {
let block_start; let block_start;
@ -917,6 +914,13 @@ impl<T: Copy> LogicalMargin<T> {
} }
LogicalMargin::new(mode, block_start, inline_end, block_end, inline_start) LogicalMargin::new(mode, block_start, inline_end, block_end, inline_start)
} }
}
impl<T: Copy> LogicalMargin<T> {
#[inline]
pub fn new_all_same(mode: WritingMode, value: T) -> LogicalMargin<T> {
LogicalMargin::new(mode, value, value, value, value)
}
#[inline] #[inline]
pub fn top(&self, mode: WritingMode) -> T { pub fn top(&self, mode: WritingMode) -> T {

View file

@ -715,7 +715,7 @@ pub trait MatchMethods: TElement {
.map_or(true, |s| s.get_font().clone_font_size() != new_font_size) .map_or(true, |s| s.get_font().clone_font_size() != new_font_size)
{ {
debug_assert!(self.owner_doc_matches_for_testing(device)); debug_assert!(self.owner_doc_matches_for_testing(device));
device.set_root_font_size(new_font_size.size()); device.set_root_font_size(new_font_size.size().into());
// If the root font-size changed since last time, and something // If the root font-size changed since last time, and something
// in the document did use rem units, ensure we recascade the // in the document did use rem units, ensure we recascade the
// entire tree. // entire tree.

View file

@ -180,7 +180,7 @@ fn top_down_dom<'a, 'scope, E, D>(
let mut traversal_data_copy = traversal_data.clone(); let mut traversal_data_copy = traversal_data.clone();
traversal_data_copy.current_dom_depth += 1; traversal_data_copy.current_dom_depth += 1;
traverse_nodes( traverse_nodes(
discovered_child_nodes.drain(), discovered_child_nodes.drain(..),
DispatchMode::NotTailCall, DispatchMode::NotTailCall,
recursion_ok, recursion_ok,
root, root,
@ -210,7 +210,7 @@ fn top_down_dom<'a, 'scope, E, D>(
if !discovered_child_nodes.is_empty() { if !discovered_child_nodes.is_empty() {
traversal_data.current_dom_depth += 1; traversal_data.current_dom_depth += 1;
traverse_nodes( traverse_nodes(
discovered_child_nodes.drain(), discovered_child_nodes.drain(..),
DispatchMode::TailCall, DispatchMode::TailCall,
recursion_ok, recursion_ok,
root, root,

View file

@ -743,6 +743,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
fn recompute_keyword_font_size_if_needed(&mut self) { fn recompute_keyword_font_size_if_needed(&mut self) {
use crate::values::computed::ToComputedValue; use crate::values::computed::ToComputedValue;
use crate::values::specified; use crate::values::specified;
use app_units::Au;
if !self.seen.contains(LonghandId::XLang) && if !self.seen.contains(LonghandId::XLang) &&
!self.seen.contains(LonghandId::FontFamily) { !self.seen.contains(LonghandId::FontFamily) {
@ -759,7 +760,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
None => return, None => return,
}; };
if font.gecko().mScriptUnconstrainedSize == new_size.size().0 { if font.gecko().mScriptUnconstrainedSize == Au::from(new_size.size()).0 {
return; return;
} }

View file

@ -10,7 +10,8 @@
# "offset-distance", # "offset-distance",
# "offset-path", # "offset-path",
# "offset-rotate", # "offset-rotate",
# "offset" # "offset",
# "text-underline-position",
COUNTED_UNKNOWN_PROPERTIES = [ COUNTED_UNKNOWN_PROPERTIES = [
"-webkit-font-smoothing", "-webkit-font-smoothing",
"-webkit-tap-highlight-color", "-webkit-tap-highlight-color",
@ -40,7 +41,6 @@ COUNTED_UNKNOWN_PROPERTIES = [
"baseline-shift", "baseline-shift",
"-webkit-hyphenate-character", "-webkit-hyphenate-character",
"page", "page",
"text-underline-position",
"-webkit-highlight", "-webkit-highlight",
"background-repeat-x", "background-repeat-x",
"-webkit-padding-end", "-webkit-padding-end",

View file

@ -385,6 +385,7 @@ class Longhand(object):
"TextDecorationLine", "TextDecorationLine",
"TextEmphasisPosition", "TextEmphasisPosition",
"TextTransform", "TextTransform",
"TextUnderlinePosition",
"TouchAction", "TouchAction",
"TransformStyle", "TransformStyle",
"UserSelect", "UserSelect",

View file

@ -1433,7 +1433,7 @@ fn report_css_errors(
selectors: Option<&SelectorList<SelectorImpl>>, selectors: Option<&SelectorList<SelectorImpl>>,
errors: &mut SmallParseErrorVec, errors: &mut SmallParseErrorVec,
) { ) {
for (error, slice, property) in errors.drain() { for (error, slice, property) in errors.drain(..) {
report_one_css_error(context, Some(block), selectors, error, slice, property) report_one_css_error(context, Some(block), selectors, error, slice, property)
} }
} }

View file

@ -426,7 +426,7 @@ def set_gecko_property(ffi_name, expr):
pub fn copy_${ident}_from(&mut self, other: &Self) { pub fn copy_${ident}_from(&mut self, other: &Self) {
use crate::gecko_bindings::structs::nsStyleSVG_${ident.upper()}_CONTEXT as CONTEXT_VALUE; use crate::gecko_bindings::structs::nsStyleSVG_${ident.upper()}_CONTEXT as CONTEXT_VALUE;
self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name}; self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name}.clone();
self.gecko.mContextFlags = self.gecko.mContextFlags =
(self.gecko.mContextFlags & !CONTEXT_VALUE) | (self.gecko.mContextFlags & !CONTEXT_VALUE) |
(other.gecko.mContextFlags & CONTEXT_VALUE); (other.gecko.mContextFlags & CONTEXT_VALUE);
@ -442,7 +442,7 @@ def set_gecko_property(ffi_name, expr):
if (self.gecko.mContextFlags & CONTEXT_VALUE) != 0 { if (self.gecko.mContextFlags & CONTEXT_VALUE) != 0 {
return SVGLength::ContextValue; return SVGLength::ContextValue;
} }
SVGLength::LengthPercentage(self.gecko.${gecko_ffi_name}) SVGLength::LengthPercentage(self.gecko.${gecko_ffi_name}.clone())
} }
</%def> </%def>
@ -563,7 +563,7 @@ def set_gecko_property(ffi_name, expr):
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn copy_${ident}_from(&mut self, other: &Self) { pub fn copy_${ident}_from(&mut self, other: &Self) {
self.gecko.${gecko_ffi_name}.${index} = self.gecko.${gecko_ffi_name}.${index} =
other.gecko.${gecko_ffi_name}.${index}; other.gecko.${gecko_ffi_name}.${index}.clone();
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn reset_${ident}(&mut self, other: &Self) { pub fn reset_${ident}(&mut self, other: &Self) {
@ -572,7 +572,7 @@ def set_gecko_property(ffi_name, expr):
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
self.gecko.${gecko_ffi_name}.${index} self.gecko.${gecko_ffi_name}.${index}.clone()
} }
</%def> </%def>
@ -601,7 +601,7 @@ def set_gecko_property(ffi_name, expr):
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn copy_${ident}_from(&mut self, other: &Self) { pub fn copy_${ident}_from(&mut self, other: &Self) {
self.gecko.${gecko_ffi_name}.${corner} = self.gecko.${gecko_ffi_name}.${corner} =
other.gecko.${gecko_ffi_name}.${corner}; other.gecko.${gecko_ffi_name}.${corner}.clone();
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn reset_${ident}(&mut self, other: &Self) { pub fn reset_${ident}(&mut self, other: &Self) {
@ -609,7 +609,7 @@ def set_gecko_property(ffi_name, expr):
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
self.gecko.${gecko_ffi_name}.${corner} self.gecko.${gecko_ffi_name}.${corner}.clone()
} }
</%def> </%def>
@ -1134,7 +1134,7 @@ fn static_assert() {
pub fn set_font_size(&mut self, v: FontSize) { pub fn set_font_size(&mut self, v: FontSize) {
use crate::values::specified::font::KeywordSize; use crate::values::specified::font::KeywordSize;
let size = v.size(); let size = Au::from(v.size());
self.gecko.mScriptUnconstrainedSize = size.0; self.gecko.mScriptUnconstrainedSize = size.0;
// These two may be changed from Cascade::fixup_font_stuff. // These two may be changed from Cascade::fixup_font_stuff.
@ -1852,7 +1852,7 @@ fn static_assert() {
for (layer, other) in self.gecko.${layers_field_name}.mLayers.iter_mut() for (layer, other) in self.gecko.${layers_field_name}.mLayers.iter_mut()
.zip(other.gecko.${layers_field_name}.mLayers.iter()) .zip(other.gecko.${layers_field_name}.mLayers.iter())
.take(count as usize) { .take(count as usize) {
layer.${field_name} = other.${field_name}; layer.${field_name} = other.${field_name}.clone();
} }
self.gecko.${layers_field_name}.${field_name}Count = count; self.gecko.${layers_field_name}.${field_name}Count = count;
} }
@ -2006,7 +2006,7 @@ fn static_assert() {
for (layer, other) in self.gecko.${image_layers_field}.mLayers.iter_mut() for (layer, other) in self.gecko.${image_layers_field}.mLayers.iter_mut()
.zip(other.gecko.${image_layers_field}.mLayers.iter()) .zip(other.gecko.${image_layers_field}.mLayers.iter())
.take(count as usize) { .take(count as usize) {
layer.mPosition.${keyword} = other.mPosition.${keyword}; layer.mPosition.${keyword} = other.mPosition.${keyword}.clone();
} }
self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count = count; self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count = count;
} }
@ -2020,7 +2020,7 @@ fn static_assert() {
longhands::${shorthand}_position_${orientation}::computed_value::List( longhands::${shorthand}_position_${orientation}::computed_value::List(
self.gecko.${image_layers_field}.mLayers.iter() self.gecko.${image_layers_field}.mLayers.iter()
.take(self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count as usize) .take(self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count as usize)
.map(|position| position.mPosition.${keyword}) .map(|position| position.mPosition.${keyword}.clone())
.collect() .collect()
) )
} }
@ -2054,7 +2054,7 @@ fn static_assert() {
pub fn clone_${shorthand}_size(&self) -> longhands::${shorthand}_size::computed_value::T { pub fn clone_${shorthand}_size(&self) -> longhands::${shorthand}_size::computed_value::T {
longhands::${shorthand}_size::computed_value::List( longhands::${shorthand}_size::computed_value::List(
self.gecko.${image_layers_field}.mLayers.iter().map(|layer| layer.mSize).collect() self.gecko.${image_layers_field}.mLayers.iter().map(|layer| layer.mSize.clone()).collect()
) )
} }

View file

@ -108,7 +108,6 @@ ${helpers.predefined_type(
"border-image-source", "border-image-source",
"ImageLayer", "ImageLayer",
engines="gecko servo-2013 servo-2020", engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
initial_value="computed::ImageLayer::none()", initial_value="computed::ImageLayer::none()",
initial_specified_value="specified::ImageLayer::none()", initial_specified_value="specified::ImageLayer::none()",
spec="https://drafts.csswg.org/css-backgrounds/#the-background-image", spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
@ -122,7 +121,6 @@ ${helpers.predefined_type(
"border-image-outset", "border-image-outset",
"NonNegativeLengthOrNumberRect", "NonNegativeLengthOrNumberRect",
engines="gecko servo-2013 servo-2020", engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
initial_value="generics::rect::Rect::all(computed::NonNegativeLengthOrNumber::zero())", initial_value="generics::rect::Rect::all(computed::NonNegativeLengthOrNumber::zero())",
initial_specified_value="generics::rect::Rect::all(specified::NonNegativeLengthOrNumber::zero())", initial_specified_value="generics::rect::Rect::all(specified::NonNegativeLengthOrNumber::zero())",
spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset", spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset",
@ -135,7 +133,6 @@ ${helpers.predefined_type(
"BorderImageRepeat", "BorderImageRepeat",
"computed::BorderImageRepeat::stretch()", "computed::BorderImageRepeat::stretch()",
engines="gecko servo-2013 servo-2020", engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
initial_specified_value="specified::BorderImageRepeat::stretch()", initial_specified_value="specified::BorderImageRepeat::stretch()",
animation_value_type="discrete", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-backgrounds/#the-border-image-repeat", spec="https://drafts.csswg.org/css-backgrounds/#the-border-image-repeat",
@ -145,7 +142,6 @@ ${helpers.predefined_type(
"border-image-width", "border-image-width",
"BorderImageWidth", "BorderImageWidth",
engines="gecko servo-2013 servo-2020", engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
initial_value="computed::BorderImageWidth::all(computed::BorderImageSideWidth::one())", initial_value="computed::BorderImageWidth::all(computed::BorderImageSideWidth::one())",
initial_specified_value="specified::BorderImageWidth::all(specified::BorderImageSideWidth::one())", initial_specified_value="specified::BorderImageWidth::all(specified::BorderImageSideWidth::one())",
spec="https://drafts.csswg.org/css-backgrounds/#border-image-width", spec="https://drafts.csswg.org/css-backgrounds/#border-image-width",
@ -157,7 +153,6 @@ ${helpers.predefined_type(
"border-image-slice", "border-image-slice",
"BorderImageSlice", "BorderImageSlice",
engines="gecko servo-2013 servo-2020", engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
initial_value="computed::BorderImageSlice::hundred_percent()", initial_value="computed::BorderImageSlice::hundred_percent()",
initial_specified_value="specified::BorderImageSlice::hundred_percent()", initial_specified_value="specified::BorderImageSlice::hundred_percent()",
spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice", spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice",

View file

@ -24,7 +24,7 @@ ${helpers.single_keyword(
"-moz-top-layer", "-moz-top-layer",
"none top", "none top",
engines="gecko", engines="gecko",
gecko_constant_prefix="NS_STYLE_TOP_LAYER", gecko_enum_prefix="StyleTopLayer",
gecko_ffi_name="mTopLayer", gecko_ffi_name="mTopLayer",
animation_value_type="none", animation_value_type="none",
enabled_in="ua", enabled_in="ua",
@ -494,6 +494,7 @@ ${helpers.single_keyword(
engines="gecko", engines="gecko",
spec="https://drafts.fxtf.org/compositing/#isolation", spec="https://drafts.fxtf.org/compositing/#isolation",
flags="CREATES_STACKING_CONTEXT", flags="CREATES_STACKING_CONTEXT",
gecko_enum_prefix="StyleIsolation",
animation_value_type="discrete", animation_value_type="discrete",
)} )}

View file

@ -16,6 +16,7 @@ ${helpers.single_keyword(
gecko_ffi_name="mVisible", gecko_ffi_name="mVisible",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
spec="https://drafts.csswg.org/css-box/#propdef-visibility", spec="https://drafts.csswg.org/css-box/#propdef-visibility",
gecko_enum_prefix="StyleVisibility",
)} )}
// CSS Writing Modes Level 3 // CSS Writing Modes Level 3

View file

@ -53,7 +53,7 @@ ${helpers.single_keyword(
"-moz-text-size-adjust", "-moz-text-size-adjust",
"auto none", "auto none",
engines="gecko", engines="gecko",
gecko_constant_prefix="NS_STYLE_TEXT_SIZE_ADJUST", gecko_enum_prefix="StyleTextSizeAdjust",
gecko_ffi_name="mTextSizeAdjust", gecko_ffi_name="mTextSizeAdjust",
animation_value_type="discrete", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-size-adjust/#adjustment-control", spec="https://drafts.csswg.org/css-size-adjust/#adjustment-control",
@ -332,6 +332,7 @@ ${helpers.single_keyword(
"space-around start center space-between", "space-around start center space-between",
engines="gecko", engines="gecko",
animation_value_type="discrete", animation_value_type="discrete",
gecko_enum_prefix="StyleRubyAlign",
spec="https://drafts.csswg.org/css-ruby/#ruby-align-property", spec="https://drafts.csswg.org/css-ruby/#ruby-align-property",
)} )}
@ -341,6 +342,7 @@ ${helpers.single_keyword(
engines="gecko", engines="gecko",
animation_value_type="discrete", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-ruby/#ruby-position-property", spec="https://drafts.csswg.org/css-ruby/#ruby-position-property",
gecko_enum_prefix="StyleRubyPosition",
)} )}
// CSS Writing Modes Module Level 3 // CSS Writing Modes Module Level 3
@ -389,6 +391,18 @@ ${helpers.predefined_type(
spec="https://drafts.csswg.org/css-text-decor-4/#underline-offset", spec="https://drafts.csswg.org/css-text-decor-4/#underline-offset",
)} )}
// text underline position
${helpers.predefined_type(
"text-underline-position",
"TextUnderlinePosition",
"computed::TextUnderlinePosition::AUTO",
engines="gecko",
animation_value_type="discrete",
gecko_pref="layout.css.text-underline-position.enabled",
has_effect_on_gecko_scrollbars=False,
spec="https://drafts.csswg.org/css-text-decor-3/#text-underline-position-property",
)}
// text decoration skip ink // text decoration skip ink
${helpers.predefined_type( ${helpers.predefined_type(
"text-decoration-skip-ink", "text-decoration-skip-ink",

View file

@ -26,6 +26,7 @@ ${helpers.single_keyword(
animation_value_type="discrete", animation_value_type="discrete",
extra_gecko_values="visiblepainted visiblefill visiblestroke visible painted fill stroke all", extra_gecko_values="visiblepainted visiblefill visiblestroke visible painted fill stroke all",
spec="https://www.w3.org/TR/SVG11/interact.html#PointerEventsProperty", spec="https://www.w3.org/TR/SVG11/interact.html#PointerEventsProperty",
gecko_enum_prefix="StylePointerEvents",
)} )}
${helpers.single_keyword( ${helpers.single_keyword(

View file

@ -3121,59 +3121,59 @@ impl ComputedValuesInner {
/// Get the logical computed inline size. /// Get the logical computed inline size.
#[inline] #[inline]
pub fn content_inline_size(&self) -> computed::Size { pub fn content_inline_size(&self) -> &computed::Size {
let position_style = self.get_position(); let position_style = self.get_position();
if self.writing_mode.is_vertical() { if self.writing_mode.is_vertical() {
position_style.height &position_style.height
} else { } else {
position_style.width &position_style.width
} }
} }
/// Get the logical computed block size. /// Get the logical computed block size.
#[inline] #[inline]
pub fn content_block_size(&self) -> computed::Size { pub fn content_block_size(&self) -> &computed::Size {
let position_style = self.get_position(); let position_style = self.get_position();
if self.writing_mode.is_vertical() { position_style.width } else { position_style.height } if self.writing_mode.is_vertical() { &position_style.width } else { &position_style.height }
} }
/// Get the logical computed min inline size. /// Get the logical computed min inline size.
#[inline] #[inline]
pub fn min_inline_size(&self) -> computed::Size { pub fn min_inline_size(&self) -> &computed::Size {
let position_style = self.get_position(); let position_style = self.get_position();
if self.writing_mode.is_vertical() { position_style.min_height } else { position_style.min_width } if self.writing_mode.is_vertical() { &position_style.min_height } else { &position_style.min_width }
} }
/// Get the logical computed min block size. /// Get the logical computed min block size.
#[inline] #[inline]
pub fn min_block_size(&self) -> computed::Size { pub fn min_block_size(&self) -> &computed::Size {
let position_style = self.get_position(); let position_style = self.get_position();
if self.writing_mode.is_vertical() { position_style.min_width } else { position_style.min_height } if self.writing_mode.is_vertical() { &position_style.min_width } else { &position_style.min_height }
} }
/// Get the logical computed max inline size. /// Get the logical computed max inline size.
#[inline] #[inline]
pub fn max_inline_size(&self) -> computed::MaxSize { pub fn max_inline_size(&self) -> &computed::MaxSize {
let position_style = self.get_position(); let position_style = self.get_position();
if self.writing_mode.is_vertical() { position_style.max_height } else { position_style.max_width } if self.writing_mode.is_vertical() { &position_style.max_height } else { &position_style.max_width }
} }
/// Get the logical computed max block size. /// Get the logical computed max block size.
#[inline] #[inline]
pub fn max_block_size(&self) -> computed::MaxSize { pub fn max_block_size(&self) -> &computed::MaxSize {
let position_style = self.get_position(); let position_style = self.get_position();
if self.writing_mode.is_vertical() { position_style.max_width } else { position_style.max_height } if self.writing_mode.is_vertical() { &position_style.max_width } else { &position_style.max_height }
} }
/// Get the logical computed padding for this writing mode. /// Get the logical computed padding for this writing mode.
#[inline] #[inline]
pub fn logical_padding(&self) -> LogicalMargin<computed::LengthPercentage> { pub fn logical_padding(&self) -> LogicalMargin<<&computed::LengthPercentage> {
let padding_style = self.get_padding(); let padding_style = self.get_padding();
LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new( LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new(
padding_style.padding_top.0, &padding_style.padding_top.0,
padding_style.padding_right.0, &padding_style.padding_right.0,
padding_style.padding_bottom.0, &padding_style.padding_bottom.0,
padding_style.padding_left.0, &padding_style.padding_left.0,
)) ))
} }
@ -3197,26 +3197,26 @@ impl ComputedValuesInner {
/// Gets the logical computed margin from this style. /// Gets the logical computed margin from this style.
#[inline] #[inline]
pub fn logical_margin(&self) -> LogicalMargin<computed::LengthPercentageOrAuto> { pub fn logical_margin(&self) -> LogicalMargin<<&computed::LengthPercentageOrAuto> {
let margin_style = self.get_margin(); let margin_style = self.get_margin();
LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new( LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new(
margin_style.margin_top, &margin_style.margin_top,
margin_style.margin_right, &margin_style.margin_right,
margin_style.margin_bottom, &margin_style.margin_bottom,
margin_style.margin_left, &margin_style.margin_left,
)) ))
} }
/// Gets the logical position from this style. /// Gets the logical position from this style.
#[inline] #[inline]
pub fn logical_position(&self) -> LogicalMargin<computed::LengthPercentageOrAuto> { pub fn logical_position(&self) -> LogicalMargin<<&computed::LengthPercentageOrAuto> {
// FIXME(SimonSapin): should be the writing mode of the containing block, maybe? // FIXME(SimonSapin): should be the writing mode of the containing block, maybe?
let position_style = self.get_position(); let position_style = self.get_position();
LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new( LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new(
position_style.top, &position_style.top,
position_style.right, &position_style.right,
position_style.bottom, &position_style.bottom,
position_style.left, &position_style.left,
)) ))
} }

View file

@ -179,6 +179,16 @@ pub fn parse_border<'i, 't>(
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> ToCss for LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
use crate::properties::longhands;
// If any of the border-image longhands differ from their initial specified values we should not
// invoke serialize_directional_border(), so there is no point in continuing on to compute all_equal.
% for name in "outset repeat slice source width".split():
if *self.border_image_${name} != longhands::border_image_${name}::get_initial_specified_value() {
return Ok(());
}
% endfor
let all_equal = { let all_equal = {
% for side in PHYSICAL_SIDES: % for side in PHYSICAL_SIDES:
let border_${side}_width = self.border_${side}_width; let border_${side}_width = self.border_${side}_width;

View file

@ -348,7 +348,8 @@ where
return; return;
} }
let outer_shadow = inner_shadow.host().containing_shadow(); let inner_shadow_host = inner_shadow.host();
let outer_shadow = inner_shadow_host.containing_shadow();
let part_rules = match outer_shadow { let part_rules = match outer_shadow {
Some(shadow) => shadow Some(shadow) => shadow
.style_data() .style_data()
@ -387,8 +388,6 @@ where
shadow_cascade_order.inc(); shadow_cascade_order.inc();
} }
let inner_shadow_host = inner_shadow.host();
inner_shadow = match outer_shadow { inner_shadow = match outer_shadow {
Some(s) => s, Some(s) => s,
None => break, // Nowhere to export to. None => break, // Nowhere to export to.

View file

@ -345,7 +345,7 @@ impl RuleTree {
important_author.sort_by_key(|&(_, order)| -order); important_author.sort_by_key(|&(_, order)| -order);
} }
for (source, shadow_cascade_order) in important_author.drain() { for (source, shadow_cascade_order) in important_author.drain(..) {
current = current.ensure_child( current = current.ensure_child(
self.root.downgrade(), self.root.downgrade(),
source, source,
@ -355,11 +355,11 @@ impl RuleTree {
); );
} }
for source in important_user.drain() { for source in important_user.drain(..) {
current = current.ensure_child(self.root.downgrade(), source, UserImportant); current = current.ensure_child(self.root.downgrade(), source, UserImportant);
} }
for source in important_ua.drain() { for source in important_ua.drain(..) {
current = current.ensure_child(self.root.downgrade(), source, UAImportant); current = current.ensure_child(self.root.downgrade(), source, UAImportant);
} }
@ -378,7 +378,7 @@ impl RuleTree {
guards: &StylesheetGuards, guards: &StylesheetGuards,
) -> StrongRuleNode { ) -> StrongRuleNode {
self.insert_ordered_rules_with_important( self.insert_ordered_rules_with_important(
applicable_declarations.drain().map(|d| d.for_rule_tree()), applicable_declarations.drain(..).map(|d| d.for_rule_tree()),
guards, guards,
) )
} }
@ -556,7 +556,7 @@ impl RuleTree {
// Now the rule is in the relevant place, push the children as // Now the rule is in the relevant place, push the children as
// necessary. // necessary.
let rule = self.insert_ordered_rules_from(current, children.drain().rev()); let rule = self.insert_ordered_rules_from(current, children.drain(..).rev());
Some(rule) Some(rule)
} }
@ -592,8 +592,8 @@ impl RuleTree {
last = node; last = node;
} }
let rule = let rule = self
self.insert_ordered_rules_from(last.parent().unwrap().clone(), children.drain().rev()); .insert_ordered_rules_from(last.parent().unwrap().clone(), children.drain(..).rev());
rule rule
} }

View file

@ -10,8 +10,8 @@ use crate::media_queries::media_feature::{Evaluator, MediaFeatureDescription};
use crate::media_queries::media_feature_expression::RangeOrOperator; use crate::media_queries::media_feature_expression::RangeOrOperator;
use crate::media_queries::MediaType; use crate::media_queries::MediaType;
use crate::properties::ComputedValues; use crate::properties::ComputedValues;
use crate::values::computed::font::FontSize;
use crate::values::computed::CSSPixelLength; use crate::values::computed::CSSPixelLength;
use crate::values::specified::font::FONT_MEDIUM_PX;
use crate::values::KeyframesName; use crate::values::KeyframesName;
use app_units::Au; use app_units::Au;
use cssparser::RGBA; use cssparser::RGBA;
@ -68,7 +68,7 @@ impl Device {
viewport_size, viewport_size,
device_pixel_ratio, device_pixel_ratio,
// FIXME(bz): Seems dubious? // FIXME(bz): Seems dubious?
root_font_size: AtomicIsize::new(FontSize::medium().size().0 as isize), root_font_size: AtomicIsize::new(Au::from_px(FONT_MEDIUM_PX).0 as isize),
used_root_font_size: AtomicBool::new(false), used_root_font_size: AtomicBool::new(false),
used_viewport_units: AtomicBool::new(false), used_viewport_units: AtomicBool::new(false),
environment: CssEnvironment, environment: CssEnvironment,

View file

@ -309,6 +309,11 @@ impl ::selectors::parser::NonTSPseudoClass for NonTSPseudoClass {
NonTSPseudoClass::Active | NonTSPseudoClass::Hover | NonTSPseudoClass::Focus NonTSPseudoClass::Active | NonTSPseudoClass::Hover | NonTSPseudoClass::Focus
) )
} }
#[inline]
fn has_zero_specificity(&self) -> bool {
false
}
} }
impl ToCss for NonTSPseudoClass { impl ToCss for NonTSPseudoClass {

View file

@ -59,6 +59,7 @@ pub use self::rules_iterator::{AllRules, EffectiveRules};
pub use self::rules_iterator::{NestedRuleIterationCondition, RulesIterator}; pub use self::rules_iterator::{NestedRuleIterationCondition, RulesIterator};
pub use self::style_rule::StyleRule; pub use self::style_rule::StyleRule;
pub use self::stylesheet::{DocumentStyleSheet, Namespaces, Stylesheet}; pub use self::stylesheet::{DocumentStyleSheet, Namespaces, Stylesheet};
pub use self::stylesheet::{SanitizationData, SanitizationKind};
pub use self::stylesheet::{StylesheetContents, StylesheetInDocument, UserAgentStylesheets}; pub use self::stylesheet::{StylesheetContents, StylesheetInDocument, UserAgentStylesheets};
pub use self::supports_rule::SupportsRule; pub use self::supports_rule::SupportsRule;
pub use self::viewport_rule::ViewportRule; pub use self::viewport_rule::ViewportRule;

View file

@ -7,8 +7,9 @@
use crate::shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; use crate::shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use crate::str::CssStringWriter; use crate::str::CssStringWriter;
use crate::{Namespace, Prefix}; use crate::{Namespace, Prefix};
use cssparser::SourceLocation; use cssparser::{self, SourceLocation};
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
/// A `@namespace` rule. /// A `@namespace` rule.
#[derive(Clone, Debug, PartialEq, ToShmem)] #[derive(Clone, Debug, PartialEq, ToShmem)]
@ -27,13 +28,12 @@ impl ToCssWithGuard for NamespaceRule {
fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result { fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
dest.write_str("@namespace ")?; dest.write_str("@namespace ")?;
if let Some(ref prefix) = self.prefix { if let Some(ref prefix) = self.prefix {
dest.write_str(&*prefix.to_string())?; let prefix = prefix.to_string();
cssparser::serialize_identifier(&prefix, dest)?;
dest.write_str(" ")?; dest.write_str(" ")?;
} }
dest.write_str("url(")?;
// FIXME(emilio): Pretty sure this needs some escaping, or something? self.url.to_string().to_css(&mut CssWriter::new(dest))?;
dest.write_str("url(\"")?; dest.write_str(");")
dest.write_str(&*self.url.to_string())?;
dest.write_str("\");")
} }
} }

View file

@ -81,6 +81,7 @@ impl StylesheetContents {
quirks_mode: QuirksMode, quirks_mode: QuirksMode,
line_number_offset: u32, line_number_offset: u32,
use_counters: Option<&UseCounters>, use_counters: Option<&UseCounters>,
sanitization_data: Option<&mut SanitizationData>,
) -> Self { ) -> Self {
let namespaces = RwLock::new(Namespaces::default()); let namespaces = RwLock::new(Namespaces::default());
let (rules, source_map_url, source_url) = Stylesheet::parse_rules( let (rules, source_map_url, source_url) = Stylesheet::parse_rules(
@ -94,6 +95,7 @@ impl StylesheetContents {
quirks_mode, quirks_mode,
line_number_offset, line_number_offset,
use_counters, use_counters,
sanitization_data,
); );
Self { Self {
@ -341,6 +343,69 @@ impl StylesheetInDocument for DocumentStyleSheet {
} }
} }
/// The kind of sanitization to use when parsing a stylesheet.
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SanitizationKind {
/// Perform no sanitization.
None,
/// Allow only @font-face, style rules, and @namespace.
Standard,
/// Allow everything but conditional rules.
NoConditionalRules,
}
impl SanitizationKind {
fn allows(self, rule: &CssRule) -> bool {
debug_assert_ne!(self, SanitizationKind::None);
// NOTE(emilio): If this becomes more complex (not filtering just by
// top-level rules), we should thread all the data through nested rules
// and such. But this doesn't seem necessary at the moment.
let is_standard = matches!(self, SanitizationKind::Standard);
match *rule {
CssRule::Document(..) |
CssRule::Media(..) |
CssRule::Supports(..) |
CssRule::Import(..) => false,
CssRule::FontFace(..) | CssRule::Namespace(..) | CssRule::Style(..) => true,
CssRule::Keyframes(..) |
CssRule::Page(..) |
CssRule::FontFeatureValues(..) |
CssRule::Viewport(..) |
CssRule::CounterStyle(..) => !is_standard,
}
}
}
/// A struct to hold the data relevant to style sheet sanitization.
#[derive(Debug)]
pub struct SanitizationData {
kind: SanitizationKind,
output: String,
}
impl SanitizationData {
/// Create a new input for sanitization.
#[inline]
pub fn new(kind: SanitizationKind) -> Option<Self> {
if matches!(kind, SanitizationKind::None) {
return None;
}
Some(Self {
kind,
output: String::new(),
})
}
/// Take the sanitized output.
#[inline]
pub fn take(self) -> String {
self.output
}
}
impl Stylesheet { impl Stylesheet {
/// Updates an empty stylesheet from a given string of text. /// Updates an empty stylesheet from a given string of text.
pub fn update_from_str( pub fn update_from_str(
@ -365,6 +430,7 @@ impl Stylesheet {
existing.contents.quirks_mode, existing.contents.quirks_mode,
line_number_offset, line_number_offset,
/* use_counters = */ None, /* use_counters = */ None,
/* sanitization_data = */ None,
); );
*existing.contents.url_data.write() = url_data; *existing.contents.url_data.write() = url_data;
@ -391,6 +457,7 @@ impl Stylesheet {
quirks_mode: QuirksMode, quirks_mode: QuirksMode,
line_number_offset: u32, line_number_offset: u32,
use_counters: Option<&UseCounters>, use_counters: Option<&UseCounters>,
mut sanitization_data: Option<&mut SanitizationData>,
) -> (Vec<CssRule>, Option<String>, Option<String>) { ) -> (Vec<CssRule>, Option<String>, Option<String>) {
let mut rules = Vec::new(); let mut rules = Vec::new();
let mut input = ParserInput::new_with_line_number_offset(css, line_number_offset); let mut input = ParserInput::new_with_line_number_offset(css, line_number_offset);
@ -419,12 +486,24 @@ impl Stylesheet {
{ {
let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser); let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser);
while let Some(result) = iter.next() { loop {
let rule_start = iter.input.position().byte_index();
let result = match iter.next() {
Some(result) => result,
None => break,
};
match result { match result {
Ok(rule) => { Ok(rule) => {
// Use a fallible push here, and if it fails, just if let Some(ref mut data) = sanitization_data {
// fall out of the loop. This will cause the page to if !data.kind.allows(&rule) {
// be shown incorrectly, but it's better than OOMing. continue;
}
let end = iter.input.position().byte_index();
data.output.push_str(&css[rule_start..end]);
}
// Use a fallible push here, and if it fails, just fall
// out of the loop. This will cause the page to be
// shown incorrectly, but it's better than OOMing.
if rules.try_push(rule).is_err() { if rules.try_push(rule).is_err() {
break; break;
} }
@ -470,6 +549,7 @@ impl Stylesheet {
quirks_mode, quirks_mode,
line_number_offset, line_number_offset,
/* use_counters = */ None, /* use_counters = */ None,
/* sanitized_output = */ None,
); );
Stylesheet { Stylesheet {

View file

@ -1013,7 +1013,7 @@ impl Stylist {
); );
if !declarations.is_empty() { if !declarations.is_empty() {
let rule_node = self.rule_tree.insert_ordered_rules_with_important( let rule_node = self.rule_tree.insert_ordered_rules_with_important(
declarations.drain().map(|a| a.for_rule_tree()), declarations.drain(..).map(|a| a.for_rule_tree()),
guards, guards,
); );
if rule_node != *self.rule_tree.root() { if rule_node != *self.rule_tree.root() {
@ -1889,18 +1889,33 @@ impl CascadeData {
self.host_rules.as_ref().and_then(|d| d.rules(pseudo)) self.host_rules.as_ref().and_then(|d| d.rules(pseudo))
} }
/// Whether there's any host rule that could match in this scope.
pub fn any_host_rules(&self) -> bool {
self.host_rules.is_some()
}
/// Returns the slotted rule map for a given pseudo-element. /// Returns the slotted rule map for a given pseudo-element.
#[inline] #[inline]
pub fn slotted_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> { pub fn slotted_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
self.slotted_rules.as_ref().and_then(|d| d.rules(pseudo)) self.slotted_rules.as_ref().and_then(|d| d.rules(pseudo))
} }
/// Whether there's any ::slotted rule that could match in this scope.
pub fn any_slotted_rule(&self) -> bool {
self.slotted_rules.is_some()
}
/// Returns the parts rule map for a given pseudo-element. /// Returns the parts rule map for a given pseudo-element.
#[inline] #[inline]
pub fn part_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&PartMap> { pub fn part_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&PartMap> {
self.part_rules.as_ref().and_then(|d| d.rules(pseudo)) self.part_rules.as_ref().and_then(|d| d.rules(pseudo))
} }
/// Whether there's any ::part rule that could match in this scope.
pub fn any_part_rule(&self) -> bool {
self.part_rules.is_some()
}
/// Collects all the applicable media query results into `results`. /// Collects all the applicable media query results into `results`.
/// ///
/// This duplicates part of the logic in `add_stylesheet`, which is /// This duplicates part of the logic in `add_stylesheet`, which is

View file

@ -1373,7 +1373,7 @@ impl ComputedTranslate {
LengthPercentage::zero(), LengthPercentage::zero(),
Length::zero(), Length::zero(),
), ),
Translate::Translate(tx, ty, tz) => (tx, ty, tz), Translate::Translate(ref tx, ref ty, ref tz) => (tx.clone(), ty.clone(), tz.clone()),
} }
} }
} }

View file

@ -21,7 +21,6 @@ use crate::values::specified::font::{
use crate::values::specified::length::{FontBaseSize, NoCalcLength}; use crate::values::specified::length::{FontBaseSize, NoCalcLength};
use crate::values::CSSFloat; use crate::values::CSSFloat;
use crate::Atom; use crate::Atom;
use app_units::Au;
use byteorder::{BigEndian, ByteOrder}; use byteorder::{BigEndian, ByteOrder};
use cssparser::{serialize_identifier, CssStringWriter, Parser}; use cssparser::{serialize_identifier, CssStringWriter, Parser};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
@ -148,15 +147,16 @@ impl FontWeight {
impl FontSize { impl FontSize {
/// The actual computed font size. /// The actual computed font size.
pub fn size(self) -> Au { #[inline]
self.size.into() pub fn size(&self) -> Length {
self.size.0
} }
#[inline] #[inline]
/// Get default value of font size. /// Get default value of font size.
pub fn medium() -> Self { pub fn medium() -> Self {
Self { Self {
size: Au::from_px(specified::FONT_MEDIUM_PX).into(), size: NonNegative(Length::new(specified::FONT_MEDIUM_PX as CSSFloat)),
keyword_info: Some(KeywordInfo::medium()), keyword_info: Some(KeywordInfo::medium()),
} }
} }

View file

@ -29,7 +29,7 @@ pub use crate::values::specified::url::UrlOrNone;
pub use crate::values::specified::{Angle, BorderStyle, Time}; pub use crate::values::specified::{Angle, BorderStyle, Time};
impl ToComputedValue for specified::NoCalcLength { impl ToComputedValue for specified::NoCalcLength {
type ComputedValue = CSSPixelLength; type ComputedValue = Length;
#[inline] #[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
@ -75,9 +75,7 @@ impl ToComputedValue for specified::Length {
/// ///
/// https://drafts.csswg.org/css-values-4/#typedef-length-percentage /// https://drafts.csswg.org/css-values-4/#typedef-length-percentage
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive( #[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize, ToAnimatedZero, ToResolvedValue)]
Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize, ToAnimatedZero, ToResolvedValue,
)]
#[repr(C)] #[repr(C)]
pub struct LengthPercentage { pub struct LengthPercentage {
length: Length, length: Length,
@ -543,14 +541,14 @@ impl ToAnimatedValue for NonNegativeLengthPercentage {
impl From<NonNegativeLength> for NonNegativeLengthPercentage { impl From<NonNegativeLength> for NonNegativeLengthPercentage {
#[inline] #[inline]
fn from(length: NonNegativeLength) -> Self { fn from(length: NonNegativeLength) -> Self {
LengthPercentage::new(length.0, None).into() NonNegative(LengthPercentage::new(length.0, None))
} }
} }
impl From<LengthPercentage> for NonNegativeLengthPercentage { impl From<LengthPercentage> for NonNegativeLengthPercentage {
#[inline] #[inline]
fn from(lp: LengthPercentage) -> Self { fn from(lp: LengthPercentage) -> Self {
NonNegative::<LengthPercentage>(lp) NonNegative(lp)
} }
} }

View file

@ -75,6 +75,7 @@ pub use self::resolution::Resolution;
pub use self::svg::MozContextProperties; pub use self::svg::MozContextProperties;
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind}; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
pub use self::text::TextUnderlinePosition;
pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight}; pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight};
pub use self::text::{OverflowWrap, TextOverflow, WordBreak, WordSpacing}; pub use self::text::{OverflowWrap, TextOverflow, WordBreak, WordSpacing};
pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle}; pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle};

View file

@ -19,6 +19,7 @@ use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss}; use style_traits::{CssWriter, ToCss};
pub use crate::values::specified::TextAlignKeyword as TextAlign; pub use crate::values::specified::TextAlignKeyword as TextAlign;
pub use crate::values::specified::TextUnderlinePosition;
pub use crate::values::specified::{LineBreak, OverflowWrap, WordBreak}; pub use crate::values::specified::{LineBreak, OverflowWrap, WordBreak};
pub use crate::values::specified::{TextDecorationLine, TextEmphasisPosition}; pub use crate::values::specified::{TextDecorationLine, TextEmphasisPosition};
pub use crate::values::specified::{TextDecorationSkipInk, TextTransform}; pub use crate::values::specified::{TextDecorationSkipInk, TextTransform};

View file

@ -207,15 +207,6 @@ impl<LengthPercentage> MaxSize<LengthPercentage> {
pub fn none() -> Self { pub fn none() -> Self {
MaxSize::None MaxSize::None
} }
/// Convert
#[cfg(not(feature = "gecko"))]
pub fn to_option(self) -> Option<LengthPercentage> {
match self {
Self::LengthPercentage(lp) => Some(lp),
Self::None => None,
}
}
} }
/// A generic `<length>` | `<number>` value for the `-moz-tab-size` property. /// A generic `<length>` | `<number>` value for the `-moz-tab-size` property.

View file

@ -691,11 +691,11 @@ fn parse_baseline<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, Pars
"first" => { "first" => {
input.expect_ident_matching("baseline")?; input.expect_ident_matching("baseline")?;
Ok(AlignFlags::BASELINE) Ok(AlignFlags::BASELINE)
} },
"last" => { "last" => {
input.expect_ident_matching("baseline")?; input.expect_ident_matching("baseline")?;
Ok(AlignFlags::LAST_BASELINE) Ok(AlignFlags::LAST_BASELINE)
} },
} }
} }
@ -794,7 +794,7 @@ fn parse_legacy<'i, 't>(input: &mut Parser<'i, 't>) -> Result<AlignFlags, ParseE
.unwrap_or(AlignFlags::empty()); .unwrap_or(AlignFlags::empty());
return Ok(AlignFlags::LEGACY | flags) return Ok(AlignFlags::LEGACY | flags)
} },
"left" => AlignFlags::LEFT, "left" => AlignFlags::LEFT,
"right" => AlignFlags::RIGHT, "right" => AlignFlags::RIGHT,
"center" => AlignFlags::CENTER, "center" => AlignFlags::CENTER,

View file

@ -389,21 +389,10 @@ impl Display {
}; };
Display::from3(DisplayOutside::Block, inside, self.is_list_item()) Display::from3(DisplayOutside::Block, inside, self.is_list_item())
}, },
// If this pref is true, then we'll blockify "-moz-inline-box" to
// "-moz-box", and blockify "-moz-box" to itself. Otherwise, we
// blockify both to "block".
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
DisplayOutside::XUL => { DisplayOutside::XUL => match self.inside() {
if static_prefs::pref!(
"layout.css.xul-box-display-values.survive-blockification.enabled"
) {
match self.inside() {
DisplayInside::MozInlineBox | DisplayInside::MozBox => Display::MozBox, DisplayInside::MozInlineBox | DisplayInside::MozBox => Display::MozBox,
_ => Display::Block, _ => Display::Block,
}
} else {
Display::Block
}
}, },
DisplayOutside::Block | DisplayOutside::None => *self, DisplayOutside::Block | DisplayOutside::None => *self,
#[cfg(any(feature = "servo-layout-2013", feature = "gecko"))] #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]

View file

@ -20,7 +20,6 @@ use crate::values::specified::{AllowQuirks, Angle, Integer, LengthPercentage};
use crate::values::specified::{NoCalcLength, NonNegativeNumber, Number, Percentage}; use crate::values::specified::{NoCalcLength, NonNegativeNumber, Number, Percentage};
use crate::values::CustomIdent; use crate::values::CustomIdent;
use crate::Atom; use crate::Atom;
use app_units::Au;
use byteorder::{BigEndian, ByteOrder}; use byteorder::{BigEndian, ByteOrder};
use cssparser::{Parser, Token}; use cssparser::{Parser, Token};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
@ -773,18 +772,18 @@ impl ToComputedValue for KeywordSize {
type ComputedValue = NonNegativeLength; type ComputedValue = NonNegativeLength;
#[inline] #[inline]
fn to_computed_value(&self, _: &Context) -> NonNegativeLength { fn to_computed_value(&self, _: &Context) -> NonNegativeLength {
let medium = Length::new(FONT_MEDIUM_PX as f32);
// https://drafts.csswg.org/css-fonts-3/#font-size-prop // https://drafts.csswg.org/css-fonts-3/#font-size-prop
match *self { NonNegative(match *self {
KeywordSize::XXSmall => Au::from_px(FONT_MEDIUM_PX) * 3 / 5, KeywordSize::XXSmall => medium * 3.0 / 5.0,
KeywordSize::XSmall => Au::from_px(FONT_MEDIUM_PX) * 3 / 4, KeywordSize::XSmall => medium * 3.0 / 4.0,
KeywordSize::Small => Au::from_px(FONT_MEDIUM_PX) * 8 / 9, KeywordSize::Small => medium * 8.0 / 9.0,
KeywordSize::Medium => Au::from_px(FONT_MEDIUM_PX), KeywordSize::Medium => medium,
KeywordSize::Large => Au::from_px(FONT_MEDIUM_PX) * 6 / 5, KeywordSize::Large => medium * 6.0 / 5.0,
KeywordSize::XLarge => Au::from_px(FONT_MEDIUM_PX) * 3 / 2, KeywordSize::XLarge => medium * 3.0 / 2.0,
KeywordSize::XXLarge => Au::from_px(FONT_MEDIUM_PX) * 2, KeywordSize::XXLarge => medium * 2.0,
KeywordSize::XXXLarge => Au::from_px(FONT_MEDIUM_PX) * 3, KeywordSize::XXXLarge => medium * 3.0,
} })
.into()
} }
#[inline] #[inline]
@ -799,7 +798,6 @@ impl ToComputedValue for KeywordSize {
#[inline] #[inline]
fn to_computed_value(&self, cx: &Context) -> NonNegativeLength { fn to_computed_value(&self, cx: &Context) -> NonNegativeLength {
use crate::context::QuirksMode; use crate::context::QuirksMode;
use crate::values::specified::length::au_to_int_px;
// The tables in this function are originally from // The tables in this function are originally from
// nsRuleNode::CalcFontPointSize in Gecko: // nsRuleNode::CalcFontPointSize in Gecko:
@ -850,22 +848,21 @@ impl ToComputedValue for KeywordSize {
Atom::with(gecko_font.mLanguage.mRawPtr, |atom| { Atom::with(gecko_font.mLanguage.mRawPtr, |atom| {
cx.font_metrics_provider cx.font_metrics_provider
.get_size(atom, gecko_font.mGenericID) .get_size(atom, gecko_font.mGenericID)
.0
}) })
}; };
let base_size_px = au_to_int_px(base_size as f32); let base_size_px = base_size.px().round() as i32;
let html_size = self.html_size() as usize; let html_size = self.html_size() as usize;
if base_size_px >= 9 && base_size_px <= 16 { NonNegative(if base_size_px >= 9 && base_size_px <= 16 {
let mapping = if cx.quirks_mode == QuirksMode::Quirks { let mapping = if cx.quirks_mode == QuirksMode::Quirks {
QUIRKS_FONT_SIZE_MAPPING QUIRKS_FONT_SIZE_MAPPING
} else { } else {
FONT_SIZE_MAPPING FONT_SIZE_MAPPING
}; };
Au::from_px(mapping[(base_size_px - 9) as usize][html_size]).into() Length::new(mapping[(base_size_px - 9) as usize][html_size] as f32)
} else { } else {
Au(FONT_SIZE_FACTORS[html_size] * base_size / 100).into() base_size * FONT_SIZE_FACTORS[html_size] as f32 / 100.0
} })
} }
#[inline] #[inline]
@ -927,7 +924,7 @@ impl FontSize {
// If the parent font was keyword-derived, this is too. // If the parent font was keyword-derived, this is too.
// Tack the % onto the factor // Tack the % onto the factor
info = compose_keyword(pc.0); info = compose_keyword(pc.0);
base_size.resolve(context).scale_by(pc.0).into() base_size.resolve(context) * pc.0
}, },
FontSize::Length(LengthPercentage::Calc(ref calc)) => { FontSize::Length(LengthPercentage::Calc(ref calc)) => {
let parent = context.style().get_parent_font().clone_font_size(); let parent = context.style().get_parent_font().clone_font_size();
@ -964,7 +961,7 @@ impl FontSize {
// others should reject negatives during parsing. But SMIL // others should reject negatives during parsing. But SMIL
// allows parsing negatives, and relies on us _not_ doing that // allows parsing negatives, and relies on us _not_ doing that
// clamping. That's so bonkers :( // clamping. That's so bonkers :(
CSSPixelLength::from(calc.to_used_value(base_size.resolve(context))) calc.percentage_relative_to(base_size.resolve(context))
.clamp_to_non_negative() .clamp_to_non_negative()
}, },
FontSize::Keyword(i) => { FontSize::Keyword(i) => {

View file

@ -5,8 +5,7 @@
//! Specified types for legacy Gecko-only properties. //! Specified types for legacy Gecko-only properties.
use crate::parser::{Parse, ParserContext}; use crate::parser::{Parse, ParserContext};
use crate::values::computed::length::CSSPixelLength; use crate::values::computed::{self, Length, LengthPercentage};
use crate::values::computed::{self, LengthPercentage};
use crate::values::generics::rect::Rect; use crate::values::generics::rect::Rect;
use cssparser::{Parser, Token}; use cssparser::{Parser, Token};
use std::fmt; use std::fmt;
@ -24,7 +23,7 @@ fn parse_pixel_or_percent<'i, 't>(
value, ref unit, .. value, ref unit, ..
} => { } => {
match_ignore_ascii_case! { unit, match_ignore_ascii_case! { unit,
"px" => Ok(LengthPercentage::new(CSSPixelLength::new(value), None)), "px" => Ok(LengthPercentage::new(Length::new(value), None)),
_ => Err(()), _ => Err(()),
} }
}, },

View file

@ -47,14 +47,6 @@ pub const AU_PER_PT: CSSFloat = AU_PER_IN / 72.;
/// Number of app units per pica /// Number of app units per pica
pub const AU_PER_PC: CSSFloat = AU_PER_PT * 12.; pub const AU_PER_PC: CSSFloat = AU_PER_PT * 12.;
/// Same as Gecko's AppUnitsToIntCSSPixels
///
/// Converts app units to integer pixel values,
/// rounding during the conversion
pub fn au_to_int_px(au: f32) -> i32 {
(au / AU_PER_PX).round() as i32
}
/// A font relative length. /// A font relative length.
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)] #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
pub enum FontRelativeLength { pub enum FontRelativeLength {
@ -87,7 +79,7 @@ pub enum FontBaseSize {
impl FontBaseSize { impl FontBaseSize {
/// Calculate the actual size for a given context /// Calculate the actual size for a given context
pub fn resolve(&self, context: &Context) -> Au { pub fn resolve(&self, context: &Context) -> computed::Length {
match *self { match *self {
FontBaseSize::CurrentStyle => context.style().get_font().clone_font_size().size(), FontBaseSize::CurrentStyle => context.style().get_font().clone_font_size().size(),
FontBaseSize::InheritedStyleButStripEmUnits | FontBaseSize::InheritedStyle => { FontBaseSize::InheritedStyleButStripEmUnits | FontBaseSize::InheritedStyle => {
@ -109,13 +101,13 @@ impl FontRelativeLength {
} }
/// Computes the font-relative length. /// Computes the font-relative length.
pub fn to_computed_value(&self, context: &Context, base_size: FontBaseSize) -> CSSPixelLength { pub fn to_computed_value(
use std::f32; &self,
context: &Context,
base_size: FontBaseSize,
) -> computed::Length {
let (reference_size, length) = self.reference_font_size_and_length(context, base_size); let (reference_size, length) = self.reference_font_size_and_length(context, base_size);
let pixel = (length * reference_size.to_f32_px()) reference_size * length
.min(f32::MAX)
.max(f32::MIN);
CSSPixelLength::new(pixel)
} }
/// Return reference font size. /// Return reference font size.
@ -129,7 +121,7 @@ impl FontRelativeLength {
&self, &self,
context: &Context, context: &Context,
base_size: FontBaseSize, base_size: FontBaseSize,
) -> (Au, CSSFloat) { ) -> (computed::Length, CSSFloat) {
fn query_font_metrics( fn query_font_metrics(
context: &Context, context: &Context,
base_size: FontBaseSize, base_size: FontBaseSize,
@ -153,7 +145,7 @@ impl FontRelativeLength {
} }
if base_size == FontBaseSize::InheritedStyleButStripEmUnits { if base_size == FontBaseSize::InheritedStyleButStripEmUnits {
(Au(0), length) (Zero::zero(), length)
} else { } else {
(reference_font_size, length) (reference_font_size, length)
} }
@ -175,7 +167,7 @@ impl FontRelativeLength {
// determine the x-height, a value of 0.5em must be // determine the x-height, a value of 0.5em must be
// assumed. // assumed.
// //
reference_font_size.scale_by(0.5) reference_font_size * 0.5
}); });
(reference_size, length) (reference_size, length)
}, },
@ -210,7 +202,7 @@ impl FontRelativeLength {
if wm.is_vertical() && wm.is_upright() { if wm.is_vertical() && wm.is_upright() {
reference_font_size reference_font_size
} else { } else {
reference_font_size.scale_by(0.5) reference_font_size * 0.5
} }
}); });
(reference_size, length) (reference_size, length)
@ -225,7 +217,7 @@ impl FontRelativeLength {
let reference_size = if context.is_root_element || context.in_media_query { let reference_size = if context.is_root_element || context.in_media_query {
reference_font_size reference_font_size
} else { } else {
context.device().root_font_size() computed::Length::new(context.device().root_font_size().to_f32_px())
}; };
(reference_size, length) (reference_size, length)
}, },
@ -290,15 +282,14 @@ pub struct CharacterWidth(pub i32);
impl CharacterWidth { impl CharacterWidth {
/// Computes the given character width. /// Computes the given character width.
pub fn to_computed_value(&self, reference_font_size: Au) -> CSSPixelLength { pub fn to_computed_value(&self, reference_font_size: computed::Length) -> computed::Length {
// This applies the *converting a character width to pixels* algorithm as specified // This applies the *converting a character width to pixels* algorithm
// in HTML5 § 14.5.4. // as specified in HTML5 § 14.5.4.
// //
// TODO(pcwalton): Find these from the font. // TODO(pcwalton): Find these from the font.
let average_advance = reference_font_size.scale_by(0.5); let average_advance = reference_font_size * 0.5;
let max_advance = reference_font_size; let max_advance = reference_font_size;
let au = average_advance.scale_by(self.0 as CSSFloat - 1.0) + max_advance; average_advance * (self.0 as CSSFloat - 1.0) + max_advance
au.into()
} }
} }

View file

@ -80,6 +80,7 @@ pub use self::svg::MozContextProperties;
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint}; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint};
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
pub use self::svg_path::SVGPathData; pub use self::svg_path::SVGPathData;
pub use self::text::TextUnderlinePosition;
pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight, TextAlign}; pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight, TextAlign};
pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle, WordBreak}; pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle, WordBreak};
pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing}; pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing};

View file

@ -77,7 +77,6 @@ impl ToComputedValue for LineHeight {
#[inline] #[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
use crate::values::computed::Length as ComputedLength;
use crate::values::specified::length::FontBaseSize; use crate::values::specified::length::FontBaseSize;
match *self { match *self {
GenericLineHeight::Normal => GenericLineHeight::Normal, GenericLineHeight::Normal => GenericLineHeight::Normal,
@ -97,16 +96,8 @@ impl ToComputedValue for LineHeight {
LengthPercentage::Calc(ref calc) => { LengthPercentage::Calc(ref calc) => {
let computed_calc = let computed_calc =
calc.to_computed_value_zoomed(context, FontBaseSize::CurrentStyle); calc.to_computed_value_zoomed(context, FontBaseSize::CurrentStyle);
let font_relative_length = let base = context.style().get_font().clone_font_size().size();
FontRelativeLength::Em(computed_calc.percentage()) computed_calc.percentage_relative_to(base)
.to_computed_value(context, FontBaseSize::CurrentStyle)
.px();
let absolute_length = computed_calc.unclamped_length().px();
let pixel = computed_calc
.clamping_mode
.clamp(absolute_length + font_relative_length);
ComputedLength::new(pixel)
}, },
}; };
GenericLineHeight::Length(result.into()) GenericLineHeight::Length(result.into())
@ -1054,3 +1045,98 @@ impl TextDecorationLength {
matches!(*self, GenericTextDecorationLength::Auto) matches!(*self, GenericTextDecorationLength::Auto)
} }
} }
bitflags! {
#[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
#[value_info(other_values = "auto,under,left,right")]
#[repr(C)]
/// Specified keyword values for the text-underline-position property.
/// (Non-exclusive, but not all combinations are allowed: only `under` may occur
/// together with either `left` or `right`.)
/// https://drafts.csswg.org/css-text-decor-3/#text-underline-position-property
pub struct TextUnderlinePosition: u8 {
/// Use automatic positioning below the alphabetic baseline.
const AUTO = 0;
/// Below the glyph box.
const UNDER = 1 << 0;
/// In vertical mode, place to the left of the text.
const LEFT = 1 << 1;
/// In vertical mode, place to the right of the text.
const RIGHT = 1 << 2;
}
}
impl Parse for TextUnderlinePosition {
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<TextUnderlinePosition, ParseError<'i>> {
let mut result = TextUnderlinePosition::empty();
loop {
let location = input.current_source_location();
let ident = match input.next() {
Ok(&Token::Ident(ref ident)) => ident,
Ok(other) => return Err(location.new_unexpected_token_error(other.clone())),
Err(..) => break,
};
match_ignore_ascii_case! { ident,
"auto" if result.is_empty() => {
return Ok(result);
},
"under" if !result.intersects(TextUnderlinePosition::UNDER) => {
result.insert(TextUnderlinePosition::UNDER);
},
"left" if !result.intersects(TextUnderlinePosition::LEFT |
TextUnderlinePosition::RIGHT) => {
result.insert(TextUnderlinePosition::LEFT);
},
"right" if !result.intersects(TextUnderlinePosition::LEFT |
TextUnderlinePosition::RIGHT) => {
result.insert(TextUnderlinePosition::RIGHT);
},
_ => return Err(location.new_custom_error(
SelectorParseErrorKind::UnexpectedIdent(ident.clone())
)),
}
}
if !result.is_empty() {
Ok(result)
} else {
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
}
}
impl ToCss for TextUnderlinePosition {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
if self.is_empty() {
return dest.write_str("auto");
}
let mut writer = SequenceWriter::new(dest, " ");
let mut any = false;
macro_rules! maybe_write {
($ident:ident => $str:expr) => {
if self.contains(TextUnderlinePosition::$ident) {
any = true;
writer.raw_item($str)?;
}
};
}
maybe_write!(UNDER => "under");
maybe_write!(LEFT => "left");
maybe_write!(RIGHT => "right");
debug_assert!(any);
Ok(())
}
}

View file

@ -17,6 +17,6 @@ gecko = []
cssparser = "0.27" cssparser = "0.27"
servo_arc = { path = "../servo_arc" } servo_arc = { path = "../servo_arc" }
smallbitvec = "2.1.1" smallbitvec = "2.1.1"
smallvec = "0.6.6" smallvec = "1.0"
string_cache = { version = "0.8", optional = true } string_cache = { version = "0.8", optional = true }
thin-slice = "0.1.0" thin-slice = "0.1.0"

View file

@ -35,6 +35,12 @@ packages = [
# https://github.com/servo/servo/pull/23288#issuecomment-494687746 # https://github.com/servo/servo/pull/23288#issuecomment-494687746
"gl_generator", "gl_generator",
# Just needs a WR update.
"derive_more",
# Lots of crates to update.
"smallvec",
# https://github.com/servo/servo/issues/24421 # https://github.com/servo/servo/issues/24421
"proc-macro2", "proc-macro2",
"quote", "quote",

View file

@ -1,4 +0,0 @@
[border-shorthand-serialization.html]
[Declaration with border longhands and border-image is not serialized to a border shorthand declaration.]
expected: FAIL