mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Split layout/background.rs file
Have background, border and gradient modules for calculation functions. Use shorter names for functions that are qualified by the module name like `border::radii`. Use push_item and push_iter to add items to WebRender.
This commit is contained in:
parent
2304f02123
commit
2ff330a5c9
7 changed files with 577 additions and 658 deletions
209
components/layout/display_list/border.rs
Normal file
209
components/layout/display_list/border.rs
Normal file
|
@ -0,0 +1,209 @@
|
|||
// FIXME(rust-lang/rust#26264): Remove GenericBorderImageSideWidth.
|
||||
|
||||
use app_units::Au;
|
||||
use display_list::ToLayout;
|
||||
use euclid::{Rect, SideOffsets2D, Size2D};
|
||||
use style::computed_values::border_image_outset::T as BorderImageOutset;
|
||||
use style::properties::style_structs::Border;
|
||||
use style::values::Either;
|
||||
use style::values::computed::{BorderCornerRadius, BorderImageWidth};
|
||||
use style::values::computed::{BorderImageSideWidth, LengthOrNumber};
|
||||
use style::values::computed::NumberOrPercentage;
|
||||
use style::values::generics::border::{BorderImageSideWidth as GenericBorderImageSideWidth};
|
||||
use style::values::generics::rect::Rect as StyleRect;
|
||||
use webrender_api::{BorderRadius, BorderSide, BorderStyle, ColorF};
|
||||
use webrender_api::{LayoutSize, LayoutSideOffsets, NormalBorder};
|
||||
|
||||
/// Computes a border radius size against the containing size.
|
||||
///
|
||||
/// Note that percentages in `border-radius` are resolved against the relevant
|
||||
/// box dimension instead of only against the width per [1]:
|
||||
///
|
||||
/// > Percentages: Refer to corresponding dimension of the border box.
|
||||
///
|
||||
/// [1]: https://drafts.csswg.org/css-backgrounds-3/#border-radius
|
||||
fn corner_radius(
|
||||
radius: BorderCornerRadius,
|
||||
containing_size: Size2D<Au>,
|
||||
) -> Size2D<Au> {
|
||||
let w = radius.0.width().to_used_value(containing_size.width);
|
||||
let h = radius.0.height().to_used_value(containing_size.height);
|
||||
Size2D::new(w, h)
|
||||
}
|
||||
|
||||
fn scaled_radii(radii: BorderRadius, factor: f32) -> BorderRadius {
|
||||
BorderRadius {
|
||||
top_left: radii.top_left * factor,
|
||||
top_right: radii.top_right * factor,
|
||||
bottom_left: radii.bottom_left * factor,
|
||||
bottom_right: radii.bottom_right * factor,
|
||||
}
|
||||
}
|
||||
|
||||
fn overlapping_radii(size: LayoutSize, radii: BorderRadius) -> BorderRadius {
|
||||
// No two corners' border radii may add up to more than the length of the edge
|
||||
// between them. To prevent that, all radii are scaled down uniformly.
|
||||
fn scale_factor(radius_a: f32, radius_b: f32, edge_length: f32) -> f32 {
|
||||
let required = radius_a + radius_b;
|
||||
|
||||
if required <= edge_length {
|
||||
1.0
|
||||
} else {
|
||||
edge_length / required
|
||||
}
|
||||
}
|
||||
|
||||
let top_factor = scale_factor(radii.top_left.width, radii.top_right.width, size.width);
|
||||
let bottom_factor = scale_factor(
|
||||
radii.bottom_left.width,
|
||||
radii.bottom_right.width,
|
||||
size.width,
|
||||
);
|
||||
let left_factor = scale_factor(radii.top_left.height, radii.bottom_left.height, size.height);
|
||||
let right_factor = scale_factor(
|
||||
radii.top_right.height,
|
||||
radii.bottom_right.height,
|
||||
size.height,
|
||||
);
|
||||
let min_factor = top_factor
|
||||
.min(bottom_factor)
|
||||
.min(left_factor)
|
||||
.min(right_factor);
|
||||
if min_factor < 1.0 {
|
||||
scaled_radii(radii, min_factor)
|
||||
} else {
|
||||
radii
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn radii(
|
||||
abs_bounds: Rect<Au>,
|
||||
border_style: &Border,
|
||||
) -> BorderRadius {
|
||||
// TODO(cgaebel): Support border radii even in the case of multiple border widths.
|
||||
// This is an extension of supporting elliptical radii. For now, all percentage
|
||||
// radii will be relative to the width.
|
||||
|
||||
overlapping_radii(
|
||||
abs_bounds.size.to_layout(),
|
||||
BorderRadius {
|
||||
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,
|
||||
).to_layout(),
|
||||
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,
|
||||
).to_layout(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Calculates radii for the inner side.
|
||||
///
|
||||
/// Radii usually describe the outer side of a border but for the lines to look nice
|
||||
/// the inner radii need to be smaller depending on the line width.
|
||||
///
|
||||
/// This is used to determine clipping areas.
|
||||
pub fn inner_radii(
|
||||
mut radii: BorderRadius,
|
||||
offsets: SideOffsets2D<Au>,
|
||||
) -> BorderRadius {
|
||||
fn inner_length(x: f32, offset: Au) -> f32 {
|
||||
0.0_f32.max(x - offset.to_f32_px())
|
||||
}
|
||||
radii.top_left.width = inner_length(radii.top_left.width, offsets.left);
|
||||
radii.bottom_left.width = inner_length(radii.bottom_left.width, offsets.left);
|
||||
|
||||
radii.top_right.width = inner_length(radii.top_right.width, offsets.right);
|
||||
radii.bottom_right.width = inner_length(radii.bottom_right.width, offsets.right);
|
||||
|
||||
radii.top_left.height = inner_length(radii.top_left.height, offsets.top);
|
||||
radii.top_right.height = inner_length(radii.top_right.height, offsets.top);
|
||||
|
||||
radii.bottom_left.height = inner_length(radii.bottom_left.height, offsets.bottom);
|
||||
radii.bottom_right.height = inner_length(radii.bottom_right.height, offsets.bottom);
|
||||
radii
|
||||
}
|
||||
|
||||
/// Creates a four-sided border with uniform color, width and corner radius.
|
||||
pub fn simple(color: ColorF, style: BorderStyle) -> NormalBorder {
|
||||
let side = BorderSide { color, style };
|
||||
NormalBorder {
|
||||
left: side,
|
||||
right: side,
|
||||
top: side,
|
||||
bottom: side,
|
||||
radius: BorderRadius::zero(),
|
||||
do_aa: true,
|
||||
}
|
||||
}
|
||||
|
||||
fn side_image_outset(outset: LengthOrNumber, border_width: Au) -> Au {
|
||||
match outset {
|
||||
Either::First(length) => length.into(),
|
||||
Either::Second(factor) => border_width.scale_by(factor),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image_outset(
|
||||
outset: BorderImageOutset,
|
||||
border: SideOffsets2D<Au>,
|
||||
) -> SideOffsets2D<Au> {
|
||||
SideOffsets2D::new(
|
||||
side_image_outset(outset.0, border.top),
|
||||
side_image_outset(outset.1, border.right),
|
||||
side_image_outset(outset.2, border.bottom),
|
||||
side_image_outset(outset.3, border.left),
|
||||
)
|
||||
}
|
||||
|
||||
fn side_image_width(
|
||||
border_image_width: BorderImageSideWidth,
|
||||
border_width: f32,
|
||||
total_length: Au,
|
||||
) -> f32 {
|
||||
match border_image_width {
|
||||
GenericBorderImageSideWidth::Length(v) => v.to_used_value(total_length).to_f32_px(),
|
||||
GenericBorderImageSideWidth::Number(x) => border_width * x,
|
||||
GenericBorderImageSideWidth::Auto => border_width,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image_width(
|
||||
width: &BorderImageWidth,
|
||||
border: LayoutSideOffsets,
|
||||
border_area: Size2D<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),
|
||||
)
|
||||
}
|
||||
|
||||
fn resolve_percentage(value: NumberOrPercentage, length: u32) -> u32 {
|
||||
match value {
|
||||
NumberOrPercentage::Percentage(p) => (p.0 * length as f32).round() as u32,
|
||||
NumberOrPercentage::Number(n) => n.round() as u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image_slice(border_image_slice: &StyleRect<NumberOrPercentage>, width: u32, height: u32) -> SideOffsets2D<u32> {
|
||||
SideOffsets2D::new(
|
||||
resolve_percentage(border_image_slice.0, height),
|
||||
resolve_percentage(border_image_slice.1, width),
|
||||
resolve_percentage(border_image_slice.2, height),
|
||||
resolve_percentage(border_image_slice.3, width),
|
||||
)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue