From 60d0c8cd76e4a5692b837c4e910309b63a7727b1 Mon Sep 17 00:00:00 2001 From: Pyfisch Date: Thu, 27 Sep 2018 22:58:09 +0200 Subject: [PATCH] Layout: stylistic changes Additionally if an image border can't be displayed show solid border. Introduce build_display_list_for_border_image to display border images. --- components/layout/display_list/background.rs | 69 +---- components/layout/display_list/builder.rs | 285 +++++++++++------- tests/wpt/metadata/MANIFEST.json | 2 +- .../border-image-width-008.html | 2 +- 4 files changed, 175 insertions(+), 183 deletions(-) diff --git a/components/layout/display_list/background.rs b/components/layout/display_list/background.rs index efe82be20fb0..3c75c250405e 100644 --- a/components/layout/display_list/background.rs +++ b/components/layout/display_list/background.rs @@ -37,8 +37,8 @@ use style::values::generics::image::GradientItem as GenericGradientItem; use style::values::specified::background::BackgroundRepeatKeyword; use style::values::specified::position::{X, Y}; use webrender_api::{BorderRadius, BorderSide, BorderStyle, BorderWidths, ColorF}; -use webrender_api::{ExtendMode, Gradient, GradientStop, LayoutSize, NinePatchBorder}; -use webrender_api::{NinePatchBorderSource, NormalBorder, RadialGradient}; +use webrender_api::{ExtendMode, Gradient, GradientStop, LayoutSize}; +use webrender_api::{NormalBorder, RadialGradient}; /// A helper data structure for gradients. #[derive(Clone, Copy)] @@ -70,7 +70,7 @@ pub struct BackgroundPlacement { pub fixed: bool, } -trait ResolvePercentage { +pub trait ResolvePercentage { fn resolve(&self, length: u32) -> u32; } @@ -801,65 +801,6 @@ pub fn calculate_inner_border_radii( radii } -/// Create the image border details. -/// -/// For a fragment with a given with a given "bounds" that has a "border_width" -/// for all four sides calculate the outset for the image border. Call the -/// "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( - bounds: Rect, - border_width: SideOffsets2D, - border_style_struct: &style_structs::Border, - build_source: F, -) -> Option<(NinePatchBorder, BorderWidths)> -where - F: FnOnce(Size2D) -> Option<(NinePatchBorderSource, Size2D)>, -{ - 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_fill = border_style_struct.border_image_slice.fill; - let border_image_slice = &border_style_struct.border_image_slice.offsets; - - if let Some((source, size)) = build_source(border_image_area) { - Some(( - NinePatchBorder { - source: source, - width: size.width, - height: size.height, - slice: SideOffsets2D::new( - border_image_slice.0.resolve(size.height), - border_image_slice.1.resolve(size.width), - border_image_slice.2.resolve(size.height), - border_image_slice.3.resolve(size.width), - ), - fill: border_image_fill, - repeat_horizontal: border_image_repeat.0.to_layout(), - repeat_vertical: border_image_repeat.1.to_layout(), - 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 { - None - } -} - fn calculate_border_image_outset_side(outset: LengthOrNumber, border_width: Au) -> Au { match outset { Either::First(length) => length.into(), @@ -867,7 +808,7 @@ fn calculate_border_image_outset_side(outset: LengthOrNumber, border_width: Au) } } -fn calculate_border_image_outset( +pub fn calculate_border_image_outset( outset: BorderImageOutset, border: SideOffsets2D, ) -> SideOffsets2D { @@ -891,7 +832,7 @@ fn calculate_border_image_width_side( } } -fn calculate_border_image_width( +pub fn calculate_border_image_width( width: &BorderImageWidth, border: BorderWidths, border_area: Size2D, diff --git a/components/layout/display_list/builder.rs b/components/layout/display_list/builder.rs index 82d162c58ee2..f473b98584a5 100644 --- a/components/layout/display_list/builder.rs +++ b/components/layout/display_list/builder.rs @@ -15,11 +15,11 @@ use block::BlockFlow; use canvas_traits::canvas::{CanvasMsg, FromLayoutMsg}; use context::LayoutContext; use display_list::ToLayout; -use display_list::background::{build_border_radius, build_border_image_details}; -use display_list::background::{calculate_inner_border_radii, compute_background_clip}; -use display_list::background::{compute_background_placement, convert_linear_gradient}; -use display_list::background::{convert_radial_gradient, get_cyclic}; -use display_list::background::simple_normal_border; +use display_list::background::{build_border_radius, calculate_inner_border_radii}; +use display_list::background::{calculate_border_image_outset, calculate_border_image_width}; +use display_list::background::{compute_background_clip, compute_background_placement}; +use display_list::background::{convert_linear_gradient, convert_radial_gradient, get_cyclic}; +use display_list::background::{simple_normal_border, ResolvePercentage}; use display_list::items::{BaseDisplayItem, BLUR_INFLATION_FACTOR, ClipScrollNode}; use display_list::items::{ClipScrollNodeIndex, ClipScrollNodeType, ClippingAndScrolling}; use display_list::items::{ClippingRegion, DisplayItem, DisplayItemMetadata, DisplayList}; @@ -62,6 +62,7 @@ use style::servo::restyle_damage::ServoRestyleDamage; use style::values::{Either, RGBA}; use style::values::computed::Gradient; use style::values::computed::effects::SimpleShadow; +use style::values::computed::image::Image as ComputedImage; use style::values::generics::background::BackgroundSize; use style::values::generics::image::{GradientKind, Image, PaintWorklet}; use style::values::generics::ui::Cursor; @@ -71,7 +72,7 @@ use style_traits::cursor::CursorKind; use table_cell::CollapsedBordersForCell; use webrender_api::{self, BorderDetails, BorderRadius, BorderSide, BoxShadowClipMode, ColorF}; use webrender_api::{ExternalScrollId, FilterOp, GlyphInstance, ImageRendering, LayoutRect}; -use webrender_api::{LayoutSize, LayoutTransform, LayoutVector2D, LineStyle}; +use webrender_api::{LayoutSize, LayoutTransform, LayoutVector2D, LineStyle, NinePatchBorder}; use webrender_api::{NinePatchBorderSource, NormalBorder, StickyOffsetBounds, ScrollSensitivity}; fn establishes_containing_block_for_absolute( @@ -666,6 +667,19 @@ pub trait FragmentDisplayListBuilding { clip: Rect, ); + /// Add display item for image border. + /// + /// Returns `Some` if the addition was successful. + fn build_display_list_for_border_image( + &self, + state: &mut DisplayListBuildState, + style: &ComputedValues, + base: BaseDisplayItem, + bounds: Rect, + image: &ComputedImage, + border_width: SideOffsets2D, + ) -> Option<()>; + /// Adds the display items necessary to paint the outline of this fragment to the display list /// if necessary. fn build_display_list_for_outline_if_applicable( @@ -1263,21 +1277,6 @@ impl FragmentDisplayListBuilding for Fragment { display_list_section: DisplayListSection, clip: Rect, ) { - fn convert_image_to_border( - image: WebRenderImageInfo, - ) -> Option<(NinePatchBorderSource, Size2D)> { - image.key.map(|key| { - ( - NinePatchBorderSource::Image(key), - Size2D::new(image.width, image.height), - ) - }) - } - - fn convert_size_au_to_u32(size: Size2D) -> Size2D { - Size2D::new(size.width.to_px() as u32, size.height.to_px() as u32) - } - let mut border = style.logical_border_width(); if let Some(inline_info) = inline_info { @@ -1330,107 +1329,159 @@ impl FragmentDisplayListBuilding for Fragment { let border_radius = build_border_radius(bounds, border_style_struct); let border_widths = border.to_physical(style.writing_mode); - let mut layout_border_width = border_widths.to_layout(); - let mut stops = Vec::new(); - let details = match border_style_struct.border_image_source { - Either::First(_) => { - if border_widths == SideOffsets2D::zero() { - None - } else { - Some(BorderDetails::Normal(NormalBorder { - left: BorderSide { - color: style.resolve_color(colors.left).to_layout(), - style: border_style.left.to_layout(), - }, - right: BorderSide { - color: style.resolve_color(colors.right).to_layout(), - style: border_style.right.to_layout(), - }, - top: BorderSide { - color: style.resolve_color(colors.top).to_layout(), - style: border_style.top.to_layout(), - }, - bottom: BorderSide { - color: style.resolve_color(colors.bottom).to_layout(), - style: border_style.bottom.to_layout(), - }, - radius: border_radius, - })) - } - }, - Either::Second(ref image) => { - build_border_image_details( + if let Either::Second(ref image) = border_style_struct.border_image_source { + if self + .build_display_list_for_border_image( + state, + style, + base.clone(), bounds, + image, border_widths, - border_style_struct, - |fallback_size| match image { - Image::Url(ref image_url) => image_url - .url() - .and_then(|url| { - state.layout_context.get_webrender_image_for_url( - self.node, - url.clone(), - UsePlaceholder::No, - ) - }).and_then(convert_image_to_border), - 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) - }) + ).is_some() + { + return; + } + // Fallback to rendering a solid border. + } + if border_widths == SideOffsets2D::zero() { + return; + } + let details = BorderDetails::Normal(NormalBorder { + left: BorderSide { + color: style.resolve_color(colors.left).to_layout(), + style: border_style.left.to_layout(), }, - }; - if let Some(details) = details { - state.add_display_item(DisplayItem::Border(CommonDisplayItem::with_data( - base, - webrender_api::BorderDisplayItem { - widths: layout_border_width, - details, + right: BorderSide { + color: style.resolve_color(colors.right).to_layout(), + style: border_style.right.to_layout(), + }, + top: BorderSide { + color: style.resolve_color(colors.top).to_layout(), + style: border_style.top.to_layout(), + }, + bottom: BorderSide { + color: style.resolve_color(colors.bottom).to_layout(), + style: border_style.bottom.to_layout(), + }, + radius: border_radius, + }); + state.add_display_item(DisplayItem::Border(CommonDisplayItem::with_data( + base, + webrender_api::BorderDisplayItem { + widths: border_widths.to_layout(), + details, + }, + Vec::new(), + ))); + } + + fn build_display_list_for_border_image( + &self, + state: &mut DisplayListBuildState, + style: &ComputedValues, + base: BaseDisplayItem, + bounds: Rect, + image: &ComputedImage, + border_width: SideOffsets2D, + ) -> Option<()> { + let border_style_struct = style.get_border(); + 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_fill = border_style_struct.border_image_slice.fill; + let border_image_slice = &border_style_struct.border_image_slice.offsets; + + let mut stops = Vec::new(); + let mut width = border_image_area.width.to_px() as u32; + let mut height = border_image_area.height.to_px() as u32; + let source = match image { + Image::Url(ref image_url) => { + let url = image_url.url()?; + let image = state.layout_context.get_webrender_image_for_url( + self.node, + url.clone(), + UsePlaceholder::No, + )?; + width = image.width; + height = image.height; + NinePatchBorderSource::Image(image.key?) + }, + Image::PaintWorklet(ref paint_worklet) => { + let image = self.get_webrender_image_for_paint_worklet( + state, + style, + paint_worklet, + border_image_area, + )?; + width = image.width; + height = image.height; + NinePatchBorderSource::Image(image.key?) + }, + Image::Gradient(ref gradient) => match gradient.kind { + GradientKind::Linear(angle_or_corner) => { + let (wr_gradient, linear_stops) = convert_linear_gradient( + style, + border_image_area, + &gradient.items[..], + angle_or_corner, + gradient.repeating, + ); + stops = linear_stops; + NinePatchBorderSource::Gradient(wr_gradient) }, - stops, - ))); - } + GradientKind::Radial(shape, center, _angle) => { + let (wr_gradient, radial_stops) = convert_radial_gradient( + style, + border_image_area, + &gradient.items[..], + shape, + center, + gradient.repeating, + ); + stops = radial_stops; + NinePatchBorderSource::RadialGradient(wr_gradient) + }, + }, + _ => return None, + }; + + let details = BorderDetails::NinePatch(NinePatchBorder { + source, + width, + height, + slice: SideOffsets2D::new( + border_image_slice.0.resolve(height), + border_image_slice.1.resolve(width), + border_image_slice.2.resolve(height), + border_image_slice.3.resolve(width), + ), + fill: border_image_fill, + repeat_horizontal: border_image_repeat.0.to_layout(), + repeat_vertical: border_image_repeat.1.to_layout(), + 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(), + ), + }); + state.add_display_item(DisplayItem::Border(CommonDisplayItem::with_data( + base, + webrender_api::BorderDisplayItem { + widths: border_image_width, + details, + }, + stops, + ))); + Some(()) } fn build_display_list_for_outline_if_applicable( diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json index e990cbd4c204..77f657b98031 100644 --- a/tests/wpt/metadata/MANIFEST.json +++ b/tests/wpt/metadata/MANIFEST.json @@ -518607,7 +518607,7 @@ "support" ], "css/css-backgrounds/border-image-width-008.html": [ - "a35c3f65c54ef34b8bd83b5c18f483302e607a26", + "3158cdb5717b873065bc70537075234492796501", "reftest" ], "css/css-backgrounds/border-images.html": [ diff --git a/tests/wpt/web-platform-tests/css/css-backgrounds/border-image-width-008.html b/tests/wpt/web-platform-tests/css/css-backgrounds/border-image-width-008.html index a35c3f65c54e..3158cdb5717b 100644 --- a/tests/wpt/web-platform-tests/css/css-backgrounds/border-image-width-008.html +++ b/tests/wpt/web-platform-tests/css/css-backgrounds/border-image-width-008.html @@ -2,7 +2,7 @@ border-image-width has the same effect as a border-width and the image is displayed even if border-width is zero - +