Add renderer probe elements
diff --git a/vello_common/assets/probe_blurred_rounded_rect.png b/vello_common/assets/probe_blurred_rounded_rect.png
new file mode 100644
index 0000000..927d59a
--- /dev/null
+++ b/vello_common/assets/probe_blurred_rounded_rect.png
Binary files differ
diff --git a/vello_common/assets/probe_blurred_rounded_rect.rgba b/vello_common/assets/probe_blurred_rounded_rect.rgba
new file mode 100644
index 0000000..1c9326b
--- /dev/null
+++ b/vello_common/assets/probe_blurred_rounded_rect.rgba
@@ -0,0 +1 @@
+ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúøüÿëåòÿåÜíÿåÜíÿåÜíÿåÜíÿëåòÿúøüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúøüÿʸÛÿi´ÿ€V«ÿ€V«ÿ€V«ÿ€V«ÿi´ÿʸÛÿúøüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëåòÿi´ÿh6›ÿf3™ÿf3™ÿf3™ÿf3™ÿh6›ÿi´ÿëåòÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿåÜíÿ€V«ÿf3™ÿf3™ÿf3™ÿf3™ÿf3™ÿf3™ÿ€V«ÿåÜíÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿåÜíÿ€V«ÿf3™ÿf3™ÿf3™ÿf3™ÿf3™ÿf3™ÿ€V«ÿåÜíÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿåÜíÿ€V«ÿf3™ÿf3™ÿf3™ÿf3™ÿf3™ÿf3™ÿ€V«ÿåÜíÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿåÜíÿ€V«ÿf3™ÿf3™ÿf3™ÿf3™ÿf3™ÿf3™ÿ€V«ÿåÜíÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëåòÿi´ÿh6›ÿf3™ÿf3™ÿf3™ÿf3™ÿh6›ÿi´ÿëåòÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúøüÿʸÛÿi´ÿ€V«ÿ€V«ÿ€V«ÿ€V«ÿi´ÿʸÛÿúøüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúøüÿëåòÿåÜíÿåÜíÿåÜíÿåÜíÿëåòÿúøüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
\ No newline at end of file
diff --git a/vello_common/assets/probe_drop_shadow.png b/vello_common/assets/probe_drop_shadow.png
new file mode 100644
index 0000000..5098c6b
--- /dev/null
+++ b/vello_common/assets/probe_drop_shadow.png
Binary files differ
diff --git a/vello_common/assets/probe_drop_shadow.rgba b/vello_common/assets/probe_drop_shadow.rgba
new file mode 100644
index 0000000..248f1d3
--- /dev/null
+++ b/vello_common/assets/probe_drop_shadow.rgba
Binary files differ
diff --git a/vello_common/assets/probe_image_bicubic.png b/vello_common/assets/probe_image_bicubic.png
new file mode 100644
index 0000000..8b6fc59
--- /dev/null
+++ b/vello_common/assets/probe_image_bicubic.png
Binary files differ
diff --git a/vello_common/assets/probe_image_bicubic.rgba b/vello_common/assets/probe_image_bicubic.rgba
new file mode 100644
index 0000000..1815fe2
--- /dev/null
+++ b/vello_common/assets/probe_image_bicubic.rgba
Binary files differ
diff --git a/vello_common/assets/probe_gradient.png b/vello_common/assets/probe_linear_gradient.png
similarity index 100%
rename from vello_common/assets/probe_gradient.png
rename to vello_common/assets/probe_linear_gradient.png
Binary files differ
diff --git a/vello_common/assets/probe_gradient.rgba b/vello_common/assets/probe_linear_gradient.rgba
similarity index 100%
rename from vello_common/assets/probe_gradient.rgba
rename to vello_common/assets/probe_linear_gradient.rgba
Binary files differ
diff --git a/vello_common/assets/probe_radial_gradient.png b/vello_common/assets/probe_radial_gradient.png
new file mode 100644
index 0000000..ff684ee
--- /dev/null
+++ b/vello_common/assets/probe_radial_gradient.png
Binary files differ
diff --git a/vello_common/assets/probe_radial_gradient.rgba b/vello_common/assets/probe_radial_gradient.rgba
new file mode 100644
index 0000000..4ca0719
--- /dev/null
+++ b/vello_common/assets/probe_radial_gradient.rgba
Binary files differ
diff --git a/vello_common/assets/probe_sweep_gradient.png b/vello_common/assets/probe_sweep_gradient.png
new file mode 100644
index 0000000..8d328b1
--- /dev/null
+++ b/vello_common/assets/probe_sweep_gradient.png
Binary files differ
diff --git a/vello_common/assets/probe_sweep_gradient.rgba b/vello_common/assets/probe_sweep_gradient.rgba
new file mode 100644
index 0000000..517d855
--- /dev/null
+++ b/vello_common/assets/probe_sweep_gradient.rgba
Binary files differ
diff --git a/vello_common/src/probe.rs b/vello_common/src/probe.rs
index ff1c2e0..ea02158 100644
--- a/vello_common/src/probe.rs
+++ b/vello_common/src/probe.rs
@@ -8,7 +8,7 @@
 use crate::filter_effects::{EdgeMode, Filter, FilterPrimitive};
 #[cfg(not(feature = "std"))]
 use crate::kurbo::common::FloatFuncs as _;
-use crate::kurbo::{Affine, BezPath, Circle, Point, Rect, Shape};
+use crate::kurbo::{Affine, BezPath, Circle, Point, Rect, Shape, Vec2};
 use crate::paint::{Image, ImageSource, PaintType};
 use crate::peniko::{
     BlendMode, ColorStop, ColorStops, Compose, Extend, Gradient, ImageAlphaType, ImageQuality,
@@ -35,7 +35,7 @@
 pub const ALL_PROBE_ELEMENTS: &[ProbeFeature] = &[
     ProbeFeature::SolidRect,
     ProbeFeature::AlphaBlending,
-    ProbeFeature::Gradient,
+    ProbeFeature::LinearGradient,
     ProbeFeature::ImageNearest,
     ProbeFeature::Filter,
     ProbeFeature::ImageBilinear,
@@ -43,6 +43,11 @@
     ProbeFeature::Blending,
     ProbeFeature::Transformed,
     ProbeFeature::DepthBuffer,
+    ProbeFeature::DropShadow,
+    ProbeFeature::BlurredRoundedRect,
+    ProbeFeature::RadialGradient,
+    ProbeFeature::SweepGradient,
+    ProbeFeature::ImageBicubic,
 ];
 
 /// Per-channel absolute tolerance used when comparing probe pixels.
@@ -76,7 +81,7 @@
     /// Alpha blending overlapping shapes.
     AlphaBlending,
     /// Drawing a linear gradient.
-    Gradient,
+    LinearGradient,
     /// Drawing an image with nearest-neighbor sampling.
     ImageNearest,
     /// Applying a filter effect.
@@ -91,6 +96,16 @@
     Transformed,
     /// Layering opaque draws and a transparent foreground to exercise depth buffering.
     DepthBuffer,
+    /// Applying an offset, blurred drop shadow to a shape.
+    DropShadow,
+    /// Drawing a blurred rounded rectangle.
+    BlurredRoundedRect,
+    /// Drawing a radial gradient.
+    RadialGradient,
+    /// Drawing a sweep gradient.
+    SweepGradient,
+    /// Drawing an image with bicubic sampling.
+    ImageBicubic,
 }
 
 /// Summary of the differences between one expected and actual probe cell.
@@ -180,6 +195,7 @@
     fn set_paint(&mut self, paint: PaintType);
     fn fill_path(&mut self, path: &BezPath);
     fn fill_rect(&mut self, rect: &Rect);
+    fn fill_blurred_rounded_rect(&mut self, rect: &Rect, radius: f32, std_dev: f32, invert: bool);
     fn push_layer(&mut self, blend_mode: Option<BlendMode>, opacity: Option<f32>);
     fn push_filter_layer(&mut self, filter: Filter);
     fn pop_layer(&mut self);
@@ -229,7 +245,7 @@
     match feature {
         ProbeFeature::SolidRect => include_bytes!("../assets/probe_solid_rect.rgba"),
         ProbeFeature::AlphaBlending => include_bytes!("../assets/probe_alpha_blending.rgba"),
-        ProbeFeature::Gradient => include_bytes!("../assets/probe_gradient.rgba"),
+        ProbeFeature::LinearGradient => include_bytes!("../assets/probe_linear_gradient.rgba"),
         ProbeFeature::ImageNearest => include_bytes!("../assets/probe_image_nearest.rgba"),
         ProbeFeature::Filter => include_bytes!("../assets/probe_filter.rgba"),
         ProbeFeature::ImageBilinear => include_bytes!("../assets/probe_image_bilinear.rgba"),
@@ -237,6 +253,13 @@
         ProbeFeature::Blending => include_bytes!("../assets/probe_blending.rgba"),
         ProbeFeature::Transformed => include_bytes!("../assets/probe_transformed.rgba"),
         ProbeFeature::DepthBuffer => include_bytes!("../assets/probe_depth_buffer.rgba"),
+        ProbeFeature::DropShadow => include_bytes!("../assets/probe_drop_shadow.rgba"),
+        ProbeFeature::BlurredRoundedRect => {
+            include_bytes!("../assets/probe_blurred_rounded_rect.rgba")
+        }
+        ProbeFeature::RadialGradient => include_bytes!("../assets/probe_radial_gradient.rgba"),
+        ProbeFeature::SweepGradient => include_bytes!("../assets/probe_sweep_gradient.rgba"),
+        ProbeFeature::ImageBicubic => include_bytes!("../assets/probe_image_bicubic.rgba"),
     }
 }
 
@@ -327,7 +350,8 @@
 pub fn draw_scene<T: ProbeRenderer>(ctx: &mut T, image: ImageSource, elements: &[ProbeFeature]) {
     let layout = GridLayout::from_elements(elements);
     let image_nearest = image_paint(image.clone(), ImageQuality::Low);
-    let image_bilinear = image_paint(image, ImageQuality::Medium);
+    let image_bilinear = image_paint(image.clone(), ImageQuality::Medium);
+    let image_bicubic = image_paint(image, ImageQuality::High);
     ctx.set_transform(Affine::IDENTITY);
 
     for (index, element) in elements.iter().copied().enumerate() {
@@ -337,6 +361,7 @@
             element,
             &image_nearest,
             &image_bilinear,
+            &image_bicubic,
         );
     }
 }
@@ -347,6 +372,7 @@
     element: ProbeFeature,
     image_nearest: &PaintType,
     image_bilinear: &PaintType,
+    image_bicubic: &PaintType,
 ) {
     match element {
         ProbeFeature::SolidRect => {
@@ -376,7 +402,7 @@
                     .to_path(PATH_TOLERANCE),
             );
         }
-        ProbeFeature::Gradient => {
+        ProbeFeature::LinearGradient => {
             let rect = centered_rect(cell, RECT_SIZE, RECT_SIZE);
             ctx.set_paint(linear_gradient(&rect).into());
             ctx.fill_rect(&rect);
@@ -391,6 +417,35 @@
         }
         ProbeFeature::Blending => draw_layered_difference_circles(ctx, cell),
         ProbeFeature::DepthBuffer => draw_depth_buffer_rects(ctx, cell),
+        ProbeFeature::DropShadow => draw_drop_shadow_rect(ctx, cell),
+        ProbeFeature::BlurredRoundedRect => {
+            ctx.set_paint(css::REBECCA_PURPLE.into());
+            ctx.fill_blurred_rounded_rect(&centered_rect(cell, 8.0, 8.0), 2.0, 0.75, false);
+        }
+        ProbeFeature::RadialGradient => {
+            let rect = centered_rect(cell, RECT_SIZE, RECT_SIZE);
+            let gradient = Gradient::new_radial(rect.center(), (RECT_SIZE * 0.5) as f32)
+                .with_stops([css::BLUE, css::RED]);
+            ctx.set_paint(gradient.into());
+            ctx.fill_rect(&rect);
+        }
+        ProbeFeature::SweepGradient => {
+            let rect = centered_rect(cell, RECT_SIZE, RECT_SIZE);
+            let gradient = Gradient::new_sweep(rect.center(), 0.0, core::f32::consts::TAU)
+                .with_stops([css::BLUE, css::RED]);
+            ctx.set_paint(gradient.into());
+            ctx.fill_rect(&rect);
+        }
+        ProbeFeature::ImageBicubic => {
+            let rect = centered_rect(cell, RECT_SIZE, RECT_SIZE);
+            ctx.set_paint(image_bicubic.clone());
+            ctx.set_paint_transform(
+                Affine::translate((rect.x0, rect.y0))
+                    * Affine::scale(RECT_SIZE / IMAGE_SOURCE_SIZE),
+            );
+            ctx.fill_rect(&rect);
+            ctx.reset_paint_transform();
+        }
     }
 }
 
@@ -439,6 +494,24 @@
     ctx.pop_layer();
 }
 
+fn draw_drop_shadow_rect(ctx: &mut impl ProbeRenderer, cell: Rect) {
+    let offset = 1.5;
+    let std_deviation = 0.5;
+    let centering_offset = f64::from(offset) * 0.5 + f64::from(std_deviation);
+    let rect = centered_rect(cell, 8.0, 8.0) - Vec2::new(centering_offset, centering_offset);
+    let shadow = Filter::from_primitive(FilterPrimitive::DropShadow {
+        dx: offset,
+        dy: offset,
+        std_deviation,
+        color: css::BLACK.with_alpha(0.75),
+        edge_mode: EdgeMode::None,
+    });
+    ctx.push_filter_layer(shadow);
+    ctx.set_paint(css::BLUE.into());
+    ctx.fill_rect(&rect);
+    ctx.pop_layer();
+}
+
 fn draw_opacity_layer_rect(ctx: &mut impl ProbeRenderer, rect: Rect) {
     ctx.push_layer(None, Some(0.5));
     ctx.set_paint(css::ORANGE_RED.into());
diff --git a/vello_gpu/src/render/webgl/probe.rs b/vello_gpu/src/render/webgl/probe.rs
index e648e90..1357e3c 100644
--- a/vello_gpu/src/render/webgl/probe.rs
+++ b/vello_gpu/src/render/webgl/probe.rs
@@ -335,6 +335,10 @@
         Self::fill_rect(self, rect);
     }
 
+    fn fill_blurred_rounded_rect(&mut self, rect: &Rect, radius: f32, std_dev: f32, invert: bool) {
+        Self::fill_blurred_rounded_rect(self, rect, radius, std_dev, invert);
+    }
+
     fn push_layer(&mut self, blend_mode: Option<BlendMode>, opacity: Option<f32>) {
         Self::push_layer(self, None, blend_mode, opacity, None, None);
     }
diff --git a/vello_tests/src/regenerate_probe_reference.rs b/vello_tests/src/regenerate_probe_reference.rs
index 0c6ed74..ca01cae 100644
--- a/vello_tests/src/regenerate_probe_reference.rs
+++ b/vello_tests/src/regenerate_probe_reference.rs
@@ -23,7 +23,7 @@
     let name = match element {
         probe::ProbeFeature::SolidRect => "probe_solid_rect",
         probe::ProbeFeature::AlphaBlending => "probe_alpha_blending",
-        probe::ProbeFeature::Gradient => "probe_gradient",
+        probe::ProbeFeature::LinearGradient => "probe_linear_gradient",
         probe::ProbeFeature::ImageNearest => "probe_image_nearest",
         probe::ProbeFeature::Filter => "probe_filter",
         probe::ProbeFeature::ImageBilinear => "probe_image_bilinear",
@@ -31,6 +31,11 @@
         probe::ProbeFeature::Blending => "probe_blending",
         probe::ProbeFeature::Transformed => "probe_transformed",
         probe::ProbeFeature::DepthBuffer => "probe_depth_buffer",
+        probe::ProbeFeature::DropShadow => "probe_drop_shadow",
+        probe::ProbeFeature::BlurredRoundedRect => "probe_blurred_rounded_rect",
+        probe::ProbeFeature::RadialGradient => "probe_radial_gradient",
+        probe::ProbeFeature::SweepGradient => "probe_sweep_gradient",
+        probe::ProbeFeature::ImageBicubic => "probe_image_bicubic",
     };
     PathBuf::from(env!("CARGO_MANIFEST_DIR"))
         .join("../vello_common/assets")
@@ -56,6 +61,11 @@
         self.0.fill_rect(rect);
     }
 
+    fn fill_blurred_rounded_rect(&mut self, rect: &Rect, radius: f32, std_dev: f32, invert: bool) {
+        self.0
+            .fill_blurred_rounded_rect(rect, radius, std_dev, invert);
+    }
+
     fn push_layer(&mut self, blend_mode: Option<BlendMode>, opacity: Option<f32>) {
         self.0.push_layer(None, blend_mode, opacity, None, None);
     }
@@ -161,7 +171,7 @@
     fn probe_failure_reports_statistics_per_cell() {
         let elements = [
             probe::ProbeFeature::SolidRect,
-            probe::ProbeFeature::Gradient,
+            probe::ProbeFeature::LinearGradient,
         ];
         let mut actual = render_probe_pixmap(&elements);
         actual.set_pixel(0, 0, css::BLACK.premultiply().to_rgba8());
@@ -173,7 +183,7 @@
         assert_eq!(statistics.len(), 2);
         assert_eq!(statistics[0].feature, probe::ProbeFeature::SolidRect);
         assert_eq!(statistics[0].different_pixel_count, 1);
-        assert_eq!(statistics[1].feature, probe::ProbeFeature::Gradient);
+        assert_eq!(statistics[1].feature, probe::ProbeFeature::LinearGradient);
         assert_eq!(statistics[1].different_pixel_count, 0);
     }
 
@@ -192,7 +202,7 @@
     fn full_probe_row_matches_reference() {
         assert_elements_match_reference(&[
             probe::ProbeFeature::SolidRect,
-            probe::ProbeFeature::Gradient,
+            probe::ProbeFeature::LinearGradient,
             probe::ProbeFeature::DepthBuffer,
         ]);
     }