diff --git a/crates/cg/src/types.rs b/crates/cg/src/types.rs index dac18502..fa45ae24 100644 --- a/crates/cg/src/types.rs +++ b/crates/cg/src/types.rs @@ -2460,49 +2460,69 @@ impl Default for LinearGradientPaint { } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +/// One intrinsic circle in gradient-local coordinates, before paint placement. +/// +/// The center is a direct `(x, y)` pair, not an alignment point. Both components +/// must be finite; the radius must be finite and nonnegative. Centers are not +/// confined to a unit box. Validation belongs to the admitting boundary. +#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] +pub struct RadialGradientCircle { + pub center: (f32, f32), + pub radius: f32, +} + +/// Ordered ramp-boundary circles: offset zero at `start`, offset one at `end`. +/// +/// Either radius may be zero, the start radius may exceed the end radius, and +/// equal circles are representable. None of these cases permits swapping or +/// clamping the circles. Representation does not guarantee backend support: +/// a consumer must preserve the geometry or explicitly refuse it. +#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] +pub struct RadialGradientGeometry { + pub start: RadialGradientCircle, + pub end: RadialGradientCircle, +} + +#[derive(Clone, PartialEq, Serialize, Deserialize)] pub struct RadialGradientPaint { pub active: bool, - /// # Radial Gradient Transform Model - /// - /// ## Coordinate Space - /// The radial gradient is defined in **unit gradient space**: - /// - Center: `(0.5, 0.5)` - /// - Radius: `0.5` - /// - /// This forms a normalized circle inside a `[0.0, 1.0] x [0.0, 1.0]` box. - /// All geometry is defined relative to this unit space. - /// - /// ## Scaling to Object Space - /// The gradient is mapped to the target rectangle by applying a scale matrix derived from its size: - /// - /// ```text - /// local_matrix = scale(width, height) × user_transform - /// ``` - /// - /// - `scale(width, height)` transforms the unit circle to match the target rectangle, - /// allowing the gradient to become elliptical if `width ≠ height`. - /// - `user_transform` is an additional affine matrix defined in gradient space (centered at 0.5, 0.5). - /// - /// ## Rendering Behavior - /// When passed to Skia, the shader uses: - /// - `center = (0.5, 0.5)` - /// - `radius = 0.5` - /// - /// These are interpreted in **local gradient space**, and the `local_matrix` maps device coordinates - /// back into that space. - /// - /// ## Summary - /// - The gradient definition is resolution-independent. - /// - `width` and `height` determine how unit space is scaled — they do **not** directly affect center or radius. - /// - All transforms (e.g. rotation, skew) should be encoded in the `user_transform`, not baked into radius or center. + /// Maps gradient-local coordinates to the target box's normalized space. + /// Placement is `scale(width, height) × transform`; intrinsic circle values + /// are not converted through center-based alignment coordinates. pub transform: AffineTransform, + /// Explicit ordered circles, or the original centered radial when absent: + /// start `(0.5, 0.5), r=0`, end `(0.5, 0.5), r=0.5`. + /// + /// Absence preserves the original rendering path and serialized field set. + /// Present geometry survives copying and serialization without normalization, + /// including a present pair numerically equal to those implicit circles. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub geometry: Option, pub stops: Vec, pub opacity: f32, pub blend_mode: BlendMode, pub tile_mode: TileMode, } +impl std::fmt::Debug for RadialGradientPaint { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut debug = f.debug_struct("RadialGradientPaint"); + debug + .field("active", &self.active) + .field("transform", &self.transform); + // Keep diagnostics of old paint values stable without hiding new facts. + if let Some(geometry) = &self.geometry { + debug.field("geometry", geometry); + } + debug + .field("stops", &self.stops) + .field("opacity", &self.opacity) + .field("blend_mode", &self.blend_mode) + .field("tile_mode", &self.tile_mode) + .finish() + } +} + impl RadialGradientPaint { pub fn from_stops(stops: Vec) -> Self { Self { @@ -2524,6 +2544,7 @@ impl Default for RadialGradientPaint { Self { active: true, transform: AffineTransform::default(), + geometry: None, stops: Vec::new(), opacity: 1.0, blend_mode: BlendMode::default(), @@ -2539,8 +2560,8 @@ pub struct DiamondGradientPaint { /// /// Figma's Diamond Gradient is equivalent to a radial gradient evaluated /// using the Manhattan distance metric. The gradient is defined in the same - /// unit space as [`RadialGradientPaint`]: center at `(0.5, 0.5)` with a - /// nominal radius of `0.5`. + /// unit space as the implicit [`RadialGradientPaint`] default: center at + /// `(0.5, 0.5)` with a nominal radius of `0.5`. /// /// Scaling to object space follows the same rule: /// diff --git a/crates/cg/tests/radial_geometry.rs b/crates/cg/tests/radial_geometry.rs new file mode 100644 index 00000000..0b2e8b2a --- /dev/null +++ b/crates/cg/tests/radial_geometry.rs @@ -0,0 +1,114 @@ +//! Serialization contract for the ordered radial-circle value, without a backend. + +use cg::{RadialGradientCircle, RadialGradientGeometry, RadialGradientPaint}; +use serde_json::json; + +#[test] +fn absent_geometry_preserves_the_old_json_field_set_and_input() { + let old = json!({ + "active": true, + "transform": {"matrix": [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]}, + "stops": [], + "opacity": 1.0, + "blend_mode": "normal", + "tile_mode": "clamp" + }); + let paint: RadialGradientPaint = serde_json::from_value(old.clone()).unwrap(); + assert_eq!(paint, RadialGradientPaint::default()); + assert_eq!(paint.geometry, None); + assert_eq!(serde_json::to_value(&paint).unwrap(), old); + assert_eq!( + serde_json::to_string(&paint).unwrap(), + r#"{"active":true,"transform":{"matrix":[[1.0,0.0,0.0],[0.0,1.0,0.0]]},"stops":[],"opacity":1.0,"blend_mode":"normal","tile_mode":"clamp"}"# + ); +} + +#[test] +fn debug_preserves_absent_values_but_never_hides_present_geometry() { + let mut paint = RadialGradientPaint::default(); + assert_eq!(format!("{paint:?}"), "RadialGradientPaint { active: true, transform: AffineTransform { matrix: [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] }, stops: [], opacity: 1.0, blend_mode: Normal, tile_mode: Clamp }"); + paint.geometry = Some(RadialGradientGeometry { + start: RadialGradientCircle { + center: (-2.0, 1.0), + radius: 0.75, + }, + end: RadialGradientCircle { + center: (0.5, 0.5), + radius: 0.0, + }, + }); + let debug = format!("{paint:?}"); + assert!(debug.contains("geometry: RadialGradientGeometry { start: RadialGradientCircle { center: (-2.0, 1.0), radius: 0.75 }, end: RadialGradientCircle { center: (0.5, 0.5), radius: 0.0 } }")); +} + +fn circle_bits(circle: RadialGradientCircle) -> [u32; 3] { + [ + circle.center.0.to_bits(), + circle.center.1.to_bits(), + circle.radius.to_bits(), + ] +} + +#[test] +fn present_geometry_round_trips_without_alignment_conversion_or_circle_reordering() { + // A subnormal, signed zero, and a radius larger than the point-sized end + // discriminate arithmetic normalization and inferred circle order. + let paint = RadialGradientPaint { + geometry: Some(RadialGradientGeometry { + start: RadialGradientCircle { + center: (f32::from_bits(1), -0.0), + radius: 1.75, + }, + end: RadialGradientCircle { + center: (3.5, -2.25), + radius: 0.0, + }, + }), + ..Default::default() + }; + let encoded = serde_json::to_string(&paint).unwrap(); + let decoded: RadialGradientPaint = serde_json::from_str(&encoded).unwrap(); + let geometry = decoded.geometry.unwrap(); + assert_eq!(circle_bits(geometry.start), [1, 0x8000_0000, 0x3fe0_0000]); + assert_eq!(circle_bits(geometry.end), [0x4060_0000, 0xc010_0000, 0]); + assert_eq!(decoded, paint); + assert_eq!( + serde_json::to_value(&decoded).unwrap()["geometry"]["end"], + json!({"center": [3.5, -2.25], "radius": 0.0}) + ); +} + +#[test] +fn explicit_implicit_circle_values_remain_present() { + let geometry = RadialGradientGeometry { + start: RadialGradientCircle { + center: (0.5, 0.5), + radius: 0.0, + }, + end: RadialGradientCircle { + center: (0.5, 0.5), + radius: 0.5, + }, + }; + let paint = RadialGradientPaint { + geometry: Some(geometry), + ..Default::default() + }; + let decoded: RadialGradientPaint = + serde_json::from_value(serde_json::to_value(paint).unwrap()).unwrap(); + assert_eq!(decoded.geometry, Some(geometry)); +} + +#[test] +fn a_present_geometry_requires_both_complete_circles() { + for incomplete in [ + json!({"start": {"center": [0.5, 0.5], "radius": 0.0}}), + json!({"end": {"center": [0.5, 0.5], "radius": 0.5}}), + json!({"start": {"center": [0.5, 0.5]}, "end": {"center": [0.5, 0.5], "radius": 0.5}}), + json!({"start": {"center": [0.5, 0.5], "radius": 0.0}, "end": {"radius": 0.5}}), + ] { + let mut json = serde_json::to_value(RadialGradientPaint::default()).unwrap(); + json["geometry"] = incomplete; + assert!(serde_json::from_value::(json).is_err()); + } +} diff --git a/crates/grida/examples/fixture_helpers/mod.rs b/crates/grida/examples/fixture_helpers/mod.rs index c4a2525d..abf40cb5 100644 --- a/crates/grida/examples/fixture_helpers/mod.rs +++ b/crates/grida/examples/fixture_helpers/mod.rs @@ -246,6 +246,7 @@ pub(crate) fn linear_gradient() -> Paint { pub(crate) fn radial_gradient() -> Paint { Paint::RadialGradient(RadialGradientPaint { + geometry: None, active: true, transform: AffineTransform::default(), stops: vec![ diff --git a/crates/grida/examples/fixtures/cover.rs b/crates/grida/examples/fixtures/cover.rs index b0b6f56c..3d900eec 100644 --- a/crates/grida/examples/fixtures/cover.rs +++ b/crates/grida/examples/fixtures/cover.rs @@ -131,6 +131,7 @@ pub(crate) fn build() -> Scene { height: 1100.0, }, fills: Paints::new(vec![Paint::RadialGradient(RadialGradientPaint { + geometry: None, active: true, transform: AffineTransform::default(), stops: vec![ @@ -190,6 +191,7 @@ pub(crate) fn build() -> Scene { height: 1000.0, }, fills: Paints::new(vec![Paint::RadialGradient(RadialGradientPaint { + geometry: None, active: true, transform: AffineTransform::default(), stops: vec![ diff --git a/crates/grida/examples/fixtures/l0_paints_stack.rs b/crates/grida/examples/fixtures/l0_paints_stack.rs index 3b502b06..dc2ae251 100644 --- a/crates/grida/examples/fixtures/l0_paints_stack.rs +++ b/crates/grida/examples/fixtures/l0_paints_stack.rs @@ -56,6 +56,7 @@ pub(crate) fn build() -> Scene { }), // [2] radial gradient yellow center→transparent Paint::RadialGradient(RadialGradientPaint { + geometry: None, active: true, transform: AffineTransform::default(), stops: vec![ diff --git a/crates/grida/src/import/svg/paint.rs b/crates/grida/src/import/svg/paint.rs index a36787d0..0312b6ca 100644 --- a/crates/grida/src/import/svg/paint.rs +++ b/crates/grida/src/import/svg/paint.rs @@ -99,6 +99,7 @@ fn svg_radial_gradient_to_paint( Paint::RadialGradient(RadialGradientPaint { active: true, transform: gradient_transform.compose(&alignment), + geometry: None, stops: radial.stops.clone(), opacity, blend_mode: BlendMode::Normal, diff --git a/crates/grida/src/io/io_grida_fbs.rs b/crates/grida/src/io/io_grida_fbs.rs index 48fd0711..092e8325 100644 --- a/crates/grida/src/io/io_grida_fbs.rs +++ b/crates/grida/src/io/io_grida_fbs.rs @@ -877,6 +877,7 @@ fn decode_paint_item(item: &fbs::PaintStackItem<'_>) -> Option { Some(Paint::RadialGradient(RadialGradientPaint { active: rgp.active(), transform, + geometry: None, stops, opacity: rgp.opacity(), blend_mode: decode_blend_mode(rgp.blend_mode()), @@ -2355,6 +2356,11 @@ use crate::node::schema::NodeId; /// - `id_map`: maps internal `NodeId` → string IDs. /// /// Returns the encoded bytes (including the `"GRID"` file identifier). +/// +/// # Panics +/// +/// Panics if a radial paint carries explicit ordered circles: the frozen +/// format cannot encode that geometry. It is never silently omitted. pub fn encode( scene: &Scene, scene_id: &str, @@ -2424,6 +2430,11 @@ pub fn encode( /// Each entry is `(scene_id, scene, id_map, position_map)`. /// All scenes share the same flat `nodes` vector; each scene's nodes /// are prefixed with a scene-type NodeSlot that references `scene_id`. +/// +/// # Panics +/// +/// Like [`encode`], refuses explicit radial circles by a named panic because +/// the frozen format has no representation for them. #[allow(clippy::type_complexity)] pub fn encode_multi( entries: &[( @@ -2910,6 +2921,10 @@ fn encode_paint_raw<'a, A: flatbuffers::Allocator + 'a>( Some((fbs::Paint::LinearGradientPaint, lgp.as_union_value())) } Paint::RadialGradient(rg) => { + assert!( + rg.geometry.is_none(), + "the frozen .grida format cannot encode explicit radial gradient circles" + ); let stops = encode_gradient_stops(fbb, &rg.stops); let transform = encode_affine_to_cg_transform(&rg.transform); let rgp = fbs::RadialGradientPaint::create( diff --git a/crates/grida/src/painter/gradient.rs b/crates/grida/src/painter/gradient.rs index 2983b689..14418f47 100644 --- a/crates/grida/src/painter/gradient.rs +++ b/crates/grida/src/painter/gradient.rs @@ -103,6 +103,12 @@ pub fn linear_gradient_shader( } } +/// Build the legacy paint while preserving explicitly ordered radial circles. +/// +/// # Panics +/// Panics if explicit circles are invalid or cannot construct a backend +/// shader. This legacy API has no typed error channel; it must not replace +/// unsupported explicit geometry with an unshaded paint. pub fn radial_gradient_paint( gradient: &RadialGradientPaint, (x, y): (f32, f32), @@ -114,9 +120,7 @@ pub fn radial_gradient_paint( matrix.pre_concat(&sk_matrix(gradient.transform.matrix)); let grad = make_gradient(&colors, &positions, gradient.tile_mode.into_skia()); - if let Some(shader) = - skia_safe::shaders::radial_gradient(((0.5_f32, 0.5_f32), 0.5_f32), &grad, Some(&matrix)) - { + if let Some(shader) = radial_geometry_shader(gradient.geometry, &grad, &matrix) { paint.set_shader(shader); } @@ -125,6 +129,11 @@ pub fn radial_gradient_paint( paint } +/// Build the legacy radial shader with the same explicit-circle boundary as +/// [`radial_gradient_paint`]. +/// +/// # Panics +/// Panics if explicit circles are invalid or the backend rejects the shader. pub fn radial_gradient_shader( gradient: &RadialGradientPaint, (x, y): (f32, f32), @@ -135,8 +144,7 @@ pub fn radial_gradient_shader( matrix.pre_concat(&sk_matrix(gradient.transform.matrix)); let grad = make_gradient(&colors, &positions, gradient.tile_mode.into_skia()); - let shader = - skia_safe::shaders::radial_gradient(((0.5_f32, 0.5_f32), 0.5_f32), &grad, Some(&matrix))?; + let shader = radial_geometry_shader(gradient.geometry, &grad, &matrix)?; if gradient.opacity < 1.0 { let opacity_color = @@ -152,6 +160,117 @@ pub fn radial_gradient_shader( } } +/// The legacy callers have no typed paint-error channel. Preserve their old +/// absent-geometry path, but fail loudly if explicit circles are invalid or +/// cannot be lowered; returning None would let callers paint a fallback. +fn radial_geometry_shader( + geometry: Option, + gradient: &Gradient<'_>, + matrix: &skia_safe::Matrix, +) -> Option { + let Some(geometry) = geometry else { + return skia_safe::shaders::radial_gradient(((0.5, 0.5), 0.5), gradient, Some(matrix)); + }; + for circle in [geometry.start, geometry.end] { + assert!( + circle.center.0.is_finite() + && circle.center.1.is_finite() + && circle.radius.is_finite() + && circle.radius >= 0.0, + "invalid explicit radial gradient circle at the legacy painter boundary" + ); + } + Some( + skia_safe::shaders::two_point_conical_gradient( + (geometry.start.center, geometry.start.radius), + (geometry.end.center, geometry.end.radius), + gradient, + Some(matrix), + ) + .expect("explicit radial gradient circles cannot be lowered by the legacy painter"), + ) +} + +#[cfg(test)] +mod radial_circle_tests { + use super::*; + + fn radial(geometry: Option) -> RadialGradientPaint { + RadialGradientPaint { + geometry, + ..RadialGradientPaint::from_colors(vec![CGColor::RED, CGColor::BLUE]) + } + } + + fn pixels(gradient: &RadialGradientPaint) -> Vec { + let mut surface = skia_safe::surfaces::raster_n32_premul((64, 64)).unwrap(); + surface.canvas().clear(skia_safe::Color::GREEN); + surface.canvas().draw_rect( + skia_safe::Rect::from_wh(64.0, 64.0), + &radial_gradient_paint(gradient, (64.0, 64.0)), + ); + let info = skia_safe::ImageInfo::new( + (64, 64), + skia_safe::ColorType::RGBA8888, + skia_safe::AlphaType::Unpremul, + None, + ); + let mut bytes = vec![0; 64 * 64 * 4]; + assert!(surface.read_pixels(&info, &mut bytes, 64 * 4, (0, 0))); + bytes + } + + #[test] + fn legacy_radial_painter_keeps_ordered_circles_and_the_unpainted_domain() { + let geometry = RadialGradientGeometry { + start: RadialGradientCircle { + center: (-0.25, 0.5), + radius: 0.125, + }, + end: RadialGradientCircle { + center: (0.5, 0.5), + radius: 0.5, + }, + }; + let plain = pixels(&radial(None)); + let painted = pixels(&radial(Some(geometry))); + assert_ne!(plain, painted, "the new geometry cannot be ignored"); + assert!( + painted + .chunks_exact(4) + .any(|pixel| pixel == [0, 255, 0, 255]), + "no-solution exterior preserves the backdrop" + ); + assert_ne!( + painted, + pixels(&radial(Some(RadialGradientGeometry { + start: geometry.end, + end: geometry.start + }))), + "circle order is semantic" + ); + assert!(radial_gradient_shader(&radial(Some(geometry)), (64.0, 64.0)).is_some()); + } + + #[test] + #[should_panic( + expected = "invalid explicit radial gradient circle at the legacy painter boundary" + )] + fn legacy_radial_painter_cannot_turn_an_invalid_circle_into_a_fallback() { + let geometry = RadialGradientGeometry { + start: RadialGradientCircle { + center: (f32::NAN, 0.5), + radius: 0.0, + }, + end: RadialGradientCircle { + center: (0.5, 0.5), + radius: 0.5, + }, + }; + let _ = radial_gradient_paint(&radial(Some(geometry)), (64.0, 64.0)); + } +} + pub fn sweep_gradient_paint(gradient: &SweepGradientPaint, (x, y): (f32, f32)) -> skia_safe::Paint { let mut paint = skia_safe::Paint::default(); let (colors, positions) = build_gradient_stops(&gradient.stops, 1.0); diff --git a/crates/grida/tests/fbs_roundtrip.rs b/crates/grida/tests/fbs_roundtrip.rs index 075faa45..3466a9ec 100644 --- a/crates/grida/tests/fbs_roundtrip.rs +++ b/crates/grida/tests/fbs_roundtrip.rs @@ -204,6 +204,7 @@ fn linear_gradient() -> Paint { fn radial_gradient() -> Paint { Paint::RadialGradient(RadialGradientPaint { + geometry: None, active: true, transform: AffineTransform::default(), stops: vec![ @@ -1345,6 +1346,80 @@ fn gen_all_paint_types() { assert_roundtrip_scene(&scene, "s1", "all_paint_types"); } +#[test] +fn frozen_format_rejects_explicit_radial_circles_instead_of_losing_them() { + let Paint::RadialGradient(mut paint) = radial_gradient() else { + unreachable!() + }; + paint.geometry = Some(RadialGradientGeometry { + start: RadialGradientCircle { + center: (0.25, 0.375), + radius: 0.125, + }, + end: RadialGradientCircle { + center: (0.5, 0.5), + radius: 0.0, + }, + }); + for (active, in_stroke) in [(true, false), (false, false), (true, true), (false, true)] { + let mut paint = paint.clone(); + paint.active = active; + let radial = Paints::new([solid(22, 163, 74, 255), Paint::RadialGradient(paint)]); + let node = Node::Rectangle(RectangleNodeRec { + active: true, + opacity: 1.0, + blend_mode: LayerBlendMode::PassThrough, + mask: None, + transform: AffineTransform::identity(), + size: Size { + width: 64.0, + height: 64.0, + }, + corner_radius: RectangularCornerRadius::default(), + corner_smoothing: CornerSmoothing(0.0), + fills: if in_stroke { + Paints::default() + } else { + radial.clone() + }, + strokes: if in_stroke { radial } else { Paints::default() }, + stroke_style: StrokeStyle::default(), + stroke_width: StrokeWidth::Uniform(0.0), + effects: LayerEffects::default(), + layout_child: None, + }); + let scene = build_scene( + "RadialCircles", + None, + vec![(1, node)], + HashMap::new(), + vec![1], + ); + let mut ids = HashMap::new(); + let mut positions = HashMap::new(); + build_maps(&scene, &mut ids, &mut positions); + for multi in [false, true] { + let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + if multi { + io_grida_fbs::encode_multi(&[("s1", &scene, &ids, &positions)]) + } else { + io_grida_fbs::encode(&scene, "s1", &ids, &positions) + } + })); + let error = result.expect_err("encoding must not omit circles or drop a paint entry"); + let reason = error + .downcast_ref::() + .map(String::as_str) + .or_else(|| error.downcast_ref::<&str>().copied()) + .unwrap_or(""); + assert_eq!( + reason, + "the frozen .grida format cannot encode explicit radial gradient circles" + ); + } + } +} + // ─── All effects on a single node ─────────────────────────────────────────── #[test] diff --git a/crates/n0-model/README.md b/crates/n0-model/README.md index 10a3f00f..b358e9e0 100644 --- a/crates/n0-model/README.md +++ b/crates/n0-model/README.md @@ -124,6 +124,14 @@ image `src` remains a logical RID and parsing performs no path I/O. Per-paint `visible`, `opacity`, and `blend-mode` lower directly to model state. Solid and stop opacity intentionally quantize into RGBA8 alpha. +The runtime radial paint can also carry ordered start/end circles in direct +gradient-local coordinates. Neither Draft 0 nor historical TextIr spells +this optional geometry: Draft 0 reads the original centered radial and its +writer refuses every present circle pair, including inactive paints and run +or stroke paints. Model validation rejects nonfinite centers and nonfinite or +negative radii, but permits zero, exterior, reversed-size, and equal circles; +backend support for such facts remains a separate admission check. + Paintable nodes also carry ordered `Vec` state. Each stroke owns its own existing `Paints` plus width, alignment, cap, join, miter, and dash geometry. Repeated strokes therefore remain independent and lossless; lines diff --git a/crates/n0-model/src/model.rs b/crates/n0-model/src/model.rs index 06f32942..1210fa1b 100644 --- a/crates/n0-model/src/model.rs +++ b/crates/n0-model/src/model.rs @@ -1030,7 +1030,13 @@ impl Default for LinearGradientPaint { #[derive(Debug, Clone, PartialEq)] pub struct RadialGradientPaint { pub active: bool, + /// Maps gradient-local coordinates into the target box's normalized space; + /// final placement is `scale(width, height) × transform`. pub transform: Affine, + /// Ordered circles, or the original centered radial when absent: start + /// `(0.5, 0.5), r=0`, end `(0.5, 0.5), r=0.5`. Present geometry is preserved + /// verbatim, never converted through alignment coordinates or normalized. + pub geometry: Option, pub stops: Vec, pub opacity: f32, pub blend_mode: BlendMode, @@ -1042,6 +1048,7 @@ impl Default for RadialGradientPaint { RadialGradientPaint { active: true, transform: Affine::IDENTITY, + geometry: None, stops: vec![], opacity: 1.0, blend_mode: BlendMode::Normal, @@ -1050,6 +1057,23 @@ impl Default for RadialGradientPaint { } } +/// One intrinsic gradient-local circle, before paint placement. The direct +/// `(x, y)` center is finite and unbounded; radius is finite and nonnegative. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct RadialGradientCircle { + pub center: (f32, f32), + pub radius: f32, +} + +/// Offset-zero and offset-one circles, in that order. Zero radii, exterior +/// centers, a larger start radius, and equal circles are representable facts. +/// Backends must paint or refuse them, never swap, clamp, or silently drop them. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct RadialGradientGeometry { + pub start: RadialGradientCircle, + pub end: RadialGradientCircle, +} + #[derive(Debug, Clone, PartialEq)] pub struct SweepGradientPaint { pub active: bool, diff --git a/crates/n0-model/src/renderability.rs b/crates/n0-model/src/renderability.rs index aad251d7..ae145b4d 100644 --- a/crates/n0-model/src/renderability.rs +++ b/crates/n0-model/src/renderability.rs @@ -320,6 +320,20 @@ pub fn validate_paint(paint: &Paint) -> Result<(), RenderabilityError> { Paint::RadialGradient(gradient) => { validate_opacity(gradient.opacity, "gradient")?; validate_affine(gradient.transform, "gradient")?; + if let Some(geometry) = gradient.geometry { + for (name, circle) in [("start", geometry.start), ("end", geometry.end)] { + if !circle.center.0.is_finite() || !circle.center.1.is_finite() { + return Err(RenderabilityError::new(format!( + "radial gradient {name} circle center must be finite" + ))); + } + if !circle.radius.is_finite() || circle.radius < 0.0 { + return Err(RenderabilityError::new(format!( + "radial gradient {name} circle radius must be finite and nonnegative" + ))); + } + } + } validate_gradient_stops(&gradient.stops, "gradient") } Paint::SweepGradient(gradient) => { diff --git a/crates/n0-model/src/textir.rs b/crates/n0-model/src/textir.rs index 3d3c6048..3682e649 100644 --- a/crates/n0-model/src/textir.rs +++ b/crates/n0-model/src/textir.rs @@ -591,6 +591,7 @@ fn parse_gradient( Paint::RadialGradient(RadialGradientPaint { active: common.active, transform, + geometry: None, stops, opacity: common.opacity, blend_mode: common.blend_mode, @@ -2602,13 +2603,20 @@ fn write_gradient(paint: &Paint, depth: usize, out: &mut String) -> Result<(), S Some(gradient.tile_mode), Some((gradient.xy1, gradient.xy2)), ), - Paint::RadialGradient(gradient) => ( - "radial", - gradient.transform, - gradient.stops.as_slice(), - Some(gradient.tile_mode), - None, - ), + Paint::RadialGradient(gradient) => { + if gradient.geometry.is_some() { + return Err( + " ordered circle geometry is not representable in Draft 0".into(), + ); + } + ( + "radial", + gradient.transform, + gradient.stops.as_slice(), + Some(gradient.tile_mode), + None, + ) + } Paint::SweepGradient(gradient) => ( "sweep", gradient.transform, diff --git a/crates/n0-model/tests/paint_rfd_conformance.rs b/crates/n0-model/tests/paint_rfd_conformance.rs index af5d8bf2..781da3bf 100644 --- a/crates/n0-model/tests/paint_rfd_conformance.rs +++ b/crates/n0-model/tests/paint_rfd_conformance.rs @@ -101,6 +101,8 @@ struct PaintObservation { struct GradientObservation { kind: PaintKind, endpoints: Option<([u32; 2], [u32; 2])>, + /// Start center/radius, then end center/radius: order and bits are facts. + radial_geometry: Option<([u32; 3], [u32; 3])>, tile: Option, transform_bits: [u32; 6], stop_count: usize, @@ -113,6 +115,13 @@ struct GradientObservation { blend: Blend, } +impl GradientObservation { + fn with_radial_geometry(mut self, geometry: Option<([u32; 3], [u32; 3])>) -> Self { + self.radial_geometry = geometry; + self + } +} + #[derive(Debug, Clone, PartialEq, Eq)] enum ResourceObservation { Hash(String), @@ -312,6 +321,7 @@ impl Cg { ) -> GradientObservation { GradientObservation { kind, + radial_geometry: None, endpoints: endpoints.map(|(from, to)| { ( [from.0.to_bits(), from.1.to_bits()], @@ -581,6 +591,7 @@ impl PaintVocabulary for Cg { let cg::RadialGradientPaint { active: radial_active, transform: radial_transform, + geometry: radial_geometry, stops: radial_stops, opacity: radial_opacity, blend_mode: radial_blend, @@ -620,7 +631,21 @@ impl PaintVocabulary for Cg { radial_active, radial_opacity, radial_blend, - ), + ) + .with_radial_geometry(radial_geometry.map(|geometry| { + ( + [ + geometry.start.center.0.to_bits(), + geometry.start.center.1.to_bits(), + geometry.start.radius.to_bits(), + ], + [ + geometry.end.center.0.to_bits(), + geometry.end.center.1.to_bits(), + geometry.end.radius.to_bits(), + ], + ) + })), Self::gradient( PaintKind::Sweep, None, @@ -674,6 +699,7 @@ impl PaintVocabulary for Cg { let cg::RadialGradientPaint { active: radial_active, transform: radial_transform, + geometry: radial_geometry, stops: radial_stops, opacity: radial_opacity, blend_mode: radial_blend, @@ -681,6 +707,16 @@ impl PaintVocabulary for Cg { } = cg::RadialGradientPaint { active: false, transform, + geometry: Some(cg::RadialGradientGeometry { + start: cg::RadialGradientCircle { + center: (-2.25, 0.375), + radius: 1.75, + }, + end: cg::RadialGradientCircle { + center: (3.5, -0.625), + radius: 0.0, + }, + }), stops: stops.clone(), opacity: 0.625, blend_mode: cg::BlendMode::SoftLight, @@ -733,7 +769,21 @@ impl PaintVocabulary for Cg { radial_active, radial_opacity, radial_blend, - ), + ) + .with_radial_geometry(radial_geometry.map(|geometry| { + ( + [ + geometry.start.center.0.to_bits(), + geometry.start.center.1.to_bits(), + geometry.start.radius.to_bits(), + ], + [ + geometry.end.center.0.to_bits(), + geometry.end.center.1.to_bits(), + geometry.end.radius.to_bits(), + ], + ) + })), Self::gradient( PaintKind::Sweep, None, @@ -1035,6 +1085,7 @@ impl N0 { ) -> GradientObservation { GradientObservation { kind, + radial_geometry: None, endpoints: endpoints.map(|(from, to)| { ( [from.0.to_bits(), from.1.to_bits()], @@ -1301,6 +1352,7 @@ impl PaintVocabulary for N0 { let n::RadialGradientPaint { active: radial_active, transform: radial_transform, + geometry: radial_geometry, stops: radial_stops, opacity: radial_opacity, blend_mode: radial_blend, @@ -1340,7 +1392,21 @@ impl PaintVocabulary for N0 { radial_active, radial_opacity, radial_blend, - ), + ) + .with_radial_geometry(radial_geometry.map(|geometry| { + ( + [ + geometry.start.center.0.to_bits(), + geometry.start.center.1.to_bits(), + geometry.start.radius.to_bits(), + ], + [ + geometry.end.center.0.to_bits(), + geometry.end.center.1.to_bits(), + geometry.end.radius.to_bits(), + ], + ) + })), Self::gradient( PaintKind::Sweep, None, @@ -1402,6 +1468,7 @@ impl PaintVocabulary for N0 { let n::RadialGradientPaint { active: radial_active, transform: radial_transform, + geometry: radial_geometry, stops: radial_stops, opacity: radial_opacity, blend_mode: radial_blend, @@ -1409,6 +1476,16 @@ impl PaintVocabulary for N0 { } = n::RadialGradientPaint { active: false, transform, + geometry: Some(n::RadialGradientGeometry { + start: n::RadialGradientCircle { + center: (-2.25, 0.375), + radius: 1.75, + }, + end: n::RadialGradientCircle { + center: (3.5, -0.625), + radius: 0.0, + }, + }), stops: stops.clone(), opacity: 0.625, blend_mode: n::BlendMode::SoftLight, @@ -1461,7 +1538,21 @@ impl PaintVocabulary for N0 { radial_active, radial_opacity, radial_blend, - ), + ) + .with_radial_geometry(radial_geometry.map(|geometry| { + ( + [ + geometry.start.center.0.to_bits(), + geometry.start.center.1.to_bits(), + geometry.start.radius.to_bits(), + ], + [ + geometry.end.center.0.to_bits(), + geometry.end.center.1.to_bits(), + geometry.end.radius.to_bits(), + ], + ) + })), Self::gradient( PaintKind::Sweep, None, @@ -1739,6 +1830,7 @@ fn expected_gradient_defaults() -> Vec { vec![ GradientObservation { kind: PaintKind::Linear, + radial_geometry: None, endpoints: Some(( [(-1.0_f32).to_bits(), 0.0_f32.to_bits()], [1.0_f32.to_bits(), 0.0_f32.to_bits()], @@ -1760,6 +1852,7 @@ fn expected_gradient_defaults() -> Vec { }, GradientObservation { kind: PaintKind::Radial, + radial_geometry: None, endpoints: None, tile: Some(Tile::Clamp), transform_bits: [ @@ -1778,6 +1871,7 @@ fn expected_gradient_defaults() -> Vec { }, GradientObservation { kind: PaintKind::Sweep, + radial_geometry: None, endpoints: None, tile: None, transform_bits: [ @@ -1796,6 +1890,7 @@ fn expected_gradient_defaults() -> Vec { }, GradientObservation { kind: PaintKind::Diamond, + radial_geometry: None, endpoints: None, tile: None, transform_bits: [ @@ -1826,6 +1921,7 @@ fn expected_gradient_sentinels() -> Vec { ]; let common = |kind, endpoints, tile| GradientObservation { kind, + radial_geometry: None, endpoints, tile, transform_bits, @@ -1847,7 +1943,14 @@ fn expected_gradient_sentinels() -> Vec { )), Some(Tile::Mirror), ), - common(PaintKind::Radial, None, Some(Tile::Decal)), + common(PaintKind::Radial, None, Some(Tile::Decal)).with_radial_geometry(Some(( + [ + (-2.25_f32).to_bits(), + 0.375_f32.to_bits(), + 1.75_f32.to_bits(), + ], + [3.5_f32.to_bits(), (-0.625_f32).to_bits(), 0.0_f32.to_bits()], + ))), common(PaintKind::Sweep, None, None), common(PaintKind::Diamond, None, None), ] diff --git a/crates/n0-model/tests/radial_geometry.rs b/crates/n0-model/tests/radial_geometry.rs new file mode 100644 index 00000000..1e1819bd --- /dev/null +++ b/crates/n0-model/tests/radial_geometry.rs @@ -0,0 +1,215 @@ +//! Model-boundary laws for ordered radial circles, independent of a painter. + +use n0_model::model::*; +use n0_model::n0_xml::{self, PrintError}; +use n0_model::properties::{PropertyKey, PropertyTarget, PropertyValue, PropertyValues, ValueView}; +use n0_model::renderability::validate_paint; + +const SOURCE: &str = r##""##; + +fn source() -> (Document, NodeId) { + let doc = n0_xml::parse(SOURCE).unwrap(); + let container = doc.get(doc.root).children[0]; + let rect = doc.get(container).children[0]; + (doc, rect) +} + +fn circle(x: f32, y: f32, radius: f32) -> RadialGradientCircle { + RadialGradientCircle { + center: (x, y), + radius, + } +} + +fn paint(geometry: RadialGradientGeometry) -> Paint { + Paint::RadialGradient(RadialGradientPaint { + geometry: Some(geometry), + stops: vec![ + GradientStop { + offset: 0.0, + color: Color::BLACK.into(), + }, + GradientStop { + offset: 1.0, + color: Color(0xffff_ffff).into(), + }, + ], + ..Default::default() + }) +} + +fn projected( + doc: &Document, + node: NodeId, + paint: Paint, +) -> Result { + PropertyValues::new( + doc, + [( + PropertyTarget::new(doc.key_of(node).unwrap(), PropertyKey::Fills), + PropertyValue::Paints(Paints::new([paint])), + )], + ) +} + +#[test] +fn zero_exterior_reversed_and_equal_circles_are_valid_facts() { + let (doc, rect) = source(); + for (start, end) in [ + (circle(0.5, 0.5, 0.0), circle(0.5, 0.5, 0.5)), + (circle(-2.25, 3.5, 1.75), circle(0.5, 0.5, 0.0)), + (circle(0.0, 0.0, 0.0), circle(1.0, 1.0, 0.0)), + (circle(0.5, 0.5, 0.5), circle(0.5, 0.5, 0.5)), + (circle(0.5, 0.5, 0.0), circle(0.5, 0.5, 0.0)), + (circle(f32::MAX, -f32::MAX, f32::MAX), circle(0.0, 0.0, 0.0)), + ] { + let paint = paint(RadialGradientGeometry { start, end }); + validate_paint(&paint).unwrap(); + let values = projected(&doc, rect, paint.clone()).unwrap(); + assert_eq!(ValueView::new(&doc, &values).unwrap().fills(rect)[0], paint); + } +} + +#[test] +fn every_nonfinite_component_and_negative_radius_is_rejected_at_admission() { + let (doc, rect) = source(); + for is_end in [false, true] { + for component in 0..3 { + for invalid in [f32::NAN, f32::INFINITY, f32::NEG_INFINITY, -1.0] { + if component != 2 && invalid == -1.0 { + continue; + } + let mut geometry = RadialGradientGeometry { + start: circle(0.25, 0.375, 0.125), + end: circle(0.5, 0.625, 0.75), + }; + let circle = if is_end { + &mut geometry.end + } else { + &mut geometry.start + }; + match component { + 0 => circle.center.0 = invalid, + 1 => circle.center.1 = invalid, + _ => circle.radius = invalid, + } + let paint = paint(geometry); + let message = validate_paint(&paint).unwrap_err().to_string(); + let role = if is_end { "end" } else { "start" }; + let field = if component == 2 { "radius" } else { "center" }; + assert!( + message.contains(&format!("radial gradient {role} circle {field}")), + "{message}" + ); + assert!( + projected(&doc, rect, paint).is_err(), + "{role} {field}={invalid}" + ); + } + } + } +} + +#[test] +fn model_copy_keeps_direct_coordinate_bits_and_circle_order() { + let (doc, rect) = source(); + let geometry = RadialGradientGeometry { + start: circle(f32::from_bits(1), -0.0, 1.75), + end: circle(3.5, -2.25, 0.0), + }; + let values = projected(&doc, rect, paint(geometry)).unwrap().clone(); + let view = ValueView::new(&doc, &values).unwrap(); + let Paint::RadialGradient(paint) = &view.fills(rect)[0] else { + panic!("radial fact") + }; + let geometry = paint.geometry.unwrap(); + assert_eq!( + [ + geometry.start.center.0.to_bits(), + geometry.start.center.1.to_bits(), + geometry.start.radius.to_bits() + ], + [1, 0x8000_0000, 0x3fe0_0000] + ); + assert_eq!( + [ + geometry.end.center.0.to_bits(), + geometry.end.center.1.to_bits(), + geometry.end.radius.to_bits() + ], + [0x4060_0000, 0xc010_0000, 0] + ); +} + +#[test] +fn draft_zero_preserves_absence_and_refuses_every_present_circle_pair() { + let (mut doc, rect) = source(); + let printed = n0_xml::print(&doc).unwrap(); + let roundtrip = n0_xml::parse(&printed).unwrap(); + assert_eq!(doc, roundtrip); + let Paint::RadialGradient(original) = &doc.get(rect).fills[0] else { + panic!("radial fact") + }; + assert_eq!(original.geometry, None); + + for geometry in [ + RadialGradientGeometry { + start: circle(0.5, 0.5, 0.0), + end: circle(0.5, 0.5, 0.5), + }, + RadialGradientGeometry { + start: circle(-1.0, 2.0, 0.75), + end: circle(0.5, 0.5, 0.0), + }, + ] { + for active in [false, true] { + let mut paint = paint(geometry); + let Paint::RadialGradient(radial) = &mut paint else { + unreachable!() + }; + radial.active = active; + doc.get_mut(rect).fills = Paints::new([paint]); + assert!( + matches!(n0_xml::print(&doc), Err(PrintError::InvalidDocument(message)) + if message.contains("ordered circle geometry is not representable in Draft 0")) + ); + assert_eq!( + n0_model::textir::try_print(&doc).unwrap_err().0, + format!( + "node {rect} has a paint stack the historical TextIr dialect cannot represent" + ) + ); + } + } +} + +#[test] +fn draft_zero_cannot_drop_ordered_circles_from_strokes_or_run_overrides() { + let geometry = RadialGradientGeometry { + start: circle(-1.0, 2.0, 0.75), + end: circle(0.5, 0.5, 0.0), + }; + let (mut doc, rect) = source(); + let mut stroke = Stroke::default_for(&doc.get(rect).payload).unwrap(); + stroke.paints = Paints::new([paint(geometry)]); + doc.get_mut(rect).strokes.push(stroke); + assert!( + matches!(n0_xml::print(&doc), Err(PrintError::InvalidDocument(message)) + if message.contains("ordered circle geometry is not representable in Draft 0")) + ); + + let mut text = n0_xml::parse(r##"a"##).unwrap(); + let container = text.get(text.root).children[0]; + let id = text.get(container).children[0]; + let Payload::AttributedText { + attributed_string, .. + } = &mut text.get_mut(id).payload + else { + panic!("run-bearing text"); + }; + attributed_string.runs[0].fills = Some(Paints::new([paint(geometry)])); + assert!( + matches!(n0_xml::print(&text), Err(PrintError::InvalidDocument(message)) + if message.contains("ordered circle geometry is not representable in Draft 0")) + ); +} diff --git a/crates/n0/src/cache.rs b/crates/n0/src/cache.rs index 7ef0617c..18718ba6 100644 --- a/crates/n0/src/cache.rs +++ b/crates/n0/src/cache.rs @@ -20,10 +20,13 @@ //! rounded, dashed, translucent, or shaped geometry even when the translation //! is an integer. Fractional pan additionally resamples. Accurate static and //! exact-time export must execute the immutable frame product directly. +//! Explicit radial circle pairs are refused by node before cache or canvas +//! mutation: their measured translated-raster quantization is not admitted +//! by this preview policy. Direct immutable-frame execution carries them. use n0_model::animation::SampleError; use n0_model::math::Affine; -use n0_model::model::{Document, NodeKey}; +use n0_model::model::{Document, NodeId, NodeKey}; use n0_model::properties::{PropertyError, PropertyValues, ValueView}; use n0_model::resolve::{ResolveOptions, RotationInFlow}; use skia_safe::{Canvas, Color, FilterMode, Image, ImageInfo, MipmapMode, SamplingOptions}; @@ -47,6 +50,11 @@ pub enum SceneCacheError { Property(PropertyError), FrameBuild(FrameBuildError), FrameExecution(FrameExecutionError), + /// Translating the offscreen raster changes this paint's quantization. + /// Execute the immutable frame directly instead of using preview policy. + ExplicitRadialGeometry { + node: NodeId, + }, } impl std::fmt::Display for SceneCacheError { @@ -55,6 +63,8 @@ impl std::fmt::Display for SceneCacheError { SceneCacheError::Property(error) => error.fmt(f), SceneCacheError::FrameBuild(error) => error.fmt(f), SceneCacheError::FrameExecution(error) => error.fmt(f), + SceneCacheError::ExplicitRadialGeometry { node } => write!(f, + "node {node}: the translated preview raster cache does not admit explicit radial gradient circles; execute the frame directly"), } } } @@ -418,6 +428,18 @@ impl SceneCache { .or(self.list.as_ref()) .expect("a retained raster has one drawlist"); + // The source-neutral geometry remains renderable; only this policy's + // +MARGIN raster-and-crop is unproved for it. Refuse before changing + // the canvas or any cache field, never silently substitute a raster. + // A retained list already passed this guard. Inspect replacements + // only: a clean camera pan must not gain an O(items) paint scan. + if let Some(node) = replacement + .as_ref() + .and_then(|input| explicit_radial_owner(&input.list)) + { + return Err(SceneCacheError::ExplicitRadialGeometry { node }); + } + let dx = view.e - self.ref_view.e; let dy = view.f - self.ref_view.f; let same_zoom = view.a == self.ref_view.a @@ -486,6 +508,48 @@ impl SceneCache { } } +fn explicit_radial_owner(list: &crate::drawlist::DrawList) -> Option { + use crate::drawlist::ItemKind; + use n0_model::model::{Paint, Paints}; + let contains = |paints: &Paints| { + paints.iter().any( + |paint| matches!(paint, Paint::RadialGradient(radial) if radial.geometry.is_some()), + ) + }; + list.items.iter().find_map(|item| { + let present = match &item.kind { + ItemKind::RectFill { paints, .. } + | ItemKind::OvalFill { paints, .. } + | ItemKind::PathFill { paints, .. } => contains(paints), + ItemKind::TextFill { paints, .. } => { + contains(&paints.node) || paints.runs.iter().flatten().flatten().any(contains) + } + ItemKind::RectStroke { stroke, .. } + | ItemKind::OvalStroke { stroke, .. } + | ItemKind::AbsoluteDashedOvalStroke { stroke, .. } + | ItemKind::LineStroke { stroke, .. } + | ItemKind::PathStroke { stroke, .. } + | ItemKind::TextStroke { stroke, .. } => contains(&stroke.paints), + ItemKind::PatternFill { pattern, .. } | ItemKind::PatternStroke { pattern, .. } => { + explicit_radial_owner(&pattern.program).is_some() + } + ItemKind::BeginOpacity { .. } + | ItemKind::BeginIsolatedOpacity { .. } + | ItemKind::EndOpacity + | ItemKind::BeginClipRect { .. } + | ItemKind::BeginClipPath { .. } + | ItemKind::EndClip + | ItemKind::BeginMaskContent + | ItemKind::BeginMaskSource { .. } + | ItemKind::EndMaskSource + | ItemKind::EndMaskContent + | ItemKind::BeginFilter { .. } + | ItemKind::EndFilter => false, + }; + present.then_some(item.node) + }) +} + /// Render one preview-composited frame to a fresh raster surface and return its /// bytes. Pairs with [`crate::paint::raster_to_bytes_unchecked`] in /// fixture-scoped cache equivalence probes. A fresh cache is passed so the diff --git a/crates/n0/src/glyphless.rs b/crates/n0/src/glyphless.rs index 7a79783d..48f1c64f 100644 --- a/crates/n0/src/glyphless.rs +++ b/crates/n0/src/glyphless.rs @@ -1384,6 +1384,18 @@ fn compile_paints(paints: &PaintStack, unit_offset: Option<(f32, f32)>) -> Paint Paint::RadialGradient(n0_model::model::RadialGradientPaint { active: gradient.active, transform: compile_gradient_transform(&gradient.transform, unit_offset), + geometry: gradient.geometry.map(|geometry| { + n0_model::model::RadialGradientGeometry { + start: n0_model::model::RadialGradientCircle { + center: geometry.start.center, + radius: geometry.start.radius, + }, + end: n0_model::model::RadialGradientCircle { + center: geometry.end.center, + radius: geometry.end.radius, + }, + } + }), stops: compile_gradient_stops(&gradient.stops), opacity: gradient.opacity, blend_mode: BlendMode::Normal, @@ -2450,6 +2462,172 @@ mod tests { assert!(reason.contains("invertible"), "unexpected reason: {reason}"); } + fn radial_circle_stack(geometry: cg::RadialGradientGeometry) -> PaintStack { + PaintStack::try_from_paints(CgPaints::new([CgPaint::RadialGradient( + cg::RadialGradientPaint { + geometry: Some(geometry), + ..cg::RadialGradientPaint::from_colors(vec![CGColor::RED, CGColor::BLUE]) + }, + )])) + .unwrap() + } + + #[test] + fn radial_circles_cross_the_seam_without_normalization_or_reordering() { + let geometry = cg::RadialGradientGeometry { + start: cg::RadialGradientCircle { + center: (-1.25, 2.5), + radius: 0.75, + }, + end: cg::RadialGradientCircle { + center: (0.375, 0.625), + radius: 0.0, + }, + }; + let compiled = compile_paints(&radial_circle_stack(geometry), None); + let Paint::RadialGradient(paint) = &compiled[0] else { + panic!("radial paint") + }; + let circles = paint.geometry.unwrap(); + assert_eq!(circles.start.center, (-1.25, 2.5)); + assert_eq!(circles.start.radius, 0.75); + assert_eq!(circles.end.center, (0.375, 0.625)); + assert_eq!(circles.end.radius, 0.0); + } + + #[test] + fn explicit_radial_circles_are_preflighted_at_the_source_owner() { + let valid = cg::RadialGradientGeometry { + start: cg::RadialGradientCircle { + center: (0.25, 0.375), + radius: 0.125, + }, + end: cg::RadialGradientCircle { + center: (0.5, 0.5), + radius: 0.5, + }, + }; + for geometry in [ + valid, + cg::RadialGradientGeometry { + end: cg::RadialGradientCircle { + radius: 0.0, + ..valid.end + }, + ..valid + }, + cg::RadialGradientGeometry { + start: valid.end, + ..valid + }, + ] { + compile(resolved_frame(radial_circle_stack(geometry))).expect("finite ordered circles"); + } + for (center, radius) in [ + ((f32::NAN, 0.5), 0.125), + ((0.25, f32::INFINITY), 0.125), + ((0.25, 0.375), -0.125), + ((0.25, 0.375), f32::INFINITY), + ] { + let geometry = cg::RadialGradientGeometry { + start: cg::RadialGradientCircle { center, radius }, + ..valid + }; + let error = compile(resolved_frame(radial_circle_stack(geometry))) + .expect_err("invalid circle before any painter call"); + let BuildError::Paint { owner, reason } = error else { + panic!("wrong error: {error:?}") + }; + assert_eq!(owner, RECT_OWNER); + assert!(reason.contains("radial"), "{reason}"); + } + } + + #[test] + fn retained_radial_circle_frame_matches_fresh_after_other_frames() { + let geometry = cg::RadialGradientGeometry { + start: cg::RadialGradientCircle { + center: (0.25, 0.375), + radius: 0.125, + }, + end: cg::RadialGradientCircle { + center: (0.5, 0.5), + radius: 0.5, + }, + }; + let build = |geometry| compile(resolved_frame(radial_circle_stack(geometry))).unwrap(); + let retained = build(geometry); + let context = PaintCtx::new(None); + let raster = |frame: &FrameProduct| { + frame + .raster_to_bytes(&AffineTransform::identity(), 64, 48, &context) + .unwrap() + }; + let original = raster(&retained); + let changed = build(cg::RadialGradientGeometry { + start: cg::RadialGradientCircle { + radius: 0.25, + ..geometry.start + }, + ..geometry + }); + assert_ne!( + original, + raster(&changed), + "the changed frame is a live control" + ); + assert_eq!(original, raster(&retained)); + assert_eq!(raster(&retained), raster(&build(geometry))); + } + + #[test] + fn a_radial_circle_change_damages_the_owning_paint() { + let geometry = cg::RadialGradientGeometry { + start: cg::RadialGradientCircle { + center: (0.25, 0.375), + radius: 0.125, + }, + end: cg::RadialGradientCircle { + center: (0.5, 0.5), + radius: 0.5, + }, + }; + let before = compile(resolved_frame(radial_circle_stack(geometry))).unwrap(); + for geometry in [ + cg::RadialGradientGeometry { + start: cg::RadialGradientCircle { + center: (0.75, 0.375), + ..geometry.start + }, + ..geometry + }, + cg::RadialGradientGeometry { + start: cg::RadialGradientCircle { + radius: 0.25, + ..geometry.start + }, + ..geometry + }, + cg::RadialGradientGeometry { + end: cg::RadialGradientCircle { + radius: 0.0, + ..geometry.end + }, + ..geometry + }, + ] { + let after = compile(resolved_frame(radial_circle_stack(geometry))).unwrap(); + assert!(!before.drawlist.raster_eq(&after.drawlist)); + assert_eq!( + diff_frame(&before, &after), + Damage { + changed: vec![RECT_OWNER], + union_frame: Some(Rectangle::from_xywh(8.0, 6.0, 20.0, 16.0)) + } + ); + } + } + /// The source-neutral seam copies one checked local-space pattern exactly; /// it does not drop, repeat, scale, renormalize, or otherwise reinterpret /// producer facts. diff --git a/crates/n0/src/paint.rs b/crates/n0/src/paint.rs index 0fffe582..84ef6cd7 100644 --- a/crates/n0/src/paint.rs +++ b/crates/n0/src/paint.rs @@ -1175,7 +1175,15 @@ fn radial_gradient_shader_mapped( let (colors, positions) = gradient_stops(&paint.stops); let stops = gradient(&colors, &positions, sk_tile_mode(paint.tile_mode)); let matrix = mapped_paint_box_matrix(paint_box, &paint.transform, paint_to_canvas); - shaders::radial_gradient(((0.5, 0.5), 0.5), &stops, Some(&matrix)) + match paint.geometry { + None => shaders::radial_gradient(((0.5, 0.5), 0.5), &stops, Some(&matrix)), + Some(geometry) => shaders::two_point_conical_gradient( + (geometry.start.center, geometry.start.radius), + (geometry.end.center, geometry.end.radius), + &stops, + Some(&matrix), + ), + } } fn sweep_gradient_shader_mapped( diff --git a/crates/n0/tests/cache.rs b/crates/n0/tests/cache.rs index 162aaea4..4e42e15f 100644 --- a/crates/n0/tests/cache.rs +++ b/crates/n0/tests/cache.rs @@ -232,6 +232,73 @@ fn doc_dirty_forces_reraster_and_matches_fresh() { ); } +#[test] +fn radial_circle_preview_cache_refuses_without_changing_canvas_or_retained_state() { + let mut doc = scene(); + let view = Affine::IDENTITY; + let context = ctx(); + let mut cache = SceneCache::new(W, H); + let radial = |radius| { + Paint::RadialGradient(RadialGradientPaint { + geometry: Some(RadialGradientGeometry { + start: RadialGradientCircle { + center: (0.25, 0.375), + radius, + }, + end: RadialGradientCircle { + center: (0.5, 0.5), + radius: 0.5, + }, + }), + stops: vec![ + GradientStop { + offset: 0.0, + color: Color(0xffff0000).into(), + }, + GradientStop { + offset: 1.0, + color: Color(0xff0000ff).into(), + }, + ], + ..Default::default() + }) + }; + let original = doc.get(1).fills.clone(); + let (cold, _) = cached_frame_bytes(&mut cache, &doc, &view, &context, false); + doc.get_mut(1).fills = Paints::new([radial(0.125)]); + let direct = fresh_frame_bytes(&doc, &view, &context); + assert_eq!(direct, fresh_frame_bytes(&doc, &view, &context)); + let mut surface = surfaces::raster_n32_premul((W, H)).unwrap(); + surface.canvas().clear(SkColor::MAGENTA); + let before = n0::paint::read_pixels(&mut surface, W, H); + let error = cache + .frame(surface.canvas(), &doc, &opts(), &view, &context, true) + .unwrap_err(); + assert_eq!( + error, + n0::cache::SceneCacheError::ExplicitRadialGeometry { node: 1 } + ); + assert!(error.to_string().contains("execute the frame directly")); + assert_eq!( + before, + n0::paint::read_pixels(&mut surface, W, H), + "refusal precedes painting" + ); + doc.get_mut(1).fills = Paints::new([radial(0.25)]); + assert_ne!( + direct, + fresh_frame_bytes(&doc, &view, &context), + "radius change is visible in direct frames" + ); + doc.get_mut(1).fills = original; + let (recovered, rerastered) = cached_frame_bytes(&mut cache, &doc, &view, &context, false); + assert!( + !rerastered, + "refusal did not replace the retained source or raster" + ); + assert_eq!(cold, recovered); +} + #[test] fn cache_builds_text_with_the_same_shaping_oracle_as_a_fresh_frame() { let doc = text_scene(); diff --git a/crates/n0_cli/README.md b/crates/n0_cli/README.md index e0eec948..761f7c2c 100644 --- a/crates/n0_cli/README.md +++ b/crates/n0_cli/README.md @@ -607,10 +607,10 @@ cargo run -p n0_cli --bin n0 -- \ The filter estate contains 26 chassis/blur cells, 60 shadow-graph, 28 native drop-shadow, 27 color-matrix, 34 component-transfer, 38 blend, 37 morphology, 91 turbulence/displacement, 41 convolution-rung, and 71 diffuse-lighting - cells. The complete primitive corpus contains 1,157 Chromium-baked cells plus + cells. The complete primitive corpus contains 1,284 Chromium-baked cells plus 16 sampled frames; the text estate contains sixteen exact text pixel cells and eight exact-number artifact-geometry witnesses (six Allerta and two - Bungee), and the named refusal register has 234 rows. `feFlood`, `feComposite`, + Bungee), and the named refusal register has 260 rows. `feFlood`, `feComposite`, `feMerge`, `feMergeNode`, `feDropShadow`, `feColorMatrix`, `feComponentTransfer`, `feBlend`, `feMorphology`, `feConvolveMatrix`, `feDiffuseLighting`, `feDistantLight`, `fePointLight`, `feSpotLight`, @@ -871,13 +871,32 @@ cargo run -p n0_cli --bin n0 -- \ or a non-gradient target); the measured correct nothings — zero stops (fallback unfired), a self-cycle, a non-invertible gradient transform, an object-bounding-box gradient on zero-area geometry — paint nothing. A - zero or negative radial radius and linear endpoints inside the backend's + zero or negative concentric radial radius and linear endpoints inside the backend's degenerate threshold resolve to the tile-specific measured solid: the last stop under `pad`, or the ramp's integral average under `reflect`/`repeat`. On zero-area line geometry, object-box paint is nothing before one-stop or degenerate classification; user-space one-stop and concentric degenerate ramps retain those source-neutral results before the live-gradient boundary. Two companion Chromium cells carry the complete unit/ordering split. + Radial `fx`/`fy`/`fr` carry signed finite numbers, percentages, and + case-insensitive `px` through the same guarded resource-length decoder. + Missing focus coordinates default to the final template-resolved `cx`/`cy`; + missing or negative `fr` resolves to zero. User-space focus percentages use + the viewport axes and `fr` uses its normalized diagonal; object-box values + use fraction space. The resolved paint preserves both circles in order, + including exterior focus, equal/reversed radii, and a zero end radius. + A one-stop explicit radial retains the conical transparent exterior instead + of filling the entire target. The default centered leaf remains unchanged. + The 127 `svg-radial-start-*` / `html-inline-svg-radial-start` cells cover + these branches, templates, mapped viewports, transforms, spread methods, + and admitted fill/stroke/resource/effect clients. Eight declare measured + one-code-value ramp bounds; the other 119 are byte-exact. This is a split, + not closure of the three attribute rows: precision aliases, CSS comments, + out-of-range used lengths, and wider computed value/context families still + refuse by the exact attribute. The shared paint contract's optional circle + pair adds no CSS matcher, external resource access, animation, or frozen + `.grida` format support. Direct frame execution carries the new paint; + translated preview raster caching refuses it by node before any mutation. The `` presentation attributes are consumed at their listed grammars (the stop rung). `stop-color` carries the `color` property's ``: hex in all four lengths, named colours, `transparent`, @@ -890,9 +909,9 @@ cargo run -p n0_cli --bin n0 -- \ the resolved contract carries that product **unquantized**, because the rasterizer interpolates the ramp before it quantizes. `initial`, `unset` and `revert` coincide with each attribute's initial and are admitted. - What refuses by name: a focal radial (`fx`/`fy` off - the center or `fr > 0` — the shared radial leaf is concentric), - `color-interpolation: linearRGB`, a degenerate paint server whose + What refuses by name: gradient geometry with source-number provenance + aliases, CSS comments, CSS-wide values, computed functions, or out-of-range + used values; `color-interpolation: linearRGB`; a degenerate paint server whose substituted colour does not land on a byte (Chromium keeps a dithering shader for those and no flat colour reproduces one — guarded as `svg-gradient-degenerate-precision`, and a gradient-geometry gap rather diff --git a/crates/rframe/README.md b/crates/rframe/README.md index 0790cd2c..92ce127a 100644 --- a/crates/rframe/README.md +++ b/crates/rframe/README.md @@ -69,13 +69,18 @@ helper never understates the mathematical bound. The vocabulary is deliberately narrower than SVG or CSS. Its ordinary leaves are solid, linear-gradient, and radial-gradient paints. A gradient is a -self-contained normal-blend color ramp stated in the unit square of the -geometry's own box. The alternative pattern value is likewise resolved: one +self-contained normal-blend color ramp with intrinsic gradient-local geometry +and affine placement in the painted geometry's box. A radial leaf may retain +an explicit ordered start/end circle pair, including exterior centers and +zero/equal/reversed radii, without renormalizing those six resolved scalars. +Absence preserves the original centered unit-circle form; the +[paint amendment](../../docs/wg/feat-painting/paint-model.md#amd-radial-circles) +states that boundary. The alternative pattern value is likewise resolved: one bounded immutable `FrameItems` program in tile-local coordinates, one positive tile extent, one finite tile-to-consumer transform, and no lookup key or resource handle. A paint that still _references_ an authored pattern, image -resource, or unresolved context-paint relationship remains inexpressible here; -so does a focal geometry the shared radial leaf cannot state. Source-level +resource, or unresolved context-paint relationship remains inexpressible here. +Source-level context paint is not a new render fact: a producer must select and fully rebase its eventual no-paint, leaf, or pattern result before this boundary, without carrying the context relation or its reference-box ownership into the frame. diff --git a/crates/rframe/tests/paint_stack.rs b/crates/rframe/tests/paint_stack.rs index 1bea5c22..ee9e646d 100644 --- a/crates/rframe/tests/paint_stack.rs +++ b/crates/rframe/tests/paint_stack.rs @@ -56,6 +56,16 @@ fn visible_gradients_are_admitted_with_their_fields_intact() { ..Default::default() }; let radial = RadialGradientPaint { + geometry: Some(cg::RadialGradientGeometry { + start: cg::RadialGradientCircle { + center: (-0.25, 0.375), + radius: 0.75, + }, + end: cg::RadialGradientCircle { + center: (0.5, 0.625), + radius: 0.0, + }, + }), stops: ramp(), ..Default::default() }; diff --git a/crates/websem/src/svg_paint_server.rs b/crates/websem/src/svg_paint_server.rs index 48002ebb..e5db29c1 100644 --- a/crates/websem/src/svg_paint_server.rs +++ b/crates/websem/src/svg_paint_server.rs @@ -24,21 +24,20 @@ //! `currentColor` resolves against the stop's own computed `color`, and //! an unparseable `stop-color` (including the `inherit` keyword) is the //! initial black. -//! - The degenerate rules are the backend's own. A one-stop ramp is spatially -//! constant but retains gradient rasterization; zero/negative radial radius -//! and linear endpoints closer than the backend threshold resolve to a -//! solid — the last stop under `pad`, the ramp's integral average under -//! `reflect`/`repeat`. Resolving those cases here keeps downstream preflight -//! inside its checked gradient domain. +//! - A one-stop ramp retains gradient rasterization. Explicit radial circles +//! also retain their conical domain: a constant color does not paint its +//! transparent exterior. Only an implicit concentric zero/negative radial +//! radius collapses to a solid, like sufficiently close linear endpoints: +//! the last stop under `pad`, the integral average under `reflect`/`repeat`. //! - `gradientTransform` and an author `transform` declaration are one //! computed value (csscascade hints the attribute), applied about the raw //! origin of the gradient's own space; percentages in it are refused by //! name (Chromium resolves them against the viewport and then applies the //! number in fraction space — an incoherence this slice will not repeat). //! -//! What refuses by name: a focal radial (resolved `fx`/`fy` off the center, -//! or `fr > 0` — the shared radial leaf is concentric), font-relative or -//! viewport-relative units in gradient geometry, `color-interpolation: +//! What refuses by name: source-number provenance aliases, CSS comments, +//! computed functions, CSS-wide values, out-of-range used lengths, and +//! font-relative or viewport-relative units in gradient geometry; `color-interpolation: //! linearRGB`, author CSS on stops (`stop-color`/`stop-opacity` in a style //! attribute), resolved stop alpha or degenerate alpha staging that the RGBA8 //! paint contract cannot preserve, an external reference, and a user-space @@ -294,6 +293,7 @@ struct ResolvedStop { color: CGColor32F, } +#[derive(Clone, Copy)] enum GradientKind { Linear, Radial, @@ -371,13 +371,15 @@ pub(crate) fn resolve( return Ok(ResolvedPaintServer::Nothing); } - if stops.len() == 1 { + if stops.len() == 1 && matches!(kind, GradientKind::Linear) { // A one-stop ramp is spatially constant but retains the backend's // gradient material route (including dithering and paint-alpha // staging). Duplicate the sole resolved stop in a source-neutral - // constant gradient. Geometry and reference-box mappings are inert for - // a constant shader; the transform outcome above still decides the - // measured non-invertible nothing before this branch. + // constant gradient. Radial start-circle geometry is not inert even + // with one stop: Chromium leaves pixels outside the focal cone + // untouched, so radial gradients must inspect their geometry first. + // The transform outcome above still decides the measured + // non-invertible nothing before this branch. return Ok(constant_gradient(kind, stops[0].color, paint_opacity)); } @@ -1344,17 +1346,36 @@ fn resolve_radial( }); let fx = read("fx")?.unwrap_or(cx); let fy = read("fy")?.unwrap_or(cy); - let fr = read("fr")?.unwrap_or(0.0); + // Chromium resolves an erroneous negative radius to zero, preserving the + // other circle. Neither an exterior center nor a radius larger than the + // other circle is clamped. Preserve both circles in their resolved local + // coordinates: normalizing by r cannot represent a zero-radius end and + // can change the backend's float/degeneracy classification. + let fr = read("fr")?.unwrap_or(0.0).max(0.0); + let geometry = (fx != cx || fy != cy || fr > 0.0).then_some(cg::RadialGradientGeometry { + start: cg::RadialGradientCircle { + center: (fx, fy), + radius: fr, + }, + end: cg::RadialGradientCircle { + center: (cx, cy), + radius: r.max(0.0), + }, + }); - if fx != cx || fy != cy || fr > 0.0 { - return Err( - "the radial gradient has a focal point or focal radius, which the shared \ - radial paint leaf cannot state (concentric radials only)" - .to_string(), - ); + // Once focal geometry has been proved absent, a one-stop radial is the + // same spatially constant gradient this route has always emitted. Keep + // this before outer-radius degeneracy so the established one-stop + // material and opacity staging remain unchanged. + if stops.len() == 1 && geometry.is_none() { + return Ok(constant_gradient( + GradientKind::Radial, + stops[0].color, + paint_opacity, + )); } - if r <= 0.0 { + if r <= 0.0 && geometry.is_none() { // A non-positive radius reaches the same tile-specific backend // degeneracy as a collapsed linear ramp. Measured at zero: clamp is // the last stop, while repeat/reflect are the ramp's integral average. @@ -1381,8 +1402,8 @@ fn resolve_radial( }; } - // A non-positive radius is already a source-neutral solid. Only a live - // radial needs the context box/space. + // Only the implicit non-positive radius became a solid above. An explicit + // pair with a zero end still needs the context box/space. let Some((reference_box, reference_to_destination)) = reference_space()? else { return Ok(ResolvedPaintServer::Nothing); }; @@ -1392,11 +1413,15 @@ fn resolve_radial( return Ok(ResolvedPaintServer::Nothing); } - // The unit circle (center ½,½, radius ½) maps to the resolved circle - // through a similarity; objectBoundingBox composes in fraction space, - // user space returns through the box inverse. - let scale = 2.0 * r; - let similarity = AffineTransform::from_acebdf(scale, 0.0, cx - r, 0.0, scale, cy - r); + // The old implicit circle keeps its exact existing similarity. Explicit + // ordered circles already carry resolved local coordinates and need only + // the resource/client placement, not a second geometry normalization. + let similarity = if geometry.is_some() { + AffineTransform::identity() + } else { + let scale = 2.0 * r; + AffineTransform::from_acebdf(scale, 0.0, cx - r, 0.0, scale, cy - r) + }; let direct_reference = destination_box == reference_box && reference_to_destination == AffineTransform::identity(); let transform = match units { @@ -1420,7 +1445,23 @@ fn resolve_radial( cg::RadialGradientPaint { active: true, transform, - stops: cg_stops(&stops), + geometry, + stops: if stops.len() == 1 { + // A constant color ramp is not an infinite spatial domain. + // Keep the conical shader, including its unpainted exterior. + vec![ + cg::GradientStop { + offset: 0.0, + color: stops[0].color, + }, + cg::GradientStop { + offset: 1.0, + color: stops[0].color, + }, + ] + } else { + cg_stops(&stops) + }, opacity: paint_opacity, blend_mode: cg::BlendMode::Normal, tile_mode, diff --git a/crates/websem/tests/capability_status.rs b/crates/websem/tests/capability_status.rs index 772425d4..9ecdc91a 100644 --- a/crates/websem/tests/capability_status.rs +++ b/crates/websem/tests/capability_status.rs @@ -115,11 +115,10 @@ fn generate() -> String { writeln!(out, "## Chromium-baked cells ({})\n", suite.fixtures.len()).unwrap(); out.push_str( - "Each renders byte-exact against its committed Chromium oracle\n\ - (seven curved cells and four gradient ramps carry a declared, bounded\n\ - tolerance — see [README.md](./README.md)). Every thumbnail below\n\ - *is* that committed oracle, which byte-exactness makes this\n\ - engine's own render too; hover for the cell's name, click through\n\ + "Cells are checked against their committed Chromium oracles using\n\ + exact bytes unless a manifest entry declares a measured, bounded\n\ + tolerance — see [README.md](./README.md). Every thumbnail below\n\ + *is* that committed oracle; hover for the cell's name, click through\n\ to its fixture source. No new image is committed for this view.\n\n", ); for cell in &suite.fixtures { diff --git a/crates/websem/tests/gradients_contract.rs b/crates/websem/tests/gradients_contract.rs index b0d8f127..8c0f66a5 100644 --- a/crates/websem/tests/gradients_contract.rs +++ b/crates/websem/tests/gradients_contract.rs @@ -680,27 +680,12 @@ fn an_external_reference_refuses_by_name() { // ─── the named refusals ────────────────────────────────────────────────── -/// The refusal boundary, each by name: a focal radial (the shared radial -/// leaf is concentric), a focal radius, `color-interpolation: linearRGB`, +/// The refusal boundary, each by name: `color-interpolation: linearRGB`, /// author CSS on a stop's style attribute, and a geometry unit whose basis /// this slice does not consume. #[test] fn the_beyond_slice_gradient_family_refuses_by_name() { for (body, needle) in [ - ( - format!( - r##" {RAMP} - {RECT}"## - ), - "focal", - ), - ( - format!( - r##" {RAMP} - {RECT}"## - ), - "focal", - ), ( format!( r##" {RAMP} @@ -731,6 +716,31 @@ fn the_beyond_slice_gradient_family_refuses_by_name() { } } +/// A one-stop radial is constant only inside its two-circle shader domain. +/// Chromium leaves the focal cone's exterior untouched, so focal geometry +/// must survive the concentric-only constant-gradient fold. +#[test] +fn a_one_stop_focal_radial_keeps_its_spatial_domain() { + let source = document( + r##" + + "##, + ); + let frame = admit_both(&source); + let cg::Paint::RadialGradient(gradient) = frame.nodes()[1].paints.iter().next().unwrap() else { + panic!("a constant ramp retains radial geometry"); + }; + let geometry = gradient + .geometry + .expect("the one-stop cone cannot become an infinite solid"); + assert_eq!(geometry.start.center, (0.25, 0.25)); + assert_eq!(geometry.start.radius, 0.15); + assert_eq!(geometry.end.center, (0.5, 0.5)); + assert_eq!(geometry.end.radius, 0.5); + assert_eq!(gradient.stops.len(), 2); + assert_eq!(gradient.stops[0].color, gradient.stops[1].color); +} + /// A live user-space ramp on a line reaches a zero-height geometry box. The /// resolved paint contract states gradients in that box's unit square, so an /// inverse map would contain infinity. Refuse at the producer seam instead of @@ -828,19 +838,22 @@ fn zero_area_geometry_splits_object_box_from_userspace_constants() { } /// A template's focal attribute makes the referencing gradient focal too: -/// the refusal runs on the resolved attribute set, because an inherited +/// the paint carries the resolved attribute set, because an inherited /// `fx` does not re-default from an overridden `cx` (measured). #[test] -fn an_inherited_focal_point_still_refuses() { - let error = refusal(&document(&format!( +fn an_inherited_focal_point_survives_a_local_end_center_override() { + let frame = admit_both(&document(&format!( r##" {RAMP} {RECT}"## ))); - let CompileError::UnsupportedFill(reason) = error else { - panic!("expected a fill refusal, got {error:?}"); + let cg::Paint::RadialGradient(gradient) = sole_fill(&frame) else { + panic!("expected radial paint"); }; - assert!(reason.contains("focal"), "{reason}"); + let geometry = gradient.geometry.unwrap(); + assert_eq!(geometry.start.center, (0.15, 0.5)); + assert_eq!(geometry.end.center, (0.8, 0.5)); + assert_eq!(geometry.end.radius, 0.45); } diff --git a/crates/websem/tests/radial_gradients_contract.rs b/crates/websem/tests/radial_gradients_contract.rs new file mode 100644 index 00000000..3cde71cb --- /dev/null +++ b/crates/websem/tests/radial_gradients_contract.rs @@ -0,0 +1,144 @@ +//! Ordered radial circles: value and refusal laws. Chromium PNG cells own +//! pixel truth; these assertions attribute the source branch that produced it. +use websem::{CompileError, DegradationAction, InitialViewport, SvgFrameSource}; + +fn source(attributes: &str) -> String { + format!( + r##""## + ) +} + +fn paint(source: &str) -> cg::RadialGradientPaint { + let viewport = InitialViewport::new(64.0, 32.0); + let strict = SvgFrameSource::from_standalone_svg(source, viewport).unwrap(); + let best = SvgFrameSource::from_standalone_svg_best_effort(source, viewport).unwrap(); + assert!( + best.degradations() + .iter() + .all(|d| d.action() == DegradationAction::SamplesAsBase) + ); + let frame = strict.base_frame(); + assert_eq!(frame, best.base_frame()); + let cg::Paint::RadialGradient(paint) = frame.nodes()[0].paints.iter().next().unwrap() else { + panic!("radial leaf") + }; + paint.clone() +} + +#[test] +fn default_and_explicit_default_keep_the_old_leaf_while_radii_remain_ordered() { + assert_eq!( + paint(&source("")), + paint(&source(r#"fx=".5" fy=".5" fr="0""#)) + ); + assert!(paint(&source("")).geometry.is_none()); + for (attrs, start, end) in [ + ( + r#"fx="-.25" fy=".75" fr=".125""#, + (-0.25, 0.75, 0.125), + (0.5, 0.5, 0.5), + ), + ( + r#"fx=".25" fy=".375" fr=".75""#, + (0.25, 0.375, 0.75), + (0.5, 0.5, 0.5), + ), + ( + r#"fx=".25" fy=".375" fr=".125" r="0""#, + (0.25, 0.375, 0.125), + (0.5, 0.5, 0.0), + ), + ( + r#"fx=".25" fy=".375" fr=".125" r="-.25""#, + (0.25, 0.375, 0.125), + (0.5, 0.5, 0.0), + ), + (r#"fx=".25" fr="-.25""#, (0.25, 0.5, 0.0), (0.5, 0.5, 0.5)), + (r#"fr=".5""#, (0.5, 0.5, 0.5), (0.5, 0.5, 0.5)), + ] { + let paint = paint(&source(attrs)); + let g = paint.geometry.unwrap(); + assert_eq!((g.start.center.0, g.start.center.1, g.start.radius), start); + assert_eq!((g.end.center.0, g.end.center.1, g.end.radius), end); + assert_eq!( + paint.transform, + math2::transform::AffineTransform::identity() + ); + } +} + +#[test] +fn user_percentages_resolve_before_placement_with_a_diagonal_radius_basis() { + let g = paint(&source( + r#"gradientUnits="userSpaceOnUse" fx="25%" fy="37.5%" fr="12.5%""#, + )) + .geometry + .unwrap(); + assert_eq!(g.start.center, (16.0, 12.0)); + // Pin the contract's multiply-before-divide arithmetic, independently of + // the resolver. The Chromium percentage/numeric PNG pair proves the + // diagonal basis, not equality of their least-significant float bits. + assert_eq!(g.start.radius.to_bits(), 1_087_005_379); + assert_ne!(g.start.radius, 8.0, "width is not the radius basis"); + assert_ne!(g.start.radius, 4.0, "height is not the radius basis"); +} + +#[test] +fn every_retained_value_family_names_the_exact_attribute_in_both_admissions() { + for attr in ["fx", "fy", "fr"] { + for (value, needle) in [ + ("57384.267578125007", "numeric precision alias"), + ("57384.267578125007%", "numeric precision alias"), + ( + "8388608.500000000000000000000000000000000000000008388608", + "numeric precision alias", + ), + ("/*a*/.25/*b*/", "CSS comment"), + (".2/**/5", "CSS comment"), + ("1e999", "admitted Web used-value range"), + ("4em", "unit whose basis"), + ("calc(25%)", "uses calc()"), + ("min(25%,50%)", "uses min()"), + ("max(25%,50%)", "uses max()"), + ("clamp(0%,25%,50%)", "uses clamp()"), + ("var(--v)", "uses var()"), + ("env(safe-area-inset-left)", "uses env()"), + ("initial", "CSS-wide value"), + ("inherit", "CSS-wide value"), + ("unset", "CSS-wide value"), + ("revert", "CSS-wide value"), + ("revert-layer", "CSS-wide value"), + ] { + let input = source(&format!(r#"{attr}="{value}""#)); + let viewport = InitialViewport::new(64.0, 32.0); + let error = SvgFrameSource::from_standalone_svg(input.as_str(), viewport).unwrap_err(); + let CompileError::UnsupportedFill(reason) = error else { + panic!("wrong refusal {error:?}") + }; + assert!( + reason.contains(&format!("gradient geometry {attr}")), + "{reason}" + ); + assert!(reason.contains(needle), "{reason}"); + let best = + SvgFrameSource::from_standalone_svg_best_effort(input.as_str(), viewport).unwrap(); + let skipped: Vec<_> = best + .degradations() + .iter() + .filter(|d| d.action() == DegradationAction::Skipped) + .collect(); + assert_eq!(skipped.len(), 1); + assert!(skipped[0].reason().to_string().contains(needle)); + assert!( + skipped[0] + .reason() + .to_string() + .contains(&format!("gradient geometry {attr}")) + ); + assert!( + best.base_frame().nodes().is_empty(), + "a refused target cannot leak concentric paint" + ); + } + } +} diff --git a/crates/websem/tests/unsupported_corpus.rs b/crates/websem/tests/unsupported_corpus.rs index eeb2a8dd..4af7b251 100644 --- a/crates/websem/tests/unsupported_corpus.rs +++ b/crates/websem/tests/unsupported_corpus.rs @@ -448,7 +448,141 @@ const CORPUS: &[(&str, Departure, &str)] = &[ DeclaredByBestEffort, "attribute x", ), - ("svg-gradient-focal", DeclaredByBestEffort, "focal"), + ( + "svg-radial-start-fx-decimal-precision", + DeclaredByBestEffort, + "numeric precision alias", + ), + ( + "svg-radial-start-fx-percentage-precision", + DeclaredByBestEffort, + "numeric precision alias", + ), + ( + "svg-radial-start-fx-midpoint-precision", + DeclaredByBestEffort, + "numeric precision alias", + ), + ( + "svg-radial-start-fx-css-comments", + DeclaredByBestEffort, + "CSS comment", + ), + ( + "svg-radial-start-fx-used-range", + DeclaredByBestEffort, + "admitted Web used-value range", + ), + ( + "svg-radial-start-fx-units", + DeclaredByBestEffort, + "unit whose basis", + ), + ( + "svg-radial-start-fx-math", + DeclaredByBestEffort, + "uses calc()", + ), + ( + "svg-radial-start-fx-var", + DeclaredByBestEffort, + "uses var()", + ), + ( + "svg-radial-start-fx-css-wide", + DeclaredByBestEffort, + "CSS-wide value", + ), + ( + "svg-radial-start-fy-decimal-precision", + DeclaredByBestEffort, + "numeric precision alias", + ), + ( + "svg-radial-start-fy-percentage-precision", + DeclaredByBestEffort, + "numeric precision alias", + ), + ( + "svg-radial-start-fy-midpoint-precision", + DeclaredByBestEffort, + "numeric precision alias", + ), + ( + "svg-radial-start-fy-css-comments", + DeclaredByBestEffort, + "CSS comment", + ), + ( + "svg-radial-start-fy-used-range", + DeclaredByBestEffort, + "admitted Web used-value range", + ), + ( + "svg-radial-start-fy-units", + DeclaredByBestEffort, + "unit whose basis", + ), + ( + "svg-radial-start-fy-math", + DeclaredByBestEffort, + "uses calc()", + ), + ( + "svg-radial-start-fy-var", + DeclaredByBestEffort, + "uses var()", + ), + ( + "svg-radial-start-fy-css-wide", + DeclaredByBestEffort, + "CSS-wide value", + ), + ( + "svg-radial-start-fr-decimal-precision", + DeclaredByBestEffort, + "numeric precision alias", + ), + ( + "svg-radial-start-fr-percentage-precision", + DeclaredByBestEffort, + "numeric precision alias", + ), + ( + "svg-radial-start-fr-midpoint-precision", + DeclaredByBestEffort, + "numeric precision alias", + ), + ( + "svg-radial-start-fr-css-comments", + DeclaredByBestEffort, + "CSS comment", + ), + ( + "svg-radial-start-fr-used-range", + DeclaredByBestEffort, + "admitted Web used-value range", + ), + ( + "svg-radial-start-fr-units", + DeclaredByBestEffort, + "unit whose basis", + ), + ( + "svg-radial-start-fr-math", + DeclaredByBestEffort, + "uses calc()", + ), + ( + "svg-radial-start-fr-var", + DeclaredByBestEffort, + "uses var()", + ), + ( + "svg-radial-start-fr-css-wide", + DeclaredByBestEffort, + "CSS-wide value", + ), ("svg-gradient-linearrgb", DeclaredByBestEffort, "linearRGB"), // Sheet-level: the pinned cascade cannot represent stop-color, so the // declaration is named against the sheet and the gradient renders with diff --git a/docs/wg/consolidation/svg-engine-of-record.md b/docs/wg/consolidation/svg-engine-of-record.md index 056fd6a1..61ae7653 100644 --- a/docs/wg/consolidation/svg-engine-of-record.md +++ b/docs/wg/consolidation/svg-engine-of-record.md @@ -114,19 +114,18 @@ from the dated addenda below: carrying admitted repeating-pattern paint and admitted source/target filter composition. `crates/n0_cli/README.md` is the statement of record. -- **The corpus** is 1,157 Chromium-baked primitive cells plus 16 sampled frames, +- **The corpus** is 1,284 Chromium-baked primitive cells plus 16 sampled frames, with a separate sixteen-cell exact text suite whose current cells select hash-pinned Ahem and Ahem-derived bytes from explicit family/face environments, and eight exact-number artifact-geometry witnesses (six Allerta and two Bungee) under the ratified text corpus-growth law. All byte-exact except seven curved cells carrying a declared, geometrically - confined tolerance (the native-oval/conic boundary) and four gradient cells - carrying a declared one-code-value ramp-quantization tolerance (one pixel - against Chromium's Skia; 18 knife-edge pixels between this engine's own - macOS and Linux Skia builds; 336 ramp pixels under an isolated layer's - restore; 576 after a masked ramp becomes luminance alpha). The named refusal - register has 234 rows. + confined tolerance (the native-oval/conic boundary) and twelve gradient cells + carrying declared one-code-value ramp-quantization bounds. The measured + per-cell counts and causes are listed in the + [corpus record](../../../fixtures/web-first/README.md). + The named refusal register has 260 rows. - **Not claimed:** no conformance score exists or may be computed — FLIP is unratified. The FLIP record and identity-changing review are prepared, but only the owner act on gridaco/nothing#49 may authorize them and the first @@ -5581,3 +5580,99 @@ named refusal register moves from 230 to 234. The CSS-property twin, dynamic substitutions, wider text painting, external resources, and animation remain their own work. No conformance score was produced, and no FLIP record, rule, or baseline changed. + +## Radial-circle split — 2026-09-07 + +This rung replaces the broad focal-radial refusal with the bounded admission +recorded in [the command's statement of record](../../../crates/n0_cli/README.md). +It closes no checklist row. The complete listed length grammar includes +Chromium-honored source aliases and CSS comments still refused here, with no +independent row to carry those gaps: the gridaco/nothing#81/#89/#90 split +precedent applies. Wider units, calculations, substitution, and CSS-wide +context retain their own-row precedents. No CSS property matching is added. + +### The contract crux + +The original start-only proposal assumed an invertible mapping to a fixed +nonzero end circle. Chromium contradicts that restriction: a zero or negative +authored outer radius still has a live radial domain when a distinct start +circle is present. Normalizing by the outer radius cannot state that image. +The owner-ratified [ordered-circle amendment](../feat-painting/paint-model.md#amd-radial-circles) +therefore preserves both centers, both nonnegative radii, and their order. +It does not sort radii, clamp exterior centers, or add resource references to +the resolved contract. The absent extension preserves the old centered form. + +The same investigation found a shipped one-stop escape: treating a single +color as an infinite spatial domain filled 109 pixels that Chromium leaves +outside the cone, at maximum channel delta 217. The baked +`svg-radial-start-one-stop-focal` cell now preserves that exterior under the +constant ramp; repeat/reflect and zero-end companions discriminate the +related branches. Zero stops remain inert. The former broad refusal source +graduates unchanged to `svg-radial-start-graduated-focal`; its assertion of +inexpressibility is deliberately dropped only after the positive oracle +re-homes its geometry. The temporary one-stop refusal is likewise replaced +by positive domain evidence, not deleted without a witness. + +### Evidence and retained boundaries + +The [corpus record](../../../fixtures/web-first/README.md) identifies 127 new +cells: defaults, signed length syntax and invalid fallbacks; object-box and +axis/diagonal user-space percentages; viewBox mapping; independent template +inheritance and local overrides; transforms; zero, equal, reversed, tangent, +intersecting, disjoint, and containing circles; all spread modes; stop order +and alpha; and admitted fill/stroke, instance, pattern, clip, mask, filter, +nested-viewport, and HTML clients. Of those cells, 119 are byte-exact. Eight +carry the existing ramp-quantization rule with measured bounds: six singleton +pixels, 613 masked-ramp pixels, and 1,465 offset-filter restore pixels, all at +one code value. No existing oracle or tolerance changes; numeric controls +remain exact. + +The nine amplified source aliases are measured against adjacent numeric +controls before any admission claim. Chromium selects the lower neighbor in +all nine, while the opposing controls differ by 718–1,024 pixels with maximum +channel deltas 14–34. Decimal/percentage controls and the radius midpoint pair +are celled; focus midpoint pairs remain **(measured, not celled)**. The +existing direct-length provenance patrol now has nine exact-attribute refusal +fixtures here. Comments, range, units, math, substitution, and CSS-wide +context add eighteen more. The broad focal row retires, moving the named +register from 234 to 260 without weakening a remaining guard. + +Additional near-equal/tangent and effect-boundary probes are +**(measured, not celled)** where no committed witness is named. Marker-source +gradients retain their existing solid/context-solid source-profile refusal. +A highly magnified diagonal-radius experiment failed to discriminate its +adjacent Chromium controls and reached the checked shader-construction +refusal in both command admissions; it proves no new normalization order. +The diagonal cell proves the correct basis, not equality of invisible float +bits. + +The source-neutral extension crosses both paint consumers without losing any +of its six scalars. Contract tests guard exact copies, validation, attributed +preflight, and paint/damage changes. The unchanged frozen `.grida` encoder and +Draft0 writer cannot represent a present circle pair and reject it instead +of silently omitting it. The legacy importer is not broadened by this work. +Direct immutable-frame execution carries the new geometry. The translated +preview raster cache does not: a native scene exposed two one-code-value +differences between its offscreen translation and fresh drawing +**(measured, not celled)**. A typed owner-attributed refusal occurs before +cache or canvas mutation; its guarding test verifies rejection and recovery. +This is a cache-policy boundary, not a second semantic interpretation. + +### Gate sensitivity + +Four deliberate implementation mutations fail the full primitive gate loudly. +Discarding the start radius fails 79 cells, reaching 3,072 changed pixels and +maximum channel delta 255; the bounded mask/filter cells also fail well beyond +their declarations. Reversing the two circles fails 108 cells, reaching all +4,096 pixels and delta 255. Resolving `fr%` against width instead of the +normalized diagonal fails both the direct and viewBox-mapped radius cells by +1,116 pixels at delta 214 each. Restoring the premature one-stop constant fold +fails four domain cells: three change 109 pixels and the zero-end witness +changes 1,938, all at delta 217. These are mutation verdicts, not additional +corpus cells. Each mutation is removed before the final full gate. + +The corpus moves from 1,157 to 1,284 primitive cells. The sixteen sampled +frames, sixteen exact text cells, and eight real-font geometry witnesses are +unchanged. External I/O, text, marker-source expansion, animation, and the +separately tracked degenerate-gradient family remain separate work. No +conformance score or FLIP record, rule, or baseline is touched. diff --git a/docs/wg/consolidation/web-checklist.md b/docs/wg/consolidation/web-checklist.md index 13a30cd6..51532c6d 100644 --- a/docs/wg/consolidation/web-checklist.md +++ b/docs/wg/consolidation/web-checklist.md @@ -2483,6 +2483,20 @@ for attributes the platform ships ahead of the SVG 2 indexes. - [ ] `fr` - [ ] `fx` - [ ] `fy` + +> **2026-09-07 radial-circle split:** 127 Chromium-baked cells carry the +> signed number/percentage/`px` slice, independent template defaults, axis and +> diagonal bases, circle order, exterior focus, zero/equal/reversed radii, +> one-stop cone domains, spreads, transforms, and admitted paint clients. +> These three rows remain open: valid source-precision aliases and CSS +> comments are honored by Chromium but refused here, with no independent +> checklist row to carry that gap (gridaco/nothing#81/#89/#90). Wider units, +> computed functions, substitution, and CSS-wide context retain their own-row +> precedents; those do not excuse the precision/comment split. Twenty-seven +> exact-attribute refusal fixtures replace the former broad focal row. +> No CSS-property row changes. See the +> [radial-circle evidence](./svg-engine-of-record.md#radial-circle-split--2026-09-07). + - [x] `gradientTransform` - [x] `gradientUnits` - [ ] `href` diff --git a/docs/wg/feat-painting/paint-model.md b/docs/wg/feat-painting/paint-model.md index fed09afa..0f1d0a5f 100644 --- a/docs/wg/feat-painting/paint-model.md +++ b/docs/wg/feat-painting/paint-model.md @@ -14,9 +14,10 @@ format: md **Status:** Ratified — accepted via [gridaco/nothing#33](https://github.com/gridaco/nothing/issues/33) -(closed by the owner, 2026-07-18). Two items flagged in the body remain -pinned as follow-up amendments: diamond-gradient extension behavior and -the tri-state run-fill verification. +(closed by the owner, 2026-07-18), with the ordered radial-circle +amendment accepted by the same owner on 2026-09-07. Two items flagged in the +body remain pinned as proposed follow-up amendments: diamond-gradient +extension behavior and the tri-state run-fill verification. This document is written for an engine developer deciding, at promotion time, what the shared paint vocabulary is — the leaf-level value types @@ -70,7 +71,8 @@ Out of scope, each with its owning home: | **Paint** | A self-contained recipe for producing color over a region: one of solid, linear, radial, sweep, diamond gradient, or image. | | **Paint stack** | An ordered, finite list of paints composited in sequence; entry zero is bottommost. | | **Stroke application** | One stroke geometry — width, align, cap, join, miter limit, dash pattern — carrying its own paint stack. Repeatable per node. | -| **Unit gradient space**| The `[0,1] × [0,1]` box in which radial, sweep, and diamond gradients are defined, with implicit center `(0.5, 0.5)`. | +| **Gradient-local space** | The coordinate system of intrinsic gradient geometry, before placement into the paint target box. Coordinates are finite but not confined to that box. | +| **Unit gradient space**| The `[0,1] × [0,1]` reference box used by implicit radial, sweep, and diamond geometry, with center `(0.5, 0.5)`. | | **Alignment point** | A point in center-based normalized coordinates over the paint target box: `(-1,-1)` top-left, `(0,0)` center, `(1,1)` bottom-right. | | **Stop** | A pair of a scalar offset in `[0,1]` and a color. | | **Quantization policy**| The declared rule a boundary applies when converting a unit-interval scalar channel to an 8-bit channel. | @@ -383,14 +385,14 @@ statements** — declared, testable deviations — instead of silent drops. ### Evidence -- All three surfaces (production runtime, v2 proof, archive schema) - agree on the field sets below with two known pressure points: - per-stop opacity and the radial focal point. +- All three original surfaces (production runtime, v2 proof, archive schema) + agreed on the field sets below with two known pressure points: + per-stop opacity and radial circle geometry. - The SVG import path today drops a source gradient's per-stop opacity - and focal point on the way to the engine model — the focal point - survives into the import's intermediate representation and is - discarded at the packing step; both drops are annotated in-source as - model mismatches and are invisible to the user. + and off-center start point on the way to the engine model — that point + survives into the import's intermediate representation and is discarded at + the packing step, while a nonzero start radius is not represented there at + all. Both losses are model mismatches and are invisible to the user. - Source SVG patterns are mapped to a transparent paint — a silent erasure; pattern paint servers are a tracked capability ([gridaco/nothing#14](https://github.com/gridaco/nothing/issues/14)). @@ -400,19 +402,20 @@ statements** — declared, testable deviations — instead of silent drops. **Common to all six variants:** active flag, opacity, blend mode (decision 3). For solid paints, opacity is the color alpha (decision 1). -**One parameterization rule for gradients.** Every gradient is defined -in a normalized space over the paint target box and positioned by an -affine transform composed as `scale(width, height) × user-transform`: -the gradient definition itself is resolution-independent, and all -rotation, skew, and offset live in the user transform — never baked -into intrinsic parameters. +**One placement rule for gradients.** Every gradient has intrinsic geometry +in gradient-local space and an affine placement composed as +`scale(width, height) × user-transform`. The user transform maps gradient-local +coordinates into the target box's normalized space. Geometry and placement +remain distinct facts: rotation, skew, and target placement do not mutate the +intrinsic parameters. Explicit circle coordinates use the same direct scalar +space as their radii, without an intermediate alignment-point conversion. | Variant | Intrinsic parameters | Stops | Tile mode | Transform | | ------- | ------------------------------------------------------------------------------------ | ----- | ----------------------------- | --------- | | Linear | Two endpoints as alignment points (defaults: center-left → center-right) | Yes | Yes | Yes | -| Radial | Implicit center `(0.5, 0.5)`, radius `0.5` in unit gradient space | Yes | Yes | Yes | +| Radial | Optional ordered start and end circles; absent means centered start point `(0.5, 0.5)`, radius `0`, and end circle `(0.5, 0.5)`, radius `0.5` | Yes | Yes | Yes | | Sweep | Implicit center `(0.5, 0.5)`; angular domain one full turn, clockwise from 0° | Yes | No — the angular domain is closed; a full turn has no exterior to tile | Yes | -| Diamond | The radial field evaluated under the Manhattan distance metric, same unit space | Yes | No — no tile mode is carried on any surface today; beyond-unit clamp behavior is proposed by `AMD-DIAMOND-CLAMP` below | Yes | +| Diamond | Implicit centered radius-`0.5` field under the Manhattan distance metric in unit gradient space | Yes | No — no tile mode is carried on any surface today; beyond-unit clamp behavior is proposed by `AMD-DIAMOND-CLAMP` below | Yes | **Stop:** `(offset ∈ [0,1], color)` — recommended without a separate opacity field; see the contested point below. @@ -446,35 +449,37 @@ it is nonconformant. The sub-8-bit precision loss is bounded by half a quantization step and is accepted until the wide-gamut successor of decision 1 revisits channel depth. -### Contested point B — the radial focal point - -A focal (two-point) radial gradient places the 0-offset point away from -the circle's center, producing isolines that are non-concentric circles. -No affine transform of a concentric radial can express this: affine maps -send concentric circles to concentric ellipses, so the focal family is -strictly outside the current parameterization. This is why the import -pipeline can only drop a source focal point today. - -| Question | Keep radial concentric-only | Optional focal point in unit gradient space (recommended) | Full two-point conical (two circles) | -| ----------------------------------------------- | --------------------------------------------------------------- | ----------------------------------------------------------------- | ---------------------------------------------------------- | -| Expressive coverage of the domain | Loses SVG focal gradients permanently | Covers SVG focal semantics (focus + one circle) | Covers SVG and more (two radii) | -| Backend support | Native everywhere | Native two-point conical exists in the raster backends | Same | -| Cost | None | One optional field, defaulting to center (degenerate = today) | Two extra parameters with no current producer | -| Design-tool precedent | Matches Figma-style radial | Superset; default behavior unchanged | No authoring surface wants the second radius today | - -**Recommendation:** extend the canonical radial with an *optional focal -point*, expressed in unit gradient space and defaulting to the center — -the default is byte-identical to today's behavior. Until the extension -is ratified and lands (a schema change, so promotion-program work — the -seam program forbids schema motion), the **conformance statement** is: -an importer meeting a source focal point must declare the deviation in -its import report; silent dropping is nonconformant. +### Contested point B — ordered radial circles + +A two-circle radial gradient maps the beginning and end of its ramp to two +circles. A zero-radius start circle is a focal point; a positive-radius start +circle maps offset zero to a perimeter. Moving either start center or start +radius can produce non-concentric isolines and a domain that does not cover +the whole paint target. No affine transform of a concentric radial can state +that family: affine maps preserve concentricity. A start circle beside a +fixed, nonzero end circle is also insufficient: an invertible affine cannot +collapse the end circle to a point while preserving a live start circle. + +| Candidate | Expressive boundary | Contract cost | Disposition | +| --------- | ------------------- | ------------- | ----------- | +| Concentric-only | No independent start geometry | No additional fact | Insufficient | +| Optional focal point | Cannot state a positive start radius | One optional point | Insufficient | +| Optional start circle, fixed end circle | Cannot state a point-sized end alongside a live start | One optional circle | Insufficient | +| Optional ordered circle pair | States both ramp boundaries, including either point-sized boundary | Two circles as one optional geometry fact | Chosen | + +**Decision:** carry an optional ordered pair of circles in gradient-local +space. Absence retains the original centered radial. Presence preserves both +centers and radii exactly, without normalizing either circle to the implicit +end circle. `AMD-RADIAL-CIRCLES` below fixes the domain. An interchange surface +that cannot state a present pair must reject that value or report a declared +deviation; silently replacing it with a concentric radial is nonconformant. ### Conformance statements (summary) 1. Per-stop opacity: fold into stop alpha; never drop. -2. Radial focal point: represent once ratified; until then, a declared - deviation, never a silent drop. +2. Ordered radial circles: preserve both centers, both radii, and their order; + a boundary that cannot carry any of these facts reports or rejects the + deviation, never silently drops it. 3. Source spread/tile methods on sweep or diamond gradients: not representable; declared deviation. 4. Source pattern paint servers: not representable @@ -504,20 +509,57 @@ contract the promotion program implements, in vocabulary terms: boundary: layout-affecting values remain with the text-resolution contract; run fills, decoration color, and text strokes are governed by this spec. -- **Gradients and images** — field sets follow the ratified decisions; - the radial focal extension remains proposed, so - importers upgrade every silent drop named in - decision 5 to its conformance behavior. +- **Gradients and images** — field sets follow the ratified decisions. The + ordered radial-circle extension is part of the shared vocabulary; boundaries + that predate it upgrade every silent drop named in decision 5 to an explicit + conformance behavior. ## Pinned amendments -These amendments are **proposed and re-pinned**, not ratified. Their named -owner is `universe@grida.co`, the -[consolidation program owner](../consolidation/index.md). Ratification remains -an owner gate under **AMD**. For a leaf whose conformance depends on an -amendment, ratification precedes that leaf's D-C disposition and deletion of -any mapping that depends on it. It does not block D-C dispositions for -unrelated leaves. +The named owner of these amendments is `universe@grida.co`, the +[consolidation program owner](../consolidation/index.md). Each amendment states +whether it is ratified or proposed. Ratification remains an owner gate under +**AMD**. For a leaf whose conformance depends on an amendment, ratification +precedes that leaf's D-C disposition and deletion of any mapping that depends +on it. It does not block D-C dispositions for unrelated leaves. + +### AMD-RADIAL-CIRCLES + +**Status:** Ratified by explicit owner GO on 2026-09-07. This replaces the +start-only proposal: a fixed nonzero end circle excluded point-sized ends, +which cannot be recovered by invertible placement. + +A radial gradient may carry one optional ordered geometry value consisting +of a start circle and an end circle in gradient-local space: + +- absence means start center `(0.5, 0.5)`, radius `0`, and end center + `(0.5, 0.5)`, radius `0.5`; it preserves the original centered radial; +- both present centers are finite direct coordinate pairs and may lie + outside the unit square; +- both present radii are finite and non-negative; either may be zero and + the start radius may exceed the end radius; +- equal circles, including equal point-sized circles, are representable; +- offset zero maps to the start-circle perimeter and offset one maps to the + end-circle perimeter, so the two circles are ordered facts; +- consumers do not swap circles, clamp a center into another circle, or + normalize away a radius; and +- presence is retained even when a pair numerically equals the implicit + geometry. This preserves exact supplied values without a hidden rewrite. + +The two circles state intrinsic geometry, not rasterization policy or a +resource reference. The affine carries placement, scale, rotation, and skew. +Representation of a numeric pair does not promise every backend can evaluate +it: a backend must preserve the ordered geometry and its painted domain or +refuse explicitly, including for equal circles and other degeneracies. A +constant color ramp does not by itself permit replacing that domain with an +unbounded solid color. Spread behavior operates on the ordered ramp parameter, +not by moving the circles. + +A serialization or import boundary whose radial representation lacks the +circle pair preserves the absent form exactly and rejects or declares every +present form. Schema evolution remains a separate owner decision. The circle +extension does not widen any earlier source grammar merely because the runtime +can carry the fact. ### AMD-DIAMOND-CLAMP diff --git a/fixtures/web-first/README.md b/fixtures/web-first/README.md index 31c35b0b..6a059c27 100644 --- a/fixtures/web-first/README.md +++ b/fixtures/web-first/README.md @@ -19,8 +19,8 @@ Every root primitive here is a closed enumeration in `primitives.json` with a committed Chromium oracle beside it. Text follows the ratified corpus-growth law in its own closed [text estate](./text/README.md): sixteen exact text cells and eight exact-number real-font artifact-geometry witnesses. The current evidence -estate is 1,157 primitive cells plus 16 sampled frames, those twenty-four text -witnesses, and 234 named refusal rows. Pixel cells use byte equality: what each +estate is 1,284 primitive cells plus 16 sampled frames, those twenty-four text +witnesses, and 260 named refusal rows. Pixel cells use byte equality: what each corpus admits is exactly what the engine renders pixel-for-pixel, except only the primitive rows carrying an explicit measured tolerance block. The real-font witness grades geometry before rasterization and makes no Chromium @@ -28,6 +28,10 @@ pixel claim. | File | Role | | --- | --- | +| `svg-radial-start-{default,explicit-default,fx-*,fy-*,fxy-*,fr-*,outer-*,one-stop-*,zero-stops-focal,same-circle-*}.svg` | Ordered radial-circle evidence: independent focus coordinates, signed/zero/positive start radius, equal/reversed/zero end radii, exterior focus, tile behavior, and one-stop transparent domains. The older focal refusal source graduates unchanged as `svg-radial-start-graduated-focal.svg`; the one-stop witness preserves the previously silent constant-fold escape as positive evidence. | +| `svg-radial-start-{grammar-*,box-percent,user-*,mapped-viewbox,template-*,transform-*,relation-*,spread-*,stops-*}.svg` | Resource-length grammar/defaults and placement: accepted signed/exponent forms versus invalid whitespace-only, trailing-dot, comma, and non-ASCII-whitespace fallbacks; axis and diagonal percentage bases; mapped user units; per-field template inheritance and local overrides; every spread mode across distinct circle relationships; transforms, stop order, duplicate stops, and alpha. Valid values surrounded by SVG whitespace match their unpadded controls in Chromium and both CLI admissions (measured, not celled). The decimal/percentage adjacent numeric controls and radius midpoint pair are byte-exact. | +| `svg-radial-start-client-*.svg` · `svg-radial-start-transparent-cone.svg` · `html-inline-svg-radial-start.html` | Paint clients through shapes, path/stroke/dashes, paint order, channel/group opacity, existing `` instances, pattern source, clip, mask, offset filter, nested viewport, transparent exterior, and HTML ingress. This does not expand the marker-source paint profile or external-resource boundary. | +| *(measured, not celled — radial-circle remainder)* | Twice-deterministic Chromium 149 matrices and both actual CLI admissions cover 35 core, 75 precision/grammar, 262 interaction, 64 boundary, two HTML, and two graduation sources. The nine amplified decimal/percentage/midpoint aliases each select the lower adjacent binary32 control; their opposing controls differ by 718–1,024 pixels at maximum channel deltas 14–34. Comments, wider units, computed functions, substitution, CSS-wide values, and range cases reach the exact-attribute refusals. Marker-source gradients reach the existing solid/context-solid marker-profile refusal. Sampled near-equal and tangent neighbors expose only the existing one-code-value ramp class; this is not a universal precision claim. A separate three-source, highly magnified diagonal-rounding experiment did not discriminate its adjacent Chromium controls and reached the checked shader-construction refusal in both CLI admissions: it establishes no new used-value rounding claim. | | `text/` | The closed text estate: sixteen exact pixel cells plus eight artifact-geometry witnesses (six Allerta, two Bungee); see [`text/README.md`](./text/README.md). | | `text/svg-text-tspan-paint-ownership.svg` · `text/geometry/svg-text-allerta-tspan-kerning.svg` | T4a's bounded flat `` split. The Ahem cell makes parent/child opaque solid fills, inherited paint, whitespace collapse across wrapper boundaries, and one parent anchor byte-exact. The Allerta `ff` geometry witness keeps Chromium's 2330/2355 advances and 4685 total across a paint boundary; shaping the fragments independently would total 4710. Bungee scratch probes establish whole-cluster ownership by the run containing the cluster's first scalar (measured, not celled). Replacing every run paint with the parent changes 1,600px/Δ197, and anchoring the runs independently changes 1,200px/Δ218. Nominal advances and parent-only paint each made `just gate` fail before restoration. Four focused refusal rows retained positioned, shaping-changing, wider-paint/effect, and nested children at that checkpoint. No checklist row closed. | | `text/svg-text-positioned-chunks.svg` · `text/geometry/svg-text-allerta-positioned-combining.svg` | T4b's bounded positioned-chunk split. The exact Ahem cell crosses x/y chunk resets, per-chunk middle anchoring, dx/dy lists, omitted members, paint ownership, integer transforms, canonical whitespace, and ``. The Allerta witness distinguishes an absolute shaping split (first `f` advance 2355) from preserved in-chunk kerning (2330/2355), and proves that a `dx` on the combining scalar carries to the following `Z`; Chromium and the projection agree exactly on total 13585 and starts 5000, 8330, 10685, and 15005. Repeated/negative positions, y-only chunks, excess members, and percentage bases are measured, not celled. Three new focused refusal rows retain wider value grammar, whitespace-index ambiguity, and an absolute split inside a combining cluster; parent lists, `rotate`, and `textLength` remain separate. Dropping first-character `dx` made the gate fail by 550 exact Ahem pixels before restoration. No checklist row closes. | @@ -367,7 +371,7 @@ still fails loudly, and `svg-circle-defaults-clip` shows the bar is not unreachable: it bakes byte-exact and declares no tolerance at all. The gradient cells brought a second tolerance kind, `ramp-quantization`, -declared on four cells with their measured bounds — always one code value, +declared on twelve cells with their measured bounds — always one code value, never confined to a boundary ring (a ramp has none; none is needed, since a wrong gradient moves far more pixels by far more than one code value and still fails loudly). `svg-gradient-radial-custom` differs in 1 pixel: an @@ -383,7 +387,14 @@ found the day the gate learned to sweep the whole suite before failing. and the two Skia builds round one code value apart across the ramp — the same physics, multiplied by the layer. `svg-mask-gradient-ramp` differs at 576 pixels by one code value after that dithered ramp is converted into -luminance alpha. Every other gradient cell — ramps, seams, hard stops, the +luminance alpha. The radial-circle rung adds eight declarations, never +changing an existing cell: `svg-radial-start-fxy-quarter`, `fx-on-end`, +`on-end-repeat`, `on-end-reflect`, `grammar-fy-signed`, and +`grammar-fy-exponent` each differ at one pixel; `client-mask` differs at 613 +pixels after mask composition, and `client-filter` at 1,465 after an offset +filter's layer restore. Each of those abbreviated names has the same +`svg-radial-start-` prefix. Bounds are measured counts, with no headroom; +adjacent numeric controls remain exact. Every other gradient cell — ramps, seams, hard stops, the dither itself, the ramp *under* the fold — is byte-exact. Render a primitive through the `n0` product command — since diff --git a/fixtures/web-first/STATUS.md b/fixtures/web-first/STATUS.md index 74ae7156..877ec689 100644 --- a/fixtures/web-first/STATUS.md +++ b/fixtures/web-first/STATUS.md @@ -19,13 +19,12 @@ Not a conformance claim: no score is computed or implied (FLIP is unratified), and the corpus enumerates constructs, not the SVG surface. -## Chromium-baked cells (1157) +## Chromium-baked cells (1284) -Each renders byte-exact against its committed Chromium oracle -(seven curved cells and four gradient ramps carry a declared, bounded -tolerance — see [README.md](./README.md)). Every thumbnail below -*is* that committed oracle, which byte-exactness makes this -engine's own render too; hover for the cell's name, click through +Cells are checked against their committed Chromium oracles using +exact bytes unless a manifest entry declares a measured, bounded +tolerance — see [README.md](./README.md). Every thumbnail below +*is* that committed oracle; hover for the cell's name, click through to its fixture source. No new image is committed for this view. html-inline-svg-ancestor-opacity @@ -33,6 +32,7 @@ to its fixture source. No new image is committed for this view. html-inline-svg-nested-viewport html-inline-svg-paint-order html-inline-svg-pattern +html-inline-svg-radial-start html-inline-svg-vector-effect html-webpage-mockup svg-anchor-container @@ -978,6 +978,132 @@ to its fixture source. No new image is committed for this view. svg-preserve-aspect-ratio-explicit svg-preserve-aspect-ratio-none-stretch svg-preserve-aspect-ratio-slice-clip +svg-radial-start-box-percent +svg-radial-start-client-channel-opacity +svg-radial-start-client-clip +svg-radial-start-client-dashes +svg-radial-start-client-ellipse +svg-radial-start-client-filter +svg-radial-start-client-group-opacity +svg-radial-start-client-mask +svg-radial-start-client-nested +svg-radial-start-client-order +svg-radial-start-client-path +svg-radial-start-client-pattern +svg-radial-start-client-stroke +svg-radial-start-client-transform +svg-radial-start-client-use +svg-radial-start-default +svg-radial-start-explicit-default +svg-radial-start-fr-decimal-higher +svg-radial-start-fr-decimal-lower +svg-radial-start-fr-equal-r +svg-radial-start-fr-greater-r +svg-radial-start-fr-midpoint-higher +svg-radial-start-fr-midpoint-lower +svg-radial-start-fr-negative +svg-radial-start-fr-negative-zero +svg-radial-start-fr-percentage-higher +svg-radial-start-fr-percentage-lower +svg-radial-start-fr-quarter +svg-radial-start-fx-decimal-higher +svg-radial-start-fx-decimal-lower +svg-radial-start-fx-negative +svg-radial-start-fx-on-end +svg-radial-start-fx-outside +svg-radial-start-fx-percentage-higher +svg-radial-start-fx-percentage-lower +svg-radial-start-fx-quarter +svg-radial-start-fxy-fr-quarter +svg-radial-start-fxy-quarter +svg-radial-start-fy-decimal-higher +svg-radial-start-fy-decimal-lower +svg-radial-start-fy-percentage-higher +svg-radial-start-fy-percentage-lower +svg-radial-start-fy-quarter +svg-radial-start-graduated-focal +svg-radial-start-grammar-fr-comma +svg-radial-start-grammar-fr-exponent +svg-radial-start-grammar-fr-integer +svg-radial-start-grammar-fr-nbsp +svg-radial-start-grammar-fr-signed +svg-radial-start-grammar-fr-trailingdot +svg-radial-start-grammar-fr-whitespace +svg-radial-start-grammar-fx-comma +svg-radial-start-grammar-fx-exponent +svg-radial-start-grammar-fx-integer +svg-radial-start-grammar-fx-nbsp +svg-radial-start-grammar-fx-signed +svg-radial-start-grammar-fx-trailingdot +svg-radial-start-grammar-fx-whitespace +svg-radial-start-grammar-fy-comma +svg-radial-start-grammar-fy-exponent +svg-radial-start-grammar-fy-integer +svg-radial-start-grammar-fy-nbsp +svg-radial-start-grammar-fy-signed +svg-radial-start-grammar-fy-trailingdot +svg-radial-start-grammar-fy-whitespace +svg-radial-start-mapped-viewbox +svg-radial-start-on-end-reflect +svg-radial-start-on-end-repeat +svg-radial-start-one-stop-default +svg-radial-start-one-stop-exterior-reflect +svg-radial-start-one-stop-exterior-repeat +svg-radial-start-one-stop-focal +svg-radial-start-outer-negative-focal +svg-radial-start-outer-zero-focal +svg-radial-start-outer-zero-fr +svg-radial-start-outer-zero-fx +svg-radial-start-outer-zero-one-stop-focal +svg-radial-start-outside-positive-fr +svg-radial-start-relation-above +svg-radial-start-relation-below +svg-radial-start-relation-containing +svg-radial-start-relation-disjoint +svg-radial-start-relation-external-tangent +svg-radial-start-relation-internal-tangent +svg-radial-start-relation-intersecting +svg-radial-start-relation-left +svg-radial-start-relation-right +svg-radial-start-same-circle-reflect +svg-radial-start-same-circle-repeat +svg-radial-start-spread-circle-reflect +svg-radial-start-spread-circle-repeat +svg-radial-start-spread-outside-reflect +svg-radial-start-spread-outside-repeat +svg-radial-start-spread-reversed-reflect +svg-radial-start-spread-reversed-repeat +svg-radial-start-spread-zero-end-reflect +svg-radial-start-spread-zero-end-repeat +svg-radial-start-stops-alpha +svg-radial-start-stops-duplicate +svg-radial-start-stops-edges +svg-radial-start-stops-unsorted +svg-radial-start-template-all +svg-radial-start-template-empty-fr +svg-radial-start-template-empty-fx +svg-radial-start-template-empty-fy +svg-radial-start-template-explicit-focus +svg-radial-start-template-fr-negative +svg-radial-start-template-fr-zero +svg-radial-start-template-invalid-fr +svg-radial-start-template-local-center +svg-radial-start-template-multihop +svg-radial-start-template-override-fr +svg-radial-start-template-override-fx +svg-radial-start-template-override-fy +svg-radial-start-template-xlink +svg-radial-start-transform-rotate +svg-radial-start-transform-scale +svg-radial-start-transform-singular +svg-radial-start-transform-skew +svg-radial-start-transform-translate +svg-radial-start-transparent-cone +svg-radial-start-user-percent-fr +svg-radial-start-user-percent-fx +svg-radial-start-user-percent-fy +svg-radial-start-user-px +svg-radial-start-zero-stops-focal svg-rect-rounded svg-rect-rounded-clamp svg-rect-rounded-elliptical @@ -1186,7 +1312,7 @@ to its fixture source. No new image is committed for this view. svg-visibility-rule-beats-attribute svg-visibility-unhide -## The refusal register (234) +## The refusal register (260) What the slice refuses, by name, in the compiler's own words — **both refuse** is a document-level contract; **declared** renders @@ -1284,7 +1410,6 @@ its row into the cells above. | `svg-geometry-xywh-used-range` | declared | skipped svg/rect[2]: unsupported SVG geometry: x exceeds the admitted Web used-value range; skipped svg/rect[3]: unsupported SVG geometry: x exceeds the admitted Web used-value range; skipped svg/rect[4]: unsupported SVG geometry: y exceeds the admitted Web used-value range; skipped svg/rect[5]: unsupported SVG geometry: y exceeds the admitted Web used-value range; skipped svg/rect[6]: unsupported SVG geometry: width exceeds the admitted Web used-value range; skipped svg/rect[7]: unsupported SVG geometry: height exceeds the admitted Web used-value range | | `svg-geometry-xywh-var-values` | declared | skipped svg/g[1]/rect[1]: attribute x="var(--x)" is not a number; skipped svg/g[1]/rect[2]: attribute y="var(--y)" is not a number; skipped svg/g[1]/rect[3]: attribute width="var(--w)" is not a number; skipped svg/g[1]/rect[4]: attribute height="var(--h)" is not a number | | `svg-gradient-degenerate-precision` | declared | skipped svg/rect[1]: unsupported fill value "url(#a): a degenerate paint server substitutes a colour this build cannot reproduce: the collapsed alpha is not exactly representable in eight bits, and Chromium dithers it"; skipped svg/rect[2]: unsupported fill value "url(#b): a degenerate paint server collapses two alpha stages, and their product is not exactly representable in eight bits"; skipped svg/rect[3]: unsupported fill value "url(#c): a degenerate paint server collapses before post-paint opacity, and the staged product is not exactly representable in eight bits"; skipped svg/rect[4]: unsupported fill value "url(#d): a degenerate paint server substitutes a colour this build cannot reproduce: the collapsed alpha is not exactly representable in eight bits, and Chromium dithers it"; skipped svg/rect[5]: unsupported fill value "url(#e): a degenerate paint server averages a ramp whose stop is not exactly representable in eight bits, and Chromium dithers the result" | -| `svg-gradient-focal` | declared | skipped svg/rect[1]: unsupported fill value "url(#g): the radial gradient has a focal point or focal radius, which the shared radial paint leaf cannot state (concentric radials only)" | | `svg-gradient-linearrgb` | declared | skipped svg/rect[1]: unsupported fill value "url(#g): color-interpolation: linearRGB interpolates stops in linear-light sRGB, which this slice does not execute (sRGB interpolation only)" | | `svg-gradient-stop-css` | declared | declaration ignored at svg/style[1]: a stylesheet declares stop-color, which this cascade does not represent; elements it matches render without it | | `svg-gradient-stop-function` | declared | skipped svg/rect[1]: unsupported fill value "url(#g): a stop-opacity is a function this build cannot evaluate without a computation context" | @@ -1367,6 +1492,33 @@ its row into the cells above. | `svg-preserve-aspect-ratio-case-folded` | **both refuse** | preserveAspectRatio "xmidymid meet" is invalid | | `svg-preserve-aspect-ratio-defer` | **both refuse** | preserveAspectRatio "defer xMidYMid meet" is invalid | | `svg-preserve-aspect-ratio-invalid-align` | **both refuse** | preserveAspectRatio "xMidYMiddle meet" is invalid | +| `svg-radial-start-fr-css-comments` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fr contains a CSS comment this direct length parser cannot tokenize" | +| `svg-radial-start-fr-css-wide` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fr uses the CSS-wide value initial, whose resource-side cascade is not represented at this Stylo pin" | +| `svg-radial-start-fr-decimal-precision` | declared | skipped svg/g[1]/rect[1]: unsupported fill value "url(#g): gradient geometry fr numeric precision alias loses Chromium used-value provenance" | +| `svg-radial-start-fr-math` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fr uses calc(), whose computed length is not represented by the direct resource decoder" | +| `svg-radial-start-fr-midpoint-precision` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fr numeric precision alias loses Chromium used-value provenance" | +| `svg-radial-start-fr-percentage-precision` | declared | skipped svg/g[1]/rect[1]: unsupported fill value "url(#g): gradient geometry fr numeric precision alias loses Chromium used-value provenance" | +| `svg-radial-start-fr-units` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fr=\"4em\" uses a unit whose basis this slice does not consume (numbers, px, and percentages only)" | +| `svg-radial-start-fr-used-range` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fr exceeds the admitted Web used-value range" | +| `svg-radial-start-fr-var` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fr uses var(), whose computed length is not represented by the direct resource decoder" | +| `svg-radial-start-fx-css-comments` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fx contains a CSS comment this direct length parser cannot tokenize" | +| `svg-radial-start-fx-css-wide` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fx uses the CSS-wide value initial, whose resource-side cascade is not represented at this Stylo pin" | +| `svg-radial-start-fx-decimal-precision` | declared | skipped svg/g[1]/rect[1]: unsupported fill value "url(#g): gradient geometry fx numeric precision alias loses Chromium used-value provenance" | +| `svg-radial-start-fx-math` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fx uses calc(), whose computed length is not represented by the direct resource decoder" | +| `svg-radial-start-fx-midpoint-precision` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fx numeric precision alias loses Chromium used-value provenance" | +| `svg-radial-start-fx-percentage-precision` | declared | skipped svg/g[1]/rect[1]: unsupported fill value "url(#g): gradient geometry fx numeric precision alias loses Chromium used-value provenance" | +| `svg-radial-start-fx-units` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fx=\"4em\" uses a unit whose basis this slice does not consume (numbers, px, and percentages only)" | +| `svg-radial-start-fx-used-range` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fx exceeds the admitted Web used-value range" | +| `svg-radial-start-fx-var` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fx uses var(), whose computed length is not represented by the direct resource decoder" | +| `svg-radial-start-fy-css-comments` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fy contains a CSS comment this direct length parser cannot tokenize" | +| `svg-radial-start-fy-css-wide` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fy uses the CSS-wide value initial, whose resource-side cascade is not represented at this Stylo pin" | +| `svg-radial-start-fy-decimal-precision` | declared | skipped svg/g[1]/rect[1]: unsupported fill value "url(#g): gradient geometry fy numeric precision alias loses Chromium used-value provenance" | +| `svg-radial-start-fy-math` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fy uses calc(), whose computed length is not represented by the direct resource decoder" | +| `svg-radial-start-fy-midpoint-precision` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fy numeric precision alias loses Chromium used-value provenance" | +| `svg-radial-start-fy-percentage-precision` | declared | skipped svg/g[1]/rect[1]: unsupported fill value "url(#g): gradient geometry fy numeric precision alias loses Chromium used-value provenance" | +| `svg-radial-start-fy-units` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fy=\"4em\" uses a unit whose basis this slice does not consume (numbers, px, and percentages only)" | +| `svg-radial-start-fy-used-range` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fy exceeds the admitted Web used-value range" | +| `svg-radial-start-fy-var` | declared | skipped svg/rect[2]: unsupported fill value "url(#g): gradient geometry fy uses var(), whose computed length is not represented by the direct resource decoder" | | `svg-smil-animate-transform` | declared | skipped svg/g[1]: its authored state is overridden at document load by the unsupported animation at svg/g[1]/animateTransform[1]: animation element is outside the rect-x proving slice | | `svg-smil-number-precision-alias` | declared | skipped svg/rect[2]: its authored state is overridden at document load by the unsupported animation at svg/rect[2]/animate[1]: from source number loses Chromium used-value provenance at the binary32 normalization boundary | | `svg-smil-number-source-syntax` | declared | skipped svg/rect[2]: its authored state is overridden at document load by the unsupported animation at svg/rect[2]/animate[1]: from="1." is not a unitless SVG number | diff --git a/fixtures/web-first/chromium/html-inline-svg-radial-start.png b/fixtures/web-first/chromium/html-inline-svg-radial-start.png new file mode 100644 index 00000000..9afa39cb Binary files /dev/null and b/fixtures/web-first/chromium/html-inline-svg-radial-start.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-box-percent.png b/fixtures/web-first/chromium/svg-radial-start-box-percent.png new file mode 100644 index 00000000..3e43dcc8 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-box-percent.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-client-channel-opacity.png b/fixtures/web-first/chromium/svg-radial-start-client-channel-opacity.png new file mode 100644 index 00000000..dba16a20 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-client-channel-opacity.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-client-clip.png b/fixtures/web-first/chromium/svg-radial-start-client-clip.png new file mode 100644 index 00000000..755018da Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-client-clip.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-client-dashes.png b/fixtures/web-first/chromium/svg-radial-start-client-dashes.png new file mode 100644 index 00000000..979f5eb3 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-client-dashes.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-client-ellipse.png b/fixtures/web-first/chromium/svg-radial-start-client-ellipse.png new file mode 100644 index 00000000..bfb450d8 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-client-ellipse.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-client-filter.png b/fixtures/web-first/chromium/svg-radial-start-client-filter.png new file mode 100644 index 00000000..672066bc Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-client-filter.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-client-group-opacity.png b/fixtures/web-first/chromium/svg-radial-start-client-group-opacity.png new file mode 100644 index 00000000..a79e35ba Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-client-group-opacity.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-client-mask.png b/fixtures/web-first/chromium/svg-radial-start-client-mask.png new file mode 100644 index 00000000..6440709d Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-client-mask.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-client-nested.png b/fixtures/web-first/chromium/svg-radial-start-client-nested.png new file mode 100644 index 00000000..c860bd4e Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-client-nested.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-client-order.png b/fixtures/web-first/chromium/svg-radial-start-client-order.png new file mode 100644 index 00000000..b82e2070 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-client-order.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-client-path.png b/fixtures/web-first/chromium/svg-radial-start-client-path.png new file mode 100644 index 00000000..59a94c6e Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-client-path.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-client-pattern.png b/fixtures/web-first/chromium/svg-radial-start-client-pattern.png new file mode 100644 index 00000000..b1c5b5e4 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-client-pattern.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-client-stroke.png b/fixtures/web-first/chromium/svg-radial-start-client-stroke.png new file mode 100644 index 00000000..d9ef3898 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-client-stroke.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-client-transform.png b/fixtures/web-first/chromium/svg-radial-start-client-transform.png new file mode 100644 index 00000000..c46d5c44 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-client-transform.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-client-use.png b/fixtures/web-first/chromium/svg-radial-start-client-use.png new file mode 100644 index 00000000..ed0dff6d Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-client-use.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-default.png b/fixtures/web-first/chromium/svg-radial-start-default.png new file mode 100644 index 00000000..db364e69 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-default.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-explicit-default.png b/fixtures/web-first/chromium/svg-radial-start-explicit-default.png new file mode 100644 index 00000000..db364e69 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-explicit-default.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fr-decimal-higher.png b/fixtures/web-first/chromium/svg-radial-start-fr-decimal-higher.png new file mode 100644 index 00000000..70b1e20d Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fr-decimal-higher.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fr-decimal-lower.png b/fixtures/web-first/chromium/svg-radial-start-fr-decimal-lower.png new file mode 100644 index 00000000..9dc7dab0 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fr-decimal-lower.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fr-equal-r.png b/fixtures/web-first/chromium/svg-radial-start-fr-equal-r.png new file mode 100644 index 00000000..193800c8 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fr-equal-r.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fr-greater-r.png b/fixtures/web-first/chromium/svg-radial-start-fr-greater-r.png new file mode 100644 index 00000000..5f2e384d Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fr-greater-r.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fr-midpoint-higher.png b/fixtures/web-first/chromium/svg-radial-start-fr-midpoint-higher.png new file mode 100644 index 00000000..02424316 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fr-midpoint-higher.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fr-midpoint-lower.png b/fixtures/web-first/chromium/svg-radial-start-fr-midpoint-lower.png new file mode 100644 index 00000000..21f494ac Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fr-midpoint-lower.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fr-negative-zero.png b/fixtures/web-first/chromium/svg-radial-start-fr-negative-zero.png new file mode 100644 index 00000000..db364e69 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fr-negative-zero.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fr-negative.png b/fixtures/web-first/chromium/svg-radial-start-fr-negative.png new file mode 100644 index 00000000..db364e69 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fr-negative.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fr-percentage-higher.png b/fixtures/web-first/chromium/svg-radial-start-fr-percentage-higher.png new file mode 100644 index 00000000..4f72091c Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fr-percentage-higher.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fr-percentage-lower.png b/fixtures/web-first/chromium/svg-radial-start-fr-percentage-lower.png new file mode 100644 index 00000000..116089c9 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fr-percentage-lower.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fr-quarter.png b/fixtures/web-first/chromium/svg-radial-start-fr-quarter.png new file mode 100644 index 00000000..3f461fac Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fr-quarter.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fx-decimal-higher.png b/fixtures/web-first/chromium/svg-radial-start-fx-decimal-higher.png new file mode 100644 index 00000000..601253e3 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fx-decimal-higher.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fx-decimal-lower.png b/fixtures/web-first/chromium/svg-radial-start-fx-decimal-lower.png new file mode 100644 index 00000000..4df98ef4 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fx-decimal-lower.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fx-negative.png b/fixtures/web-first/chromium/svg-radial-start-fx-negative.png new file mode 100644 index 00000000..1ebfbc65 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fx-negative.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fx-on-end.png b/fixtures/web-first/chromium/svg-radial-start-fx-on-end.png new file mode 100644 index 00000000..0927dab3 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fx-on-end.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fx-outside.png b/fixtures/web-first/chromium/svg-radial-start-fx-outside.png new file mode 100644 index 00000000..98b7b5ed Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fx-outside.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fx-percentage-higher.png b/fixtures/web-first/chromium/svg-radial-start-fx-percentage-higher.png new file mode 100644 index 00000000..67764b40 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fx-percentage-higher.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fx-percentage-lower.png b/fixtures/web-first/chromium/svg-radial-start-fx-percentage-lower.png new file mode 100644 index 00000000..4df98ef4 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fx-percentage-lower.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fx-quarter.png b/fixtures/web-first/chromium/svg-radial-start-fx-quarter.png new file mode 100644 index 00000000..096e78b8 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fx-quarter.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fxy-fr-quarter.png b/fixtures/web-first/chromium/svg-radial-start-fxy-fr-quarter.png new file mode 100644 index 00000000..9afa39cb Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fxy-fr-quarter.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fxy-quarter.png b/fixtures/web-first/chromium/svg-radial-start-fxy-quarter.png new file mode 100644 index 00000000..6f14e08d Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fxy-quarter.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fy-decimal-higher.png b/fixtures/web-first/chromium/svg-radial-start-fy-decimal-higher.png new file mode 100644 index 00000000..5d46edf7 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fy-decimal-higher.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fy-decimal-lower.png b/fixtures/web-first/chromium/svg-radial-start-fy-decimal-lower.png new file mode 100644 index 00000000..4df98ef4 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fy-decimal-lower.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fy-percentage-higher.png b/fixtures/web-first/chromium/svg-radial-start-fy-percentage-higher.png new file mode 100644 index 00000000..083e949e Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fy-percentage-higher.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fy-percentage-lower.png b/fixtures/web-first/chromium/svg-radial-start-fy-percentage-lower.png new file mode 100644 index 00000000..4df98ef4 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fy-percentage-lower.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-fy-quarter.png b/fixtures/web-first/chromium/svg-radial-start-fy-quarter.png new file mode 100644 index 00000000..132363dc Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-fy-quarter.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-graduated-focal.png b/fixtures/web-first/chromium/svg-radial-start-graduated-focal.png new file mode 100644 index 00000000..ddc5a0e1 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-graduated-focal.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fr-comma.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fr-comma.png new file mode 100644 index 00000000..096e78b8 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fr-comma.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fr-exponent.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fr-exponent.png new file mode 100644 index 00000000..1d9de097 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fr-exponent.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fr-integer.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fr-integer.png new file mode 100644 index 00000000..096e78b8 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fr-integer.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fr-nbsp.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fr-nbsp.png new file mode 100644 index 00000000..096e78b8 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fr-nbsp.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fr-signed.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fr-signed.png new file mode 100644 index 00000000..1d9de097 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fr-signed.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fr-trailingdot.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fr-trailingdot.png new file mode 100644 index 00000000..096e78b8 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fr-trailingdot.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fr-whitespace.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fr-whitespace.png new file mode 100644 index 00000000..096e78b8 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fr-whitespace.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fx-comma.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fx-comma.png new file mode 100644 index 00000000..83b8d488 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fx-comma.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fx-exponent.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fx-exponent.png new file mode 100644 index 00000000..3e490257 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fx-exponent.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fx-integer.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fx-integer.png new file mode 100644 index 00000000..c0cd9fe3 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fx-integer.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fx-nbsp.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fx-nbsp.png new file mode 100644 index 00000000..83b8d488 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fx-nbsp.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fx-signed.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fx-signed.png new file mode 100644 index 00000000..3e490257 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fx-signed.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fx-trailingdot.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fx-trailingdot.png new file mode 100644 index 00000000..83b8d488 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fx-trailingdot.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fx-whitespace.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fx-whitespace.png new file mode 100644 index 00000000..83b8d488 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fx-whitespace.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fy-comma.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fy-comma.png new file mode 100644 index 00000000..096e78b8 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fy-comma.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fy-exponent.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fy-exponent.png new file mode 100644 index 00000000..6f14e08d Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fy-exponent.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fy-integer.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fy-integer.png new file mode 100644 index 00000000..cce640c3 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fy-integer.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fy-nbsp.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fy-nbsp.png new file mode 100644 index 00000000..096e78b8 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fy-nbsp.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fy-signed.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fy-signed.png new file mode 100644 index 00000000..6f14e08d Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fy-signed.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fy-trailingdot.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fy-trailingdot.png new file mode 100644 index 00000000..096e78b8 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fy-trailingdot.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-grammar-fy-whitespace.png b/fixtures/web-first/chromium/svg-radial-start-grammar-fy-whitespace.png new file mode 100644 index 00000000..096e78b8 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-grammar-fy-whitespace.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-mapped-viewbox.png b/fixtures/web-first/chromium/svg-radial-start-mapped-viewbox.png new file mode 100644 index 00000000..753e216a Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-mapped-viewbox.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-on-end-reflect.png b/fixtures/web-first/chromium/svg-radial-start-on-end-reflect.png new file mode 100644 index 00000000..859f9b13 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-on-end-reflect.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-on-end-repeat.png b/fixtures/web-first/chromium/svg-radial-start-on-end-repeat.png new file mode 100644 index 00000000..957f8202 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-on-end-repeat.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-one-stop-default.png b/fixtures/web-first/chromium/svg-radial-start-one-stop-default.png new file mode 100644 index 00000000..d8b24dce Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-one-stop-default.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-one-stop-exterior-reflect.png b/fixtures/web-first/chromium/svg-radial-start-one-stop-exterior-reflect.png new file mode 100644 index 00000000..63f513f3 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-one-stop-exterior-reflect.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-one-stop-exterior-repeat.png b/fixtures/web-first/chromium/svg-radial-start-one-stop-exterior-repeat.png new file mode 100644 index 00000000..63f513f3 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-one-stop-exterior-repeat.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-one-stop-focal.png b/fixtures/web-first/chromium/svg-radial-start-one-stop-focal.png new file mode 100644 index 00000000..63f513f3 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-one-stop-focal.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-outer-negative-focal.png b/fixtures/web-first/chromium/svg-radial-start-outer-negative-focal.png new file mode 100644 index 00000000..0a7b5414 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-outer-negative-focal.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-outer-zero-focal.png b/fixtures/web-first/chromium/svg-radial-start-outer-zero-focal.png new file mode 100644 index 00000000..0a7b5414 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-outer-zero-focal.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-outer-zero-fr.png b/fixtures/web-first/chromium/svg-radial-start-outer-zero-fr.png new file mode 100644 index 00000000..ad7ed064 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-outer-zero-fr.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-outer-zero-fx.png b/fixtures/web-first/chromium/svg-radial-start-outer-zero-fx.png new file mode 100644 index 00000000..118bdd83 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-outer-zero-fx.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-outer-zero-one-stop-focal.png b/fixtures/web-first/chromium/svg-radial-start-outer-zero-one-stop-focal.png new file mode 100644 index 00000000..c651c7a7 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-outer-zero-one-stop-focal.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-outside-positive-fr.png b/fixtures/web-first/chromium/svg-radial-start-outside-positive-fr.png new file mode 100644 index 00000000..f09eb09c Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-outside-positive-fr.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-relation-above.png b/fixtures/web-first/chromium/svg-radial-start-relation-above.png new file mode 100644 index 00000000..8957e9dd Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-relation-above.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-relation-below.png b/fixtures/web-first/chromium/svg-radial-start-relation-below.png new file mode 100644 index 00000000..c6192a36 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-relation-below.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-relation-containing.png b/fixtures/web-first/chromium/svg-radial-start-relation-containing.png new file mode 100644 index 00000000..dbce8f28 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-relation-containing.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-relation-disjoint.png b/fixtures/web-first/chromium/svg-radial-start-relation-disjoint.png new file mode 100644 index 00000000..fb3ea417 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-relation-disjoint.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-relation-external-tangent.png b/fixtures/web-first/chromium/svg-radial-start-relation-external-tangent.png new file mode 100644 index 00000000..cdeac97a Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-relation-external-tangent.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-relation-internal-tangent.png b/fixtures/web-first/chromium/svg-radial-start-relation-internal-tangent.png new file mode 100644 index 00000000..99b75ea9 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-relation-internal-tangent.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-relation-intersecting.png b/fixtures/web-first/chromium/svg-radial-start-relation-intersecting.png new file mode 100644 index 00000000..edb1dbf3 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-relation-intersecting.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-relation-left.png b/fixtures/web-first/chromium/svg-radial-start-relation-left.png new file mode 100644 index 00000000..8d49abdb Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-relation-left.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-relation-right.png b/fixtures/web-first/chromium/svg-radial-start-relation-right.png new file mode 100644 index 00000000..6b29d652 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-relation-right.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-same-circle-reflect.png b/fixtures/web-first/chromium/svg-radial-start-same-circle-reflect.png new file mode 100644 index 00000000..65b0461c Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-same-circle-reflect.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-same-circle-repeat.png b/fixtures/web-first/chromium/svg-radial-start-same-circle-repeat.png new file mode 100644 index 00000000..65b0461c Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-same-circle-repeat.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-spread-circle-reflect.png b/fixtures/web-first/chromium/svg-radial-start-spread-circle-reflect.png new file mode 100644 index 00000000..23daa4f8 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-spread-circle-reflect.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-spread-circle-repeat.png b/fixtures/web-first/chromium/svg-radial-start-spread-circle-repeat.png new file mode 100644 index 00000000..edbe331f Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-spread-circle-repeat.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-spread-outside-reflect.png b/fixtures/web-first/chromium/svg-radial-start-spread-outside-reflect.png new file mode 100644 index 00000000..19c8cf2f Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-spread-outside-reflect.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-spread-outside-repeat.png b/fixtures/web-first/chromium/svg-radial-start-spread-outside-repeat.png new file mode 100644 index 00000000..30f320ac Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-spread-outside-repeat.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-spread-reversed-reflect.png b/fixtures/web-first/chromium/svg-radial-start-spread-reversed-reflect.png new file mode 100644 index 00000000..acd2b59a Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-spread-reversed-reflect.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-spread-reversed-repeat.png b/fixtures/web-first/chromium/svg-radial-start-spread-reversed-repeat.png new file mode 100644 index 00000000..c53182df Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-spread-reversed-repeat.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-spread-zero-end-reflect.png b/fixtures/web-first/chromium/svg-radial-start-spread-zero-end-reflect.png new file mode 100644 index 00000000..2fce2702 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-spread-zero-end-reflect.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-spread-zero-end-repeat.png b/fixtures/web-first/chromium/svg-radial-start-spread-zero-end-repeat.png new file mode 100644 index 00000000..3d1a4e7d Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-spread-zero-end-repeat.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-stops-alpha.png b/fixtures/web-first/chromium/svg-radial-start-stops-alpha.png new file mode 100644 index 00000000..5e5ff972 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-stops-alpha.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-stops-duplicate.png b/fixtures/web-first/chromium/svg-radial-start-stops-duplicate.png new file mode 100644 index 00000000..ee5133d1 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-stops-duplicate.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-stops-edges.png b/fixtures/web-first/chromium/svg-radial-start-stops-edges.png new file mode 100644 index 00000000..9c3073a2 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-stops-edges.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-stops-unsorted.png b/fixtures/web-first/chromium/svg-radial-start-stops-unsorted.png new file mode 100644 index 00000000..8c76a8b2 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-stops-unsorted.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-template-all.png b/fixtures/web-first/chromium/svg-radial-start-template-all.png new file mode 100644 index 00000000..5cd1fdaf Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-template-all.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-template-empty-fr.png b/fixtures/web-first/chromium/svg-radial-start-template-empty-fr.png new file mode 100644 index 00000000..3e490257 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-template-empty-fr.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-template-empty-fx.png b/fixtures/web-first/chromium/svg-radial-start-template-empty-fx.png new file mode 100644 index 00000000..c6395ef7 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-template-empty-fx.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-template-empty-fy.png b/fixtures/web-first/chromium/svg-radial-start-template-empty-fy.png new file mode 100644 index 00000000..1d9de097 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-template-empty-fy.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-template-explicit-focus.png b/fixtures/web-first/chromium/svg-radial-start-template-explicit-focus.png new file mode 100644 index 00000000..0b3f4342 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-template-explicit-focus.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-template-fr-negative.png b/fixtures/web-first/chromium/svg-radial-start-template-fr-negative.png new file mode 100644 index 00000000..3e490257 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-template-fr-negative.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-template-fr-zero.png b/fixtures/web-first/chromium/svg-radial-start-template-fr-zero.png new file mode 100644 index 00000000..3e490257 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-template-fr-zero.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-template-invalid-fr.png b/fixtures/web-first/chromium/svg-radial-start-template-invalid-fr.png new file mode 100644 index 00000000..3e490257 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-template-invalid-fr.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-template-local-center.png b/fixtures/web-first/chromium/svg-radial-start-template-local-center.png new file mode 100644 index 00000000..09c2f732 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-template-local-center.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-template-multihop.png b/fixtures/web-first/chromium/svg-radial-start-template-multihop.png new file mode 100644 index 00000000..5cd1fdaf Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-template-multihop.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-template-override-fr.png b/fixtures/web-first/chromium/svg-radial-start-template-override-fr.png new file mode 100644 index 00000000..ca8c8f92 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-template-override-fr.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-template-override-fx.png b/fixtures/web-first/chromium/svg-radial-start-template-override-fx.png new file mode 100644 index 00000000..f19c91c9 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-template-override-fx.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-template-override-fy.png b/fixtures/web-first/chromium/svg-radial-start-template-override-fy.png new file mode 100644 index 00000000..b1564003 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-template-override-fy.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-template-xlink.png b/fixtures/web-first/chromium/svg-radial-start-template-xlink.png new file mode 100644 index 00000000..5cd1fdaf Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-template-xlink.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-transform-rotate.png b/fixtures/web-first/chromium/svg-radial-start-transform-rotate.png new file mode 100644 index 00000000..97675164 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-transform-rotate.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-transform-scale.png b/fixtures/web-first/chromium/svg-radial-start-transform-scale.png new file mode 100644 index 00000000..bfd0ee66 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-transform-scale.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-transform-singular.png b/fixtures/web-first/chromium/svg-radial-start-transform-singular.png new file mode 100644 index 00000000..118bdd83 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-transform-singular.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-transform-skew.png b/fixtures/web-first/chromium/svg-radial-start-transform-skew.png new file mode 100644 index 00000000..db7af2b0 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-transform-skew.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-transform-translate.png b/fixtures/web-first/chromium/svg-radial-start-transform-translate.png new file mode 100644 index 00000000..72ab0956 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-transform-translate.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-transparent-cone.png b/fixtures/web-first/chromium/svg-radial-start-transparent-cone.png new file mode 100644 index 00000000..c27c3137 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-transparent-cone.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-user-percent-fr.png b/fixtures/web-first/chromium/svg-radial-start-user-percent-fr.png new file mode 100644 index 00000000..753e216a Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-user-percent-fr.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-user-percent-fx.png b/fixtures/web-first/chromium/svg-radial-start-user-percent-fx.png new file mode 100644 index 00000000..753e216a Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-user-percent-fx.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-user-percent-fy.png b/fixtures/web-first/chromium/svg-radial-start-user-percent-fy.png new file mode 100644 index 00000000..753e216a Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-user-percent-fy.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-user-px.png b/fixtures/web-first/chromium/svg-radial-start-user-px.png new file mode 100644 index 00000000..7c2d7305 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-user-px.png differ diff --git a/fixtures/web-first/chromium/svg-radial-start-zero-stops-focal.png b/fixtures/web-first/chromium/svg-radial-start-zero-stops-focal.png new file mode 100644 index 00000000..118bdd83 Binary files /dev/null and b/fixtures/web-first/chromium/svg-radial-start-zero-stops-focal.png differ diff --git a/fixtures/web-first/html-inline-svg-radial-start.html b/fixtures/web-first/html-inline-svg-radial-start.html new file mode 100644 index 00000000..47774ca9 --- /dev/null +++ b/fixtures/web-first/html-inline-svg-radial-start.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/fixtures/web-first/oracle-bake.json b/fixtures/web-first/oracle-bake.json index 9b289dea..377c2b73 100644 --- a/fixtures/web-first/oracle-bake.json +++ b/fixtures/web-first/oracle-bake.json @@ -5,7 +5,7 @@ "bake_script_sha256": "2bdb5f933d072a1e87c9a675c3342fcf506c0955c0f5c26e2988f4e8fa37c4f2", "capture_module_sha256": "069296201718c43d29efe356fbea893781b73250dca51de3b6d47468d74027b0", "suite": "primitives.json", - "suite_sha256": "fdd8b6dec491334a09867d0913c75861e2812a6e2cea161b244e4fdd26c5bca2", + "suite_sha256": "9cc3c4ad2a2e4e31483b2895e4458618189361e767c55a0b788605d8090ec468", "capture": { "device_scale_factor": 1, "omit_background": true, @@ -64,6 +64,15 @@ "width": 64, "height": 64 }, + { + "id": "html-inline-svg-radial-start", + "source": "html-inline-svg-radial-start.html", + "source_sha256": "e86031f1909d87ec8cd44eb4942d9b7da62c0c02ef1294f7506cfba3eb6dd845", + "oracle": "chromium/html-inline-svg-radial-start.png", + "oracle_sha256": "431394a51976e5721a7498470d69eedcebabef0c36d96846a734e618fe4c204f", + "width": 64, + "height": 64 + }, { "id": "html-inline-svg-vector-effect", "source": "html-inline-svg-vector-effect.html", @@ -8569,6 +8578,1140 @@ "width": 64, "height": 32 }, + { + "id": "svg-radial-start-box-percent", + "source": "svg-radial-start-box-percent.svg", + "source_sha256": "4af3e02a80db580d74459115c14ab584501c3d1fe0673452b1cef94e7797a907", + "oracle": "chromium/svg-radial-start-box-percent.png", + "oracle_sha256": "eae5604f7426036c13116059be0b93adc7c847d73570e0cab073011680c65f8b", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-channel-opacity", + "source": "svg-radial-start-client-channel-opacity.svg", + "source_sha256": "eda98511e873788fae27fa3e8cb19c6cb09d7637c473d094efe45bdaf493a05c", + "oracle": "chromium/svg-radial-start-client-channel-opacity.png", + "oracle_sha256": "5f948dcda15edcc1361621d2f91965a19c7622ca3d6175ab259a8f6d342b5f9c", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-clip", + "source": "svg-radial-start-client-clip.svg", + "source_sha256": "724794298c2046d18445d28c8e1d68cec5bd6c6643124ae1705ed041f7663b95", + "oracle": "chromium/svg-radial-start-client-clip.png", + "oracle_sha256": "b40ee0aee40b0ffd441fcf5c56ee124997b11832eea1dd3084d2a7d9cc9581f2", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-dashes", + "source": "svg-radial-start-client-dashes.svg", + "source_sha256": "cb3711e7554f8756294c921084b196dbc0dc487aab15d22bbd798b56cdec4188", + "oracle": "chromium/svg-radial-start-client-dashes.png", + "oracle_sha256": "fc9e39903177dee5a9ad6e7260ea5e38eb3eced9ab8ab6be0b07f96861e17207", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-ellipse", + "source": "svg-radial-start-client-ellipse.svg", + "source_sha256": "0612dedb2a68b73fc809ed8d1aabee17a9790f96af42d0845a8b80c6c4e097fa", + "oracle": "chromium/svg-radial-start-client-ellipse.png", + "oracle_sha256": "6bf16910508a44ec6185d90bc81564c83de95c3fcd56e52668bc6c56b301fe90", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-filter", + "source": "svg-radial-start-client-filter.svg", + "source_sha256": "b765ab8ffe8f70d4e8921301de461e1712e7ad861ce0b67828a522b0f64df095", + "oracle": "chromium/svg-radial-start-client-filter.png", + "oracle_sha256": "4382643475775ebb6e1028c09312cef2ad05d2d7bde65a3d0010f3f87f302312", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-group-opacity", + "source": "svg-radial-start-client-group-opacity.svg", + "source_sha256": "341afecd8fb4e5c8a8f0343b87615762027aca19742941346626f074e02d4a7d", + "oracle": "chromium/svg-radial-start-client-group-opacity.png", + "oracle_sha256": "edb010afa22920ac3c885f8e64feee16c1ca2d505a3da2778cecddfaa1514797", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-mask", + "source": "svg-radial-start-client-mask.svg", + "source_sha256": "d4c9761124fc3bd0ef5623e2602175e99e402fcea54acd6768df148d5eb93046", + "oracle": "chromium/svg-radial-start-client-mask.png", + "oracle_sha256": "fe3cc50e9ba2a8ecd209f91c4e4dfe4f6e04f5b702e57a7666d495643e23a0cc", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-nested", + "source": "svg-radial-start-client-nested.svg", + "source_sha256": "b0fce77c0db8e48cc9a11f8ba62eb5ce4d0675af2fb9c9a6d85296c2ed8d61fe", + "oracle": "chromium/svg-radial-start-client-nested.png", + "oracle_sha256": "531733367de4787c7bcdd02cea7758c6e5884689aa57b7cfb13dba64f79a2f98", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-order", + "source": "svg-radial-start-client-order.svg", + "source_sha256": "92e8a4715c13ec4e0ea565bce0b46b80d425177d06bdd0250c77045457b586ff", + "oracle": "chromium/svg-radial-start-client-order.png", + "oracle_sha256": "745ca083ddbef622654e823b7c54e87e4f3820c2a378b1949a673d71633bf4a6", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-path", + "source": "svg-radial-start-client-path.svg", + "source_sha256": "59de0c061638721ceb5c0ac7ccc4d42b572f65cd1b87f873bd1f416a6dbfa280", + "oracle": "chromium/svg-radial-start-client-path.png", + "oracle_sha256": "b0d2d4c8cf4d3872d51bf1282837daec0290ce948fb3b4b28b6a99a93a49e11a", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-pattern", + "source": "svg-radial-start-client-pattern.svg", + "source_sha256": "7263e4d83ffe51c34facbc36c8d7e04d39cd166ce8c7f69c4628615ad2a2ba78", + "oracle": "chromium/svg-radial-start-client-pattern.png", + "oracle_sha256": "70a35490638a5489e11d8205b538e43fd96444b19ee73714a58f60d179613d18", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-stroke", + "source": "svg-radial-start-client-stroke.svg", + "source_sha256": "389d8db642f5090c72457d69044798189dc484ab3e74aa3bb5ad7d9c1f5a237b", + "oracle": "chromium/svg-radial-start-client-stroke.png", + "oracle_sha256": "7367248a7fe4540da5c7f54b8946ffedfdc8bab83e919c0c4e2f927c68a1950b", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-transform", + "source": "svg-radial-start-client-transform.svg", + "source_sha256": "b027142733f95ec756761d03dfac749daf8ab0703e883200b3a23766727c0b9b", + "oracle": "chromium/svg-radial-start-client-transform.png", + "oracle_sha256": "29de8801246f17f78aa4c1f1831b06a78f45c97ebccaf77ce055d0686c190efb", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-use", + "source": "svg-radial-start-client-use.svg", + "source_sha256": "8d0b977e4c4953164b09a6fc857d5cab0ce409d0c25961b2d54eefabe1d0ee3f", + "oracle": "chromium/svg-radial-start-client-use.png", + "oracle_sha256": "c077dca1df419ade7fded64b6338b936dad687f072fa5315b1ef88a8e42e0f05", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-default", + "source": "svg-radial-start-default.svg", + "source_sha256": "edee25f315a2c8b9095e419cb63b948325110a561673b3c2da738fbb4dfeed99", + "oracle": "chromium/svg-radial-start-default.png", + "oracle_sha256": "2521ab1422e4dbf213bb3655ad4efc9470e1bfe41f9f592ce506a8ed846d3a82", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-explicit-default", + "source": "svg-radial-start-explicit-default.svg", + "source_sha256": "e9b4bbc95c5e153abdba5fb4604a2f11167ade07ee051370f5a171dc8e00a99f", + "oracle": "chromium/svg-radial-start-explicit-default.png", + "oracle_sha256": "2521ab1422e4dbf213bb3655ad4efc9470e1bfe41f9f592ce506a8ed846d3a82", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-decimal-higher", + "source": "svg-radial-start-fr-decimal-higher.svg", + "source_sha256": "d290d163d90424c02e59c63dd968c878776db8b0c155662236d7b72aae06a6a2", + "oracle": "chromium/svg-radial-start-fr-decimal-higher.png", + "oracle_sha256": "666340d8e8634055aeb3e93adefac9a497a0344a3525593dcdce07eaab111d3a", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-decimal-lower", + "source": "svg-radial-start-fr-decimal-lower.svg", + "source_sha256": "432e2570a0802ddd0d6fd2ecd4289a07cdb17ea10b26b9554f72d9ad443c0a75", + "oracle": "chromium/svg-radial-start-fr-decimal-lower.png", + "oracle_sha256": "ee3e00b7a496bc55d8f141f77fd03cb5a766c15ed75410312af2ac2c26c9ba95", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-equal-r", + "source": "svg-radial-start-fr-equal-r.svg", + "source_sha256": "5abae6cc0237a065ad67b93c76800547a620c09a7458f9516c3d6aa3b8677f5d", + "oracle": "chromium/svg-radial-start-fr-equal-r.png", + "oracle_sha256": "fc9d92604b350638a0d198f01c24a9e15f683ec001e7e03ab28c6d309f83251f", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-greater-r", + "source": "svg-radial-start-fr-greater-r.svg", + "source_sha256": "9e43ebc581f35a202d60903b6cd2329a8b81fb339aa21cc91594157e60c9b9fe", + "oracle": "chromium/svg-radial-start-fr-greater-r.png", + "oracle_sha256": "65cf78f4fd59ba0bd2c4e6681de3cf7ffde12f147b85563e2e6a55ba3fdf0b06", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-midpoint-higher", + "source": "svg-radial-start-fr-midpoint-higher.svg", + "source_sha256": "301b48c9e6390754764c5bf1ea4092fdc0d35dc5cf7e8aaf89e9e46dba07bf02", + "oracle": "chromium/svg-radial-start-fr-midpoint-higher.png", + "oracle_sha256": "093c43915fada446b20e5ca09dfd1bd5aca6ecfb5160886803577aa5fa6b8135", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-midpoint-lower", + "source": "svg-radial-start-fr-midpoint-lower.svg", + "source_sha256": "32034be42b46297743af033ad304944ebdbac594847b892c139623a7b9b770a7", + "oracle": "chromium/svg-radial-start-fr-midpoint-lower.png", + "oracle_sha256": "77b6de01604f4575632b931b8e4bcd772fc9f69541daaf966ecb8de5d6b5cbb0", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-negative", + "source": "svg-radial-start-fr-negative.svg", + "source_sha256": "fb957fa71a676b8afea6e9d53e1d85eefd5675652a989d288f062cc028532449", + "oracle": "chromium/svg-radial-start-fr-negative.png", + "oracle_sha256": "2521ab1422e4dbf213bb3655ad4efc9470e1bfe41f9f592ce506a8ed846d3a82", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-negative-zero", + "source": "svg-radial-start-fr-negative-zero.svg", + "source_sha256": "aa3d75e31bc59b75f0fa18e8c104998d94fc53120bbb134719cfd12bd18cf23a", + "oracle": "chromium/svg-radial-start-fr-negative-zero.png", + "oracle_sha256": "2521ab1422e4dbf213bb3655ad4efc9470e1bfe41f9f592ce506a8ed846d3a82", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-percentage-higher", + "source": "svg-radial-start-fr-percentage-higher.svg", + "source_sha256": "5b2eec28b16211eb7a10ac553bf51d4b211d0eaa575b7960f406bd3a04753cbd", + "oracle": "chromium/svg-radial-start-fr-percentage-higher.png", + "oracle_sha256": "13849c6ef93b616263e5cf43f5c5e1c40f4fb8deb8f2c1666552bd8b52bc631a", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-percentage-lower", + "source": "svg-radial-start-fr-percentage-lower.svg", + "source_sha256": "d2fcb4cb933ce879daf11ff2dc75dd8c51c5921fd363ac31f365081534f453d3", + "oracle": "chromium/svg-radial-start-fr-percentage-lower.png", + "oracle_sha256": "f78bb8b118b0d02e662d25cb7703496503843369f4b076cbf8ed0eb802e505ce", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-quarter", + "source": "svg-radial-start-fr-quarter.svg", + "source_sha256": "9f0ab74d61a286f1849cae4ef4f54b2cb7cb7206f85164853bf32e1fef88b338", + "oracle": "chromium/svg-radial-start-fr-quarter.png", + "oracle_sha256": "80a2b84481dc3612b664c8218877abe79a3e6acd87bf49898f7555edb50d84cc", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fx-decimal-higher", + "source": "svg-radial-start-fx-decimal-higher.svg", + "source_sha256": "c100913c407ab32f8677ddbea5a311079998d388739ac5261bbf82f4bdf79e74", + "oracle": "chromium/svg-radial-start-fx-decimal-higher.png", + "oracle_sha256": "fdb707ffbb341a3d6f3c1873952e39256e65c651ef1c06fece2551dcde870970", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fx-decimal-lower", + "source": "svg-radial-start-fx-decimal-lower.svg", + "source_sha256": "c9f7f5a7dcade0c2c3104249fbf728d774547ace51e1076d1fb73c3353375bcf", + "oracle": "chromium/svg-radial-start-fx-decimal-lower.png", + "oracle_sha256": "0d5301e34192577504096ce24e2701d12f4c87718e5c7eb973c77cd417686788", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fx-negative", + "source": "svg-radial-start-fx-negative.svg", + "source_sha256": "4b1acadd38d22e820d407a5f7b1c7da84257d7cdd72b85b9961a4db39d42c643", + "oracle": "chromium/svg-radial-start-fx-negative.png", + "oracle_sha256": "9d487686544f2fc22fdd7226d021ee8981d5d4dc81c4b1360b20b085e08ed301", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fx-on-end", + "source": "svg-radial-start-fx-on-end.svg", + "source_sha256": "ace61df249dfaebf4f0162ea2f425085b6a15d4f96f94e364158ddf834fe9666", + "oracle": "chromium/svg-radial-start-fx-on-end.png", + "oracle_sha256": "b46960a20dcbce78b6d2f55c9a3833d62e05b5d7ec4751aa389ebaeb7d15c355", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fx-outside", + "source": "svg-radial-start-fx-outside.svg", + "source_sha256": "a566f438d8e6c7e9584467d19d9a00e3d74e2e1d3dbfd64093d01891bc44f2d3", + "oracle": "chromium/svg-radial-start-fx-outside.png", + "oracle_sha256": "14c681e4553c162af59d00e341aef5d70823b7e98d9439508d10178e6dd46edd", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fx-percentage-higher", + "source": "svg-radial-start-fx-percentage-higher.svg", + "source_sha256": "46a763d9c31e50975962b2824a4a7dd0b942689b20a9a434185e115167811b3a", + "oracle": "chromium/svg-radial-start-fx-percentage-higher.png", + "oracle_sha256": "3b12d84cc89f39b2c87d222c7899a4cbd0ea40c8062484128a79a081e2ca54bf", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fx-percentage-lower", + "source": "svg-radial-start-fx-percentage-lower.svg", + "source_sha256": "2c636a1458f627fb95c02de8f6c28d339582115f973b6aacf59340fbf01136da", + "oracle": "chromium/svg-radial-start-fx-percentage-lower.png", + "oracle_sha256": "0d5301e34192577504096ce24e2701d12f4c87718e5c7eb973c77cd417686788", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fx-quarter", + "source": "svg-radial-start-fx-quarter.svg", + "source_sha256": "a5c59a017a9c7cfa40c2b13aee92194ae5d9c1767e30806f524d64f860d4d096", + "oracle": "chromium/svg-radial-start-fx-quarter.png", + "oracle_sha256": "e5334f527f556396ebb58a9f5fd7235304fce458d7b79134553c2fa4f1ad5018", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fxy-fr-quarter", + "source": "svg-radial-start-fxy-fr-quarter.svg", + "source_sha256": "d02390d8f32df5daa297870d5b164eb28abacbe1ea7a6c72f88634e3bff8415e", + "oracle": "chromium/svg-radial-start-fxy-fr-quarter.png", + "oracle_sha256": "431394a51976e5721a7498470d69eedcebabef0c36d96846a734e618fe4c204f", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fxy-quarter", + "source": "svg-radial-start-fxy-quarter.svg", + "source_sha256": "ea3500f44977115ebdf3799bd56a1ac95453b862619d4fac21b677f70eb00b3b", + "oracle": "chromium/svg-radial-start-fxy-quarter.png", + "oracle_sha256": "305ab2f625c42b9a5adfc6acc501687734e98b146b82210c3fc37b1060eea480", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fy-decimal-higher", + "source": "svg-radial-start-fy-decimal-higher.svg", + "source_sha256": "9e0ccfee412b09700358e386f9e52df41a095b68b412805898b4e7e1a46655e2", + "oracle": "chromium/svg-radial-start-fy-decimal-higher.png", + "oracle_sha256": "56408367f7f169c4f29dd0a7d5b732d8e10aa5246320300adbc2ad960240a615", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fy-decimal-lower", + "source": "svg-radial-start-fy-decimal-lower.svg", + "source_sha256": "92a8bd9a160713c65158442c0b9cc80a57c03ec0b1693fced6d8f0f1b85a086a", + "oracle": "chromium/svg-radial-start-fy-decimal-lower.png", + "oracle_sha256": "0d5301e34192577504096ce24e2701d12f4c87718e5c7eb973c77cd417686788", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fy-percentage-higher", + "source": "svg-radial-start-fy-percentage-higher.svg", + "source_sha256": "f325e0b9eccdb40a903e302b1e606f90d724c97acc9162cb010c43f5ee6fe6ff", + "oracle": "chromium/svg-radial-start-fy-percentage-higher.png", + "oracle_sha256": "5542e71d522e5778c99f9115a14f7dbbd2ef690d849f33e9d34ef07c025ac887", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fy-percentage-lower", + "source": "svg-radial-start-fy-percentage-lower.svg", + "source_sha256": "f17a0bf0cf09e13f2e061f2d8a0c5590b03c09ca425ada5a5eb92f2aa0b40627", + "oracle": "chromium/svg-radial-start-fy-percentage-lower.png", + "oracle_sha256": "0d5301e34192577504096ce24e2701d12f4c87718e5c7eb973c77cd417686788", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fy-quarter", + "source": "svg-radial-start-fy-quarter.svg", + "source_sha256": "c7286f99262d6f32cf271685c8c8c3d1e3596c5cfa31672faef41fca3d8ce480", + "oracle": "chromium/svg-radial-start-fy-quarter.png", + "oracle_sha256": "f940e782a2f68b2af833fde9870c4c163bd4a121c1d99c691534eb0cce74a0cd", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-graduated-focal", + "source": "svg-radial-start-graduated-focal.svg", + "source_sha256": "70c417e69bcc76c274f3c73596da711cc60efec8f7262abcb8b5851c4a16d06e", + "oracle": "chromium/svg-radial-start-graduated-focal.png", + "oracle_sha256": "c1477f001a2a2a7e1bb341cb393627b84e78ef28f25b1029a215b8516aa0e887", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fr-comma", + "source": "svg-radial-start-grammar-fr-comma.svg", + "source_sha256": "a06a6924b9ffb77ca2f6d9d279f73ef912158f2966a7235c0c9c5fcbde89ed84", + "oracle": "chromium/svg-radial-start-grammar-fr-comma.png", + "oracle_sha256": "e5334f527f556396ebb58a9f5fd7235304fce458d7b79134553c2fa4f1ad5018", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fr-exponent", + "source": "svg-radial-start-grammar-fr-exponent.svg", + "source_sha256": "2cf7094a4e3f7d19e3a15d57849b73bf841b22c43ce0c072152327f41190202b", + "oracle": "chromium/svg-radial-start-grammar-fr-exponent.png", + "oracle_sha256": "ebef51b8e9e7a6be894c1a3809f65ceecbe6d0eca71c61737f064ca163d3d0b5", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fr-integer", + "source": "svg-radial-start-grammar-fr-integer.svg", + "source_sha256": "1199c54d60ae7f251ec20d56d5c787b82da7f40ac9163a5644ffe1010c157a50", + "oracle": "chromium/svg-radial-start-grammar-fr-integer.png", + "oracle_sha256": "e5334f527f556396ebb58a9f5fd7235304fce458d7b79134553c2fa4f1ad5018", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fr-nbsp", + "source": "svg-radial-start-grammar-fr-nbsp.svg", + "source_sha256": "63f9e6d4bdfc4c79b4ec54f3d97c49d8e3743c45f2a81b7c1cda151b4d9bca8e", + "oracle": "chromium/svg-radial-start-grammar-fr-nbsp.png", + "oracle_sha256": "e5334f527f556396ebb58a9f5fd7235304fce458d7b79134553c2fa4f1ad5018", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fr-signed", + "source": "svg-radial-start-grammar-fr-signed.svg", + "source_sha256": "962b39030c539bc373c00bc53e40841432582ee70162d5f240db9db0957aa65e", + "oracle": "chromium/svg-radial-start-grammar-fr-signed.png", + "oracle_sha256": "ebef51b8e9e7a6be894c1a3809f65ceecbe6d0eca71c61737f064ca163d3d0b5", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fr-trailingdot", + "source": "svg-radial-start-grammar-fr-trailingdot.svg", + "source_sha256": "d3d905b63226ca5401df8254084e02e68c9f81c8724c4be479039bbf84618cd0", + "oracle": "chromium/svg-radial-start-grammar-fr-trailingdot.png", + "oracle_sha256": "e5334f527f556396ebb58a9f5fd7235304fce458d7b79134553c2fa4f1ad5018", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fr-whitespace", + "source": "svg-radial-start-grammar-fr-whitespace.svg", + "source_sha256": "593857c97a61bef7093e4219446771ab500390c7bbd1a9b71d64c2b507724278", + "oracle": "chromium/svg-radial-start-grammar-fr-whitespace.png", + "oracle_sha256": "e5334f527f556396ebb58a9f5fd7235304fce458d7b79134553c2fa4f1ad5018", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fx-comma", + "source": "svg-radial-start-grammar-fx-comma.svg", + "source_sha256": "550b5c7e79943d010574448e5bda8699043b9c714213e3e43016162d5e646d4a", + "oracle": "chromium/svg-radial-start-grammar-fx-comma.png", + "oracle_sha256": "917e9e95db49d09af380721d53277dffa4218c4f89b15f0a34dad24cee584bd7", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fx-exponent", + "source": "svg-radial-start-grammar-fx-exponent.svg", + "source_sha256": "53afc6392613cb4602577add797e9c29a940a7637f407ab84a60286187cb980b", + "oracle": "chromium/svg-radial-start-grammar-fx-exponent.png", + "oracle_sha256": "6534f8dda4e541a71ef65bb7b3ee1455bd361e82cdf591404e3ddd35a37f1227", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fx-integer", + "source": "svg-radial-start-grammar-fx-integer.svg", + "source_sha256": "ff503adcf180eddc897419974ce9f09f81a6373279c99acdac6cb15baa1eb229", + "oracle": "chromium/svg-radial-start-grammar-fx-integer.png", + "oracle_sha256": "c64a039ab50019eaa1c7614b8b1e8ba68fa8a81c7f44d7e5728e75ce2cc4e72d", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fx-nbsp", + "source": "svg-radial-start-grammar-fx-nbsp.svg", + "source_sha256": "6413b6beaeae0ce9f7c1a83951d6a558490a672393219d5a020625c63351a950", + "oracle": "chromium/svg-radial-start-grammar-fx-nbsp.png", + "oracle_sha256": "917e9e95db49d09af380721d53277dffa4218c4f89b15f0a34dad24cee584bd7", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fx-signed", + "source": "svg-radial-start-grammar-fx-signed.svg", + "source_sha256": "831092b1c549586f536c235bcefdbc36ac669ea659604b4ebc48db8d605d71ad", + "oracle": "chromium/svg-radial-start-grammar-fx-signed.png", + "oracle_sha256": "6534f8dda4e541a71ef65bb7b3ee1455bd361e82cdf591404e3ddd35a37f1227", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fx-trailingdot", + "source": "svg-radial-start-grammar-fx-trailingdot.svg", + "source_sha256": "ac346555fadbba337168d4bd0eb28d5a8c6cee992800184bb177ddab12e86769", + "oracle": "chromium/svg-radial-start-grammar-fx-trailingdot.png", + "oracle_sha256": "917e9e95db49d09af380721d53277dffa4218c4f89b15f0a34dad24cee584bd7", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fx-whitespace", + "source": "svg-radial-start-grammar-fx-whitespace.svg", + "source_sha256": "c8deafec16ecacfe3daa99540a6c0d4760c4d4127ad6b3c5bbe2a9ff7575b0a5", + "oracle": "chromium/svg-radial-start-grammar-fx-whitespace.png", + "oracle_sha256": "917e9e95db49d09af380721d53277dffa4218c4f89b15f0a34dad24cee584bd7", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fy-comma", + "source": "svg-radial-start-grammar-fy-comma.svg", + "source_sha256": "9eb25501e987e39a4444f3a6e5309d456f96994eb681b6bb3f7cbf38a386c8a7", + "oracle": "chromium/svg-radial-start-grammar-fy-comma.png", + "oracle_sha256": "e5334f527f556396ebb58a9f5fd7235304fce458d7b79134553c2fa4f1ad5018", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fy-exponent", + "source": "svg-radial-start-grammar-fy-exponent.svg", + "source_sha256": "524dd36cecb17d7cb2d0f1fc4fe0b7744e8e36dde065df16f49424d36389ba1c", + "oracle": "chromium/svg-radial-start-grammar-fy-exponent.png", + "oracle_sha256": "305ab2f625c42b9a5adfc6acc501687734e98b146b82210c3fc37b1060eea480", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fy-integer", + "source": "svg-radial-start-grammar-fy-integer.svg", + "source_sha256": "14ff0306d4a26f7e7f58858fff8acf2d76a9b247770645006aec097a678df8fa", + "oracle": "chromium/svg-radial-start-grammar-fy-integer.png", + "oracle_sha256": "2b425ae05af82f207be35dc76d4803ec44b5a6a80ddd7e804f54324ca01dab4b", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fy-nbsp", + "source": "svg-radial-start-grammar-fy-nbsp.svg", + "source_sha256": "39e93a2cfc5b667c1e579d50e647ab458561a1ecf674c319fed12b0535b6d60f", + "oracle": "chromium/svg-radial-start-grammar-fy-nbsp.png", + "oracle_sha256": "e5334f527f556396ebb58a9f5fd7235304fce458d7b79134553c2fa4f1ad5018", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fy-signed", + "source": "svg-radial-start-grammar-fy-signed.svg", + "source_sha256": "091931ddee48e758835703826499205a214f1d0c53a938d26acd4c3b0dcc3831", + "oracle": "chromium/svg-radial-start-grammar-fy-signed.png", + "oracle_sha256": "305ab2f625c42b9a5adfc6acc501687734e98b146b82210c3fc37b1060eea480", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fy-trailingdot", + "source": "svg-radial-start-grammar-fy-trailingdot.svg", + "source_sha256": "69bc7833cb3be8f879d7d700132d7d8c9952c355dfbdd6cf85c0860446af05c9", + "oracle": "chromium/svg-radial-start-grammar-fy-trailingdot.png", + "oracle_sha256": "e5334f527f556396ebb58a9f5fd7235304fce458d7b79134553c2fa4f1ad5018", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fy-whitespace", + "source": "svg-radial-start-grammar-fy-whitespace.svg", + "source_sha256": "d5f8c6ad9b56ab9a1b84f3c6d0301b114e3b8b93f08e008ae2b2e23a55fc4ad1", + "oracle": "chromium/svg-radial-start-grammar-fy-whitespace.png", + "oracle_sha256": "e5334f527f556396ebb58a9f5fd7235304fce458d7b79134553c2fa4f1ad5018", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-mapped-viewbox", + "source": "svg-radial-start-mapped-viewbox.svg", + "source_sha256": "78d1108f8116f8281cce13d3fd3b441a668a03ef75d72d11bd9c647344b0dab3", + "oracle": "chromium/svg-radial-start-mapped-viewbox.png", + "oracle_sha256": "99b098487564030537529948bf95654428e511ec72e296a64f82eb39db92e5e9", + "width": 64, + "height": 32 + }, + { + "id": "svg-radial-start-on-end-reflect", + "source": "svg-radial-start-on-end-reflect.svg", + "source_sha256": "6737665bced7278e441b47357466f10f04a8ef699288b2857192c8389a4731c8", + "oracle": "chromium/svg-radial-start-on-end-reflect.png", + "oracle_sha256": "89c8444919f4d818f4af4fe14a82ab7ab7b13c86b6ca74ddce3147624b4cbe53", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-on-end-repeat", + "source": "svg-radial-start-on-end-repeat.svg", + "source_sha256": "658a63ff138b02afa93fb555372d4ad6fdd8859844b8a38cfa79f623c637f1d7", + "oracle": "chromium/svg-radial-start-on-end-repeat.png", + "oracle_sha256": "57ee46d50c23446d0d03df7c4ca47808f8b1354bbe1a34f255481010a4c6ea5c", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-one-stop-default", + "source": "svg-radial-start-one-stop-default.svg", + "source_sha256": "621fe484dee548718c0e1389e5536a4b65f460ae0129982574e7d86eff82e663", + "oracle": "chromium/svg-radial-start-one-stop-default.png", + "oracle_sha256": "55b21ea5b5edbaec8ac477bba6274fa81ca5f4060a0443e4d71e100ffb51ecb9", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-one-stop-exterior-reflect", + "source": "svg-radial-start-one-stop-exterior-reflect.svg", + "source_sha256": "4e8b7636df56a0d633cc579fc813c2b512f88a3f84743a1596fc461c8f071b4b", + "oracle": "chromium/svg-radial-start-one-stop-exterior-reflect.png", + "oracle_sha256": "df1860aa6733e26cf277a4a28252f05f859fc61cdeee7e90a9c65a981f508e71", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-one-stop-exterior-repeat", + "source": "svg-radial-start-one-stop-exterior-repeat.svg", + "source_sha256": "9813b5c76707c77fe9ac20fb0fcb1467b9932a7a959f6b5f9b097d67a5d25ace", + "oracle": "chromium/svg-radial-start-one-stop-exterior-repeat.png", + "oracle_sha256": "df1860aa6733e26cf277a4a28252f05f859fc61cdeee7e90a9c65a981f508e71", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-one-stop-focal", + "source": "svg-radial-start-one-stop-focal.svg", + "source_sha256": "f8cea8a66e37633f677d1c33911bb3a8c1d6dff1f55d2d1258954588da8b34bb", + "oracle": "chromium/svg-radial-start-one-stop-focal.png", + "oracle_sha256": "df1860aa6733e26cf277a4a28252f05f859fc61cdeee7e90a9c65a981f508e71", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-outer-negative-focal", + "source": "svg-radial-start-outer-negative-focal.svg", + "source_sha256": "329e9d27b0671cdd77b2641470db92642f2bd0ee1aed6b88d67f0339c9efe448", + "oracle": "chromium/svg-radial-start-outer-negative-focal.png", + "oracle_sha256": "ac74c3bed32526a16ef620dff4610ad854f070130065a4bcac535c843e9ef531", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-outer-zero-focal", + "source": "svg-radial-start-outer-zero-focal.svg", + "source_sha256": "e5ecb4672323d67126cf042d14763319e0a9b489f204faa588572d6fab37ba97", + "oracle": "chromium/svg-radial-start-outer-zero-focal.png", + "oracle_sha256": "ac74c3bed32526a16ef620dff4610ad854f070130065a4bcac535c843e9ef531", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-outer-zero-fr", + "source": "svg-radial-start-outer-zero-fr.svg", + "source_sha256": "a4b19687c4ac2f99085f201b0b795291198e8ad36f71ba5eed024c520b5a1fee", + "oracle": "chromium/svg-radial-start-outer-zero-fr.png", + "oracle_sha256": "68da8f0feb4b29f520d5159fbdf75cc83e27036828e737fad4ce57ac2683c0db", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-outer-zero-fx", + "source": "svg-radial-start-outer-zero-fx.svg", + "source_sha256": "500c53da6c77884404273d44b2fe34ac67ad0042bf7b9f84fb79e77e86bfc7f3", + "oracle": "chromium/svg-radial-start-outer-zero-fx.png", + "oracle_sha256": "6f4bc09437add7d83beb4429ffec5327b45c94ae909eab27f1225d6f82451d29", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-outer-zero-one-stop-focal", + "source": "svg-radial-start-outer-zero-one-stop-focal.svg", + "source_sha256": "47f0d969aaae043e23b8d4e6cf6a8739f2af1e8b849a769884f6dab4eef25d7f", + "oracle": "chromium/svg-radial-start-outer-zero-one-stop-focal.png", + "oracle_sha256": "1924a802682cafbcbad1a56367a93306e74fa62754ef5ea5486364ed97a3d6dd", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-outside-positive-fr", + "source": "svg-radial-start-outside-positive-fr.svg", + "source_sha256": "b473984c137fb3d8823f3733da7390cb7602ad70bf1052830511e1a7ba44de2a", + "oracle": "chromium/svg-radial-start-outside-positive-fr.png", + "oracle_sha256": "914e90d7e35715efad599840133a97dacf6a21ec5c16d33ae277a0b23616b838", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-relation-above", + "source": "svg-radial-start-relation-above.svg", + "source_sha256": "8ef770cdca9b6ca502f40e8ad4c255907fba76e3cf5abb80bc9e89ba834b69ed", + "oracle": "chromium/svg-radial-start-relation-above.png", + "oracle_sha256": "b16b44d438dac193895dd352f169fca5796e8ced683183cddcfaee67e7ed5d2c", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-relation-below", + "source": "svg-radial-start-relation-below.svg", + "source_sha256": "e8cb5906fa2bd8768185f1339695bb0bdc39443cec155a8989f0060d4edaf108", + "oracle": "chromium/svg-radial-start-relation-below.png", + "oracle_sha256": "4f0eadf498e6ed05d8362f29cf65bbc04d41c4859c80c0cebacb9ffe2f1ae41a", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-relation-containing", + "source": "svg-radial-start-relation-containing.svg", + "source_sha256": "62a8d29313498b09280ddc8cdac9464d99c5074357ea7e375505fe1cb5f2df74", + "oracle": "chromium/svg-radial-start-relation-containing.png", + "oracle_sha256": "b6f7aa1f7efabd472aefb2d66477f24f40c642b69c80928448c6be841ae22265", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-relation-disjoint", + "source": "svg-radial-start-relation-disjoint.svg", + "source_sha256": "151f537a12d993fdca8945fadedf21fb79a02a2ff4285351bc42f71b19b1f6e0", + "oracle": "chromium/svg-radial-start-relation-disjoint.png", + "oracle_sha256": "77d70ba0147ad931f86144fa91e6fa20a5273ab039217e6246f527a49f083895", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-relation-external-tangent", + "source": "svg-radial-start-relation-external-tangent.svg", + "source_sha256": "1c5331a52099b7c4b90b6f68772f0695ee4a5337aef3b66896101627fa7b5f5f", + "oracle": "chromium/svg-radial-start-relation-external-tangent.png", + "oracle_sha256": "3feb78fe38869fd53292d212ca20637f234c1fbf56c285f542b7d2762cca38bc", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-relation-internal-tangent", + "source": "svg-radial-start-relation-internal-tangent.svg", + "source_sha256": "3c2088f965e781024ca223f875539eabf7b0273f5f2e1b9405a81c6c7dcb990a", + "oracle": "chromium/svg-radial-start-relation-internal-tangent.png", + "oracle_sha256": "361cfdd770979e42392c0111311b2303fbff151a26f79ad24a66087994117746", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-relation-intersecting", + "source": "svg-radial-start-relation-intersecting.svg", + "source_sha256": "27fe9450c5bc6cca03c3d0c2bcd40788367a6031c9e300112411e13cca759bf2", + "oracle": "chromium/svg-radial-start-relation-intersecting.png", + "oracle_sha256": "34ba1e3fa79bf92dea2d1197a269de4bfcd32864504ccefe29c33e1948fa9a6d", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-relation-left", + "source": "svg-radial-start-relation-left.svg", + "source_sha256": "1f293eb11298eeeeab7cc2e0b9048ee913418974221e8804825c4e029b66b027", + "oracle": "chromium/svg-radial-start-relation-left.png", + "oracle_sha256": "3a664371ccd6fcca8c3c0cb4e19d8ef03c431aed35e2bbccafcdbd093596b051", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-relation-right", + "source": "svg-radial-start-relation-right.svg", + "source_sha256": "3dc08cb2a7560e9a1dac16394be06b82389f8b4032c4263d2095746409c3cf03", + "oracle": "chromium/svg-radial-start-relation-right.png", + "oracle_sha256": "ab97caf638fef1190e57dfc4b547a5bf80dea8d235df857a2e6dc2413b76a99d", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-same-circle-reflect", + "source": "svg-radial-start-same-circle-reflect.svg", + "source_sha256": "5e868076070c6fe173335c998f80cb7fe8d653ed15d310bd962764fc94a5d525", + "oracle": "chromium/svg-radial-start-same-circle-reflect.png", + "oracle_sha256": "4693b5e85e4c51a97270905cfdf2242c746fd4d2397a933791c9724a05e36984", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-same-circle-repeat", + "source": "svg-radial-start-same-circle-repeat.svg", + "source_sha256": "e5196b827a06dd8114c1410e25fd963040086e15bf2d998f6575235166ef165f", + "oracle": "chromium/svg-radial-start-same-circle-repeat.png", + "oracle_sha256": "4693b5e85e4c51a97270905cfdf2242c746fd4d2397a933791c9724a05e36984", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-spread-circle-reflect", + "source": "svg-radial-start-spread-circle-reflect.svg", + "source_sha256": "db4717b2853c41436d0d12a4379660078f8358570957841e59a2f8c44d233fcc", + "oracle": "chromium/svg-radial-start-spread-circle-reflect.png", + "oracle_sha256": "afad5d6014197fd02ed0c8757ac5bd1e8caa67c3692f1f42471cdce3e9036785", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-spread-circle-repeat", + "source": "svg-radial-start-spread-circle-repeat.svg", + "source_sha256": "2d370178ee41ef10da5d5f27408fed8f557062b9467f8fd45a1b9d01f619569b", + "oracle": "chromium/svg-radial-start-spread-circle-repeat.png", + "oracle_sha256": "a4f330f8746e9f7fcc1c5e4c18e7f77c9dd58b8c055560099fc6e27416facf9f", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-spread-outside-reflect", + "source": "svg-radial-start-spread-outside-reflect.svg", + "source_sha256": "51ee436bc421fb0393d84340f66e5b421305767f53dded980a16944feb465f81", + "oracle": "chromium/svg-radial-start-spread-outside-reflect.png", + "oracle_sha256": "29e0a6237be007419c18d998a449bc471e9cb935ab451a38acc292bb5556a169", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-spread-outside-repeat", + "source": "svg-radial-start-spread-outside-repeat.svg", + "source_sha256": "70ebadfd58ebd96d38db2938ee9cfdea2174e8cbd985101c2143768faa295bea", + "oracle": "chromium/svg-radial-start-spread-outside-repeat.png", + "oracle_sha256": "4ab77c7b881a34009e862d601dd239e8aa4526729d0d2cffad196366458a6ccc", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-spread-reversed-reflect", + "source": "svg-radial-start-spread-reversed-reflect.svg", + "source_sha256": "ea602c3bf8490d1af217006db23f4c28335a10d6f5f07fe4978fee2d000f7295", + "oracle": "chromium/svg-radial-start-spread-reversed-reflect.png", + "oracle_sha256": "c0291e09565d0a2364f55ec6aa36efdd8f11a60596b0c1057dd9255f90f5e26c", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-spread-reversed-repeat", + "source": "svg-radial-start-spread-reversed-repeat.svg", + "source_sha256": "596457f8f588892bca1b232ea1f7019004ddfc8466ae4841f53d12e3db94ac6e", + "oracle": "chromium/svg-radial-start-spread-reversed-repeat.png", + "oracle_sha256": "3f026bf07ca7436a83fc386208981691d898b8b1690cfde9c5b6a68d9dcef5e6", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-spread-zero-end-reflect", + "source": "svg-radial-start-spread-zero-end-reflect.svg", + "source_sha256": "b5f499df2431372624d84c6c9a078cde3f06ee23a87a93308f62c096099bacc5", + "oracle": "chromium/svg-radial-start-spread-zero-end-reflect.png", + "oracle_sha256": "e7f9bfef44095b456546dce865ace8f27a1a60f80c204d9a6bda855a0308065b", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-spread-zero-end-repeat", + "source": "svg-radial-start-spread-zero-end-repeat.svg", + "source_sha256": "9ffaa0125d07eb43732915493085daa1253d281b0dfbffdfc74170eadf15c72d", + "oracle": "chromium/svg-radial-start-spread-zero-end-repeat.png", + "oracle_sha256": "1ae3ce11d5cd86740bc91144aa19ea06d2a092a88ae154e259422278326b488d", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-stops-alpha", + "source": "svg-radial-start-stops-alpha.svg", + "source_sha256": "b2ff62a0e49262ffc0213d8e5d37b62136b58ef019cd103680b91959631e59bf", + "oracle": "chromium/svg-radial-start-stops-alpha.png", + "oracle_sha256": "4c0532e3496d4e1492df0234218efe9d62a2b7512d174c9f43598684510b3bb2", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-stops-duplicate", + "source": "svg-radial-start-stops-duplicate.svg", + "source_sha256": "3c53a98d5252bf4fc4606c6fa8612ddf03218bab52748545daa8d78385ea92ac", + "oracle": "chromium/svg-radial-start-stops-duplicate.png", + "oracle_sha256": "e7782de5839d8cffa2454c12ddbc189e9be6c9675eed89dd94a0d9023830d8d6", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-stops-edges", + "source": "svg-radial-start-stops-edges.svg", + "source_sha256": "0850ba587968dc1b32c02e79142708b07820e2c298aa536cfc004aa7499a30f8", + "oracle": "chromium/svg-radial-start-stops-edges.png", + "oracle_sha256": "0e4d12b58618fb759e3ec51fe41675b31c76adbdfd5c43dee5fc68f3b13d9c65", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-stops-unsorted", + "source": "svg-radial-start-stops-unsorted.svg", + "source_sha256": "905c239e0a0581c21aa4f628f1b590eeb894730f0442745243fe5ecf21d9ec63", + "oracle": "chromium/svg-radial-start-stops-unsorted.png", + "oracle_sha256": "7752804bc7de1c6f712a27b16e6e3bfdf410635440a483555aec2af9ef67e5e6", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-all", + "source": "svg-radial-start-template-all.svg", + "source_sha256": "25e2d302ebcec8271104f17f13dba0efdd23e4a5d78d5afa99ebe7ca818147a3", + "oracle": "chromium/svg-radial-start-template-all.png", + "oracle_sha256": "6852a4292ec18dcc524b95a66d21525fef6bb772859e4ba5bf85b77dfc2ba647", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-empty-fr", + "source": "svg-radial-start-template-empty-fr.svg", + "source_sha256": "0c07dbdcef5f45accde316aa4fcddb71901047d3a44a299fff44d77930339209", + "oracle": "chromium/svg-radial-start-template-empty-fr.png", + "oracle_sha256": "6534f8dda4e541a71ef65bb7b3ee1455bd361e82cdf591404e3ddd35a37f1227", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-empty-fx", + "source": "svg-radial-start-template-empty-fx.svg", + "source_sha256": "97dd74cd44631f41b91fed502d8c01e020735409f5722bfa952b978a3650d1da", + "oracle": "chromium/svg-radial-start-template-empty-fx.png", + "oracle_sha256": "2d3fd98c7d079cee77cc194a0f9b667e591424655b98aa9647d0801b078ba72f", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-empty-fy", + "source": "svg-radial-start-template-empty-fy.svg", + "source_sha256": "8507edfd6ffb994185d5d1c43b02bc768970749517e35b954ecf2ce9dd58bb81", + "oracle": "chromium/svg-radial-start-template-empty-fy.png", + "oracle_sha256": "ebef51b8e9e7a6be894c1a3809f65ceecbe6d0eca71c61737f064ca163d3d0b5", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-explicit-focus", + "source": "svg-radial-start-template-explicit-focus.svg", + "source_sha256": "6c79e250e16d606af381c72e6ac1f9d31d075c11de73aafac6ea5694897dc819", + "oracle": "chromium/svg-radial-start-template-explicit-focus.png", + "oracle_sha256": "c83ec0ec82c5ef86e6616a8ee3c66cdeeb6ef0cfbdf4479fb630a46aa880a6c6", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-fr-negative", + "source": "svg-radial-start-template-fr-negative.svg", + "source_sha256": "661de9aa0f2e75b7e5a0dd18746e03c59d1a255b05b8abc534b7cb96dd3af837", + "oracle": "chromium/svg-radial-start-template-fr-negative.png", + "oracle_sha256": "6534f8dda4e541a71ef65bb7b3ee1455bd361e82cdf591404e3ddd35a37f1227", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-fr-zero", + "source": "svg-radial-start-template-fr-zero.svg", + "source_sha256": "422fa949d37d35ee70ceb30bc3e15819dfccead87f5266360a6f7c5986b65381", + "oracle": "chromium/svg-radial-start-template-fr-zero.png", + "oracle_sha256": "6534f8dda4e541a71ef65bb7b3ee1455bd361e82cdf591404e3ddd35a37f1227", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-invalid-fr", + "source": "svg-radial-start-template-invalid-fr.svg", + "source_sha256": "e8aaec17c19df0f9f5886ae98e6567c6d7d9d557002779621da403253d6012ef", + "oracle": "chromium/svg-radial-start-template-invalid-fr.png", + "oracle_sha256": "6534f8dda4e541a71ef65bb7b3ee1455bd361e82cdf591404e3ddd35a37f1227", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-local-center", + "source": "svg-radial-start-template-local-center.svg", + "source_sha256": "82a4166d6506d6f71dff61ae3b36e9b70a9c82a6ec9b96748177cdbc16e49312", + "oracle": "chromium/svg-radial-start-template-local-center.png", + "oracle_sha256": "13fb674aec4eda5e29584853f8df1d8f67b3466342e760cc5df83cf965da9430", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-multihop", + "source": "svg-radial-start-template-multihop.svg", + "source_sha256": "1e9ef28aa2de31cbf23fbf0db3b9650270474eb4c77d0b3f4b721df093e85346", + "oracle": "chromium/svg-radial-start-template-multihop.png", + "oracle_sha256": "6852a4292ec18dcc524b95a66d21525fef6bb772859e4ba5bf85b77dfc2ba647", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-override-fr", + "source": "svg-radial-start-template-override-fr.svg", + "source_sha256": "93b4b8950a846072eaefab48cf19d99252cf078c1ff76df5b0919c704053b9e8", + "oracle": "chromium/svg-radial-start-template-override-fr.png", + "oracle_sha256": "bf542f4067a8557e9baa211601d28aa4211b17827eb1f50194c623424fc85460", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-override-fx", + "source": "svg-radial-start-template-override-fx.svg", + "source_sha256": "f33975ddf5cfdb308f6ca8723ff1c5c89e97215a643577c8a49329614831efbf", + "oracle": "chromium/svg-radial-start-template-override-fx.png", + "oracle_sha256": "1eb93120dfcdcec750e284b6e9df5087f35ba72239243f9c2e22258fdb55cb04", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-override-fy", + "source": "svg-radial-start-template-override-fy.svg", + "source_sha256": "12e7607c7650ea55f5a5d97160ee3d8555ba3d94417930da0d9431dc5c2e8269", + "oracle": "chromium/svg-radial-start-template-override-fy.png", + "oracle_sha256": "1572b7f0d48e1e74e21a0440411dbb788e466d7db91d3b1c9040407abd70e02b", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-xlink", + "source": "svg-radial-start-template-xlink.svg", + "source_sha256": "80728913316f097d22fad02884c15dddd7db90cfbbee106e7427ed65e385ce15", + "oracle": "chromium/svg-radial-start-template-xlink.png", + "oracle_sha256": "6852a4292ec18dcc524b95a66d21525fef6bb772859e4ba5bf85b77dfc2ba647", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-transform-rotate", + "source": "svg-radial-start-transform-rotate.svg", + "source_sha256": "314b5e2223f3e223dcdaf4780d12da40ff95d75cf489c1744ec77fc95d11e684", + "oracle": "chromium/svg-radial-start-transform-rotate.png", + "oracle_sha256": "fec2d2fb756b3a804a520869f594e7fc546a7c1c6fec3858349d9f55ce61f76b", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-transform-scale", + "source": "svg-radial-start-transform-scale.svg", + "source_sha256": "67ffcb5f5f8580fc4a1b02bc36ab41bb4d43909aed4d3c875c317297b6675cc4", + "oracle": "chromium/svg-radial-start-transform-scale.png", + "oracle_sha256": "2dc123861114172f7df4bc4007f7f21cce3e0f02a23ef4e96fc753d01598d176", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-transform-singular", + "source": "svg-radial-start-transform-singular.svg", + "source_sha256": "32293b5fcd06f70625023e88996dc3e6dbc74298dfa8f1dab7c20114a8f3aded", + "oracle": "chromium/svg-radial-start-transform-singular.png", + "oracle_sha256": "6f4bc09437add7d83beb4429ffec5327b45c94ae909eab27f1225d6f82451d29", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-transform-skew", + "source": "svg-radial-start-transform-skew.svg", + "source_sha256": "4d86c97659381d1ae7e0950fa075bf9a35cc8ab43289a529907f649e878d8112", + "oracle": "chromium/svg-radial-start-transform-skew.png", + "oracle_sha256": "f8d69958c99486194826dc4bbdb56d565d5131b1a382c9f73011f4477e507011", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-transform-translate", + "source": "svg-radial-start-transform-translate.svg", + "source_sha256": "de502c4f4a8a481cd7805f181236386e40810894a04987b81c0bec5fdc8fae0b", + "oracle": "chromium/svg-radial-start-transform-translate.png", + "oracle_sha256": "7a3c12e9c0cb258f1fc7700f24c16800ec423225278e579c04f46c6c86e0097d", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-transparent-cone", + "source": "svg-radial-start-transparent-cone.svg", + "source_sha256": "6fde32b5f7193fb3d04fb5f60db42ddcb4bb6da63952541cc9759bb2f8a753d4", + "oracle": "chromium/svg-radial-start-transparent-cone.png", + "oracle_sha256": "5499a18296e821d032ca84d0f309a4cf75e7bcc5ce1dbc8a9d5ba6005131edc6", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-user-percent-fr", + "source": "svg-radial-start-user-percent-fr.svg", + "source_sha256": "9743b6956a95d6f6fd69ce8b9d5088a69f18b453e2c6af3a2cf5ad0b7a7d86b5", + "oracle": "chromium/svg-radial-start-user-percent-fr.png", + "oracle_sha256": "99b098487564030537529948bf95654428e511ec72e296a64f82eb39db92e5e9", + "width": 64, + "height": 32 + }, + { + "id": "svg-radial-start-user-percent-fx", + "source": "svg-radial-start-user-percent-fx.svg", + "source_sha256": "db38a2dcb28a5a65bcbd2130a4c633d0324b3af7bdde3a75002156c1b452d83f", + "oracle": "chromium/svg-radial-start-user-percent-fx.png", + "oracle_sha256": "99b098487564030537529948bf95654428e511ec72e296a64f82eb39db92e5e9", + "width": 64, + "height": 32 + }, + { + "id": "svg-radial-start-user-percent-fy", + "source": "svg-radial-start-user-percent-fy.svg", + "source_sha256": "d7a9c23470a71c991492acd7e6ceba640e10e8ec0659ae79f08ca20588554615", + "oracle": "chromium/svg-radial-start-user-percent-fy.png", + "oracle_sha256": "99b098487564030537529948bf95654428e511ec72e296a64f82eb39db92e5e9", + "width": 64, + "height": 32 + }, + { + "id": "svg-radial-start-user-px", + "source": "svg-radial-start-user-px.svg", + "source_sha256": "d92eb0081af402a8ed835520d36cb38df7daa822d5216b9f229c2926559087a2", + "oracle": "chromium/svg-radial-start-user-px.png", + "oracle_sha256": "99a82542cf90d191408c0f560a80e1bd71ae5df5fcbf4535919591c36de2683f", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-zero-stops-focal", + "source": "svg-radial-start-zero-stops-focal.svg", + "source_sha256": "53b3ed6cfed8f5e6a3246108e82f86bb0553bf5bb2451122f401997c4f2192a5", + "oracle": "chromium/svg-radial-start-zero-stops-focal.png", + "oracle_sha256": "6f4bc09437add7d83beb4429ffec5327b45c94ae909eab27f1225d6f82451d29", + "width": 64, + "height": 64 + }, { "id": "svg-rect-rounded", "source": "svg-rect-rounded.svg", diff --git a/fixtures/web-first/primitives.json b/fixtures/web-first/primitives.json index 3875cfd2..d89a20ef 100644 --- a/fixtures/web-first/primitives.json +++ b/fixtures/web-first/primitives.json @@ -41,6 +41,14 @@ "width": 64, "height": 64 }, + { + "id": "html-inline-svg-radial-start", + "source": "html-inline-svg-radial-start.html", + "entry": "html-inline-svg", + "oracle": "chromium/html-inline-svg-radial-start.png", + "width": 64, + "height": 64 + }, { "id": "html-inline-svg-vector-effect", "source": "html-inline-svg-vector-effect.html", @@ -7699,6 +7707,1054 @@ "width": 64, "height": 32 }, + { + "id": "svg-radial-start-box-percent", + "source": "svg-radial-start-box-percent.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-box-percent.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-channel-opacity", + "source": "svg-radial-start-client-channel-opacity.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-client-channel-opacity.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-clip", + "source": "svg-radial-start-client-clip.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-client-clip.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-dashes", + "source": "svg-radial-start-client-dashes.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-client-dashes.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-ellipse", + "source": "svg-radial-start-client-ellipse.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-client-ellipse.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-filter", + "source": "svg-radial-start-client-filter.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-client-filter.png", + "width": 64, + "height": 64, + "tolerance": { + "kind": "ramp-quantization", + "max_differing_pixels": 1465, + "max_channel_delta": 1 + } + }, + { + "id": "svg-radial-start-client-group-opacity", + "source": "svg-radial-start-client-group-opacity.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-client-group-opacity.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-mask", + "source": "svg-radial-start-client-mask.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-client-mask.png", + "width": 64, + "height": 64, + "tolerance": { + "kind": "ramp-quantization", + "max_differing_pixels": 613, + "max_channel_delta": 1 + } + }, + { + "id": "svg-radial-start-client-nested", + "source": "svg-radial-start-client-nested.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-client-nested.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-order", + "source": "svg-radial-start-client-order.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-client-order.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-path", + "source": "svg-radial-start-client-path.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-client-path.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-pattern", + "source": "svg-radial-start-client-pattern.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-client-pattern.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-stroke", + "source": "svg-radial-start-client-stroke.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-client-stroke.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-transform", + "source": "svg-radial-start-client-transform.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-client-transform.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-client-use", + "source": "svg-radial-start-client-use.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-client-use.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-default", + "source": "svg-radial-start-default.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-default.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-explicit-default", + "source": "svg-radial-start-explicit-default.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-explicit-default.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-decimal-higher", + "source": "svg-radial-start-fr-decimal-higher.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fr-decimal-higher.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-decimal-lower", + "source": "svg-radial-start-fr-decimal-lower.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fr-decimal-lower.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-equal-r", + "source": "svg-radial-start-fr-equal-r.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fr-equal-r.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-greater-r", + "source": "svg-radial-start-fr-greater-r.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fr-greater-r.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-midpoint-higher", + "source": "svg-radial-start-fr-midpoint-higher.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fr-midpoint-higher.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-midpoint-lower", + "source": "svg-radial-start-fr-midpoint-lower.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fr-midpoint-lower.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-negative", + "source": "svg-radial-start-fr-negative.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fr-negative.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-negative-zero", + "source": "svg-radial-start-fr-negative-zero.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fr-negative-zero.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-percentage-higher", + "source": "svg-radial-start-fr-percentage-higher.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fr-percentage-higher.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-percentage-lower", + "source": "svg-radial-start-fr-percentage-lower.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fr-percentage-lower.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fr-quarter", + "source": "svg-radial-start-fr-quarter.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fr-quarter.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fx-decimal-higher", + "source": "svg-radial-start-fx-decimal-higher.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fx-decimal-higher.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fx-decimal-lower", + "source": "svg-radial-start-fx-decimal-lower.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fx-decimal-lower.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fx-negative", + "source": "svg-radial-start-fx-negative.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fx-negative.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fx-on-end", + "source": "svg-radial-start-fx-on-end.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fx-on-end.png", + "width": 64, + "height": 64, + "tolerance": { + "kind": "ramp-quantization", + "max_differing_pixels": 1, + "max_channel_delta": 1 + } + }, + { + "id": "svg-radial-start-fx-outside", + "source": "svg-radial-start-fx-outside.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fx-outside.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fx-percentage-higher", + "source": "svg-radial-start-fx-percentage-higher.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fx-percentage-higher.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fx-percentage-lower", + "source": "svg-radial-start-fx-percentage-lower.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fx-percentage-lower.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fx-quarter", + "source": "svg-radial-start-fx-quarter.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fx-quarter.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fxy-fr-quarter", + "source": "svg-radial-start-fxy-fr-quarter.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fxy-fr-quarter.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fxy-quarter", + "source": "svg-radial-start-fxy-quarter.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fxy-quarter.png", + "width": 64, + "height": 64, + "tolerance": { + "kind": "ramp-quantization", + "max_differing_pixels": 1, + "max_channel_delta": 1 + } + }, + { + "id": "svg-radial-start-fy-decimal-higher", + "source": "svg-radial-start-fy-decimal-higher.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fy-decimal-higher.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fy-decimal-lower", + "source": "svg-radial-start-fy-decimal-lower.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fy-decimal-lower.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fy-percentage-higher", + "source": "svg-radial-start-fy-percentage-higher.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fy-percentage-higher.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fy-percentage-lower", + "source": "svg-radial-start-fy-percentage-lower.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fy-percentage-lower.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-fy-quarter", + "source": "svg-radial-start-fy-quarter.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-fy-quarter.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-graduated-focal", + "source": "svg-radial-start-graduated-focal.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-graduated-focal.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fr-comma", + "source": "svg-radial-start-grammar-fr-comma.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fr-comma.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fr-exponent", + "source": "svg-radial-start-grammar-fr-exponent.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fr-exponent.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fr-integer", + "source": "svg-radial-start-grammar-fr-integer.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fr-integer.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fr-nbsp", + "source": "svg-radial-start-grammar-fr-nbsp.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fr-nbsp.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fr-signed", + "source": "svg-radial-start-grammar-fr-signed.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fr-signed.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fr-trailingdot", + "source": "svg-radial-start-grammar-fr-trailingdot.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fr-trailingdot.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fr-whitespace", + "source": "svg-radial-start-grammar-fr-whitespace.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fr-whitespace.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fx-comma", + "source": "svg-radial-start-grammar-fx-comma.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fx-comma.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fx-exponent", + "source": "svg-radial-start-grammar-fx-exponent.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fx-exponent.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fx-integer", + "source": "svg-radial-start-grammar-fx-integer.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fx-integer.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fx-nbsp", + "source": "svg-radial-start-grammar-fx-nbsp.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fx-nbsp.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fx-signed", + "source": "svg-radial-start-grammar-fx-signed.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fx-signed.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fx-trailingdot", + "source": "svg-radial-start-grammar-fx-trailingdot.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fx-trailingdot.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fx-whitespace", + "source": "svg-radial-start-grammar-fx-whitespace.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fx-whitespace.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fy-comma", + "source": "svg-radial-start-grammar-fy-comma.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fy-comma.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fy-exponent", + "source": "svg-radial-start-grammar-fy-exponent.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fy-exponent.png", + "width": 64, + "height": 64, + "tolerance": { + "kind": "ramp-quantization", + "max_differing_pixels": 1, + "max_channel_delta": 1 + } + }, + { + "id": "svg-radial-start-grammar-fy-integer", + "source": "svg-radial-start-grammar-fy-integer.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fy-integer.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fy-nbsp", + "source": "svg-radial-start-grammar-fy-nbsp.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fy-nbsp.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fy-signed", + "source": "svg-radial-start-grammar-fy-signed.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fy-signed.png", + "width": 64, + "height": 64, + "tolerance": { + "kind": "ramp-quantization", + "max_differing_pixels": 1, + "max_channel_delta": 1 + } + }, + { + "id": "svg-radial-start-grammar-fy-trailingdot", + "source": "svg-radial-start-grammar-fy-trailingdot.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fy-trailingdot.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-grammar-fy-whitespace", + "source": "svg-radial-start-grammar-fy-whitespace.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-grammar-fy-whitespace.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-mapped-viewbox", + "source": "svg-radial-start-mapped-viewbox.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-mapped-viewbox.png", + "width": 64, + "height": 32 + }, + { + "id": "svg-radial-start-on-end-reflect", + "source": "svg-radial-start-on-end-reflect.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-on-end-reflect.png", + "width": 64, + "height": 64, + "tolerance": { + "kind": "ramp-quantization", + "max_differing_pixels": 1, + "max_channel_delta": 1 + } + }, + { + "id": "svg-radial-start-on-end-repeat", + "source": "svg-radial-start-on-end-repeat.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-on-end-repeat.png", + "width": 64, + "height": 64, + "tolerance": { + "kind": "ramp-quantization", + "max_differing_pixels": 1, + "max_channel_delta": 1 + } + }, + { + "id": "svg-radial-start-one-stop-default", + "source": "svg-radial-start-one-stop-default.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-one-stop-default.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-one-stop-exterior-reflect", + "source": "svg-radial-start-one-stop-exterior-reflect.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-one-stop-exterior-reflect.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-one-stop-exterior-repeat", + "source": "svg-radial-start-one-stop-exterior-repeat.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-one-stop-exterior-repeat.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-one-stop-focal", + "source": "svg-radial-start-one-stop-focal.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-one-stop-focal.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-outer-negative-focal", + "source": "svg-radial-start-outer-negative-focal.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-outer-negative-focal.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-outer-zero-focal", + "source": "svg-radial-start-outer-zero-focal.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-outer-zero-focal.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-outer-zero-fr", + "source": "svg-radial-start-outer-zero-fr.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-outer-zero-fr.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-outer-zero-fx", + "source": "svg-radial-start-outer-zero-fx.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-outer-zero-fx.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-outer-zero-one-stop-focal", + "source": "svg-radial-start-outer-zero-one-stop-focal.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-outer-zero-one-stop-focal.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-outside-positive-fr", + "source": "svg-radial-start-outside-positive-fr.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-outside-positive-fr.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-relation-above", + "source": "svg-radial-start-relation-above.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-relation-above.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-relation-below", + "source": "svg-radial-start-relation-below.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-relation-below.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-relation-containing", + "source": "svg-radial-start-relation-containing.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-relation-containing.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-relation-disjoint", + "source": "svg-radial-start-relation-disjoint.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-relation-disjoint.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-relation-external-tangent", + "source": "svg-radial-start-relation-external-tangent.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-relation-external-tangent.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-relation-internal-tangent", + "source": "svg-radial-start-relation-internal-tangent.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-relation-internal-tangent.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-relation-intersecting", + "source": "svg-radial-start-relation-intersecting.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-relation-intersecting.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-relation-left", + "source": "svg-radial-start-relation-left.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-relation-left.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-relation-right", + "source": "svg-radial-start-relation-right.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-relation-right.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-same-circle-reflect", + "source": "svg-radial-start-same-circle-reflect.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-same-circle-reflect.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-same-circle-repeat", + "source": "svg-radial-start-same-circle-repeat.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-same-circle-repeat.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-spread-circle-reflect", + "source": "svg-radial-start-spread-circle-reflect.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-spread-circle-reflect.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-spread-circle-repeat", + "source": "svg-radial-start-spread-circle-repeat.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-spread-circle-repeat.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-spread-outside-reflect", + "source": "svg-radial-start-spread-outside-reflect.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-spread-outside-reflect.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-spread-outside-repeat", + "source": "svg-radial-start-spread-outside-repeat.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-spread-outside-repeat.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-spread-reversed-reflect", + "source": "svg-radial-start-spread-reversed-reflect.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-spread-reversed-reflect.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-spread-reversed-repeat", + "source": "svg-radial-start-spread-reversed-repeat.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-spread-reversed-repeat.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-spread-zero-end-reflect", + "source": "svg-radial-start-spread-zero-end-reflect.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-spread-zero-end-reflect.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-spread-zero-end-repeat", + "source": "svg-radial-start-spread-zero-end-repeat.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-spread-zero-end-repeat.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-stops-alpha", + "source": "svg-radial-start-stops-alpha.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-stops-alpha.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-stops-duplicate", + "source": "svg-radial-start-stops-duplicate.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-stops-duplicate.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-stops-edges", + "source": "svg-radial-start-stops-edges.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-stops-edges.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-stops-unsorted", + "source": "svg-radial-start-stops-unsorted.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-stops-unsorted.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-all", + "source": "svg-radial-start-template-all.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-template-all.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-empty-fr", + "source": "svg-radial-start-template-empty-fr.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-template-empty-fr.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-empty-fx", + "source": "svg-radial-start-template-empty-fx.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-template-empty-fx.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-empty-fy", + "source": "svg-radial-start-template-empty-fy.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-template-empty-fy.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-explicit-focus", + "source": "svg-radial-start-template-explicit-focus.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-template-explicit-focus.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-fr-negative", + "source": "svg-radial-start-template-fr-negative.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-template-fr-negative.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-fr-zero", + "source": "svg-radial-start-template-fr-zero.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-template-fr-zero.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-invalid-fr", + "source": "svg-radial-start-template-invalid-fr.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-template-invalid-fr.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-local-center", + "source": "svg-radial-start-template-local-center.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-template-local-center.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-multihop", + "source": "svg-radial-start-template-multihop.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-template-multihop.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-override-fr", + "source": "svg-radial-start-template-override-fr.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-template-override-fr.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-override-fx", + "source": "svg-radial-start-template-override-fx.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-template-override-fx.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-override-fy", + "source": "svg-radial-start-template-override-fy.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-template-override-fy.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-template-xlink", + "source": "svg-radial-start-template-xlink.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-template-xlink.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-transform-rotate", + "source": "svg-radial-start-transform-rotate.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-transform-rotate.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-transform-scale", + "source": "svg-radial-start-transform-scale.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-transform-scale.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-transform-singular", + "source": "svg-radial-start-transform-singular.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-transform-singular.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-transform-skew", + "source": "svg-radial-start-transform-skew.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-transform-skew.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-transform-translate", + "source": "svg-radial-start-transform-translate.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-transform-translate.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-transparent-cone", + "source": "svg-radial-start-transparent-cone.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-transparent-cone.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-user-percent-fr", + "source": "svg-radial-start-user-percent-fr.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-user-percent-fr.png", + "width": 64, + "height": 32 + }, + { + "id": "svg-radial-start-user-percent-fx", + "source": "svg-radial-start-user-percent-fx.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-user-percent-fx.png", + "width": 64, + "height": 32 + }, + { + "id": "svg-radial-start-user-percent-fy", + "source": "svg-radial-start-user-percent-fy.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-user-percent-fy.png", + "width": 64, + "height": 32 + }, + { + "id": "svg-radial-start-user-px", + "source": "svg-radial-start-user-px.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-user-px.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-radial-start-zero-stops-focal", + "source": "svg-radial-start-zero-stops-focal.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-radial-start-zero-stops-focal.png", + "width": 64, + "height": 64 + }, { "id": "svg-rect-rounded", "source": "svg-rect-rounded.svg", diff --git a/fixtures/web-first/probe_harness.ts b/fixtures/web-first/probe_harness.ts index c897069e..889735ee 100644 --- a/fixtures/web-first/probe_harness.ts +++ b/fixtures/web-first/probe_harness.ts @@ -60,8 +60,10 @@ export function comparePngs(a: Buffer, b: Buffer): ProbeComparison { } export interface ProbeMatrix { - /** id → standalone SVG source. */ + /** id → source in the declared entry grammar. */ probes: Record; + /** Same ingress choice as the baker; standalone SVG remains the default. */ + entry?: "standalone-svg" | "html-inline-svg"; /** [left id, right id, what identity/difference would mean]. */ pairs: Array<[string, string, string]>; /** Where captures are written for eyeballing (scratch space). */ @@ -88,7 +90,7 @@ export async function runProbeMatrix(matrix: ProbeMatrix): Promise { for (const [id, svg] of Object.entries(matrix.probes)) { const page = await context.newPage(); const capture = { - media: "image/svg+xml" as const, + media: matrix.entry === "html-inline-svg" ? "text/html" as const : "image/svg+xml" as const, source: Buffer.from(svg), width, height, diff --git a/fixtures/web-first/svg-radial-start-box-percent.svg b/fixtures/web-first/svg-radial-start-box-percent.svg new file mode 100644 index 00000000..8273a849 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-box-percent.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-client-channel-opacity.svg b/fixtures/web-first/svg-radial-start-client-channel-opacity.svg new file mode 100644 index 00000000..8ac9bdec --- /dev/null +++ b/fixtures/web-first/svg-radial-start-client-channel-opacity.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-client-clip.svg b/fixtures/web-first/svg-radial-start-client-clip.svg new file mode 100644 index 00000000..8741455c --- /dev/null +++ b/fixtures/web-first/svg-radial-start-client-clip.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-client-dashes.svg b/fixtures/web-first/svg-radial-start-client-dashes.svg new file mode 100644 index 00000000..19f2535f --- /dev/null +++ b/fixtures/web-first/svg-radial-start-client-dashes.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-client-ellipse.svg b/fixtures/web-first/svg-radial-start-client-ellipse.svg new file mode 100644 index 00000000..47106e63 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-client-ellipse.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-client-filter.svg b/fixtures/web-first/svg-radial-start-client-filter.svg new file mode 100644 index 00000000..2c28199c --- /dev/null +++ b/fixtures/web-first/svg-radial-start-client-filter.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-client-group-opacity.svg b/fixtures/web-first/svg-radial-start-client-group-opacity.svg new file mode 100644 index 00000000..2fa97be4 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-client-group-opacity.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-client-mask.svg b/fixtures/web-first/svg-radial-start-client-mask.svg new file mode 100644 index 00000000..5b06c66e --- /dev/null +++ b/fixtures/web-first/svg-radial-start-client-mask.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-client-nested.svg b/fixtures/web-first/svg-radial-start-client-nested.svg new file mode 100644 index 00000000..a629a6b9 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-client-nested.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-client-order.svg b/fixtures/web-first/svg-radial-start-client-order.svg new file mode 100644 index 00000000..7fc31dad --- /dev/null +++ b/fixtures/web-first/svg-radial-start-client-order.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-client-path.svg b/fixtures/web-first/svg-radial-start-client-path.svg new file mode 100644 index 00000000..99ce188e --- /dev/null +++ b/fixtures/web-first/svg-radial-start-client-path.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-client-pattern.svg b/fixtures/web-first/svg-radial-start-client-pattern.svg new file mode 100644 index 00000000..05c1ae41 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-client-pattern.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-client-stroke.svg b/fixtures/web-first/svg-radial-start-client-stroke.svg new file mode 100644 index 00000000..d3775aad --- /dev/null +++ b/fixtures/web-first/svg-radial-start-client-stroke.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-client-transform.svg b/fixtures/web-first/svg-radial-start-client-transform.svg new file mode 100644 index 00000000..acb40063 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-client-transform.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-client-use.svg b/fixtures/web-first/svg-radial-start-client-use.svg new file mode 100644 index 00000000..fdfcc2a0 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-client-use.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-default.svg b/fixtures/web-first/svg-radial-start-default.svg new file mode 100644 index 00000000..7f5648f4 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-default.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-explicit-default.svg b/fixtures/web-first/svg-radial-start-explicit-default.svg new file mode 100644 index 00000000..f12c013a --- /dev/null +++ b/fixtures/web-first/svg-radial-start-explicit-default.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-fr-decimal-higher.svg b/fixtures/web-first/svg-radial-start-fr-decimal-higher.svg new file mode 100644 index 00000000..2be2409e --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fr-decimal-higher.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-fr-decimal-lower.svg b/fixtures/web-first/svg-radial-start-fr-decimal-lower.svg new file mode 100644 index 00000000..a2080186 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fr-decimal-lower.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-fr-equal-r.svg b/fixtures/web-first/svg-radial-start-fr-equal-r.svg new file mode 100644 index 00000000..a857344f --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fr-equal-r.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-fr-greater-r.svg b/fixtures/web-first/svg-radial-start-fr-greater-r.svg new file mode 100644 index 00000000..2036849f --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fr-greater-r.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-fr-midpoint-higher.svg b/fixtures/web-first/svg-radial-start-fr-midpoint-higher.svg new file mode 100644 index 00000000..8c5bc892 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fr-midpoint-higher.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-fr-midpoint-lower.svg b/fixtures/web-first/svg-radial-start-fr-midpoint-lower.svg new file mode 100644 index 00000000..93b95608 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fr-midpoint-lower.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-fr-negative-zero.svg b/fixtures/web-first/svg-radial-start-fr-negative-zero.svg new file mode 100644 index 00000000..2102e7c7 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fr-negative-zero.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-fr-negative.svg b/fixtures/web-first/svg-radial-start-fr-negative.svg new file mode 100644 index 00000000..b54162eb --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fr-negative.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-fr-percentage-higher.svg b/fixtures/web-first/svg-radial-start-fr-percentage-higher.svg new file mode 100644 index 00000000..5c3ee8ce --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fr-percentage-higher.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-fr-percentage-lower.svg b/fixtures/web-first/svg-radial-start-fr-percentage-lower.svg new file mode 100644 index 00000000..5f4547f9 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fr-percentage-lower.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-fr-quarter.svg b/fixtures/web-first/svg-radial-start-fr-quarter.svg new file mode 100644 index 00000000..7f6a1bf8 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fr-quarter.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-fx-decimal-higher.svg b/fixtures/web-first/svg-radial-start-fx-decimal-higher.svg new file mode 100644 index 00000000..1eb669bd --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fx-decimal-higher.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-fx-decimal-lower.svg b/fixtures/web-first/svg-radial-start-fx-decimal-lower.svg new file mode 100644 index 00000000..33f9dedd --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fx-decimal-lower.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-fx-negative.svg b/fixtures/web-first/svg-radial-start-fx-negative.svg new file mode 100644 index 00000000..8b171dd9 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fx-negative.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-fx-on-end.svg b/fixtures/web-first/svg-radial-start-fx-on-end.svg new file mode 100644 index 00000000..dac4d4df --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fx-on-end.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-fx-outside.svg b/fixtures/web-first/svg-radial-start-fx-outside.svg new file mode 100644 index 00000000..6b96e33f --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fx-outside.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-fx-percentage-higher.svg b/fixtures/web-first/svg-radial-start-fx-percentage-higher.svg new file mode 100644 index 00000000..50dea443 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fx-percentage-higher.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-fx-percentage-lower.svg b/fixtures/web-first/svg-radial-start-fx-percentage-lower.svg new file mode 100644 index 00000000..48cf4e91 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fx-percentage-lower.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-fx-quarter.svg b/fixtures/web-first/svg-radial-start-fx-quarter.svg new file mode 100644 index 00000000..0c363b70 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fx-quarter.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-fxy-fr-quarter.svg b/fixtures/web-first/svg-radial-start-fxy-fr-quarter.svg new file mode 100644 index 00000000..4ae6cf67 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fxy-fr-quarter.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-fxy-quarter.svg b/fixtures/web-first/svg-radial-start-fxy-quarter.svg new file mode 100644 index 00000000..0b7c4c1a --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fxy-quarter.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-fy-decimal-higher.svg b/fixtures/web-first/svg-radial-start-fy-decimal-higher.svg new file mode 100644 index 00000000..4da91830 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fy-decimal-higher.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-fy-decimal-lower.svg b/fixtures/web-first/svg-radial-start-fy-decimal-lower.svg new file mode 100644 index 00000000..41dce44a --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fy-decimal-lower.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-fy-percentage-higher.svg b/fixtures/web-first/svg-radial-start-fy-percentage-higher.svg new file mode 100644 index 00000000..6b4291d0 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fy-percentage-higher.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-fy-percentage-lower.svg b/fixtures/web-first/svg-radial-start-fy-percentage-lower.svg new file mode 100644 index 00000000..d31bc339 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fy-percentage-lower.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-fy-quarter.svg b/fixtures/web-first/svg-radial-start-fy-quarter.svg new file mode 100644 index 00000000..d65fc897 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-fy-quarter.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/unsupported/svg-gradient-focal.svg b/fixtures/web-first/svg-radial-start-graduated-focal.svg similarity index 100% rename from fixtures/web-first/unsupported/svg-gradient-focal.svg rename to fixtures/web-first/svg-radial-start-graduated-focal.svg diff --git a/fixtures/web-first/svg-radial-start-grammar-fr-comma.svg b/fixtures/web-first/svg-radial-start-grammar-fr-comma.svg new file mode 100644 index 00000000..c9a49c6a --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fr-comma.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fr-exponent.svg b/fixtures/web-first/svg-radial-start-grammar-fr-exponent.svg new file mode 100644 index 00000000..cec265eb --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fr-exponent.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fr-integer.svg b/fixtures/web-first/svg-radial-start-grammar-fr-integer.svg new file mode 100644 index 00000000..70df71a8 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fr-integer.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fr-nbsp.svg b/fixtures/web-first/svg-radial-start-grammar-fr-nbsp.svg new file mode 100644 index 00000000..b5761d98 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fr-nbsp.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fr-signed.svg b/fixtures/web-first/svg-radial-start-grammar-fr-signed.svg new file mode 100644 index 00000000..8129f933 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fr-signed.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fr-trailingdot.svg b/fixtures/web-first/svg-radial-start-grammar-fr-trailingdot.svg new file mode 100644 index 00000000..4e738e37 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fr-trailingdot.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fr-whitespace.svg b/fixtures/web-first/svg-radial-start-grammar-fr-whitespace.svg new file mode 100644 index 00000000..e3926cfd --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fr-whitespace.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fx-comma.svg b/fixtures/web-first/svg-radial-start-grammar-fx-comma.svg new file mode 100644 index 00000000..a2b84168 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fx-comma.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fx-exponent.svg b/fixtures/web-first/svg-radial-start-grammar-fx-exponent.svg new file mode 100644 index 00000000..8cab680c --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fx-exponent.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fx-integer.svg b/fixtures/web-first/svg-radial-start-grammar-fx-integer.svg new file mode 100644 index 00000000..bfca28ce --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fx-integer.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fx-nbsp.svg b/fixtures/web-first/svg-radial-start-grammar-fx-nbsp.svg new file mode 100644 index 00000000..0cb1f98c --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fx-nbsp.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fx-signed.svg b/fixtures/web-first/svg-radial-start-grammar-fx-signed.svg new file mode 100644 index 00000000..6b3eb53e --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fx-signed.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fx-trailingdot.svg b/fixtures/web-first/svg-radial-start-grammar-fx-trailingdot.svg new file mode 100644 index 00000000..20a46dfe --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fx-trailingdot.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fx-whitespace.svg b/fixtures/web-first/svg-radial-start-grammar-fx-whitespace.svg new file mode 100644 index 00000000..f8ad0651 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fx-whitespace.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fy-comma.svg b/fixtures/web-first/svg-radial-start-grammar-fy-comma.svg new file mode 100644 index 00000000..80f27600 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fy-comma.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fy-exponent.svg b/fixtures/web-first/svg-radial-start-grammar-fy-exponent.svg new file mode 100644 index 00000000..75416145 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fy-exponent.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fy-integer.svg b/fixtures/web-first/svg-radial-start-grammar-fy-integer.svg new file mode 100644 index 00000000..35e99cdc --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fy-integer.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fy-nbsp.svg b/fixtures/web-first/svg-radial-start-grammar-fy-nbsp.svg new file mode 100644 index 00000000..19dda84f --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fy-nbsp.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fy-signed.svg b/fixtures/web-first/svg-radial-start-grammar-fy-signed.svg new file mode 100644 index 00000000..49d6dc30 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fy-signed.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fy-trailingdot.svg b/fixtures/web-first/svg-radial-start-grammar-fy-trailingdot.svg new file mode 100644 index 00000000..5f484e24 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fy-trailingdot.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-grammar-fy-whitespace.svg b/fixtures/web-first/svg-radial-start-grammar-fy-whitespace.svg new file mode 100644 index 00000000..281da21d --- /dev/null +++ b/fixtures/web-first/svg-radial-start-grammar-fy-whitespace.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-mapped-viewbox.svg b/fixtures/web-first/svg-radial-start-mapped-viewbox.svg new file mode 100644 index 00000000..524b0d97 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-mapped-viewbox.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-on-end-reflect.svg b/fixtures/web-first/svg-radial-start-on-end-reflect.svg new file mode 100644 index 00000000..9879d0cd --- /dev/null +++ b/fixtures/web-first/svg-radial-start-on-end-reflect.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-on-end-repeat.svg b/fixtures/web-first/svg-radial-start-on-end-repeat.svg new file mode 100644 index 00000000..f295bffb --- /dev/null +++ b/fixtures/web-first/svg-radial-start-on-end-repeat.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-one-stop-default.svg b/fixtures/web-first/svg-radial-start-one-stop-default.svg new file mode 100644 index 00000000..e26c3a5d --- /dev/null +++ b/fixtures/web-first/svg-radial-start-one-stop-default.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/fixtures/web-first/svg-radial-start-one-stop-exterior-reflect.svg b/fixtures/web-first/svg-radial-start-one-stop-exterior-reflect.svg new file mode 100644 index 00000000..ba1a5434 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-one-stop-exterior-reflect.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-one-stop-exterior-repeat.svg b/fixtures/web-first/svg-radial-start-one-stop-exterior-repeat.svg new file mode 100644 index 00000000..a54d027f --- /dev/null +++ b/fixtures/web-first/svg-radial-start-one-stop-exterior-repeat.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-one-stop-focal.svg b/fixtures/web-first/svg-radial-start-one-stop-focal.svg new file mode 100644 index 00000000..c60d76ae --- /dev/null +++ b/fixtures/web-first/svg-radial-start-one-stop-focal.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/fixtures/web-first/svg-radial-start-outer-negative-focal.svg b/fixtures/web-first/svg-radial-start-outer-negative-focal.svg new file mode 100644 index 00000000..0bbce2bd --- /dev/null +++ b/fixtures/web-first/svg-radial-start-outer-negative-focal.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-outer-zero-focal.svg b/fixtures/web-first/svg-radial-start-outer-zero-focal.svg new file mode 100644 index 00000000..9a8cd523 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-outer-zero-focal.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-outer-zero-fr.svg b/fixtures/web-first/svg-radial-start-outer-zero-fr.svg new file mode 100644 index 00000000..c842ead7 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-outer-zero-fr.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-outer-zero-fx.svg b/fixtures/web-first/svg-radial-start-outer-zero-fx.svg new file mode 100644 index 00000000..82496eb3 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-outer-zero-fx.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-outer-zero-one-stop-focal.svg b/fixtures/web-first/svg-radial-start-outer-zero-one-stop-focal.svg new file mode 100644 index 00000000..1dcf09ce --- /dev/null +++ b/fixtures/web-first/svg-radial-start-outer-zero-one-stop-focal.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/fixtures/web-first/svg-radial-start-outside-positive-fr.svg b/fixtures/web-first/svg-radial-start-outside-positive-fr.svg new file mode 100644 index 00000000..0c96108d --- /dev/null +++ b/fixtures/web-first/svg-radial-start-outside-positive-fr.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-relation-above.svg b/fixtures/web-first/svg-radial-start-relation-above.svg new file mode 100644 index 00000000..20ae2359 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-relation-above.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-relation-below.svg b/fixtures/web-first/svg-radial-start-relation-below.svg new file mode 100644 index 00000000..e3a75447 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-relation-below.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-relation-containing.svg b/fixtures/web-first/svg-radial-start-relation-containing.svg new file mode 100644 index 00000000..f8d181b6 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-relation-containing.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-relation-disjoint.svg b/fixtures/web-first/svg-radial-start-relation-disjoint.svg new file mode 100644 index 00000000..3412e133 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-relation-disjoint.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-relation-external-tangent.svg b/fixtures/web-first/svg-radial-start-relation-external-tangent.svg new file mode 100644 index 00000000..e113e11d --- /dev/null +++ b/fixtures/web-first/svg-radial-start-relation-external-tangent.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-relation-internal-tangent.svg b/fixtures/web-first/svg-radial-start-relation-internal-tangent.svg new file mode 100644 index 00000000..a326673a --- /dev/null +++ b/fixtures/web-first/svg-radial-start-relation-internal-tangent.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-relation-intersecting.svg b/fixtures/web-first/svg-radial-start-relation-intersecting.svg new file mode 100644 index 00000000..dc8012e3 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-relation-intersecting.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-relation-left.svg b/fixtures/web-first/svg-radial-start-relation-left.svg new file mode 100644 index 00000000..93bef6b5 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-relation-left.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-relation-right.svg b/fixtures/web-first/svg-radial-start-relation-right.svg new file mode 100644 index 00000000..1af9abbe --- /dev/null +++ b/fixtures/web-first/svg-radial-start-relation-right.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-same-circle-reflect.svg b/fixtures/web-first/svg-radial-start-same-circle-reflect.svg new file mode 100644 index 00000000..253b50c3 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-same-circle-reflect.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-same-circle-repeat.svg b/fixtures/web-first/svg-radial-start-same-circle-repeat.svg new file mode 100644 index 00000000..9f503468 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-same-circle-repeat.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-radial-start-spread-circle-reflect.svg b/fixtures/web-first/svg-radial-start-spread-circle-reflect.svg new file mode 100644 index 00000000..edd6ff1b --- /dev/null +++ b/fixtures/web-first/svg-radial-start-spread-circle-reflect.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-spread-circle-repeat.svg b/fixtures/web-first/svg-radial-start-spread-circle-repeat.svg new file mode 100644 index 00000000..b4f8c5d8 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-spread-circle-repeat.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-spread-outside-reflect.svg b/fixtures/web-first/svg-radial-start-spread-outside-reflect.svg new file mode 100644 index 00000000..36f451ca --- /dev/null +++ b/fixtures/web-first/svg-radial-start-spread-outside-reflect.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-spread-outside-repeat.svg b/fixtures/web-first/svg-radial-start-spread-outside-repeat.svg new file mode 100644 index 00000000..90d53121 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-spread-outside-repeat.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-spread-reversed-reflect.svg b/fixtures/web-first/svg-radial-start-spread-reversed-reflect.svg new file mode 100644 index 00000000..0e2b518d --- /dev/null +++ b/fixtures/web-first/svg-radial-start-spread-reversed-reflect.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-spread-reversed-repeat.svg b/fixtures/web-first/svg-radial-start-spread-reversed-repeat.svg new file mode 100644 index 00000000..906d3b9d --- /dev/null +++ b/fixtures/web-first/svg-radial-start-spread-reversed-repeat.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-spread-zero-end-reflect.svg b/fixtures/web-first/svg-radial-start-spread-zero-end-reflect.svg new file mode 100644 index 00000000..6d76566c --- /dev/null +++ b/fixtures/web-first/svg-radial-start-spread-zero-end-reflect.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-spread-zero-end-repeat.svg b/fixtures/web-first/svg-radial-start-spread-zero-end-repeat.svg new file mode 100644 index 00000000..cd1d7fc0 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-spread-zero-end-repeat.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-stops-alpha.svg b/fixtures/web-first/svg-radial-start-stops-alpha.svg new file mode 100644 index 00000000..e4440d8d --- /dev/null +++ b/fixtures/web-first/svg-radial-start-stops-alpha.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-stops-duplicate.svg b/fixtures/web-first/svg-radial-start-stops-duplicate.svg new file mode 100644 index 00000000..d864839e --- /dev/null +++ b/fixtures/web-first/svg-radial-start-stops-duplicate.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-stops-edges.svg b/fixtures/web-first/svg-radial-start-stops-edges.svg new file mode 100644 index 00000000..310e7442 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-stops-edges.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-stops-unsorted.svg b/fixtures/web-first/svg-radial-start-stops-unsorted.svg new file mode 100644 index 00000000..d97a1aa5 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-stops-unsorted.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-template-all.svg b/fixtures/web-first/svg-radial-start-template-all.svg new file mode 100644 index 00000000..0437bfbf --- /dev/null +++ b/fixtures/web-first/svg-radial-start-template-all.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-template-empty-fr.svg b/fixtures/web-first/svg-radial-start-template-empty-fr.svg new file mode 100644 index 00000000..5a686dca --- /dev/null +++ b/fixtures/web-first/svg-radial-start-template-empty-fr.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-template-empty-fx.svg b/fixtures/web-first/svg-radial-start-template-empty-fx.svg new file mode 100644 index 00000000..4d5c15f5 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-template-empty-fx.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-template-empty-fy.svg b/fixtures/web-first/svg-radial-start-template-empty-fy.svg new file mode 100644 index 00000000..7be2cf14 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-template-empty-fy.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-template-explicit-focus.svg b/fixtures/web-first/svg-radial-start-template-explicit-focus.svg new file mode 100644 index 00000000..159ec64f --- /dev/null +++ b/fixtures/web-first/svg-radial-start-template-explicit-focus.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-template-fr-negative.svg b/fixtures/web-first/svg-radial-start-template-fr-negative.svg new file mode 100644 index 00000000..f1ab92e1 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-template-fr-negative.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-template-fr-zero.svg b/fixtures/web-first/svg-radial-start-template-fr-zero.svg new file mode 100644 index 00000000..529ad7e4 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-template-fr-zero.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-template-invalid-fr.svg b/fixtures/web-first/svg-radial-start-template-invalid-fr.svg new file mode 100644 index 00000000..ff1661a0 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-template-invalid-fr.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-template-local-center.svg b/fixtures/web-first/svg-radial-start-template-local-center.svg new file mode 100644 index 00000000..fa4f01b5 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-template-local-center.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-template-multihop.svg b/fixtures/web-first/svg-radial-start-template-multihop.svg new file mode 100644 index 00000000..b764f334 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-template-multihop.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-template-override-fr.svg b/fixtures/web-first/svg-radial-start-template-override-fr.svg new file mode 100644 index 00000000..11c56655 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-template-override-fr.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-template-override-fx.svg b/fixtures/web-first/svg-radial-start-template-override-fx.svg new file mode 100644 index 00000000..a8414c02 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-template-override-fx.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-template-override-fy.svg b/fixtures/web-first/svg-radial-start-template-override-fy.svg new file mode 100644 index 00000000..e3c4bbb4 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-template-override-fy.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-template-xlink.svg b/fixtures/web-first/svg-radial-start-template-xlink.svg new file mode 100644 index 00000000..d087813e --- /dev/null +++ b/fixtures/web-first/svg-radial-start-template-xlink.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-transform-rotate.svg b/fixtures/web-first/svg-radial-start-transform-rotate.svg new file mode 100644 index 00000000..6c29ea12 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-transform-rotate.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-transform-scale.svg b/fixtures/web-first/svg-radial-start-transform-scale.svg new file mode 100644 index 00000000..ae5e436e --- /dev/null +++ b/fixtures/web-first/svg-radial-start-transform-scale.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-transform-singular.svg b/fixtures/web-first/svg-radial-start-transform-singular.svg new file mode 100644 index 00000000..7c49fd5f --- /dev/null +++ b/fixtures/web-first/svg-radial-start-transform-singular.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-transform-skew.svg b/fixtures/web-first/svg-radial-start-transform-skew.svg new file mode 100644 index 00000000..33625b9f --- /dev/null +++ b/fixtures/web-first/svg-radial-start-transform-skew.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-transform-translate.svg b/fixtures/web-first/svg-radial-start-transform-translate.svg new file mode 100644 index 00000000..66e33413 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-transform-translate.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-transparent-cone.svg b/fixtures/web-first/svg-radial-start-transparent-cone.svg new file mode 100644 index 00000000..e7e51af2 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-transparent-cone.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-user-percent-fr.svg b/fixtures/web-first/svg-radial-start-user-percent-fr.svg new file mode 100644 index 00000000..b76101c0 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-user-percent-fr.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-user-percent-fx.svg b/fixtures/web-first/svg-radial-start-user-percent-fx.svg new file mode 100644 index 00000000..b2c5cce8 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-user-percent-fx.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-user-percent-fy.svg b/fixtures/web-first/svg-radial-start-user-percent-fy.svg new file mode 100644 index 00000000..2f5f0f3c --- /dev/null +++ b/fixtures/web-first/svg-radial-start-user-percent-fy.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-user-px.svg b/fixtures/web-first/svg-radial-start-user-px.svg new file mode 100644 index 00000000..42256c25 --- /dev/null +++ b/fixtures/web-first/svg-radial-start-user-px.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-radial-start-zero-stops-focal.svg b/fixtures/web-first/svg-radial-start-zero-stops-focal.svg new file mode 100644 index 00000000..f5e60ade --- /dev/null +++ b/fixtures/web-first/svg-radial-start-zero-stops-focal.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/fixtures/web-first/unsupported/README.md b/fixtures/web-first/unsupported/README.md index a5f21e9e..220ac448 100644 --- a/fixtures/web-first/unsupported/README.md +++ b/fixtures/web-first/unsupported/README.md @@ -99,7 +99,10 @@ The scannable, generated view of this register (beside the baked cells) is | `svg-pattern-source-unsupported.svg` | Any unsupported child invalidates pattern-source compilation transactionally. The witness places a valid rectangle before an unsupported image; best effort skips the whole affected client, so a plausible partial tile can never escape. | | `svg-pattern-source-viewport.svg` | A nested `` in a pattern source retains the pattern element's own source-program boundary. A simple visible-overflow viewport was byte-exact to its flattened control in Chromium and both admissions, but that single probe does not admit viewport clipping, effects, nesting, or the picture-shader precision envelope for pattern sources (measured, not celled). | | `svg-pattern-transform-none-provenance.svg` | Refuse the narrow derived-template case where an author stylesheet may contribute `transform:none`. The computed empty transform loses whether the sheet supplied `none` or no declaration; inheriting the template's `patternTransform` would resurrect a transform Chromium suppresses. Inline declarations remain attributable and admitted. | -| `svg-gradient-focal.svg` | A focal radial (`fx`/`fy` off the center, `fr > 0` alike) refuses by name: the shared radial paint leaf is concentric, and Chromium's focal cone — unclamped, leaving pixels unpainted (measured) — is inexpressible in it until its owner amendment. | +| `svg-radial-start-{fx,fy,fr}-decimal-precision.svg` · `svg-radial-start-{fx,fy,fr}-percentage-precision.svg` · `svg-radial-start-{fx,fy,fr}-midpoint-precision.svg` | Nine exact-attribute provenance refusals. Amplified Chromium pairs make all nine valid source aliases equal the lower adjacent binary32 control and visibly different from the higher; the raw lexical route cannot recover that choice. Decimal/percentage controls and the radius midpoint pair are baked in the primitive suite; focus midpoint probes are measured, not celled. No private matcher or replacement CSS parser is introduced. | +| `svg-radial-start-{fx,fy,fr}-css-comments.svg` | Three exact-attribute refusals for CSS comment tokenization. Chromium honors a valid length surrounded by comments; silently defaulting it would move the focal cone (measured, not celled). This honored grammar member has no own checklist row and keeps these attribute rows open. | +| `svg-radial-start-{fx,fy,fr}-used-range.svg` | Three exact-attribute refusals for a resolved length outside the admitted finite Web range. The overflow sources are measured against missing values and are not harmless defaults (measured, not celled). | +| `svg-radial-start-{fx,fy,fr}-units.svg` · `svg-radial-start-{fx,fy,fr}-math.svg` · `svg-radial-start-{fx,fy,fr}-var.svg` · `svg-radial-start-{fx,fy,fr}-css-wide.svg` | Twelve named wider-value/context refusals. Unit bases, computed math, substitution, and CSS-wide resource-side resolution remain separate feature families; each source is attributed in strict and best-effort paths. Their own checklist rows carry these gaps, but do not excuse the precision/comment gaps above. Chromium counterparts were measured, not celled. | | `svg-gradient-linearrgb.svg` | `color-interpolation="linearRGB"` is honored by Chromium (measured: the linear-light midpoint, not the sRGB one) and refuses by name — one backend ramp cannot interpolate in a second space. | | `svg-gradient-stop-css.svg` | A stylesheet declaring `stop-color` is a document-level declaration: the pinned cascade has no such longhand (Gecko-only at the Stylo pin), so the sheet is named and the gradient renders with its attribute colors — a declared divergence, since Chromium honors the sheet. | | `svg-gradient-stop-style-attr.svg` | `stop-color` in a stop's own style attribute wins in Chromium (measured); the cascade cannot represent it, so the referencing paint refuses by name. | diff --git a/fixtures/web-first/unsupported/svg-radial-start-fr-css-comments.svg b/fixtures/web-first/unsupported/svg-radial-start-fr-css-comments.svg new file mode 100644 index 00000000..3ae179d1 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fr-css-comments.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fr-css-wide.svg b/fixtures/web-first/unsupported/svg-radial-start-fr-css-wide.svg new file mode 100644 index 00000000..d3ad6ace --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fr-css-wide.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fr-decimal-precision.svg b/fixtures/web-first/unsupported/svg-radial-start-fr-decimal-precision.svg new file mode 100644 index 00000000..db9a67ff --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fr-decimal-precision.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fr-math.svg b/fixtures/web-first/unsupported/svg-radial-start-fr-math.svg new file mode 100644 index 00000000..e14eb391 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fr-math.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fr-midpoint-precision.svg b/fixtures/web-first/unsupported/svg-radial-start-fr-midpoint-precision.svg new file mode 100644 index 00000000..6dfdad58 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fr-midpoint-precision.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fr-percentage-precision.svg b/fixtures/web-first/unsupported/svg-radial-start-fr-percentage-precision.svg new file mode 100644 index 00000000..24a047e1 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fr-percentage-precision.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fr-units.svg b/fixtures/web-first/unsupported/svg-radial-start-fr-units.svg new file mode 100644 index 00000000..aa2fd59e --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fr-units.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fr-used-range.svg b/fixtures/web-first/unsupported/svg-radial-start-fr-used-range.svg new file mode 100644 index 00000000..40122547 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fr-used-range.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fr-var.svg b/fixtures/web-first/unsupported/svg-radial-start-fr-var.svg new file mode 100644 index 00000000..6a1858fc --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fr-var.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fx-css-comments.svg b/fixtures/web-first/unsupported/svg-radial-start-fx-css-comments.svg new file mode 100644 index 00000000..11c07682 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fx-css-comments.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fx-css-wide.svg b/fixtures/web-first/unsupported/svg-radial-start-fx-css-wide.svg new file mode 100644 index 00000000..c54785bd --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fx-css-wide.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fx-decimal-precision.svg b/fixtures/web-first/unsupported/svg-radial-start-fx-decimal-precision.svg new file mode 100644 index 00000000..8f7196c0 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fx-decimal-precision.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fx-math.svg b/fixtures/web-first/unsupported/svg-radial-start-fx-math.svg new file mode 100644 index 00000000..b92c59e1 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fx-math.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fx-midpoint-precision.svg b/fixtures/web-first/unsupported/svg-radial-start-fx-midpoint-precision.svg new file mode 100644 index 00000000..e78a1240 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fx-midpoint-precision.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fx-percentage-precision.svg b/fixtures/web-first/unsupported/svg-radial-start-fx-percentage-precision.svg new file mode 100644 index 00000000..e595ee80 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fx-percentage-precision.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fx-units.svg b/fixtures/web-first/unsupported/svg-radial-start-fx-units.svg new file mode 100644 index 00000000..f824bb27 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fx-units.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fx-used-range.svg b/fixtures/web-first/unsupported/svg-radial-start-fx-used-range.svg new file mode 100644 index 00000000..73384a2d --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fx-used-range.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fx-var.svg b/fixtures/web-first/unsupported/svg-radial-start-fx-var.svg new file mode 100644 index 00000000..b26aef85 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fx-var.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fy-css-comments.svg b/fixtures/web-first/unsupported/svg-radial-start-fy-css-comments.svg new file mode 100644 index 00000000..c9d39c27 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fy-css-comments.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fy-css-wide.svg b/fixtures/web-first/unsupported/svg-radial-start-fy-css-wide.svg new file mode 100644 index 00000000..40f5a809 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fy-css-wide.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fy-decimal-precision.svg b/fixtures/web-first/unsupported/svg-radial-start-fy-decimal-precision.svg new file mode 100644 index 00000000..42e9b2b0 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fy-decimal-precision.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fy-math.svg b/fixtures/web-first/unsupported/svg-radial-start-fy-math.svg new file mode 100644 index 00000000..86c2adf5 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fy-math.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fy-midpoint-precision.svg b/fixtures/web-first/unsupported/svg-radial-start-fy-midpoint-precision.svg new file mode 100644 index 00000000..5c41edd6 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fy-midpoint-precision.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fy-percentage-precision.svg b/fixtures/web-first/unsupported/svg-radial-start-fy-percentage-precision.svg new file mode 100644 index 00000000..c273b964 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fy-percentage-precision.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fy-units.svg b/fixtures/web-first/unsupported/svg-radial-start-fy-units.svg new file mode 100644 index 00000000..04ef8391 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fy-units.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fy-used-range.svg b/fixtures/web-first/unsupported/svg-radial-start-fy-used-range.svg new file mode 100644 index 00000000..38ac1ce5 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fy-used-range.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/svg-radial-start-fy-var.svg b/fixtures/web-first/unsupported/svg-radial-start-fy-var.svg new file mode 100644 index 00000000..9e7ed987 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-radial-start-fy-var.svg @@ -0,0 +1 @@ +