mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Improve border images
Respect CSS border-image-width. Properly support gradients as a border-image-source. Only emit a border item if the border-width is non-zero for simple borders but still emit one if the item is an image as paint worklet that are not drawn cause servo to hang and fail tests. Add a new test and mark 4 more as passing.
This commit is contained in:
parent
41a2010ee7
commit
fabb70f874
9 changed files with 272 additions and 163 deletions
|
@ -9,11 +9,11 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
|
|
||||||
// FIXME(rust-lang/rust#26264): Remove GenericEndingShape and GenericGradientItem.
|
// FIXME(rust-lang/rust#26264): Remove GenericEndingShape, GenericGradientItem,
|
||||||
|
// GenericBackgroundSize and GenericBorderImageSideWidth.
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use display_list::ToLayout;
|
use display_list::ToLayout;
|
||||||
use display_list::items::WebRenderImageInfo;
|
|
||||||
use euclid::{Point2D, Rect, SideOffsets2D, Size2D, Vector2D};
|
use euclid::{Point2D, Rect, SideOffsets2D, Size2D, Vector2D};
|
||||||
use model::{self, MaybeAuto};
|
use model::{self, MaybeAuto};
|
||||||
use style::computed_values::background_attachment::single_value::T as BackgroundAttachment;
|
use style::computed_values::background_attachment::single_value::T as BackgroundAttachment;
|
||||||
|
@ -23,20 +23,22 @@ use style::computed_values::border_image_outset::T as BorderImageOutset;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::properties::style_structs::{self, Background};
|
use style::properties::style_structs::{self, Background};
|
||||||
use style::values::Either;
|
use style::values::Either;
|
||||||
use style::values::computed::{Angle, GradientItem, BackgroundSize as ComputedBackgroundSize};
|
use style::values::computed::{Angle, GradientItem, BackgroundSize};
|
||||||
|
use style::values::computed::{BorderImageWidth, BorderImageSideWidth};
|
||||||
use style::values::computed::{LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
|
use style::values::computed::{LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||||
use style::values::computed::{NumberOrPercentage, Percentage, Position};
|
use style::values::computed::{NumberOrPercentage, Percentage, Position};
|
||||||
use style::values::computed::image::{EndingShape, LineDirection};
|
use style::values::computed::image::{EndingShape, LineDirection};
|
||||||
use style::values::generics::NonNegative;
|
use style::values::generics::NonNegative;
|
||||||
use style::values::generics::background::BackgroundSize;
|
use style::values::generics::background::BackgroundSize as GenericBackgroundSize;
|
||||||
|
use style::values::generics::border::{BorderImageSideWidth as GenericBorderImageSideWidth};
|
||||||
use style::values::generics::image::{Circle, Ellipse, ShapeExtent};
|
use style::values::generics::image::{Circle, Ellipse, ShapeExtent};
|
||||||
use style::values::generics::image::EndingShape as GenericEndingShape;
|
use style::values::generics::image::EndingShape as GenericEndingShape;
|
||||||
use style::values::generics::image::GradientItem as GenericGradientItem;
|
use style::values::generics::image::GradientItem as GenericGradientItem;
|
||||||
use style::values::specified::background::BackgroundRepeatKeyword;
|
use style::values::specified::background::BackgroundRepeatKeyword;
|
||||||
use style::values::specified::position::{X, Y};
|
use style::values::specified::position::{X, Y};
|
||||||
use webrender_api::{BorderDetails, BorderRadius, BorderSide, BorderStyle, ColorF, ExtendMode};
|
use webrender_api::{BorderRadius, BorderSide, BorderStyle, BorderWidths, ColorF};
|
||||||
use webrender_api::{Gradient, GradientStop, LayoutSize, NinePatchBorder, NinePatchBorderSource};
|
use webrender_api::{ExtendMode, Gradient, GradientStop, LayoutSize, NinePatchBorder};
|
||||||
use webrender_api::{NormalBorder, RadialGradient};
|
use webrender_api::{NinePatchBorderSource, NormalBorder, RadialGradient};
|
||||||
|
|
||||||
/// A helper data structure for gradients.
|
/// A helper data structure for gradients.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
@ -94,14 +96,14 @@ pub fn get_cyclic<T>(arr: &[T], index: usize) -> &T {
|
||||||
/// For a given area and an image compute how big the
|
/// For a given area and an image compute how big the
|
||||||
/// image should be displayed on the background.
|
/// image should be displayed on the background.
|
||||||
fn compute_background_image_size(
|
fn compute_background_image_size(
|
||||||
bg_size: ComputedBackgroundSize,
|
bg_size: BackgroundSize,
|
||||||
bounds_size: Size2D<Au>,
|
bounds_size: Size2D<Au>,
|
||||||
intrinsic_size: Option<Size2D<Au>>,
|
intrinsic_size: Option<Size2D<Au>>,
|
||||||
) -> Size2D<Au> {
|
) -> Size2D<Au> {
|
||||||
match intrinsic_size {
|
match intrinsic_size {
|
||||||
None => match bg_size {
|
None => match bg_size {
|
||||||
BackgroundSize::Cover | BackgroundSize::Contain => bounds_size,
|
GenericBackgroundSize::Cover | GenericBackgroundSize::Contain => bounds_size,
|
||||||
BackgroundSize::Explicit { width, height } => Size2D::new(
|
GenericBackgroundSize::Explicit { width, height } => Size2D::new(
|
||||||
MaybeAuto::from_style(width.0, bounds_size.width)
|
MaybeAuto::from_style(width.0, bounds_size.width)
|
||||||
.specified_or_default(bounds_size.width),
|
.specified_or_default(bounds_size.width),
|
||||||
MaybeAuto::from_style(height.0, bounds_size.height)
|
MaybeAuto::from_style(height.0, bounds_size.height)
|
||||||
|
@ -115,16 +117,20 @@ fn compute_background_image_size(
|
||||||
let bounds_aspect_ratio =
|
let bounds_aspect_ratio =
|
||||||
bounds_size.width.to_f32_px() / bounds_size.height.to_f32_px();
|
bounds_size.width.to_f32_px() / bounds_size.height.to_f32_px();
|
||||||
match (bg_size, image_aspect_ratio < bounds_aspect_ratio) {
|
match (bg_size, image_aspect_ratio < bounds_aspect_ratio) {
|
||||||
(BackgroundSize::Contain, false) | (BackgroundSize::Cover, true) => Size2D::new(
|
(GenericBackgroundSize::Contain, false) | (GenericBackgroundSize::Cover, true) => {
|
||||||
|
Size2D::new(
|
||||||
bounds_size.width,
|
bounds_size.width,
|
||||||
bounds_size.width.scale_by(image_aspect_ratio.recip()),
|
bounds_size.width.scale_by(image_aspect_ratio.recip()),
|
||||||
),
|
)
|
||||||
(BackgroundSize::Contain, true) | (BackgroundSize::Cover, false) => Size2D::new(
|
},
|
||||||
|
(GenericBackgroundSize::Contain, true) | (GenericBackgroundSize::Cover, false) => {
|
||||||
|
Size2D::new(
|
||||||
bounds_size.height.scale_by(image_aspect_ratio),
|
bounds_size.height.scale_by(image_aspect_ratio),
|
||||||
bounds_size.height,
|
bounds_size.height,
|
||||||
),
|
)
|
||||||
|
},
|
||||||
(
|
(
|
||||||
BackgroundSize::Explicit {
|
GenericBackgroundSize::Explicit {
|
||||||
width,
|
width,
|
||||||
height: NonNegative(LengthOrPercentageOrAuto::Auto),
|
height: NonNegative(LengthOrPercentageOrAuto::Auto),
|
||||||
},
|
},
|
||||||
|
@ -135,7 +141,7 @@ fn compute_background_image_size(
|
||||||
Size2D::new(width, width.scale_by(image_aspect_ratio.recip()))
|
Size2D::new(width, width.scale_by(image_aspect_ratio.recip()))
|
||||||
},
|
},
|
||||||
(
|
(
|
||||||
BackgroundSize::Explicit {
|
GenericBackgroundSize::Explicit {
|
||||||
width: NonNegative(LengthOrPercentageOrAuto::Auto),
|
width: NonNegative(LengthOrPercentageOrAuto::Auto),
|
||||||
height,
|
height,
|
||||||
},
|
},
|
||||||
|
@ -145,7 +151,7 @@ fn compute_background_image_size(
|
||||||
.specified_or_default(own_size.height);
|
.specified_or_default(own_size.height);
|
||||||
Size2D::new(height.scale_by(image_aspect_ratio), height)
|
Size2D::new(height.scale_by(image_aspect_ratio), height)
|
||||||
},
|
},
|
||||||
(BackgroundSize::Explicit { width, height }, _) => Size2D::new(
|
(GenericBackgroundSize::Explicit { width, height }, _) => Size2D::new(
|
||||||
MaybeAuto::from_style(width.0, bounds_size.width)
|
MaybeAuto::from_style(width.0, bounds_size.width)
|
||||||
.specified_or_default(own_size.width),
|
.specified_or_default(own_size.width),
|
||||||
MaybeAuto::from_style(height.0, bounds_size.height)
|
MaybeAuto::from_style(height.0, bounds_size.height)
|
||||||
|
@ -795,32 +801,60 @@ pub fn calculate_inner_border_radii(
|
||||||
radii
|
radii
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given an image and a border style constructs a border image.
|
/// Create the image border details.
|
||||||
///
|
///
|
||||||
/// See: https://drafts.csswg.org/css-backgrounds-3/#border-images
|
/// For a fragment with a given with a given "bounds" that has a "border_width"
|
||||||
pub fn build_image_border_details(
|
/// for all four sides calculate the outset for the image border. Call the
|
||||||
webrender_image: WebRenderImageInfo,
|
/// "build_source" function to get the image which is either a gradient
|
||||||
|
/// or an image. The supplied "fallback_size" is used to size gradients
|
||||||
|
/// and other images without an intrinsic size. The actual size of the image
|
||||||
|
/// is also returned. Apply all other attributes for border images and return
|
||||||
|
/// the "NinePatchBorder".
|
||||||
|
pub fn build_border_image_details<F>(
|
||||||
|
bounds: Rect<Au>,
|
||||||
|
border_width: SideOffsets2D<Au>,
|
||||||
border_style_struct: &style_structs::Border,
|
border_style_struct: &style_structs::Border,
|
||||||
outset: SideOffsets2D<f32>,
|
build_source: F,
|
||||||
) -> Option<BorderDetails> {
|
) -> Option<(NinePatchBorder, BorderWidths)>
|
||||||
let corners = &border_style_struct.border_image_slice.offsets;
|
where
|
||||||
|
F: FnOnce(Size2D<Au>) -> Option<(NinePatchBorderSource, Size2D<u32>)>,
|
||||||
|
{
|
||||||
|
let border_image_outset =
|
||||||
|
calculate_border_image_outset(border_style_struct.border_image_outset, border_width);
|
||||||
|
let border_image_area = bounds.outer_rect(border_image_outset).size;
|
||||||
|
let border_image_width = calculate_border_image_width(
|
||||||
|
&border_style_struct.border_image_width,
|
||||||
|
border_width.to_layout(),
|
||||||
|
border_image_area,
|
||||||
|
);
|
||||||
let border_image_repeat = &border_style_struct.border_image_repeat;
|
let border_image_repeat = &border_style_struct.border_image_repeat;
|
||||||
if let Some(image_key) = webrender_image.key {
|
let border_image_fill = border_style_struct.border_image_slice.fill;
|
||||||
Some(BorderDetails::NinePatch(NinePatchBorder {
|
let border_image_slice = &border_style_struct.border_image_slice.offsets;
|
||||||
source: NinePatchBorderSource::Image(image_key),
|
|
||||||
width: webrender_image.width,
|
if let Some((source, size)) = build_source(border_image_area) {
|
||||||
height: webrender_image.height,
|
Some((
|
||||||
|
NinePatchBorder {
|
||||||
|
source: source,
|
||||||
|
width: size.width,
|
||||||
|
height: size.height,
|
||||||
slice: SideOffsets2D::new(
|
slice: SideOffsets2D::new(
|
||||||
corners.0.resolve(webrender_image.height),
|
border_image_slice.0.resolve(size.height),
|
||||||
corners.1.resolve(webrender_image.width),
|
border_image_slice.1.resolve(size.width),
|
||||||
corners.2.resolve(webrender_image.height),
|
border_image_slice.2.resolve(size.height),
|
||||||
corners.3.resolve(webrender_image.width),
|
border_image_slice.3.resolve(size.width),
|
||||||
),
|
),
|
||||||
fill: border_style_struct.border_image_slice.fill,
|
fill: border_image_fill,
|
||||||
repeat_horizontal: border_image_repeat.0.to_layout(),
|
repeat_horizontal: border_image_repeat.0.to_layout(),
|
||||||
repeat_vertical: border_image_repeat.1.to_layout(),
|
repeat_vertical: border_image_repeat.1.to_layout(),
|
||||||
outset: outset,
|
outset: SideOffsets2D::new(
|
||||||
}))
|
border_image_outset.top.to_f32_px(),
|
||||||
|
border_image_outset.right.to_f32_px(),
|
||||||
|
border_image_outset.bottom.to_f32_px(),
|
||||||
|
border_image_outset.left.to_f32_px(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
border_image_width,
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -833,7 +867,7 @@ fn calculate_border_image_outset_side(outset: LengthOrNumber, border_width: Au)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate_border_image_outset(
|
fn calculate_border_image_outset(
|
||||||
outset: BorderImageOutset,
|
outset: BorderImageOutset,
|
||||||
border: SideOffsets2D<Au>,
|
border: SideOffsets2D<Au>,
|
||||||
) -> SideOffsets2D<Au> {
|
) -> SideOffsets2D<Au> {
|
||||||
|
@ -844,3 +878,28 @@ pub fn calculate_border_image_outset(
|
||||||
calculate_border_image_outset_side(outset.3, border.left),
|
calculate_border_image_outset_side(outset.3, border.left),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn calculate_border_image_width_side(
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calculate_border_image_width(
|
||||||
|
width: &BorderImageWidth,
|
||||||
|
border: BorderWidths,
|
||||||
|
border_area: Size2D<Au>,
|
||||||
|
) -> BorderWidths {
|
||||||
|
BorderWidths {
|
||||||
|
left: calculate_border_image_width_side(width.3, border.left, border_area.width),
|
||||||
|
top: calculate_border_image_width_side(width.0, border.top, border_area.height),
|
||||||
|
right: calculate_border_image_width_side(width.1, border.right, border_area.width),
|
||||||
|
bottom: calculate_border_image_width_side(width.2, border.bottom, border_area.height),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,10 +15,10 @@ use block::BlockFlow;
|
||||||
use canvas_traits::canvas::{CanvasMsg, FromLayoutMsg};
|
use canvas_traits::canvas::{CanvasMsg, FromLayoutMsg};
|
||||||
use context::LayoutContext;
|
use context::LayoutContext;
|
||||||
use display_list::ToLayout;
|
use display_list::ToLayout;
|
||||||
use display_list::background::{build_border_radius, build_image_border_details};
|
use display_list::background::{build_border_radius, build_border_image_details};
|
||||||
use display_list::background::{calculate_border_image_outset, calculate_inner_border_radii};
|
use display_list::background::{calculate_inner_border_radii, compute_background_clip};
|
||||||
use display_list::background::{compute_background_clip, compute_background_placement};
|
use display_list::background::{compute_background_placement, convert_linear_gradient};
|
||||||
use display_list::background::{convert_linear_gradient, convert_radial_gradient, get_cyclic};
|
use display_list::background::{convert_radial_gradient, get_cyclic};
|
||||||
use display_list::background::simple_normal_border;
|
use display_list::background::simple_normal_border;
|
||||||
use display_list::items::{BaseDisplayItem, BLUR_INFLATION_FACTOR, ClipScrollNode};
|
use display_list::items::{BaseDisplayItem, BLUR_INFLATION_FACTOR, ClipScrollNode};
|
||||||
use display_list::items::{ClipScrollNodeIndex, ClipScrollNodeType, ClippingAndScrolling};
|
use display_list::items::{ClipScrollNodeIndex, ClipScrollNodeType, ClippingAndScrolling};
|
||||||
|
@ -71,8 +71,8 @@ use style_traits::cursor::CursorKind;
|
||||||
use table_cell::CollapsedBordersForCell;
|
use table_cell::CollapsedBordersForCell;
|
||||||
use webrender_api::{self, BorderDetails, BorderRadius, BorderSide, BoxShadowClipMode, ColorF};
|
use webrender_api::{self, BorderDetails, BorderRadius, BorderSide, BoxShadowClipMode, ColorF};
|
||||||
use webrender_api::{ExternalScrollId, FilterOp, GlyphInstance, ImageRendering, LayoutRect};
|
use webrender_api::{ExternalScrollId, FilterOp, GlyphInstance, ImageRendering, LayoutRect};
|
||||||
use webrender_api::{LayoutSize, LayoutTransform, LayoutVector2D, LineStyle, NormalBorder};
|
use webrender_api::{LayoutSize, LayoutTransform, LayoutVector2D, LineStyle};
|
||||||
use webrender_api::{StickyOffsetBounds, ScrollSensitivity};
|
use webrender_api::{NinePatchBorderSource, NormalBorder, StickyOffsetBounds, ScrollSensitivity};
|
||||||
|
|
||||||
fn establishes_containing_block_for_absolute(
|
fn establishes_containing_block_for_absolute(
|
||||||
flags: StackingContextCollectionFlags,
|
flags: StackingContextCollectionFlags,
|
||||||
|
@ -1263,6 +1263,21 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
display_list_section: DisplayListSection,
|
display_list_section: DisplayListSection,
|
||||||
clip: Rect<Au>,
|
clip: Rect<Au>,
|
||||||
) {
|
) {
|
||||||
|
fn convert_image_to_border(
|
||||||
|
image: WebRenderImageInfo,
|
||||||
|
) -> Option<(NinePatchBorderSource, Size2D<u32>)> {
|
||||||
|
image.key.map(|key| {
|
||||||
|
(
|
||||||
|
NinePatchBorderSource::Image(key),
|
||||||
|
Size2D::new(image.width, image.height),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_size_au_to_u32(size: Size2D<Au>) -> Size2D<u32> {
|
||||||
|
Size2D::new(size.width.to_px() as u32, size.height.to_px() as u32)
|
||||||
|
}
|
||||||
|
|
||||||
let mut border = style.logical_border_width();
|
let mut border = style.logical_border_width();
|
||||||
|
|
||||||
if let Some(inline_info) = inline_info {
|
if let Some(inline_info) = inline_info {
|
||||||
|
@ -1276,10 +1291,6 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
},
|
},
|
||||||
BorderPaintingMode::Hidden => return,
|
BorderPaintingMode::Hidden => return,
|
||||||
}
|
}
|
||||||
if border.is_zero() {
|
|
||||||
// TODO: check if image-border-outset is zero
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let border_style_struct = style.get_border();
|
let border_style_struct = style.get_border();
|
||||||
let mut colors = SideOffsets2D::new(
|
let mut colors = SideOffsets2D::new(
|
||||||
|
@ -1319,19 +1330,15 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
|
|
||||||
let border_radius = build_border_radius(bounds, border_style_struct);
|
let border_radius = build_border_radius(bounds, border_style_struct);
|
||||||
let border_widths = border.to_physical(style.writing_mode);
|
let border_widths = border.to_physical(style.writing_mode);
|
||||||
let outset =
|
let mut layout_border_width = border_widths.to_layout();
|
||||||
calculate_border_image_outset(border_style_struct.border_image_outset, border_widths);
|
|
||||||
let outset_layout = SideOffsets2D::new(
|
|
||||||
outset.top.to_f32_px(),
|
|
||||||
outset.right.to_f32_px(),
|
|
||||||
outset.bottom.to_f32_px(),
|
|
||||||
outset.left.to_f32_px(),
|
|
||||||
);
|
|
||||||
let size = bounds.outer_rect(outset).size;
|
|
||||||
|
|
||||||
let mut stops = Vec::new();
|
let mut stops = Vec::new();
|
||||||
let details = match border_style_struct.border_image_source {
|
let details = match border_style_struct.border_image_source {
|
||||||
Either::First(_) => Some(BorderDetails::Normal(NormalBorder {
|
Either::First(_) => {
|
||||||
|
if border_widths == SideOffsets2D::zero() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(BorderDetails::Normal(NormalBorder {
|
||||||
left: BorderSide {
|
left: BorderSide {
|
||||||
color: style.resolve_color(colors.left).to_layout(),
|
color: style.resolve_color(colors.left).to_layout(),
|
||||||
style: border_style.left.to_layout(),
|
style: border_style.left.to_layout(),
|
||||||
|
@ -1349,64 +1356,16 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
style: border_style.bottom.to_layout(),
|
style: border_style.bottom.to_layout(),
|
||||||
},
|
},
|
||||||
radius: border_radius,
|
radius: border_radius,
|
||||||
})),
|
}))
|
||||||
Either::Second(Image::Gradient(ref gradient)) => Some(match gradient.kind {
|
}
|
||||||
GradientKind::Linear(angle_or_corner) => {
|
|
||||||
let (wr_gradient, linear_stops) = convert_linear_gradient(
|
|
||||||
style,
|
|
||||||
bounds.size,
|
|
||||||
&gradient.items[..],
|
|
||||||
angle_or_corner,
|
|
||||||
gradient.repeating,
|
|
||||||
);
|
|
||||||
stops = linear_stops;
|
|
||||||
BorderDetails::NinePatch(webrender_api::NinePatchBorder {
|
|
||||||
source: webrender_api::NinePatchBorderSource::Gradient(wr_gradient),
|
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
slice: SideOffsets2D::zero(),
|
|
||||||
fill: false,
|
|
||||||
repeat_horizontal: webrender_api::RepeatMode::Stretch,
|
|
||||||
repeat_vertical: webrender_api::RepeatMode::Stretch,
|
|
||||||
outset: outset_layout,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
GradientKind::Radial(shape, center, _angle) => {
|
Either::Second(ref image) => {
|
||||||
let (wr_gradient, radial_stops) = convert_radial_gradient(
|
build_border_image_details(
|
||||||
style,
|
bounds,
|
||||||
bounds.size,
|
border_widths,
|
||||||
&gradient.items[..],
|
border_style_struct,
|
||||||
shape,
|
|fallback_size| match image {
|
||||||
center,
|
Image::Url(ref image_url) => image_url
|
||||||
gradient.repeating,
|
|
||||||
);
|
|
||||||
stops = radial_stops;
|
|
||||||
BorderDetails::NinePatch(webrender_api::NinePatchBorder {
|
|
||||||
source: webrender_api::NinePatchBorderSource::RadialGradient(wr_gradient),
|
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
slice: SideOffsets2D::zero(),
|
|
||||||
fill: false,
|
|
||||||
repeat_horizontal: webrender_api::RepeatMode::Stretch,
|
|
||||||
repeat_vertical: webrender_api::RepeatMode::Stretch,
|
|
||||||
outset: outset_layout,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
Either::Second(Image::PaintWorklet(ref paint_worklet)) => self
|
|
||||||
.get_webrender_image_for_paint_worklet(state, style, paint_worklet, size)
|
|
||||||
.and_then(|image| {
|
|
||||||
build_image_border_details(image, border_style_struct, outset_layout)
|
|
||||||
}),
|
|
||||||
Either::Second(Image::Rect(..)) => {
|
|
||||||
// TODO: Handle border-image with `-moz-image-rect`.
|
|
||||||
None
|
|
||||||
},
|
|
||||||
Either::Second(Image::Element(..)) => {
|
|
||||||
// TODO: Handle border-image with `-moz-element`.
|
|
||||||
None
|
|
||||||
},
|
|
||||||
Either::Second(Image::Url(ref image_url)) => image_url
|
|
||||||
.url()
|
.url()
|
||||||
.and_then(|url| {
|
.and_then(|url| {
|
||||||
state.layout_context.get_webrender_image_for_url(
|
state.layout_context.get_webrender_image_for_url(
|
||||||
|
@ -1414,15 +1373,59 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
url.clone(),
|
url.clone(),
|
||||||
UsePlaceholder::No,
|
UsePlaceholder::No,
|
||||||
)
|
)
|
||||||
}).and_then(|image| {
|
}).and_then(convert_image_to_border),
|
||||||
build_image_border_details(image, border_style_struct, outset_layout)
|
Image::PaintWorklet(ref paint_worklet) => self
|
||||||
}),
|
.get_webrender_image_for_paint_worklet(
|
||||||
|
state,
|
||||||
|
style,
|
||||||
|
paint_worklet,
|
||||||
|
fallback_size,
|
||||||
|
).and_then(convert_image_to_border),
|
||||||
|
Image::Gradient(ref gradient) => match gradient.kind {
|
||||||
|
GradientKind::Linear(angle_or_corner) => {
|
||||||
|
let (wr_gradient, linear_stops) = convert_linear_gradient(
|
||||||
|
style,
|
||||||
|
fallback_size,
|
||||||
|
&gradient.items[..],
|
||||||
|
angle_or_corner,
|
||||||
|
gradient.repeating,
|
||||||
|
);
|
||||||
|
stops = linear_stops;
|
||||||
|
Some((
|
||||||
|
NinePatchBorderSource::Gradient(wr_gradient),
|
||||||
|
convert_size_au_to_u32(fallback_size),
|
||||||
|
))
|
||||||
|
},
|
||||||
|
GradientKind::Radial(shape, center, _angle) => {
|
||||||
|
let (wr_gradient, radial_stops) = convert_radial_gradient(
|
||||||
|
style,
|
||||||
|
fallback_size,
|
||||||
|
&gradient.items[..],
|
||||||
|
shape,
|
||||||
|
center,
|
||||||
|
gradient.repeating,
|
||||||
|
);
|
||||||
|
stops = radial_stops;
|
||||||
|
Some((
|
||||||
|
NinePatchBorderSource::RadialGradient(wr_gradient),
|
||||||
|
convert_size_au_to_u32(fallback_size),
|
||||||
|
))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
).map(|(details, border)| {
|
||||||
|
// The image's border width can differ from the "simple" color border width.
|
||||||
|
layout_border_width = border;
|
||||||
|
BorderDetails::NinePatch(details)
|
||||||
|
})
|
||||||
|
},
|
||||||
};
|
};
|
||||||
if let Some(details) = details {
|
if let Some(details) = details {
|
||||||
state.add_display_item(DisplayItem::Border(CommonDisplayItem::with_data(
|
state.add_display_item(DisplayItem::Border(CommonDisplayItem::with_data(
|
||||||
base,
|
base,
|
||||||
webrender_api::BorderDisplayItem {
|
webrender_api::BorderDisplayItem {
|
||||||
widths: border_widths.to_layout(),
|
widths: layout_border_width,
|
||||||
details,
|
details,
|
||||||
},
|
},
|
||||||
stops,
|
stops,
|
||||||
|
|
|
@ -106531,6 +106531,18 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"css/css-backgrounds/border-image-width-008.html": [
|
||||||
|
[
|
||||||
|
"/css/css-backgrounds/border-image-width-008.html",
|
||||||
|
[
|
||||||
|
[
|
||||||
|
"/css/css-backgrounds/border-image-width-008-ref.html",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"css/css-backgrounds/border-radius-001.xht": [
|
"css/css-backgrounds/border-radius-001.xht": [
|
||||||
[
|
[
|
||||||
"/css/css-backgrounds/border-radius-001.xht",
|
"/css/css-backgrounds/border-radius-001.xht",
|
||||||
|
@ -243889,6 +243901,11 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"css/css-backgrounds/border-image-width-008-ref.html": [
|
||||||
|
[
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"css/css-backgrounds/border-radius-001-ref.xht": [
|
"css/css-backgrounds/border-radius-001-ref.xht": [
|
||||||
[
|
[
|
||||||
{}
|
{}
|
||||||
|
@ -518585,6 +518602,14 @@
|
||||||
"61726c00873739c076812f72645d8324494ff44c",
|
"61726c00873739c076812f72645d8324494ff44c",
|
||||||
"reftest"
|
"reftest"
|
||||||
],
|
],
|
||||||
|
"css/css-backgrounds/border-image-width-008-ref.html": [
|
||||||
|
"9a066443920726b79d69a0301d814b5211b7df0a",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"css/css-backgrounds/border-image-width-008.html": [
|
||||||
|
"a35c3f65c54ef34b8bd83b5c18f483302e607a26",
|
||||||
|
"reftest"
|
||||||
|
],
|
||||||
"css/css-backgrounds/border-images.html": [
|
"css/css-backgrounds/border-images.html": [
|
||||||
"930a1df3b7fda4098f36cc9691a544f46e2311d5",
|
"930a1df3b7fda4098f36cc9691a544f46e2311d5",
|
||||||
"visual"
|
"visual"
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[border-image-width-005.xht]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[border-image-width-006.xht]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
|
@ -1,4 +0,0 @@
|
||||||
[geometry-border-image-002.https.html]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
||||||
bug: https://github.com/servo/servo/issues/17860
|
|
|
@ -1,4 +0,0 @@
|
||||||
[geometry-border-image-003.https.html]
|
|
||||||
type: reftest
|
|
||||||
expected: FAIL
|
|
||||||
bug: https://github.com/servo/servo/issues/17860
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>border-image with different widths</title>
|
||||||
|
<style>
|
||||||
|
#ref {
|
||||||
|
width: 360px;
|
||||||
|
height: 240px;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 40px 40px 20px 0px;
|
||||||
|
border-image-source: url("support/border.png");
|
||||||
|
border-image-slice: 27;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<div id="ref"></div>
|
||||||
|
</body>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>border-image-width has the same effect as a border-width and the image is displayed even if border-width is zero</title>
|
||||||
|
<link rel="match" href="border-image-width-008-ref.html">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#propdef-border-image-width" />
|
||||||
|
<style>
|
||||||
|
#test {
|
||||||
|
width: 400px;
|
||||||
|
height: 300px;
|
||||||
|
border-style: solid;
|
||||||
|
/* Note: Chrome does not display an image if border-width is 0 */
|
||||||
|
border-width: 0px;
|
||||||
|
border-image-source: url("support/border.png");
|
||||||
|
border-image-width: 40px 40px 20px 0px;
|
||||||
|
border-image-slice: 27;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<div id="test"></div>
|
||||||
|
</body>
|
Loading…
Add table
Add a link
Reference in a new issue