Repository: servo/servo
File: components/layout/display_list/mod.rs (Rust)

Code before:
        );
        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 stops = Vec::new();
        let mut width = border_image_size.width;
        let mut height = border_image_size.height;
        let node = self.fragment.base.tag.map(|tag| tag.node);
        let source = match builder
            .image_resolver
            .resolve_image(node, &border.border_image_source)
        {
            Err(_) => return false,
            Ok(ResolvedImage::Image { image, size }) => {
                let Some(image) = image.as_raster_image() else {
                    return false;
                };

                let Some(key) = image.id else {
                    return false;
                };

                // From <https://www.w3.org/TR/paint-timing/#sec-terminology>:
                // > An element target is contentful when one or more of the following apply:
                // > - target is a replaced element representing an available image.
                builder.mark_is_contentful();
                width = size.width;
                height = size.height;
                let image_rendering = style.clone_image_rendering().to_webrender();
                NinePatchBorderSource::Image(key, image_rendering)
            },
            Ok(ResolvedImage::Gradient(gradient)) => {
                match gradient::build(&style, gradient, border_image_size, builder) {
                    WebRenderGradient::Linear(gradient) => {
                        NinePatchBorderSource::Gradient(gradient)
                    },
                    WebRenderGradient::Radial(gradient) => {
                        NinePatchBorderSource::RadialGradient(gradient)
                    },
                    WebRenderGradient::Conic(gradient) => {
                        NinePatchBorderSource::ConicGradient(gradient)
                    },
                }
            },
        };

        let size = Size2D::new(width as i32, height as i32);

        // If the size of the border is zero or the size of the border image is zero, just
        // don't render anything. Zero-sized gradients cause problems in WebRender.

Review comment (bug):
Given the NOTE in https://www.w3.org/TR/css-backgrounds-3/#layering (`The border-image properties can also define a background image, which, if present, is painted on top of the background layers created by the background properties.`), I think we should quote this text instead:

>target has a [background-image](https://www.w3.org/TR/css-backgrounds-3/#propdef-background-image) which is a [contentful image](https://www.w3.org/TR/paint-timing/#contentful-image), and its [used](https://www.w3.org/TR/css-cascade-5/#used-value) [background-size](https://www.w3.org/TR/css-backgrounds-3/#background-size) has non-zero width and height values.

However, we're not actually checking the used size until later, so it's confusing that the test doesn't fail.

Code after:
            right: self.build_border_side(style_color.right),
            bottom: self.build_border_side(style_color.bottom),
            left: self.build_border_side(style_color.left),
            radius: self.border_radius,
            do_aa: true,
        });
        builder
            .wr()
            .push_border(&common, self.border_rect, border_widths, details)
    }

    /// Add a display item for image borders if necessary.
    fn build_border_image(
        &self,
        builder: &mut DisplayListBuilder,
        common: &CommonItemProperties,
        border: &Border,
        border_widths: SideOffsets2D<f32, LayoutPixel>,
    ) -> bool {
        let style = self.fragment.style();
        let border_style_struct = style.get_border();
        let border_image_outset =
            resolve_border_image_outset(border_style_struct.border_image_outset, border_widths);
        let border_image_area = self.border_rect.to_rect().outer_rect(border_image_outset);
        let border_image_size = border_image_area.size;
        let border_image_widths = resolve_border_image_width(
            &border_style_struct.border_image_width,
            border_widths,
            border_image_size,
        );
        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 stops = Vec::new();
        let mut width = border_image_size.width;
        let mut height = border_image_size.height;
        let node = self.fragment.base.tag.map(|tag| tag.node);
        let source = match builder
            .image_resolver
            .resolve_image(node, &border.border_image_source)
        {
            Err(_) => return false,
            Ok(ResolvedImage::Image { image, size }) => {
                let Some(image) = image.as_raster_image() else {
                    return false;
                };

                let Some(key) = image.id else {
                    return false;
                };