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

View file

@ -10,7 +10,7 @@ name = "fallible"
path = "lib.rs"
[dependencies]
smallvec = "0.6"
smallvec = "1.0"
hashglobe = { path = "../hashglobe" }
# 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 {
template_descriptor: FontTemplateDescriptor::from(style),
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();
let cache_key = FontGroupCacheKey {
size: style.font_size.size(),
size: Au::from_f32_px(style.font_size.size().px()),
style,
};

View file

@ -2029,7 +2029,7 @@ impl BlockFlow {
// 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
// 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;
}
@ -2548,8 +2548,16 @@ impl Flow for BlockFlow {
.base
.flags
.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) &&
self.fragment.style().logical_position().inline_start == LengthPercentageOrAuto::Auto &&
self.fragment.style().logical_position().inline_end == LengthPercentageOrAuto::Auto
self.fragment
.style()
.logical_position()
.inline_start
.is_auto() &&
self.fragment
.style()
.logical_position()
.inline_end
.is_auto()
{
self.base.position.start.i = inline_position
}
@ -2560,8 +2568,12 @@ impl Flow for BlockFlow {
.base
.flags
.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) &&
self.fragment.style().logical_position().block_start == LengthPercentageOrAuto::Auto &&
self.fragment.style().logical_position().block_end == LengthPercentageOrAuto::Auto
self.fragment
.style()
.logical_position()
.block_start
.is_auto() &&
self.fragment.style().logical_position().block_end.is_auto()
{
self.base.position.start.b = block_position
}
@ -2848,16 +2860,15 @@ pub trait ISizeAndMarginsComputer {
parent_flow_inline_size: Au,
shared_context: &SharedStyleContext,
) -> MaybeAuto {
let inline_size =
self.containing_block_inline_size(block, parent_flow_inline_size, shared_context);
MaybeAuto::from_option(
block
.fragment()
.style()
.content_inline_size()
.to_used_value(self.containing_block_inline_size(
block,
parent_flow_inline_size,
shared_context,
)),
.to_used_value(inline_size),
)
}

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
/// image should be displayed on the background.
fn compute_background_image_size(
bg_size: BackgroundSize,
bg_size: &BackgroundSize,
bounds_size: Size2D<Au>,
intrinsic_size: Option<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_y = get_cyclic(&bg.background_position_y.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(
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
fn corner_radius(
radius: BorderCornerRadius,
radius: &BorderCornerRadius,
containing_size: UntypedSize2D<Au>,
) -> UntypedSize2D<Au> {
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(
abs_bounds.size.to_layout(),
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(),
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(),
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(),
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(),
},
)
@ -161,7 +161,7 @@ pub fn image_outset(
}
fn side_image_width(
border_image_width: BorderImageSideWidth,
border_image_width: &BorderImageSideWidth,
border_width: f32,
total_length: Au,
) -> f32 {
@ -178,10 +178,10 @@ pub fn image_width(
border_area: UntypedSize2D<Au>,
) -> LayoutSideOffsets {
LayoutSideOffsets::new(
side_image_width(width.0, border.top, border_area.height),
side_image_width(width.1, border.right, border_area.width),
side_image_width(width.2, border.bottom, border_area.height),
side_image_width(width.3, border.left, border_area.width),
side_image_width(&width.0, border.top, border_area.height),
side_image_width(&width.1, border.right, border_area.width),
side_image_width(&width.2, border.bottom, border_area.height),
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))
},
GradientKind::Radial(shape, center) => {
GradientKind::Radial(ref shape, ref center) => {
let (gradient, stops) = gradient::radial(
style,
placement.tile_size,
@ -1238,7 +1238,7 @@ impl Fragment {
stops = linear_stops;
NinePatchBorderSource::Gradient(wr_gradient)
},
GradientKind::Radial(shape, center) => {
GradientKind::Radial(ref shape, ref center) => {
let (wr_gradient, radial_stops) = gradient::radial(
style,
border_image_area,

View file

@ -91,9 +91,12 @@ fn convert_gradient_stops(
color,
position: None,
}),
GradientItem::ComplexColorStop { color, position } => Some(ColorStop {
GradientItem::ComplexColorStop {
color,
position: Some(position),
ref position,
} => Some(ColorStop {
color,
position: Some(position.clone()),
}),
_ => None,
})
@ -122,15 +125,24 @@ fn convert_gradient_stops(
// Step 2: Move any stops placed before earlier stops to the
// 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) {
if let Some(pos) = stop.position {
if position_to_offset(last_stop_position, total_length) >
if let Some(ref pos) = stop.position {
if position_to_offset(&last_stop_position, total_length) >
position_to_offset(pos, total_length)
{
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.
// `unwrap()` here should never fail because this is the beginning of
// a stop run, which is always bounded by a length or percentage.
let start_offset =
position_to_offset(stop_items[i - 1].position.unwrap(), total_length);
let start_offset = position_to_offset(
stop_items[i - 1].position.as_ref().unwrap(),
total_length,
);
// `unwrap()` here should never fail because this is the end of
// a stop run, which is always bounded by a length or percentage.
let (end_index, end_stop) = stop_items[(i + 1)..]
@ -153,7 +167,8 @@ fn convert_gradient_stops(
.enumerate()
.find(|&(_, ref stop)| stop.position.is_some())
.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 {
start_offset,
end_offset,
@ -168,7 +183,7 @@ fn convert_gradient_stops(
stop_run_length * (i - stop_run.start_index) as f32 /
((2 + stop_run.stop_count) as f32)
},
Some(position) => {
Some(ref position) => {
stop_run = None;
position_to_offset(position, total_length)
},
@ -212,7 +227,7 @@ where
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) {
return 0.0;
}
@ -289,8 +304,8 @@ pub fn radial(
style: &ComputedValues,
size: Size2D<Au>,
stops: &[GradientItem],
shape: EndingShape,
center: Position,
shape: &EndingShape,
center: &Position,
repeating: bool,
) -> (RadialGradient, Vec<GradientStop>) {
let center = Point2D::new(
@ -299,15 +314,15 @@ pub fn radial(
);
let radius = match shape {
EndingShape::Circle(Circle::Radius(length)) => {
let length = Au::from(length);
let length = Au::from(*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)) => {
Size2D::new(x.to_used_value(size.width), y.to_used_value(size.height))
},
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 {
/// Generate a new available cross or main axis size from the specified size of the container,
/// 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 {
Size::Auto => AxisSize::MinMax(SizeConstraint::new(content_size, min, max, None)),
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
/// determining the flex base size and to indicate whether the main size of the item
/// 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 {
FlexBasis::Content => return MaybeAuto::Auto,
FlexBasis::Size(width) => width,
FlexBasis::Size(ref width) => width,
};
let width = match width {
@ -135,7 +135,7 @@ impl FlexItem {
// https://drafts.csswg.org/css-flexbox-1/#min-size-auto
Direction::Inline => {
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(),
containing_length,
);
@ -170,7 +170,7 @@ impl FlexItem {
},
Direction::Block => {
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(),
containing_length,
);
@ -452,7 +452,7 @@ impl FlexFlow {
fn inline_mode_bubble_inline_sizes(&mut self) {
// FIXME(emilio): This doesn't handle at all writing-modes.
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();
let mut computation = self.block_flow.fragment.compute_intrinsic_inline_sizes();
@ -478,7 +478,7 @@ impl FlexFlow {
// stripped out.
fn block_mode_bubble_inline_sizes(&mut self) {
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();
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 (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 {
(style.get_position().height, style.get_position().width)
(&style.get_position().height, &style.get_position().width)
};
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::selector_parser::RestyleDamage;
use style::servo::restyle_damage::ServoRestyleDamage;
use style::values::computed::LengthPercentageOrAuto;
use webrender_api::units::LayoutTransform;
/// 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);
let logical_position = style.logical_position();
if logical_position.inline_start == LengthPercentageOrAuto::Auto &&
logical_position.inline_end == LengthPercentageOrAuto::Auto
if logical_position.inline_start.is_auto() &&
logical_position.inline_end.is_auto()
{
flags.insert(FlowFlags::INLINE_POSITION_IS_STATIC);
}
if logical_position.block_start == LengthPercentageOrAuto::Auto &&
logical_position.block_end == LengthPercentageOrAuto::Auto
if logical_position.block_start.is_auto() &&
logical_position.block_end.is_auto()
{
flags.insert(FlowFlags::BLOCK_POSITION_IS_STATIC);
}
@ -1113,13 +1112,12 @@ impl BaseFlow {
let logical_position = style.logical_position();
self.flags.set(
FlowFlags::INLINE_POSITION_IS_STATIC,
logical_position.inline_start == LengthPercentageOrAuto::Auto &&
logical_position.inline_end == LengthPercentageOrAuto::Auto,
logical_position.inline_start.is_auto() &&
logical_position.inline_end.is_auto(),
);
self.flags.set(
FlowFlags::BLOCK_POSITION_IS_STATIC,
logical_position.block_start == LengthPercentageOrAuto::Auto &&
logical_position.block_end == LengthPercentageOrAuto::Auto,
logical_position.block_start.is_auto() && logical_position.block_end.is_auto(),
);
}
}

View file

@ -61,10 +61,9 @@ use style::selector_parser::RestyleDamage;
use style::servo::restyle_damage::ServoRestyleDamage;
use style::str::char_is_whitespace;
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::transform;
use style::Zero;
use webrender_api;
use webrender_api::units::LayoutTransform;
@ -1329,13 +1328,17 @@ impl Fragment {
return;
},
_ => {
let margin = self.style().logical_margin();
self.margin.inline_start =
MaybeAuto::from_style(margin.inline_start, containing_block_inline_size)
.specified_or_zero();
self.margin.inline_end =
MaybeAuto::from_style(margin.inline_end, containing_block_inline_size)
.specified_or_zero();
let (inline_start, inline_end) = {
let margin = self.style().logical_margin();
(
MaybeAuto::from_style(margin.inline_start, containing_block_inline_size)
.specified_or_zero(),
MaybeAuto::from_style(margin.inline_end, containing_block_inline_size)
.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)
// per CSS 2.1.
let margin = self.style().logical_margin();
self.margin.block_start =
MaybeAuto::from_style(margin.block_start, containing_block_inline_size)
.specified_or_zero();
self.margin.block_end =
MaybeAuto::from_style(margin.block_end, containing_block_inline_size)
.specified_or_zero();
let (block_start, block_end) = {
let margin = self.style().logical_margin();
(
MaybeAuto::from_style(margin.block_start, containing_block_inline_size)
.specified_or_zero(),
MaybeAuto::from_style(margin.block_end, containing_block_inline_size)
.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> {
fn from_style(style: &ComputedValues, container_size: &LogicalSize<Au>) -> LogicalSize<Au> {
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)
.specified_or_zero()
} else {
-MaybeAuto::from_style(offsets.inline_end, container_size.inline)
.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()
} else {
-MaybeAuto::from_style(offsets.block_end, container_size.block).specified_or_zero()
@ -2520,13 +2527,19 @@ impl Fragment {
{
continue;
}
if inline_context_node.style.logical_margin().inline_end !=
LengthPercentageOrAuto::zero()
if !inline_context_node
.style
.logical_margin()
.inline_end
.is_definitely_zero()
{
return false;
}
if inline_context_node.style.logical_padding().inline_end !=
LengthPercentage::zero()
if !inline_context_node
.style
.logical_padding()
.inline_end
.is_definitely_zero()
{
return false;
}
@ -2546,13 +2559,19 @@ impl Fragment {
{
continue;
}
if inline_context_node.style.logical_margin().inline_start !=
LengthPercentageOrAuto::zero()
if !inline_context_node
.style
.logical_margin()
.inline_start
.is_definitely_zero()
{
return false;
}
if inline_context_node.style.logical_padding().inline_start !=
LengthPercentage::zero()
if !inline_context_node
.style
.logical_padding()
.inline_start
.is_definitely_zero()
{
return false;
}
@ -3193,7 +3212,7 @@ impl Fragment {
) -> Option<LayoutTransform> {
match self.style().get_box().perspective {
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(
perspective_origin
.horizontal

View file

@ -1275,7 +1275,7 @@ impl InlineFlow {
&mut line_metrics,
&inline_metrics,
style.get_box().display,
VerticalAlign::baseline(),
&VerticalAlign::baseline(),
&mut largest_block_size_for_top_fragments,
&mut largest_block_size_for_bottom_fragments,
);
@ -1296,7 +1296,7 @@ impl InlineFlow {
&mut line_metrics,
&inline_metrics,
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_bottom_fragments,
);
@ -1318,7 +1318,7 @@ impl InlineFlow {
line_metrics: &mut LineMetrics,
inline_metrics: &InlineMetrics,
display_value: Display,
vertical_align_value: VerticalAlign,
vertical_align_value: &VerticalAlign,
largest_block_size_for_top_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/. */
#![deny(unsafe_code)]
#![feature(matches_macro)]
#[macro_use]
extern crate bitflags;

View file

@ -437,7 +437,7 @@ pub enum MaybeAuto {
impl MaybeAuto {
#[inline]
pub fn from_style(length: LengthPercentageOrAuto, containing_length: Au) -> MaybeAuto {
pub fn from_style(length: &LengthPercentageOrAuto, containing_length: Au) -> MaybeAuto {
match length {
LengthPercentageOrAuto::Auto => MaybeAuto::Auto,
LengthPercentageOrAuto::LengthPercentage(ref lp) => {
@ -498,7 +498,7 @@ impl MaybeAuto {
/// Receive an optional container size and return used value for width or height.
///
/// `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 {
Size::Auto => MaybeAuto::Auto,
Size::LengthPercentage(ref lp) => {
@ -546,10 +546,10 @@ pub fn specified_margin_from_style(
LogicalMargin::from_physical(
writing_mode,
SideOffsets2D::new(
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_bottom, Au(0)).specified_or_zero(),
MaybeAuto::from_style(margin_style.margin_left, 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_bottom, 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.
pub fn new(
container_size: Option<Au>,
min_size: Size,
max_size: MaxSize,
min_size: &Size,
max_size: &MaxSize,
border: Option<Au>,
) -> SizeConstraint {
let mut min_size = match min_size {

View file

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

View file

@ -76,7 +76,7 @@ impl Flow for TableColGroupFlow {
// Retrieve the specified value from the appropriate CSS property.
let inline_size = fragment.style().content_inline_size();
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_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_row_span = child_table_cell.row_span;
@ -422,6 +417,13 @@ impl Flow for TableRowFlow {
&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

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();
match style.get_inherited_text().line_height {
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),
}
}

View file

@ -175,13 +175,18 @@ impl flow_relative::Vec2<MaxSize<LengthPercentage>> {
containing_block: &ContainingBlock,
) -> flow_relative::Vec2<Option<Length>> {
flow_relative::Vec2 {
inline: self
.inline
.to_option()
.map(|lp| 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())
}),
inline: match self.inline {
MaxSize::None => None,
MaxSize::LengthPercentage(ref lp) => {
Some(lp.percentage_relative_to(containing_block.inline_size))
},
},
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>,
}
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Debug)]
pub(crate) enum AbsoluteBoxOffsets {
StaticStart {
start: Length,
@ -113,13 +113,13 @@ impl AbsolutelyPositionedBox {
box_offsets: Vec2 {
inline: absolute_box_offsets(
initial_start_corner.inline,
box_offsets.inline_start,
box_offsets.inline_end,
box_offsets.inline_start.clone(),
box_offsets.inline_end.clone(),
),
block: absolute_box_offsets(
initial_start_corner.block,
box_offsets.block_start,
box_offsets.block_end,
box_offsets.block_start.clone(),
box_offsets.block_end.clone(),
),
},
}
@ -372,20 +372,20 @@ impl<'box_tree> HoistedAbsolutelyPositionedBox<'box_tree> {
let inline_axis = solve_axis(
cbis,
pb.inline_sum(),
computed_margin.inline_start,
computed_margin.inline_end,
computed_margin.inline_start.clone(),
computed_margin.inline_end.clone(),
/* avoid_negative_margin_start */ true,
self.box_offsets.inline,
self.box_offsets.inline.clone(),
size.inline,
);
let block_axis = solve_axis(
cbis,
pb.block_sum(),
computed_margin.block_start,
computed_margin.block_end,
computed_margin.block_start.clone(),
computed_margin.block_end.clone(),
/* avoid_negative_margin_start */ false,
self.box_offsets.block,
self.box_offsets.block.clone(),
size.block,
);

View file

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

View file

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

View file

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

View file

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

View file

@ -17,7 +17,7 @@
//! is non-trivial. This module encapsulates those details and presents an
//! 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 servo_arc::{Arc, HeaderWithLength, ThinArc};
use smallvec::{self, SmallVec};
@ -142,7 +142,7 @@ impl<Impl: SelectorImpl> SelectorBuilder<Impl> {
let iter = SelectorBuilderIter {
current_simple_selectors: current.iter(),
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))
@ -152,7 +152,7 @@ impl<Impl: SelectorImpl> SelectorBuilder<Impl> {
struct SelectorBuilderIter<'a, Impl: SelectorImpl> {
current_simple_selectors: slice::Iter<'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> {
@ -322,10 +322,14 @@ where
Component::NthLastOfType(..) |
Component::FirstOfType |
Component::LastOfType |
Component::OnlyOfType |
Component::NonTSPseudoClass(..) => {
Component::OnlyOfType => {
specificity.class_like_selectors += 1;
},
Component::NonTSPseudoClass(ref pseudo) => {
if !pseudo.has_zero_specificity() {
specificity.class_like_selectors += 1;
}
},
Component::ExplicitUniversalType |
Component::ExplicitAnyNamespace |
Component::ExplicitNoNamespace |

View file

@ -52,6 +52,9 @@ pub trait NonTSPseudoClass: Sized + ToCss {
///
/// https://drafts.csswg.org/selectors-4/#useraction-pseudos
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
@ -2336,6 +2339,11 @@ pub mod tests {
fn is_user_action_state(&self) -> bool {
self.is_active_or_hover()
}
#[inline]
fn has_zero_specificity(&self) -> bool {
false
}
}
impl ToCss for PseudoClass {

View file

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

View file

@ -216,7 +216,7 @@ impl<E: TElement> StyleBloom<E> {
self.filter.clear();
self.pushed_hashes.clear();
} else {
for hash in self.pushed_hashes.drain() {
for hash in self.pushed_hashes.drain(..) {
self.filter.remove_hash(hash);
}
debug_assert!(self.filter.is_zeroed());
@ -233,7 +233,7 @@ impl<E: TElement> StyleBloom<E> {
element = parent;
}
for parent in parents_to_insert.drain().rev() {
for parent in parents_to_insert.drain(..).rev() {
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
// collecting so far.
for parent in parents_to_insert.drain().rev() {
for parent in parents_to_insert.drain(..).rev() {
self.push(parent);
}

View file

@ -807,6 +807,9 @@ pub trait TElement:
/// data if it comes from Shadow DOM.
///
/// 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
where
Self: 'a,
@ -841,11 +844,42 @@ pub trait TElement:
// Slots can only have assigned nodes when in a shadow tree.
let shadow = slot.containing_shadow().unwrap();
if let Some(data) = shadow.style_data() {
f(data, shadow.host());
if data.any_slotted_rule() {
f(data, shadow.host());
}
}
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
}

View file

@ -7,17 +7,17 @@
#![deny(missing_docs)]
use crate::context::SharedStyleContext;
use crate::values::computed::Length;
use crate::Atom;
use app_units::Au;
/// Represents the font metrics that style needs from a font to compute the
/// value of certain CSS units like `ex`.
#[derive(Clone, Debug, Default, PartialEq)]
pub struct FontMetrics {
/// 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
pub zero_advance_measure: Option<Au>,
pub zero_advance_measure: Option<Length>,
}
/// Type of font metrics to retrieve.
@ -47,7 +47,7 @@ pub trait FontMetricsProvider {
&self,
font_name: &Atom,
font_family: crate::values::computed::font::GenericFontFamily,
) -> Au;
) -> Length;
/// Construct from a shared style context
fn create_from(context: &SharedStyleContext) -> Self
@ -70,7 +70,7 @@ impl FontMetricsProvider for 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")
}
}

View file

@ -11,10 +11,9 @@ use crate::gecko_bindings::structs;
use crate::media_queries::MediaType;
use crate::properties::ComputedValues;
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 app_units::Au;
use app_units::AU_PER_PX;
use app_units::{Au, AU_PER_PX};
use cssparser::RGBA;
use euclid::default::Size2D;
use euclid::Scale;
@ -87,7 +86,7 @@ impl Device {
document,
default_values: ComputedValues::default_values(doc),
// 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),
used_root_font_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, _),
("-moz-devtools-highlighted", MozDevtoolsHighlighted, mozDevtoolsHighlighted, IN_DEVTOOLS_HIGHLIGHTED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS),
("-moz-styleeditor-transitioning", MozStyleeditorTransitioning, mozStyleeditorTransitioning, IN_STYLEEDITOR_TRANSITIONING_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS),
("fullscreen", Fullscreen, fullscreen, IN_FULLSCREEN_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME),
("-moz-full-screen", MozFullScreen, mozFullScreen, IN_FULLSCREEN_STATE, _),
("fullscreen", Fullscreen, fullscreen, IN_FULLSCREEN_STATE, _),
// TODO(emilio): This is inconsistently named (the capital R).
("-moz-focusring", MozFocusRing, mozFocusRing, IN_FOCUSRING_STATE, _),
("-moz-broken", MozBroken, mozBroken, IN_BROKEN_STATE, _),
@ -94,6 +93,7 @@ macro_rules! apply_non_ts_list {
("-moz-last-node", MozLastNode, lastNode, _, _),
("-moz-only-whitespace", MozOnlyWhitespace, mozOnlyWhitespace, _, _),
("-moz-native-anonymous", MozNativeAnonymous, mozNativeAnonymous, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS),
("-moz-native-anonymous-no-specificity", MozNativeAnonymousNoSpecificity, mozNativeAnonymousNoSpecificity, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS),
("-moz-use-shadow-tree-root", MozUseShadowTreeRoot, mozUseShadowTreeRoot, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS),
("-moz-is-html", MozIsHTML, mozIsHTML, _, _),
("-moz-placeholder", MozPlaceholder, mozPlaceholder, _, _),

View file

@ -193,18 +193,18 @@ impl PseudoElement {
% for pseudo in SIMPLE_PSEUDOS:
"${pseudo.value[1:]}" => {
return Some(${pseudo_element_variant(pseudo)})
}
},
% endfor
// Alias some legacy prefixed pseudos to their standardized name at parse time:
"-moz-selection" => {
return Some(PseudoElement::Selection);
}
},
"-moz-placeholder" => {
return Some(PseudoElement::Placeholder);
}
},
"-moz-list-bullet" | "-moz-list-number" => {
return Some(PseudoElement::Marker);
}
},
_ => {
if starts_with_ignore_ascii_case(name, "-moz-tree-") {
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),)*]) => {
match_ignore_ascii_case! { &name,
$($css => Some(NonTSPseudoClass::$name),)*
"-moz-full-screen" => Some(NonTSPseudoClass::Fullscreen),
_ => None,
}
}
@ -169,16 +170,9 @@ impl NonTSPseudoClass {
}
/// Returns whether the pseudo-class is enabled in content sheets.
#[inline]
fn is_enabled_in_content(&self) -> bool {
match *self {
// 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),
}
!self.has_any_flag(NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME)
}
/// 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
// checked for by our caching precondtions.
NonTSPseudoClass::MozIsHTML |
// We prevent style sharing for NAC.
NonTSPseudoClass::MozNativeAnonymous |
NonTSPseudoClass::MozNativeAnonymousNoSpecificity |
// :-moz-placeholder is parsed but never matches.
NonTSPseudoClass::MozPlaceholder |
// :-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
)
}
#[inline]
fn has_zero_specificity(&self) -> bool {
matches!(*self, NonTSPseudoClass::MozNativeAnonymousNoSpecificity)
}
}
/// The dummy struct we use to implement our selector parsing.
@ -394,7 +396,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
parser,
)?.into()
)
}
},
_ => return Err(parser.new_custom_error(
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
/// class or id change.
/// class / id
#[inline]
pub fn other_attr_changed(&self) -> bool {
self.mOtherAttributeChanged()

View file

@ -68,6 +68,7 @@ use crate::shared_lock::Locked;
use crate::string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
use crate::stylist::CascadeData;
use crate::values::computed::font::GenericFontFamily;
use crate::values::computed::Length;
use crate::values::specified::length::FontBaseSize;
use crate::CaseSensitivityExt;
use app_units::Au;
@ -929,7 +930,7 @@ impl FontMetricsProvider for GeckoFontMetricsProvider {
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();
if let Some(sizes) = cache.iter().find(|el| el.0 == *font_name) {
return sizes.1.size_for_generic(font_family);
@ -950,7 +951,7 @@ impl FontMetricsProvider for GeckoFontMetricsProvider {
None => return Default::default(),
};
let size = base_size.resolve(context);
let size = Au::from(base_size.resolve(context));
let style = context.style();
let (wm, font) = match base_size {
@ -977,9 +978,9 @@ impl FontMetricsProvider for GeckoFontMetricsProvider {
)
};
FontMetrics {
x_height: Some(Au(gecko_metrics.mXSize)),
x_height: Some(Au(gecko_metrics.mXSize).into()),
zero_advance_measure: if gecko_metrics.mChSize >= 0 {
Some(Au(gecko_metrics.mChSize))
Some(Au(gecko_metrics.mChSize).into())
} else {
None
},
@ -988,7 +989,7 @@ impl FontMetricsProvider for GeckoFontMetricsProvider {
}
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 {
GenericFontFamily::None => self.mDefaultVariableSize,
GenericFontFamily::Serif => self.mDefaultSerifSize,
@ -1000,6 +1001,7 @@ impl structs::FontSizePrefs {
"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::Checked |
NonTSPseudoClass::Fullscreen |
NonTSPseudoClass::MozFullScreen |
NonTSPseudoClass::Indeterminate |
NonTSPseudoClass::PlaceholderShown |
NonTSPseudoClass::Target |
@ -2130,7 +2131,10 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
}
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::MozTableBorderNonzero => unsafe {
bindings::Gecko_IsTableBorderNonzero(self.0)

View file

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

View file

@ -142,6 +142,19 @@ pub struct DocumentStateDependency {
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.
///
/// 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>,
/// A map of other attribute affecting selectors.
pub other_attribute_affecting_selectors: SelectorMap<Dependency>,
/// Whether there are attribute rules of the form `[class~="foo"]` that may
/// match. In that case, we need to look at
/// `other_attribute_affecting_selectors` too even if only the `class` has
/// 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,
/// A set of flags that contain whether various special attributes are used
/// in this invalidation map.
pub flags: InvalidationMapFlags,
}
impl InvalidationMap {
@ -185,8 +191,7 @@ impl InvalidationMap {
state_affecting_selectors: SelectorMap::new(),
document_state_selectors: Vec::new(),
other_attribute_affecting_selectors: SelectorMap::new(),
has_class_attribute_selectors: false,
has_id_attribute_selectors: false,
flags: InvalidationMapFlags::empty(),
}
}
@ -210,8 +215,7 @@ impl InvalidationMap {
self.state_affecting_selectors.clear();
self.document_state_selectors.clear();
self.other_attribute_affecting_selectors.clear();
self.has_id_attribute_selectors = false;
self.has_class_attribute_selectors = false;
self.flags = InvalidationMapFlags::empty();
}
/// Adds a selector to this `InvalidationMap`. Returns Err(..) to
@ -238,8 +242,7 @@ impl InvalidationMap {
state: ElementState::empty(),
document_state: &mut document_state,
other_attributes: false,
has_id_attribute_selectors: false,
has_class_attribute_selectors: false,
flags: &mut self.flags,
};
// Visit all the simple selectors in this sequence.
@ -255,9 +258,6 @@ impl InvalidationMap {
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 {
self.class_to_selector
.try_entry(class, quirks_mode)?
@ -349,11 +349,8 @@ struct CompoundSelectorDependencyCollector<'a> {
/// [id] attribute selectors).
other_attributes: bool,
/// Whether there were attribute selectors with the id attribute.
has_id_attribute_selectors: bool,
/// Whether there were attribute selectors with the class attribute.
has_class_attribute_selectors: bool,
/// The invalidation map flags, that we set when some attribute selectors are present.
flags: &'a mut InvalidationMapFlags,
}
impl<'a> SelectorVisitor for CompoundSelectorDependencyCollector<'a> {
@ -398,8 +395,13 @@ impl<'a> SelectorVisitor for CompoundSelectorDependencyCollector<'a> {
};
if may_match_in_no_namespace {
self.has_id_attribute_selectors |= *local_name_lower == local_name!("id");
self.has_class_attribute_selectors |= *local_name_lower == local_name!("class");
if *local_name_lower == local_name!("id") {
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

View file

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

View file

@ -42,6 +42,7 @@ where
descendant_invalidations: &'a mut DescendantInvalidationLists<'selectors>,
sibling_invalidations: &'a mut InvalidationVector<'selectors>,
invalidates_self: bool,
attr_selector_flags: InvalidationMapFlags,
}
/// An invalidation processor for style changes due to state and attribute
@ -155,6 +156,8 @@ where
return false;
}
let mut attr_selector_flags = InvalidationMapFlags::empty();
// 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
// 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_added = SmallVec::<[Atom; 8]>::new();
if snapshot.class_changed() {
attr_selector_flags.insert(InvalidationMapFlags::HAS_CLASS_ATTR_SELECTOR);
// TODO(emilio): Do this more efficiently!
snapshot.each_class(|c| {
if !element.has_class(c, CaseSensitivity::CaseSensitive) {
@ -189,6 +193,7 @@ where
let mut id_removed = None;
let mut id_added = None;
if snapshot.id_changed() {
attr_selector_flags.insert(InvalidationMapFlags::HAS_ID_ATTR_SELECTOR);
let old_id = snapshot.id_attr();
let current_id = element.id();
@ -199,7 +204,10 @@ where
}
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() {
debug!(" > state: {:?}", state_changes);
}
@ -247,6 +255,7 @@ where
descendant_invalidations,
sibling_invalidations,
invalidates_self: false,
attr_selector_flags,
};
let document_origins = if !matches_document_author_rules {
@ -356,9 +365,8 @@ where
}
}
let should_examine_attribute_selector_map = self.snapshot.other_attr_changed() ||
(self.snapshot.class_changed() && map.has_class_attribute_selectors) ||
(self.snapshot.id_changed() && map.has_id_attribute_selectors);
let should_examine_attribute_selector_map =
self.snapshot.other_attr_changed() || map.flags.intersects(self.attr_selector_flags);
if should_examine_attribute_selector_map {
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]
pub fn new(mode: WritingMode, inline: T, block: T) -> LogicalSize<T> {
LogicalSize {
@ -486,7 +486,9 @@ impl<T: Copy> LogicalSize<T> {
LogicalSize::new(mode, size.width, size.height)
}
}
}
impl<T: Copy> LogicalSize<T> {
#[inline]
pub fn width(&self, mode: WritingMode) -> T {
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]
pub fn new(
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]
pub fn from_physical(mode: WritingMode, offsets: SideOffsets2D<T>) -> LogicalMargin<T> {
let block_start;
@ -917,6 +914,13 @@ impl<T: Copy> LogicalMargin<T> {
}
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]
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)
{
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
// in the document did use rem units, ensure we recascade the
// entire tree.

View file

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

View file

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

View file

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

View file

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

View file

@ -1433,7 +1433,7 @@ fn report_css_errors(
selectors: Option<&SelectorList<SelectorImpl>>,
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)
}
}

View file

@ -426,7 +426,7 @@ def set_gecko_property(ffi_name, expr):
pub fn copy_${ident}_from(&mut self, other: &Self) {
use crate::gecko_bindings::structs::nsStyleSVG_${ident.upper()}_CONTEXT as CONTEXT_VALUE;
self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name};
self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name}.clone();
self.gecko.mContextFlags =
(self.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 {
return SVGLength::ContextValue;
}
SVGLength::LengthPercentage(self.gecko.${gecko_ffi_name})
SVGLength::LengthPercentage(self.gecko.${gecko_ffi_name}.clone())
}
</%def>
@ -563,7 +563,7 @@ def set_gecko_property(ffi_name, expr):
#[allow(non_snake_case)]
pub fn copy_${ident}_from(&mut self, other: &Self) {
self.gecko.${gecko_ffi_name}.${index} =
other.gecko.${gecko_ffi_name}.${index};
other.gecko.${gecko_ffi_name}.${index}.clone();
}
#[allow(non_snake_case)]
pub fn reset_${ident}(&mut self, other: &Self) {
@ -572,7 +572,7 @@ def set_gecko_property(ffi_name, expr):
#[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
self.gecko.${gecko_ffi_name}.${index}
self.gecko.${gecko_ffi_name}.${index}.clone()
}
</%def>
@ -601,7 +601,7 @@ def set_gecko_property(ffi_name, expr):
#[allow(non_snake_case)]
pub fn copy_${ident}_from(&mut self, other: &Self) {
self.gecko.${gecko_ffi_name}.${corner} =
other.gecko.${gecko_ffi_name}.${corner};
other.gecko.${gecko_ffi_name}.${corner}.clone();
}
#[allow(non_snake_case)]
pub fn reset_${ident}(&mut self, other: &Self) {
@ -609,7 +609,7 @@ def set_gecko_property(ffi_name, expr):
}
#[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
self.gecko.${gecko_ffi_name}.${corner}
self.gecko.${gecko_ffi_name}.${corner}.clone()
}
</%def>
@ -1134,7 +1134,7 @@ fn static_assert() {
pub fn set_font_size(&mut self, v: FontSize) {
use crate::values::specified::font::KeywordSize;
let size = v.size();
let size = Au::from(v.size());
self.gecko.mScriptUnconstrainedSize = size.0;
// 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()
.zip(other.gecko.${layers_field_name}.mLayers.iter())
.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;
}
@ -2006,7 +2006,7 @@ fn static_assert() {
for (layer, other) in self.gecko.${image_layers_field}.mLayers.iter_mut()
.zip(other.gecko.${image_layers_field}.mLayers.iter())
.take(count as usize) {
layer.mPosition.${keyword} = other.mPosition.${keyword};
layer.mPosition.${keyword} = other.mPosition.${keyword}.clone();
}
self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count = count;
}
@ -2020,7 +2020,7 @@ fn static_assert() {
longhands::${shorthand}_position_${orientation}::computed_value::List(
self.gecko.${image_layers_field}.mLayers.iter()
.take(self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count as usize)
.map(|position| position.mPosition.${keyword})
.map(|position| position.mPosition.${keyword}.clone())
.collect()
)
}
@ -2054,7 +2054,7 @@ fn static_assert() {
pub fn clone_${shorthand}_size(&self) -> longhands::${shorthand}_size::computed_value::T {
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",
"ImageLayer",
engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
initial_value="computed::ImageLayer::none()",
initial_specified_value="specified::ImageLayer::none()",
spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
@ -122,7 +121,6 @@ ${helpers.predefined_type(
"border-image-outset",
"NonNegativeLengthOrNumberRect",
engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
initial_value="generics::rect::Rect::all(computed::NonNegativeLengthOrNumber::zero())",
initial_specified_value="generics::rect::Rect::all(specified::NonNegativeLengthOrNumber::zero())",
spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset",
@ -135,7 +133,6 @@ ${helpers.predefined_type(
"BorderImageRepeat",
"computed::BorderImageRepeat::stretch()",
engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
initial_specified_value="specified::BorderImageRepeat::stretch()",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-backgrounds/#the-border-image-repeat",
@ -145,7 +142,6 @@ ${helpers.predefined_type(
"border-image-width",
"BorderImageWidth",
engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
initial_value="computed::BorderImageWidth::all(computed::BorderImageSideWidth::one())",
initial_specified_value="specified::BorderImageWidth::all(specified::BorderImageSideWidth::one())",
spec="https://drafts.csswg.org/css-backgrounds/#border-image-width",
@ -157,7 +153,6 @@ ${helpers.predefined_type(
"border-image-slice",
"BorderImageSlice",
engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
initial_value="computed::BorderImageSlice::hundred_percent()",
initial_specified_value="specified::BorderImageSlice::hundred_percent()",
spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice",

View file

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

View file

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

View file

@ -53,7 +53,7 @@ ${helpers.single_keyword(
"-moz-text-size-adjust",
"auto none",
engines="gecko",
gecko_constant_prefix="NS_STYLE_TEXT_SIZE_ADJUST",
gecko_enum_prefix="StyleTextSizeAdjust",
gecko_ffi_name="mTextSizeAdjust",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-size-adjust/#adjustment-control",
@ -332,6 +332,7 @@ ${helpers.single_keyword(
"space-around start center space-between",
engines="gecko",
animation_value_type="discrete",
gecko_enum_prefix="StyleRubyAlign",
spec="https://drafts.csswg.org/css-ruby/#ruby-align-property",
)}
@ -341,6 +342,7 @@ ${helpers.single_keyword(
engines="gecko",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-ruby/#ruby-position-property",
gecko_enum_prefix="StyleRubyPosition",
)}
// CSS Writing Modes Module Level 3
@ -389,6 +391,18 @@ ${helpers.predefined_type(
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
${helpers.predefined_type(
"text-decoration-skip-ink",

View file

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

View file

@ -3121,59 +3121,59 @@ impl ComputedValuesInner {
/// Get the logical computed inline size.
#[inline]
pub fn content_inline_size(&self) -> computed::Size {
pub fn content_inline_size(&self) -> &computed::Size {
let position_style = self.get_position();
if self.writing_mode.is_vertical() {
position_style.height
&position_style.height
} else {
position_style.width
&position_style.width
}
}
/// Get the logical computed block size.
#[inline]
pub fn content_block_size(&self) -> computed::Size {
pub fn content_block_size(&self) -> &computed::Size {
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.
#[inline]
pub fn min_inline_size(&self) -> computed::Size {
pub fn min_inline_size(&self) -> &computed::Size {
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.
#[inline]
pub fn min_block_size(&self) -> computed::Size {
pub fn min_block_size(&self) -> &computed::Size {
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.
#[inline]
pub fn max_inline_size(&self) -> computed::MaxSize {
pub fn max_inline_size(&self) -> &computed::MaxSize {
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.
#[inline]
pub fn max_block_size(&self) -> computed::MaxSize {
pub fn max_block_size(&self) -> &computed::MaxSize {
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.
#[inline]
pub fn logical_padding(&self) -> LogicalMargin<computed::LengthPercentage> {
pub fn logical_padding(&self) -> LogicalMargin<<&computed::LengthPercentage> {
let padding_style = self.get_padding();
LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new(
padding_style.padding_top.0,
padding_style.padding_right.0,
padding_style.padding_bottom.0,
padding_style.padding_left.0,
&padding_style.padding_top.0,
&padding_style.padding_right.0,
&padding_style.padding_bottom.0,
&padding_style.padding_left.0,
))
}
@ -3197,26 +3197,26 @@ impl ComputedValuesInner {
/// Gets the logical computed margin from this style.
#[inline]
pub fn logical_margin(&self) -> LogicalMargin<computed::LengthPercentageOrAuto> {
pub fn logical_margin(&self) -> LogicalMargin<<&computed::LengthPercentageOrAuto> {
let margin_style = self.get_margin();
LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new(
margin_style.margin_top,
margin_style.margin_right,
margin_style.margin_bottom,
margin_style.margin_left,
&margin_style.margin_top,
&margin_style.margin_right,
&margin_style.margin_bottom,
&margin_style.margin_left,
))
}
/// Gets the logical position from this style.
#[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?
let position_style = self.get_position();
LogicalMargin::from_physical(self.writing_mode, SideOffsets2D::new(
position_style.top,
position_style.right,
position_style.bottom,
position_style.left,
&position_style.top,
&position_style.right,
&position_style.bottom,
&position_style.left,
))
}

View file

@ -179,6 +179,16 @@ pub fn parse_border<'i, 't>(
impl<'a> ToCss for LonghandsToSerialize<'a> {
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 = {
% for side in PHYSICAL_SIDES:
let border_${side}_width = self.border_${side}_width;

View file

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

View file

@ -345,7 +345,7 @@ impl RuleTree {
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(
self.root.downgrade(),
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);
}
for source in important_ua.drain() {
for source in important_ua.drain(..) {
current = current.ensure_child(self.root.downgrade(), source, UAImportant);
}
@ -378,7 +378,7 @@ impl RuleTree {
guards: &StylesheetGuards,
) -> StrongRuleNode {
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,
)
}
@ -556,7 +556,7 @@ impl RuleTree {
// Now the rule is in the relevant place, push the children as
// 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)
}
@ -592,8 +592,8 @@ impl RuleTree {
last = node;
}
let rule =
self.insert_ordered_rules_from(last.parent().unwrap().clone(), children.drain().rev());
let rule = self
.insert_ordered_rules_from(last.parent().unwrap().clone(), children.drain(..).rev());
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::MediaType;
use crate::properties::ComputedValues;
use crate::values::computed::font::FontSize;
use crate::values::computed::CSSPixelLength;
use crate::values::specified::font::FONT_MEDIUM_PX;
use crate::values::KeyframesName;
use app_units::Au;
use cssparser::RGBA;
@ -68,7 +68,7 @@ impl Device {
viewport_size,
device_pixel_ratio,
// 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_viewport_units: AtomicBool::new(false),
environment: CssEnvironment,

View file

@ -309,6 +309,11 @@ impl ::selectors::parser::NonTSPseudoClass for NonTSPseudoClass {
NonTSPseudoClass::Active | NonTSPseudoClass::Hover | NonTSPseudoClass::Focus
)
}
#[inline]
fn has_zero_specificity(&self) -> bool {
false
}
}
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::style_rule::StyleRule;
pub use self::stylesheet::{DocumentStyleSheet, Namespaces, Stylesheet};
pub use self::stylesheet::{SanitizationData, SanitizationKind};
pub use self::stylesheet::{StylesheetContents, StylesheetInDocument, UserAgentStylesheets};
pub use self::supports_rule::SupportsRule;
pub use self::viewport_rule::ViewportRule;

View file

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

View file

@ -81,6 +81,7 @@ impl StylesheetContents {
quirks_mode: QuirksMode,
line_number_offset: u32,
use_counters: Option<&UseCounters>,
sanitization_data: Option<&mut SanitizationData>,
) -> Self {
let namespaces = RwLock::new(Namespaces::default());
let (rules, source_map_url, source_url) = Stylesheet::parse_rules(
@ -94,6 +95,7 @@ impl StylesheetContents {
quirks_mode,
line_number_offset,
use_counters,
sanitization_data,
);
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 {
/// Updates an empty stylesheet from a given string of text.
pub fn update_from_str(
@ -365,6 +430,7 @@ impl Stylesheet {
existing.contents.quirks_mode,
line_number_offset,
/* use_counters = */ None,
/* sanitization_data = */ None,
);
*existing.contents.url_data.write() = url_data;
@ -391,6 +457,7 @@ impl Stylesheet {
quirks_mode: QuirksMode,
line_number_offset: u32,
use_counters: Option<&UseCounters>,
mut sanitization_data: Option<&mut SanitizationData>,
) -> (Vec<CssRule>, Option<String>, Option<String>) {
let mut rules = Vec::new();
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);
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 {
Ok(rule) => {
// 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 let Some(ref mut data) = sanitization_data {
if !data.kind.allows(&rule) {
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() {
break;
}
@ -470,6 +549,7 @@ impl Stylesheet {
quirks_mode,
line_number_offset,
/* use_counters = */ None,
/* sanitized_output = */ None,
);
Stylesheet {

View file

@ -1013,7 +1013,7 @@ impl Stylist {
);
if !declarations.is_empty() {
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,
);
if rule_node != *self.rule_tree.root() {
@ -1889,18 +1889,33 @@ impl CascadeData {
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.
#[inline]
pub fn slotted_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
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.
#[inline]
pub fn part_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&PartMap> {
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`.
///
/// This duplicates part of the logic in `add_stylesheet`, which is

View file

@ -1373,7 +1373,7 @@ impl ComputedTranslate {
LengthPercentage::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::CSSFloat;
use crate::Atom;
use app_units::Au;
use byteorder::{BigEndian, ByteOrder};
use cssparser::{serialize_identifier, CssStringWriter, Parser};
#[cfg(feature = "gecko")]
@ -148,15 +147,16 @@ impl FontWeight {
impl FontSize {
/// The actual computed font size.
pub fn size(self) -> Au {
self.size.into()
#[inline]
pub fn size(&self) -> Length {
self.size.0
}
#[inline]
/// Get default value of font size.
pub fn medium() -> 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()),
}
}

View file

@ -29,7 +29,7 @@ pub use crate::values::specified::url::UrlOrNone;
pub use crate::values::specified::{Angle, BorderStyle, Time};
impl ToComputedValue for specified::NoCalcLength {
type ComputedValue = CSSPixelLength;
type ComputedValue = Length;
#[inline]
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
#[allow(missing_docs)]
#[derive(
Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize, ToAnimatedZero, ToResolvedValue,
)]
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize, ToAnimatedZero, ToResolvedValue)]
#[repr(C)]
pub struct LengthPercentage {
length: Length,
@ -543,14 +541,14 @@ impl ToAnimatedValue for NonNegativeLengthPercentage {
impl From<NonNegativeLength> for NonNegativeLengthPercentage {
#[inline]
fn from(length: NonNegativeLength) -> Self {
LengthPercentage::new(length.0, None).into()
NonNegative(LengthPercentage::new(length.0, None))
}
}
impl From<LengthPercentage> for NonNegativeLengthPercentage {
#[inline]
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::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
pub use self::text::TextUnderlinePosition;
pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight};
pub use self::text::{OverflowWrap, TextOverflow, WordBreak, WordSpacing};
pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle};

View file

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

View file

@ -207,15 +207,6 @@ impl<LengthPercentage> MaxSize<LengthPercentage> {
pub fn none() -> Self {
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.

View file

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

View file

@ -389,21 +389,10 @@ impl Display {
};
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")]
DisplayOutside::XUL => {
if static_prefs::pref!(
"layout.css.xul-box-display-values.survive-blockification.enabled"
) {
match self.inside() {
DisplayInside::MozInlineBox | DisplayInside::MozBox => Display::MozBox,
_ => Display::Block,
}
} else {
Display::Block
}
DisplayOutside::XUL => match self.inside() {
DisplayInside::MozInlineBox | DisplayInside::MozBox => Display::MozBox,
_ => Display::Block,
},
DisplayOutside::Block | DisplayOutside::None => *self,
#[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::CustomIdent;
use crate::Atom;
use app_units::Au;
use byteorder::{BigEndian, ByteOrder};
use cssparser::{Parser, Token};
#[cfg(feature = "gecko")]
@ -773,18 +772,18 @@ impl ToComputedValue for KeywordSize {
type ComputedValue = NonNegativeLength;
#[inline]
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
match *self {
KeywordSize::XXSmall => Au::from_px(FONT_MEDIUM_PX) * 3 / 5,
KeywordSize::XSmall => Au::from_px(FONT_MEDIUM_PX) * 3 / 4,
KeywordSize::Small => Au::from_px(FONT_MEDIUM_PX) * 8 / 9,
KeywordSize::Medium => Au::from_px(FONT_MEDIUM_PX),
KeywordSize::Large => Au::from_px(FONT_MEDIUM_PX) * 6 / 5,
KeywordSize::XLarge => Au::from_px(FONT_MEDIUM_PX) * 3 / 2,
KeywordSize::XXLarge => Au::from_px(FONT_MEDIUM_PX) * 2,
KeywordSize::XXXLarge => Au::from_px(FONT_MEDIUM_PX) * 3,
}
.into()
NonNegative(match *self {
KeywordSize::XXSmall => medium * 3.0 / 5.0,
KeywordSize::XSmall => medium * 3.0 / 4.0,
KeywordSize::Small => medium * 8.0 / 9.0,
KeywordSize::Medium => medium,
KeywordSize::Large => medium * 6.0 / 5.0,
KeywordSize::XLarge => medium * 3.0 / 2.0,
KeywordSize::XXLarge => medium * 2.0,
KeywordSize::XXXLarge => medium * 3.0,
})
}
#[inline]
@ -799,7 +798,6 @@ impl ToComputedValue for KeywordSize {
#[inline]
fn to_computed_value(&self, cx: &Context) -> NonNegativeLength {
use crate::context::QuirksMode;
use crate::values::specified::length::au_to_int_px;
// The tables in this function are originally from
// nsRuleNode::CalcFontPointSize in Gecko:
@ -850,22 +848,21 @@ impl ToComputedValue for KeywordSize {
Atom::with(gecko_font.mLanguage.mRawPtr, |atom| {
cx.font_metrics_provider
.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;
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 {
QUIRKS_FONT_SIZE_MAPPING
} else {
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 {
Au(FONT_SIZE_FACTORS[html_size] * base_size / 100).into()
}
base_size * FONT_SIZE_FACTORS[html_size] as f32 / 100.0
})
}
#[inline]
@ -927,7 +924,7 @@ impl FontSize {
// If the parent font was keyword-derived, this is too.
// Tack the % onto the factor
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)) => {
let parent = context.style().get_parent_font().clone_font_size();
@ -964,7 +961,7 @@ impl FontSize {
// others should reject negatives during parsing. But SMIL
// allows parsing negatives, and relies on us _not_ doing that
// 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()
},
FontSize::Keyword(i) => {

View file

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

View file

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

View file

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

View file

@ -77,7 +77,6 @@ impl ToComputedValue for LineHeight {
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
use crate::values::computed::Length as ComputedLength;
use crate::values::specified::length::FontBaseSize;
match *self {
GenericLineHeight::Normal => GenericLineHeight::Normal,
@ -97,16 +96,8 @@ impl ToComputedValue for LineHeight {
LengthPercentage::Calc(ref calc) => {
let computed_calc =
calc.to_computed_value_zoomed(context, FontBaseSize::CurrentStyle);
let font_relative_length =
FontRelativeLength::Em(computed_calc.percentage())
.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)
let base = context.style().get_font().clone_font_size().size();
computed_calc.percentage_relative_to(base)
},
};
GenericLineHeight::Length(result.into())
@ -1054,3 +1045,98 @@ impl TextDecorationLength {
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"
servo_arc = { path = "../servo_arc" }
smallbitvec = "2.1.1"
smallvec = "0.6.6"
smallvec = "1.0"
string_cache = { version = "0.8", optional = true }
thin-slice = "0.1.0"

View file

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