diff --git a/crates/n0/src/drawlist.rs b/crates/n0/src/drawlist.rs index da9cf277..ac3504b8 100644 --- a/crates/n0/src/drawlist.rs +++ b/crates/n0/src/drawlist.rs @@ -118,6 +118,13 @@ pub(crate) enum ResolvedFilterDisplacementChannel { Alpha, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum ResolvedFilterConvolveEdgeMode { + Duplicate, + Wrap, + None, +} + /// The private filter-operation vocabulary admitted by the painter. #[derive(Debug, Clone, PartialEq)] pub(crate) enum ResolvedFilterPrimitive { @@ -171,6 +178,17 @@ pub(crate) enum ResolvedFilterPrimitive { x_channel: ResolvedFilterDisplacementChannel, y_channel: ResolvedFilterDisplacementChannel, }, + ConvolveMatrix { + order_x: u16, + order_y: u16, + kernel: Arc<[f32]>, + gain: f32, + bias: f32, + target_x: u16, + target_y: u16, + edge_mode: ResolvedFilterConvolveEdgeMode, + preserve_alpha: bool, + }, Merge, } diff --git a/crates/n0/src/glyphless.rs b/crates/n0/src/glyphless.rs index a3efb80a..bcd6c168 100644 --- a/crates/n0/src/glyphless.rs +++ b/crates/n0/src/glyphless.rs @@ -23,9 +23,9 @@ use n0_model::model::{ }; use n0_model::path::ResolvedPathArtifact; use rframe::{ - ClipPath, FilterBlend, FilterColorSpace, FilterComposite, FilterDisplacementChannel, - FilterInput, FilterMorphology, FilterPrimitive, FilterTurbulenceKind, Frame, FrameItem, - Geometry, MaskMode, PaintStack, ScopeEffect, VisualRef, + ClipPath, FilterBlend, FilterColorSpace, FilterComposite, FilterConvolveEdgeMode, + FilterDisplacementChannel, FilterInput, FilterMorphology, FilterPrimitive, + FilterTurbulenceKind, Frame, FrameItem, Geometry, MaskMode, PaintStack, ScopeEffect, VisualRef, }; use crate::damage::{diff_inputs, DamageOwner, FrameDamageInput}; @@ -33,9 +33,9 @@ use crate::drawlist::{ DrawList, GlyphlessOwnerSlot, Item, ItemKind, PostPaintOpacity, ResolvedClipGeometry, ResolvedClipGeometryKind, ResolvedClipLayer, ResolvedClipPath, ResolvedFilter, ResolvedFilterBlend, ResolvedFilterColorSpace, ResolvedFilterComposite, - ResolvedFilterDisplacementChannel, ResolvedFilterInput, ResolvedFilterMorphology, - ResolvedFilterNode, ResolvedFilterPrimitive, ResolvedFilterTurbulenceKind, ResolvedMaskMode, - StrokeDashPhase, + ResolvedFilterConvolveEdgeMode, ResolvedFilterDisplacementChannel, ResolvedFilterInput, + ResolvedFilterMorphology, ResolvedFilterNode, ResolvedFilterPrimitive, + ResolvedFilterTurbulenceKind, ResolvedMaskMode, StrokeDashPhase, }; use crate::frame::FrameExecutionError; use crate::paint::PaintCtx; @@ -1027,6 +1027,33 @@ fn compile_filter(filter: &rframe::Filter) -> ResolvedFilter { } }, }, + FilterPrimitive::ConvolveMatrix { + order_x, + order_y, + kernel, + gain, + bias, + target_x, + target_y, + edge_mode, + preserve_alpha, + } => ResolvedFilterPrimitive::ConvolveMatrix { + order_x, + order_y, + kernel, + gain, + bias, + target_x, + target_y, + edge_mode: match edge_mode { + FilterConvolveEdgeMode::Duplicate => { + ResolvedFilterConvolveEdgeMode::Duplicate + } + FilterConvolveEdgeMode::Wrap => ResolvedFilterConvolveEdgeMode::Wrap, + FilterConvolveEdgeMode::None => ResolvedFilterConvolveEdgeMode::None, + }, + preserve_alpha, + }, FilterPrimitive::Merge => ResolvedFilterPrimitive::Merge, }, }) diff --git a/crates/n0/src/paint.rs b/crates/n0/src/paint.rs index 6789ecdf..bcb69078 100644 --- a/crates/n0/src/paint.rs +++ b/crates/n0/src/paint.rs @@ -36,9 +36,9 @@ use skia_safe::{ use crate::drawlist::{ DrawList, ItemKind, PostPaintOpacity, ResolvedClipGeometry, ResolvedClipGeometryKind, ResolvedClipLayer, ResolvedClipPath, ResolvedFilter, ResolvedFilterBlend, - ResolvedFilterColorSpace, ResolvedFilterComposite, ResolvedFilterDisplacementChannel, - ResolvedFilterInput, ResolvedFilterMorphology, ResolvedFilterPrimitive, - ResolvedFilterTurbulenceKind, ResolvedMaskMode, StrokeDashPhase, + ResolvedFilterColorSpace, ResolvedFilterComposite, ResolvedFilterConvolveEdgeMode, + ResolvedFilterDisplacementChannel, ResolvedFilterInput, ResolvedFilterMorphology, + ResolvedFilterPrimitive, ResolvedFilterTurbulenceKind, ResolvedMaskMode, StrokeDashPhase, }; /// The gradient family whose local matrix could not be represented by the @@ -2331,6 +2331,14 @@ fn sk_displacement_channel(channel: ResolvedFilterDisplacementChannel) -> ColorC } } +fn sk_convolve_tile_mode(mode: ResolvedFilterConvolveEdgeMode) -> skia_safe::TileMode { + match mode { + ResolvedFilterConvolveEdgeMode::Duplicate => skia_safe::TileMode::Clamp, + ResolvedFilterConvolveEdgeMode::Wrap => skia_safe::TileMode::Repeat, + ResolvedFilterConvolveEdgeMode::None => skia_safe::TileMode::Decal, + } +} + /// Build one checked private filter graph and its final-composition policy. fn build_filter(filter: &ResolvedFilter) -> Result { let explicit_transparent_source = if filter.source_is_transparent { @@ -2428,6 +2436,10 @@ fn build_filter(filter: &ResolvedFilter) -> Result { &node.primitive, ResolvedFilterPrimitive::Morphology { radius_x, radius_y, .. } if source_dependent && (*radius_x > 0.0 || *radius_y > 0.0) + ) + || matches!( + &node.primitive, + ResolvedFilterPrimitive::ConvolveMatrix { .. } if source_dependent ); let has_procedural_input = inputs.iter().any(|input| input.procedural_provenance); let mut procedural_provenance = has_procedural_input @@ -2845,6 +2857,48 @@ fn build_filter(filter: &ResolvedFilter) -> Result { requires_exact_restore || node.color_space == ResolvedFilterColorSpace::Srgb, ) } + ResolvedFilterPrimitive::ConvolveMatrix { + order_x, + order_y, + kernel, + gain, + bias, + target_x, + target_y, + edge_mode, + preserve_alpha, + } => { + let input = inputs + .pop() + .expect("convolution matrix has one checked input"); + procedural_unorm8_blend = false; + if node.color_space == ResolvedFilterColorSpace::Srgb + && !input.requires_exact_restore + { + procedural_provenance = false; + } + let filter = skia_safe::image_filters::matrix_convolution( + (i32::from(order_x), i32::from(order_y)), + &kernel, + gain, + bias * 255.0, + (i32::from(target_x), i32::from(target_y)), + sk_convolve_tile_mode(edge_mode), + !preserve_alpha, + input.image_filter, + crop, + ) + .ok_or_else(|| { + "the backend could not construct a convolution-matrix operation".to_string() + })?; + ( + Some(filter), + node.color_space, + input.source_dependent, + input.requires_exact_restore + || node.color_space == ResolvedFilterColorSpace::Srgb, + ) + } ResolvedFilterPrimitive::Merge => { let mut inputs = inputs.into_iter(); let image_filter = if let Some(first) = inputs.next() { @@ -2948,7 +3002,9 @@ mod filter_policy_tests { use n0_model::math::RectF; use n0_model::model::Color32F; - use crate::drawlist::{ResolvedFilterMorphology, ResolvedFilterNode}; + use crate::drawlist::{ + ResolvedFilterConvolveEdgeMode, ResolvedFilterMorphology, ResolvedFilterNode, + }; use super::{ build_filter, ResolvedFilter, ResolvedFilterColorSpace, ResolvedFilterInput, @@ -3173,6 +3229,54 @@ mod filter_policy_tests { let generated = build_filter(&generated).expect("generated morphology builds"); assert!(!generated.source_preflatten); } + + #[test] + fn checked_convolution_builds_at_the_kernel_bound_and_keeps_source_policy() { + let convolve = |input, count, bias, preserve_alpha| ResolvedFilterNode { + inputs: Arc::from([input]), + region: REGION, + color_space: ResolvedFilterColorSpace::Srgb, + primitive: ResolvedFilterPrimitive::ConvolveMatrix { + order_x: count, + order_y: 1, + kernel: vec![0.0; usize::from(count)].into(), + gain: 1.0, + bias, + target_x: count / 2, + target_y: 0, + edge_mode: ResolvedFilterConvolveEdgeMode::Wrap, + preserve_alpha, + }, + }; + let one = |node, may_paint_transparent_input| ResolvedFilter { + region: REGION, + nodes: Arc::from([node]), + may_paint_transparent_input, + source_is_transparent: false, + }; + + let bounded = build_filter(&one( + convolve(ResolvedFilterInput::Source, 256, 0.0, false), + false, + )) + .expect("the checked maximum kernel builds transactionally"); + assert!(bounded.source_preflatten); + assert!(bounded.restore_blender.is_some()); + + let alpha_creating = build_filter(&one( + convolve(ResolvedFilterInput::Source, 1, 0.25, false), + true, + )) + .expect("a biased convolution builds over an explicit source"); + assert!(alpha_creating.source_preflatten); + + let alpha_preserving = build_filter(&one( + convolve(ResolvedFilterInput::SourceAlpha, 1, 0.25, true), + false, + )) + .expect("preserved alpha remains a checked native operation"); + assert!(alpha_preserving.source_preflatten); + } } /// Product-build preflight for a resolved image-filter graph. Replay repeats diff --git a/crates/n0_cli/README.md b/crates/n0_cli/README.md index d3f899f0..993ea3bb 100644 --- a/crates/n0_cli/README.md +++ b/crates/n0_cli/README.md @@ -286,8 +286,8 @@ cargo run -p n0_cli --bin n0 -- \ is sampled from effective `.5` through `1.875`, while `.25` and `2` are exact (measured, not celled). The patrol conservatively refuses the open interval between those endpoints after target mapping. Current Chromium - ignores `edgeMode` on blur (measured, not celled); its global row remains open - because the attribute also applies to ``. + ignores `edgeMode` on blur; a dedicated Chromium-baked drop cell and the + complete convolution behavior now close that shared attribute row. Native drop shadow carries its own operation rather than lowering to the blur-plus-offset graph. Missing `dx`, `dy`, and `stdDeviation` use `2`; one or two sigma axes, negative-axis clamping, measured number spellings, @@ -403,6 +403,33 @@ cargo run -p n0_cli --bin n0 -- \ retained fill-only ellipse coverage boundary. Rounded rectangles, curved paths, and circle/path strokes stay admitted. That last patrol leaves gridaco/nothing#88 separate and unchanged. + Convolve matrix carries one checked rectangular kernel of at most 256 finite + coefficients. One/two-member `order` values normalize by truncation toward + zero; the matrix must contain exactly the resulting product. The authored + coefficients reverse once to state SVG convolution rather than correlation. + Missing or malformed order selects 3×3, while non-positive order, a missing + or wrong-count matrix, and an over-bound kernel produce Chromium's + transparent result instead of an unfiltered fallback. + `divisor` carries one signed number. Missing, exactly empty, and signed-zero + values use the ordered binary32 kernel sum, with a zero sum becoming one; a + present nonempty malformed value uses one. `bias` carries one signed number + with initial zero. `targetX`/`targetY` use signed integer text, default to + half their respective order axes, reset malformed authored text to zero, and + produce transparent when a valid value lies outside the kernel. The complete + case-sensitive `duplicate | wrap | none` edge vocabulary and `false | true` + alpha-preservation vocabulary are admitted. Chromium ignores + `kernelUnitLength` on convolution; that drop is baked, while its shared + lighting applicability remains open. + Both filter color spaces, SourceGraphic/SourceAlpha/previous/named/generated + inputs, result reuse, hard regions, primitive units, paths, strokes, groups, + safe axis mappings, exact quarter turns, target opacity/clip/mask, + blur/morphology ordering, ``, and `viewBox` are exact. General affine target + mappings, source-dependent paint servers, and divisors whose reciprocal is + not finite refuse by three stable convolution names before paint. Fractional + axis maps, reflections, exact quarter turns, generated inputs, and every + accepted kernel-size strategy through 256 stay admitted. Representative + fallback branches are celled; the wider invalid-spelling matrix is measured, + not all separately celled. Turbulence carries both procedural formulas: the case-sensitive values `turbulence` and `fractalNoise`, one/two-axis non-negative `baseFrequency`, integer `numOctaves` capped at nine, signed `seed`, and the case-sensitive @@ -469,27 +496,29 @@ cargo run -p n0_cli --bin n0 -- \ Skia source located them in an uninitialized runtime raster-pipeline dispatch: x86 stayed on baseline non-fused Perlin arithmetic while ARM used fused NEON. Initializing Skia before drawlist replay selects the fused AVX2 path on x86. - The complete 700-cell gate is byte-exact on ARM and hosted x86 without a - tolerance. - The same hosted workspace test covers the earlier two hundred - forty-eight-cell estate; all three hundred thirty-nine - Chromium-baked filter cells are exact on the current ARM host without a - tolerance. The filter estate contains 26 chassis/blur cells, 60 shadow-graph, - 28 native drop-shadow, 27 color-matrix, 32 component-transfer, 38 blend, 37 - morphology, and 91 turbulence/displacement cells. The complete corpus - contains 700 Chromium-baked cells plus 10 sampled frames, with 143 named + The 700-cell baseline is byte-exact on ARM and hosted x86 without a + tolerance. The forty-one-cell convolution rung keeps the complete 741-cell + gate byte-exact on ARM and hosted x86 without a new tolerance. All three + hundred eighty Chromium-baked filter cells are exact on both hosts. + The filter estate contains 26 chassis/blur cells, 60 shadow-graph, 28 native + drop-shadow, 27 color-matrix, 32 component-transfer, 38 blend, 37 morphology, + 91 turbulence/displacement, and 41 convolution-rung cells. The complete corpus + contains 741 Chromium-baked cells plus 10 sampled frames, with 146 named refusal rows. `feFlood`, `feComposite`, `feMerge`, `feMergeNode`, `feDropShadow`, `feColorMatrix`, `feComponentTransfer`, `feBlend`, - `feMorphology`, `feTurbulence`, `feDisplacementMap`, `feFuncR`, `feFuncG`, - `feFuncB`, `feFuncA`, `k1`–`k4`, `amplitude`, `exponent`, `intercept`, + `feMorphology`, `feConvolveMatrix`, `feTurbulence`, `feDisplacementMap`, + `feFuncR`, `feFuncG`, `feFuncB`, `feFuncA`, `k1`–`k4`, `amplitude`, + `exponent`, `intercept`, `slope`, `tableValues`, blend-only `mode`, `baseFrequency`, `numOctaves`, `seed`, `stitchTiles`, displacement `scale`, `xChannelSelector`, and - `yChannelSelector` close; `feOffset`, `feGaussianBlur`, ``, + `yChannelSelector`, `bias`, `divisor`, `edgeMode`, `kernelMatrix`, + convolution `order`, `preserveAlpha`, `targetX`, and `targetY` close; + `feOffset`, `feGaussianBlur`, ``, `filter`, `color-interpolation-filters`, `in`, `in2`, `operator`, `result`, - `radius`, `dx`, `dy`, `stdDeviation`, `flood-color`, and `flood-opacity` - remain open for the named precision, applicability, resource, cascade, or - value remainder. + `radius`, `kernelUnitLength`, `dx`, `dy`, `stdDeviation`, `flood-color`, and + `flood-opacity` remain open for the named precision, applicability, resource, + cascade, or value remainder. A stroke is centred, its width is a cascaded length in either spelling — numbers, absolute units, `em`/`rem` against an authored or default font-size, percentages against the normalized diagonal, and pure-length diff --git a/crates/rframe/src/filter.rs b/crates/rframe/src/filter.rs index daca866a..4d8a12cf 100644 --- a/crates/rframe/src/filter.rs +++ b/crates/rframe/src/filter.rs @@ -18,6 +18,13 @@ use math2::transform::AffineTransform; /// graph exceeds it refuses before constructing a frame. pub const MAX_FILTER_NODES: usize = 256; +/// The largest spatial convolution kernel carried by the resolved contract. +/// +/// The bound keeps the operation finite and cheap to validate before paint. +/// A source producer resolves any source-language behavior beyond it before +/// constructing a program. +pub const MAX_FILTER_CONVOLVE_KERNEL_VALUES: usize = 256; + /// The pixel interpolation space in which one operation executes. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum FilterColorSpace { @@ -97,6 +104,14 @@ pub enum FilterDisplacementChannel { Alpha, } +/// Sampling outside the input image for one resolved convolution kernel. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum FilterConvolveEdgeMode { + Duplicate, + Wrap, + None, +} + /// Four exact byte lookup tables for one non-premultiplied RGBA operation. /// /// Channel order is named at construction and access, so a producer cannot @@ -202,6 +217,25 @@ pub enum FilterPrimitive { x_channel: FilterDisplacementChannel, y_channel: FilterDisplacementChannel, }, + /// One finite rectangular convolution over premultiplied channels, or + /// over unpremultiplied colors while preserving the input alpha. + /// + /// `kernel` is row-major in sample order: its first member weights the + /// top-left sample around `target_x,target_y`. Source-language rotation + /// or orientation conventions have already been resolved by the producer. + ConvolveMatrix { + order_x: u16, + order_y: u16, + kernel: Arc<[f32]>, + gain: f32, + /// Unit-range channel bias. A painter converts it to any backend-local + /// channel scale only at the backend call. + bias: f32, + target_x: u16, + target_y: u16, + edge_mode: FilterConvolveEdgeMode, + preserve_alpha: bool, + }, Merge, } @@ -292,6 +326,9 @@ pub enum FilterProgramError { InvalidDisplacementMap { node: usize, }, + InvalidConvolveMatrix { + node: usize, + }, } impl std::fmt::Display for FilterProgramError { @@ -351,6 +388,10 @@ impl std::fmt::Display for FilterProgramError { Self::InvalidDisplacementMap { node } => { write!(f, "filter node {node} has a non-finite displacement scale") } + Self::InvalidConvolveMatrix { node } => write!( + f, + "filter node {node} has an invalid convolution order, kernel, target, gain, or bias" + ), } } } @@ -376,7 +417,8 @@ impl FilterProgram { | FilterPrimitive::DropShadow { .. } | FilterPrimitive::ColorMatrix { .. } | FilterPrimitive::ComponentTransfer { .. } - | FilterPrimitive::Morphology { .. } => Some(1), + | FilterPrimitive::Morphology { .. } + | FilterPrimitive::ConvolveMatrix { .. } => Some(1), FilterPrimitive::SolidColor { .. } | FilterPrimitive::Turbulence { .. } => Some(0), FilterPrimitive::Composite { .. } | FilterPrimitive::Blend { .. } @@ -464,6 +506,30 @@ impl FilterProgram { FilterPrimitive::DisplacementMap { scale, .. } if !scale.is_finite() => { return Err(FilterProgramError::InvalidDisplacementMap { node: index }); } + FilterPrimitive::ConvolveMatrix { + order_x, + order_y, + ref kernel, + gain, + bias, + target_x, + target_y, + .. + } if order_x == 0 + || order_y == 0 + || usize::from(order_x) + .checked_mul(usize::from(order_y)) + .is_none_or(|area| { + area > MAX_FILTER_CONVOLVE_KERNEL_VALUES || area != kernel.len() + }) + || !kernel.iter().all(|value| value.is_finite()) + || !gain.is_finite() + || !bias.is_finite() + || target_x >= order_x + || target_y >= order_y => + { + return Err(FilterProgramError::InvalidConvolveMatrix { node: index }); + } FilterPrimitive::Offset { .. } | FilterPrimitive::SolidColor { .. } | FilterPrimitive::Composite { .. } @@ -474,6 +540,7 @@ impl FilterProgram { | FilterPrimitive::Morphology { .. } | FilterPrimitive::Turbulence { .. } | FilterPrimitive::DisplacementMap { .. } + | FilterPrimitive::ConvolveMatrix { .. } | FilterPrimitive::Merge => {} } } @@ -500,6 +567,11 @@ impl FilterProgram { FilterPrimitive::ColorMatrix { matrix } => matrix[19] > 0.0, FilterPrimitive::ComponentTransfer { tables } => tables.alpha()[0] > 0, FilterPrimitive::Turbulence { .. } => true, + FilterPrimitive::ConvolveMatrix { + bias, + preserve_alpha, + .. + } => !preserve_alpha && bias > 0.0, FilterPrimitive::GaussianBlur { .. } | FilterPrimitive::Offset { .. } | FilterPrimitive::Composite { .. } diff --git a/crates/rframe/src/lib.rs b/crates/rframe/src/lib.rs index e183402e..7a038f99 100644 --- a/crates/rframe/src/lib.rs +++ b/crates/rframe/src/lib.rs @@ -26,8 +26,9 @@ pub use clip::{ }; pub use filter::{ Filter, FilterBlend, FilterChannelTables, FilterColorSpace, FilterComposite, - FilterDisplacementChannel, FilterError, FilterInput, FilterMorphology, FilterNode, - FilterPrimitive, FilterProgram, FilterProgramError, FilterTurbulenceKind, MAX_FILTER_NODES, + FilterConvolveEdgeMode, FilterDisplacementChannel, FilterError, FilterInput, FilterMorphology, + FilterNode, FilterPrimitive, FilterProgram, FilterProgramError, FilterTurbulenceKind, + MAX_FILTER_CONVOLVE_KERNEL_VALUES, MAX_FILTER_NODES, }; pub use frame::{ Frame, FrameItem, FrameItems, FrameItemsError, FrameNode, Geometry, Identity, MAX_SCOPE_DEPTH, diff --git a/crates/rframe/tests/filter_contract.rs b/crates/rframe/tests/filter_contract.rs index 15a9aa55..8fec5d45 100644 --- a/crates/rframe/tests/filter_contract.rs +++ b/crates/rframe/tests/filter_contract.rs @@ -6,8 +6,9 @@ use math2::Rectangle; use math2::transform::AffineTransform; use rframe::{ Filter, FilterBlend, FilterChannelTables, FilterColorSpace, FilterComposite, - FilterDisplacementChannel, FilterError, FilterInput, FilterMorphology, FilterNode, - FilterPrimitive, FilterProgram, FilterProgramError, FilterTurbulenceKind, MAX_FILTER_NODES, + FilterConvolveEdgeMode, FilterDisplacementChannel, FilterError, FilterInput, FilterMorphology, + FilterNode, FilterPrimitive, FilterProgram, FilterProgramError, FilterTurbulenceKind, + MAX_FILTER_CONVOLVE_KERNEL_VALUES, MAX_FILTER_NODES, }; fn blur(input: FilterInput, sigma_x: f32, sigma_y: f32) -> FilterNode { @@ -538,6 +539,201 @@ fn displacement_map_has_two_ordered_inputs_and_checked_channel_vocabulary() { } } +#[test] +fn convolution_has_one_input_and_a_bounded_finite_checked_kernel() { + let region = Rectangle::from_xywh(0.0, 0.0, 10.0, 10.0); + let convolve = |inputs: Arc<[FilterInput]>, + order_x, + order_y, + kernel: Arc<[f32]>, + gain, + bias, + target_x, + target_y, + edge_mode, + preserve_alpha| { + FilterNode::new( + inputs, + region, + FilterColorSpace::Srgb, + FilterPrimitive::ConvolveMatrix { + order_x, + order_y, + kernel, + gain, + bias, + target_x, + target_y, + edge_mode, + preserve_alpha, + }, + ) + }; + + assert_eq!( + FilterProgram::new(Arc::from([convolve( + Arc::from([]), + 1, + 1, + Arc::from([1.0]), + 1.0, + 0.0, + 0, + 0, + FilterConvolveEdgeMode::None, + false, + )])), + Err(FilterProgramError::InvalidInputCount { + node: 0, + expected: 1, + actual: 0, + }) + ); + + for node in [ + convolve( + Arc::from([FilterInput::Source]), + 0, + 1, + Arc::from([]), + 1.0, + 0.0, + 0, + 0, + FilterConvolveEdgeMode::Duplicate, + false, + ), + convolve( + Arc::from([FilterInput::Source]), + 2, + 2, + Arc::from([1.0, 0.0, 0.0]), + 1.0, + 0.0, + 0, + 0, + FilterConvolveEdgeMode::Wrap, + false, + ), + convolve( + Arc::from([FilterInput::Source]), + 1, + 1, + Arc::from([f32::NAN]), + 1.0, + 0.0, + 0, + 0, + FilterConvolveEdgeMode::None, + false, + ), + convolve( + Arc::from([FilterInput::Source]), + 1, + 1, + Arc::from([1.0]), + f32::INFINITY, + 0.0, + 0, + 0, + FilterConvolveEdgeMode::None, + false, + ), + convolve( + Arc::from([FilterInput::Source]), + 1, + 1, + Arc::from([1.0]), + 1.0, + f32::NAN, + 0, + 0, + FilterConvolveEdgeMode::None, + false, + ), + convolve( + Arc::from([FilterInput::Source]), + 2, + 2, + Arc::from([1.0, 0.0, 0.0, 0.0]), + 1.0, + 0.0, + 2, + 0, + FilterConvolveEdgeMode::None, + false, + ), + convolve( + Arc::from([FilterInput::Source]), + 257, + 1, + vec![0.0; MAX_FILTER_CONVOLVE_KERNEL_VALUES + 1].into(), + 1.0, + 0.0, + 0, + 0, + FilterConvolveEdgeMode::None, + false, + ), + ] { + assert_eq!( + FilterProgram::new(Arc::from([node])), + Err(FilterProgramError::InvalidConvolveMatrix { node: 0 }) + ); + } + + for edge_mode in [ + FilterConvolveEdgeMode::Duplicate, + FilterConvolveEdgeMode::Wrap, + FilterConvolveEdgeMode::None, + ] { + let ordinary = FilterProgram::new(Arc::from([convolve( + Arc::from([FilterInput::Source]), + 16, + 16, + vec![0.0; MAX_FILTER_CONVOLVE_KERNEL_VALUES].into(), + -2.0, + -0.5, + 15, + 15, + edge_mode, + false, + )])) + .expect("the maximum finite checked kernel is a resolved fact"); + assert!(!ordinary.may_paint_transparent_input()); + + let additive = FilterProgram::new(Arc::from([convolve( + Arc::from([FilterInput::Source]), + 1, + 1, + Arc::from([1.0]), + 1.0, + 0.25, + 0, + 0, + edge_mode, + false, + )])) + .expect("positive alpha bias can create output"); + assert!(additive.may_paint_transparent_input()); + + let preserved = FilterProgram::new(Arc::from([convolve( + Arc::from([FilterInput::Source]), + 1, + 1, + Arc::from([1.0]), + 1.0, + 0.25, + 0, + 0, + edge_mode, + true, + )])) + .expect("preserved alpha suppresses generated RGB on a transparent input"); + assert!(!preserved.may_paint_transparent_input()); + } +} + #[test] fn a_filter_invocation_names_when_its_source_is_fully_transparent() { let region = Rectangle::from_xywh(0.0, 0.0, 10.0, 10.0); diff --git a/crates/websem/src/svg.rs b/crates/websem/src/svg.rs index 50223236..6495107f 100644 --- a/crates/websem/src/svg.rs +++ b/crates/websem/src/svg.rs @@ -136,9 +136,10 @@ use math2::Rectangle; use math2::transform::AffineTransform; use rframe::{ ClipGeometry, ClipLayer, ClipPath, FillRule, Filter, FilterBlend, FilterChannelTables, - FilterColorSpace, FilterComposite, FilterDisplacementChannel, FilterInput, FilterMorphology, - FilterNode, FilterPrimitive, FilterProgram, FilterTurbulenceKind, Frame, FrameItem, FrameItems, - FrameItemsError, FrameNode, Geometry, Identity, Mask, MaskMode, PaintAlphaFactor, PaintStack, + FilterColorSpace, FilterComposite, FilterConvolveEdgeMode, FilterDisplacementChannel, + FilterInput, FilterMorphology, FilterNode, FilterPrimitive, FilterProgram, + FilterTurbulenceKind, Frame, FrameItem, FrameItems, FrameItemsError, FrameNode, Geometry, + Identity, MAX_FILTER_CONVOLVE_KERNEL_VALUES, Mask, MaskMode, PaintAlphaFactor, PaintStack, PathData, Provenance, Scope, ScopeEffect, ScopeOpacity, Stroke, StrokeCap, StrokeDash, StrokeDashIntervals, StrokeDashIntervalsError, StrokeJoin, VisualRef, }; @@ -5080,6 +5081,159 @@ mod filter_resource { } } + /// Blink's `order` wrapper parses one or two SVG numbers and truncates + /// each toward zero. Missing, empty, and lexical failures retain the + /// initial 3-by-3 order; a parsed non-positive member is an invalid + /// convolution and therefore resolves to transparent black. + fn convolve_order(element: HtmlElement<'_>) -> Option<(u16, u16)> { + let values = get_attr(element, "order") + .filter(|raw| !trim_svg_whitespace(raw).is_empty()) + .as_deref() + .and_then(crate::svg_number_list::parse); + let (x, y) = match values.as_deref() { + None => (3.0, 3.0), + Some([value]) => (*value, *value), + Some([x, y]) => (*x, *y), + _ => (3.0, 3.0), + }; + let x = x.trunc(); + let y = y.trunc(); + if x <= 0.0 || y <= 0.0 || x > u16::MAX as f32 || y > u16::MAX as f32 { + return None; + } + Some((x as u16, y as u16)) + } + + /// One complete SVG integer field. Unlike `order`, target coordinates use + /// the integer lexical grammar: fractions and exponents are invalid and + /// reset an authored field to zero in Blink. + fn convolve_target(element: HtmlElement<'_>, name: &str, default: u16) -> Option { + let Some(raw) = get_attr(element, name) else { + return Some(default); + }; + let bytes = trim_svg_whitespace(&raw).as_bytes(); + let (negative, digits) = match bytes.first() { + Some(b'+') => (false, &bytes[1..]), + Some(b'-') => (true, &bytes[1..]), + _ => (false, bytes), + }; + let parsed = if digits.is_empty() || !digits.iter().all(u8::is_ascii_digit) { + 0_i64 + } else { + let magnitude = std::str::from_utf8(digits) + .ok() + .and_then(|digits| digits.parse::().ok()); + let signed = magnitude.and_then(|magnitude| { + if negative { + magnitude.checked_neg() + } else { + Some(magnitude) + } + }); + // Overflowing the SVG integer storage is a lexical failure and + // retains the animated property's initial zero. + signed + .filter(|value| i32::try_from(*value).is_ok()) + .unwrap_or(0) + }; + if parsed < 0 || parsed > i64::from(u16::MAX) { + return None; + } + Some(parsed as u16) + } + + /// Resolve one complete `` operation. `None` is + /// Chromium's transparent-black error image, not a compiler refusal. + fn convolve_matrix(element: HtmlElement<'_>) -> Result, CompileError> { + let Some((order_x, order_y)) = convolve_order(element) else { + return Ok(None); + }; + let Some(area) = usize::from(order_x).checked_mul(usize::from(order_y)) else { + return Ok(None); + }; + // Chromium 149's Skia construction returns transparent black above + // this bound. Resolve it before allocating or entering the painter. + if area > MAX_FILTER_CONVOLVE_KERNEL_VALUES { + return Ok(None); + } + + let Some(mut kernel) = get_attr(element, "kernelMatrix") + .as_deref() + .and_then(crate::svg_number_list::parse) + .filter(|kernel| kernel.len() == area) + else { + return Ok(None); + }; + + let divisor = match get_attr(element, "divisor") { + None => 0.0, + Some(raw) if raw.is_empty() => 0.0, + Some(raw) => match crate::svg_number_list::parse(&raw).as_deref() { + Some([value]) => *value, + // A present, non-empty malformed divisor retains the SVG + // animated-number initial value 1 rather than becoming + // unspecified. + _ => 1.0, + }, + }; + let divisor = if divisor == 0.0 { + let sum = kernel + .iter() + .copied() + .fold(0.0_f32, |sum, value| sum + value); + if sum == 0.0 { 1.0 } else { sum } + } else { + divisor + }; + let gain = 1.0 / divisor; + let bias = get_attr(element, "bias") + .as_deref() + .and_then(crate::svg_number_list::parse) + .and_then(|values| match values.as_slice() { + [value] => Some(*value), + _ => None, + }) + .unwrap_or(0.0); + if !gain.is_finite() || !bias.is_finite() { + return Err(CompileError::UnsupportedFilter( + "feConvolveMatrix divisor or bias crosses the finite native-convolution arithmetic boundary" + .to_string(), + )); + } + + let Some(target_x) = convolve_target(element, "targetX", order_x / 2) else { + return Ok(None); + }; + let Some(target_y) = convolve_target(element, "targetY", order_y / 2) else { + return Ok(None); + }; + if target_x >= order_x || target_y >= order_y { + return Ok(None); + } + + // SVG defines a convolution rather than correlation. Blink rotates + // the authored matrix once before handing the resolved operation to + // its image-filter backend. + kernel.reverse(); + Ok(Some(FilterPrimitive::ConvolveMatrix { + order_x, + order_y, + kernel: kernel.into(), + gain, + bias, + target_x, + target_y, + edge_mode: match get_attr(element, "edgeMode").as_deref() { + Some("wrap") => FilterConvolveEdgeMode::Wrap, + Some("none") => FilterConvolveEdgeMode::None, + // Missing, invalid, wrong-case, whitespace-padded, and + // CSS-wide spellings retain the initial duplicate member. + _ => FilterConvolveEdgeMode::Duplicate, + }, + preserve_alpha: get_attr(element, "preserveAlpha").as_deref() == Some("true"), + })) + } + enum ComponentTransferFunction { Identity, Table(Vec), @@ -5887,6 +6041,21 @@ mod filter_resource { }, ) } + "feConvolveMatrix" => { + patrol_color_style(element)?; + match convolve_matrix(element)? { + Some(primitive) => ( + vec![resolve_input(element, "in", previous, &names)], + primitive, + ), + None => ( + Vec::new(), + FilterPrimitive::SolidColor { + color: CGColor32F::TRANSPARENT, + }, + ), + } + } "feMerge" => { patrol_color_style(element)?; let mut inputs = Vec::new(); @@ -6027,8 +6196,10 @@ mod filter_resource { let mut has_morphology = false; let mut has_turbulence = false; let mut has_displacement_map = false; + let mut has_convolve_matrix = false; let mut has_source_dependent_morphology = false; let mut has_source_dependent_active_morphology = false; + let mut has_source_dependent_convolve_matrix = false; for node in &nodes { let source_dependent = node.inputs().iter().any(|input| match *input { FilterInput::Source | FilterInput::SourceAlpha => true, @@ -6062,6 +6233,10 @@ mod filter_resource { has_turbulence |= matches!(node.primitive(), FilterPrimitive::Turbulence { .. }); has_displacement_map |= matches!(node.primitive(), FilterPrimitive::DisplacementMap { .. }); + if matches!(node.primitive(), FilterPrimitive::ConvolveMatrix { .. }) { + has_convolve_matrix = true; + has_source_dependent_convolve_matrix |= source_dependent; + } source_dependencies.push(source_dependent); } if has_blend { @@ -6102,6 +6277,18 @@ mod filter_resource { .to_string(), )); } + if has_convolve_matrix && !morphology_mapping_is_admitted(target_to_frame) { + return Err(CompileError::UnsupportedFilter( + "feConvolveMatrix's target mapping crosses the pinned-backend convolution-filter transform precision boundary" + .to_string(), + )); + } + if has_source_dependent_convolve_matrix && filter_source_has_paint_server(target)? { + return Err(CompileError::UnsupportedFilter( + "feConvolveMatrix's source image crosses the pinned-backend convolution-filter paint-server precision boundary" + .to_string(), + )); + } if has_source_dependent_morphology && filter_source_has_paint_server(target)? { return Err(CompileError::UnsupportedFilter( "feMorphology's source image crosses the pinned-backend morphology paint-server precision boundary" diff --git a/crates/websem/tests/unsupported_corpus.rs b/crates/websem/tests/unsupported_corpus.rs index f961fe98..b73977ff 100644 --- a/crates/websem/tests/unsupported_corpus.rs +++ b/crates/websem/tests/unsupported_corpus.rs @@ -140,6 +140,21 @@ const CORPUS: &[(&str, Departure, &str)] = &[ DeclaredByBestEffort, "table-filter transform precision boundary", ), + ( + "svg-filter-convolve-arithmetic-range", + DeclaredByBestEffort, + "finite native-convolution arithmetic boundary", + ), + ( + "svg-filter-convolve-paint-server-precision", + DeclaredByBestEffort, + "convolution-filter paint-server precision boundary", + ), + ( + "svg-filter-convolve-transform-precision", + DeclaredByBestEffort, + "convolution-filter transform precision boundary", + ), ( "svg-filter-color-raw-syntax", DeclaredByBestEffort, diff --git a/docs/wg/consolidation/svg-engine-of-record.md b/docs/wg/consolidation/svg-engine-of-record.md index 7b4dd136..7433f9e0 100644 --- a/docs/wg/consolidation/svg-engine-of-record.md +++ b/docs/wg/consolidation/svg-engine-of-record.md @@ -67,7 +67,8 @@ from the dated addenda below: modes, ordered `feMerge`/`feMergeNode`, native one-input `feDropShadow`, one-input `feColorMatrix`, one-input `feComponentTransfer` with its direct `feFuncR`/`feFuncG`/`feFuncB`/`feFuncA` children, and one-input - `feMorphology`, plus zero-input `feTurbulence` and two-input + `feMorphology` and `feConvolveMatrix`, plus zero-input `feTurbulence` and + two-input `feDisplacementMap`; graph inputs resolve from `SourceGraphic`/`SourceAlpha`/prior and named results, with both filter coordinate systems and color spaces, hard regions, nesting, admitted @@ -76,14 +77,14 @@ from the dated addenda below: the full `preserveAspectRatio` grammar; and one exact-time `` on a top-level ``. `crates/n0_cli/README.md` is the statement of record. -- **The corpus** is 700 Chromium-baked primitive cells plus 10 sampled frames. +- **The corpus** is 741 Chromium-baked primitive cells plus 10 sampled frames. 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 143 rows. + register has 146 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 @@ -2681,9 +2682,10 @@ celled). The admitted direct inherited attribute preserves conversions at each operation. CSS ingress, comments, escapes, and `var()` remain named gaps at the Stylo boundary. All three valid `edgeMode` values and the missing value were byte-identical even on a boundary-sensitive source; current Blink has no blur -edge-mode field and uses transparent decal. That browser-dropped behavior is -measured, not celled, and cannot close the global attribute row because -`edgeMode` also belongs to `feConvolveMatrix`. +edge-mode field and uses transparent decal. At this rung that browser-dropped +behavior was measured but not celled, so the global attribute row stayed open +for `feConvolveMatrix`. The convolution rung below commits the blur drop and +closes the shared row. Composition stays one meaning across effects. Filter isolation encloses fill, stroke, descendants, and overlaps; target transforms carry its operation @@ -3543,3 +3545,116 @@ primitive corpus moves from 609 to 700 cells; the ten exact-time sampled frames are unchanged. Exactly nine checklist rows tick: the two elements and seven element-specific attributes named above. This records no conformance score and takes no FLIP action. + +## Rung: `feConvolveMatrix` (2026-08-27) + +The verdict is CLOSE/SPLIT. `` closes for its complete static +Chromium behavior. Eight attribute rows close with it: `bias`, `divisor`, +`edgeMode`, `kernelMatrix`, convolution `order`, `preserveAlpha`, `targetX`, +and `targetY`. `kernelUnitLength` remains open because it also applies to the +still-open lighting primitives. The shared `in`, `result`, primitive-region, +`color-interpolation-filters`, filter-resource, and dynamics rows remain open +for their wider applicability. No CSS property row closes. + +Chromium 149.0.7827.55 establishes one rectangular convolution. `order` takes +one or two values, with one supplying both axes; Blink normalizes finite values +by truncating toward zero. Missing, empty, malformed, wrong-count, +unit-bearing, function-valued, and CSS-wide spellings retain the initial 3×3 +order. A parsed non-positive axis produces a transparent operation result. The +wider invalid-spelling matrix is measured, not all separately celled. +`kernelMatrix` is an SVG number list whose length must equal the product of the +two order axes. Missing, malformed, non-finite, and wrong-count lists likewise +produce transparent. The authored matrix is reversed once so the operation is +convolution rather than correlation. One-hot left/right and asymmetric target +cells distinguish that direction from a backend correlation. + +The pinned operation accepts at most 256 coefficients. Chromium executes the +measured strategy boundaries at 28, 29, 64, 65, and 256 coefficients, while a +257-coefficient kernel produces transparent. Those accepted boundaries and +the browser drop are committed exact evidence. This follows the browser-drop +precedent established by +[gridaco/nothing#77](https://github.com/gridaco/nothing/pull/77): a listed +value the oracle itself drops does not require this engine to invent pixels. + +`divisor` carries one signed SVG number. Missing, an exactly empty attribute, +and either signed zero select the kernel's ordered binary32 sum; a zero sum +becomes one. A present, nonempty malformed value selects one rather than the +sum. Positive and negative nonzero values remain active. The ordered sum is +observable: cancellation in `1e20 1 -1e20` is not interchangeable with a +reassociated sum. A default sum that overflows produces Chromium's measured +transparent output. `bias` carries one signed SVG number with initial zero; +missing and malformed values select that initial, while large finite values +clamp only at output. + +`targetX` and `targetY` use the signed SVG-integer grammar. When absent, each +defaults independently to the floor of half its order axis. An authored +fraction, exponent, malformed token, or integer-storage overflow selects zero. +A valid negative target or a value at or beyond its order axis produces +transparent. `edgeMode` is the case-sensitive `duplicate | wrap | none` +enumeration with initial `duplicate`; all three differ at an actual input-image +boundary. `preserveAlpha` is the case-sensitive `false | true` enumeration with +initial `false`. SourceAlpha and positive-bias controls prove that false +convolves alpha and may create coverage over a transparent source, while true +retains the input alpha. + +The other listed `edgeMode` applicability is `feGaussianBlur`. Current Chromium +ignores every blur spelling; a dedicated committed cell now carries the drop +that the chassis rung had only measured. Current Chromium likewise ignores +every sampled `kernelUnitLength` spelling on convolution: positive one- and +two-axis values, zero, negative, malformed, units, percentages, functions, +custom properties, and CSS-wide values all leave a discriminating kernel +unchanged (measured, not all separately celled). The drop is celled, but the row +cannot close before its lighting applicability is earned. + +The operation participates in the established filter graph and effect order. +Committed exact cells cover SourceGraphic, SourceAlpha, previous and named +results, generated input, result reuse, hard primitive crops, both primitive +unit systems, default linearRGB, explicit linearRGB and sRGB, Chromium's +`auto`-to-sRGB behavior, paths, strokes, groups, ``, non-uniform `viewBox`, +fractional axis mapping, exact quarter turns, target opacity, clip, and mask, +and ordering beside blur and morphology. Stroke geometry enters the isolated +source before convolution; target effects remain outside the filter scope in +their established order. + +The numeric probe found the source-parser crux rather than assuming it away. +An amplified decimal just above the midpoint between adjacent binary32 values +selects the upper neighbor in Chromium and is exact through the shared ordered +SVG-number evaluator. Kernel-size strategy boundaries, ordered divisor sums, +sum overflow, large bias, and accepted finite arithmetic all reproduce without +a tolerance. Unit, percentage, CSS-function, custom-property, and CSS-wide +spellings take their measured fallback or transparent-error branch; none +silently becomes a different valid kernel. + +Three remaining silent classes are stable refusals. Fractional translation and +scale, reflections, axis maps, and exact quarter turns are exact, but a sampled +17-degree target rotation differs by 462 pixels at maximum channel delta 15 +and a shear by 632 at delta 13. Arbitrarily small sampled rotations and shears +reproduce the class. A source-dependent linear-gradient fill differs by 1,425 +pixels, a radial fill by 1,658, and a gradient stroke by 609, each at maximum +delta 7; generated-only input stays exact. Finally, a valid nonzero divisor of +`1e-45` has a reciprocal outside the finite resolved arithmetic domain. +Chromium executes it and the sampled pixels equal a nearby finite-gain control, +so the engine refuses that narrow arithmetic range rather than emit a +non-finite operation. These pixel verdicts are measured, not celled; three +focused refusal fixtures guard their stable names in strict and best-effort +admission. + +Four twice-deterministic scratch matrices exercised grammar, error states, +operation semantics, precision boundaries, graph routing, composition, and +source classes. Every candidate also rendered through both actual command +admissions; every admitted result was compared by pixels, not merely by process +success. Three dense grammar atlases and thirty-seven focused convolution cells +carry the accepted surface. One further cell commits the blur `edgeMode` drop. +All forty-one are byte-exact without a new tolerance. + +Gate sensitivity was proved by temporarily removing the required matrix +reversal. `just gate` rejected eleven convolution cells. The dedicated reversal +cell changed 230 pixels at maximum channel delta 202; the broad failures reached +2,814 pixels and maximum delta 250. Restoring the reversal returned the complete +741-cell gate to green. + +Three focused rows join the refusal register, moving it from 143 to 146. The +primitive corpus moves from 700 to 741 cells; the ten exact-time sampled frames +are unchanged. Exactly nine checklist rows tick: the element and eight +attributes named above. This records no conformance score and takes no FLIP +action. diff --git a/docs/wg/consolidation/web-checklist.md b/docs/wg/consolidation/web-checklist.md index 221e72de..2fd1843f 100644 --- a/docs/wg/consolidation/web-checklist.md +++ b/docs/wg/consolidation/web-checklist.md @@ -1449,7 +1449,25 @@ for attributes the platform ships ahead of the SVG 2 indexes. - [x] `` - [x] `` - [x] `` -- [ ] `` +- [x] `` + +> **2026-08-27 close/split:** `feConvolveMatrix` carries Chromium's complete +> static convolution behavior: rectangular kernels through 256 coefficients, +> kernel reversal, divisor and bias arithmetic, asymmetric targets, all three +> edge modes, alpha preservation, both filter color spaces, graph inputs and +> reuse, hard regions and primitive units, safe mappings, source geometry, +> blur/morphology ordering, target effects, ``, and `viewBox`. +> Invalid operation states and Chromium's 257-coefficient construction limit +> produce the browser's transparent result rather than an unfiltered fallback. +> Chromium ignores `kernelUnitLength` on this primitive; the drop is celled, +> while that attribute row stays open for its lighting applicability. General +> affine mappings, paint-server source images, and a divisor whose reciprocal +> exceeds finite resolved arithmetic refuse by three stable names before paint. +> Forty exact convolution cells and one blur-edge drop cell move the complete +> gate to 741. Removing the required kernel reversal makes eleven cells fail, +> up to 2,814 pixels and maximum channel delta 250; restoration returns the +> gate to green. The shared graph, region, interpolation, filter-resource, and +> dynamics rows remain open. - [ ] `` - [x] `` - [ ] `` @@ -1563,8 +1581,9 @@ for attributes the platform ships ahead of the SVG 2 indexes. > multi-operation lists, host, and dynamics surface; `` still > has valid empty primitive results, inherited raw-syntax gaps, animation, and > a measured small-kernel backend precision boundary. Current Chromium -> drops every `edgeMode` spelling on this primitive (measured, not celled), but -> that attribute also applies to `` and stays open. +> drops every `edgeMode` spelling on this primitive. The later convolution rung +> commits that drop and closes the shared attribute row; it does not close the +> blur element's other remainders. > **2026-08-25 close/split:** `feFlood`, `feComposite`, `feMerge`, and > `feMergeNode` now carry the complete static primitive behavior for their > rows: zero-, two-, and ordered N-input graph nodes; all seven composite @@ -1915,7 +1934,15 @@ for attributes the platform ships ahead of the SVG 2 indexes. > axes; comma-wsp, leading plus, exponent, and the measured lone trailing comma > are carried. Missing, malformed, unit-bearing, and overlong lists select the > initial zero pair; either negative member makes the whole pair initial. -- [ ] `bias` +- [x] `bias` + +> **2026-08-27 close:** convolution `bias` carries one signed SVG number with +> initial zero; missing, empty, malformed, unit-bearing, CSS-function, and +> CSS-wide text selects that initial. `divisor` carries the same one-number +> grammar. Missing, exactly empty, and explicit positive or negative zero use +> the kernel's ordered binary32 sum; a zero sum becomes one. A present nonempty +> malformed divisor uses one. Signed nonzero divisors remain active. The wider +> invalid-spelling matrix is measured, not all separately celled. - [ ] `class` - [x] `clipPathUnits` @@ -1929,11 +1956,17 @@ for attributes the platform ships ahead of the SVG 2 indexes. - [ ] `data-*` - [ ] `decoding` - [ ] `diffuseConstant` -- [ ] `divisor` +- [x] `divisor` - [ ] `download` - [ ] `dx` - [ ] `dy` -- [ ] `edgeMode` +- [x] `edgeMode` + +> **2026-08-27 close:** the complete case-sensitive `duplicate | wrap | none` +> grammar is Chromium-baked at actual input boundaries; missing and every +> invalid spelling select `duplicate`. The attribute's other listed +> applicability is blur, where current Chromium drops all spellings; one +> committed drop cell records that browser behavior. - [ ] `elevation` - [x] `exponent` - [ ] `fetchpriority` @@ -1965,8 +1998,17 @@ for attributes the platform ships ahead of the SVG 2 indexes. > background, and constant terms are Chromium-baked; signs, decimals, and > exponents are carried, and output channels clamp to the unit interval. -- [ ] `kernelMatrix` +- [x] `kernelMatrix` - [ ] `kernelUnitLength` + +> **2026-08-27 close/split:** `kernelMatrix` carries the complete SVG +> number-list grammar and must contain exactly `order-x × order-y` values. +> Missing, malformed, non-finite, or wrong-count matrices produce the measured +> transparent result. Kernels at the measured native strategy boundaries—28, +> 29, 64, 65, and 256 coefficients—are exact; 257 coefficients produce the +> celled Chromium drop. `kernelUnitLength` stays open: Chromium ignores every +> sampled valid and invalid spelling on convolution, while the attribute also +> applies to the still-open lighting primitives. - [ ] `lang` - [ ] `lengthAdjust` - [ ] `limitingConeAngle` @@ -2077,7 +2119,14 @@ for attributes the platform ships ahead of the SVG 2 indexes. - [ ] `onwaiting` - [ ] `onwheel` - [ ] `operator` -- [ ] `order` +- [x] `order` + +> **2026-08-27 close:** convolution `order` carries one or two values; one +> supplies both axes, and Chromium truncates each finite value toward zero. +> Missing, empty, malformed, wrong-count, unit-bearing, CSS-function, and +> CSS-wide text selects the initial 3×3 order. A parsed non-positive member or +> an unconstructable finite area produces the measured transparent result. The +> wider invalid-spelling matrix is measured, not all separately celled. - [ ] `orient` - [ ] `path` - [x] `pathLength` @@ -2090,7 +2139,12 @@ for attributes the platform ships ahead of the SVG 2 indexes. - [ ] `pointsAtX` - [ ] `pointsAtY` - [ ] `pointsAtZ` -- [ ] `preserveAlpha` +- [x] `preserveAlpha` + +> **2026-08-27 close:** the complete case-sensitive `false | true` grammar is +> Chromium-baked. Missing and invalid spellings select `false`; committed +> SourceAlpha and positive-bias pairs distinguish convolved alpha from +> preserved input alpha. - [x] `preserveAspectRatio` - [x] `primitiveUnits` @@ -2148,8 +2202,14 @@ for attributes the platform ships ahead of the SVG 2 indexes. > clamping, and byte truncation are Chromium-gated. The wider shared `type` > row remains open. - [ ] `target` -- [ ] `targetX` -- [ ] `targetY` +- [x] `targetX` +- [x] `targetY` + +> **2026-08-27 close:** both target coordinates carry the signed SVG-integer +> grammar. Missing values default independently to the floor of half their +> order axis. An authored lexical failure or integer-storage overflow selects +> zero; a valid negative or value outside its kernel axis produces the measured +> transparent result. Asymmetric x/y cells distinguish both coordinates. - [ ] `textLength` - [ ] `timelinebegin` - [ ] `title` diff --git a/fixtures/web-first/README.md b/fixtures/web-first/README.md index 160ccdfc..8651abaf 100644 --- a/fixtures/web-first/README.md +++ b/fixtures/web-first/README.md @@ -185,10 +185,11 @@ is exactly what the engine renders pixel-for-pixel. | *(measured, not celled — mask split)* | Scratch matrices used the shared hash-pinned capture posture and rendered every candidate through the actual CLI. They established the reference fallbacks, inert resource-own `display`/opacity/transform/mask/clip-path properties, luma/alpha and overlap rules, region defaults and operation order, `viewBox`, groups, shapes, ``, clips, nested masks, and same-element effect order. Both `clip-path` ingresses on the resource were byte-identical to the inert baseline and differed by 1,152 pixels at Δ255 from clipping the source. A resource-own CSS `filter` was likewise inert and 2,304 pixels at Δ255 from filtering a child; its attribute twin remains a deliberate over-refusal under the filter row. An inline style on the resource is not generally inert: Chromium inherited `shape-rendering: crispEdges` into the source exactly like the same child declaration, 96 pixels at Δ63 from the default, while the former n0 route emitted the default byte-identically. Resource-own `color-interpolation: linearRGB` also moved 30 pixels at Δ1 from the default. Both now trip the focused source-side-cascade patrol. Inline and stylesheet CSS `x`/`width` declarations on `` were inert, while changing the SVG attributes changed 2,304/1,152 pixels. Region `initial`, `unset`, `revert`, and `inherit` spellings are all byte-identical to the missing-value default; even `inherit` under a parent `width: 50%` differs by 2,048 pixels at Δ255 from a half-width region. The proposed source-number alias did **not** reproduce on the new CSS-token route: direct-number and `px` midpoint sources selected the lower adjacent control in Chromium and n0 under an admitted pure translation; with the independent upscale patrol temporarily bypassed, the percentage source selected the upper control in both. Each opposite control differed by 96 pixels. Percentages still retain Blink's observable `basis × percentage ÷ 100` operation order. The used-range class did reproduce: Chromium clamps huge and adjacent-high `x` values to 33,554,428, while the former route lost 1,728 pixels for the huge sources and 96/192 for 33,554,430/33,554,432, all at Δ255. A separate hard-region transform class also reproduced. Translation and sampled positive axis-aligned downscales through identity were exact; at x-scale 1.01 the threshold-aligned lower and upper controls differed from Chromium by 96 and 48 pixels respectively, both at Δ255. The mask route therefore refuses upscales, and conservatively over-refuses rotations, reflections, and shears through the same boundary. CSS mask-family declarations, root masks, external resources, full shorthand/layers, cycles, unsupported source elements, resource-side cascade gaps, non-`px` units, CSS math, `var()`, range, and unresolved `mask-type` cascade values make up the focused 16-row remainder. These are probe verdicts and refusal boundaries, not extra cells. | | `svg-filter-gaussian-blur-{basic,axis-clamp,number-list,invalid-list,zero}.svg` | The first kernel and its committed value branches. One value blurs both axes; a negative second axis clamps independently so `3 -1` is `3 0`; comma-separated two-number input is accepted; an extra member invalidates the value to pass-through; and zero is the identity operation while still respecting the filter's hard region. All five are byte-exact. | | `svg-filter-blur-zero-primitive-region.svg` | Zero sigma leaves the input samples unchanged but does not erase the primitive operation: its explicit primitive rectangle still crops the result. A pass-through mutation changes 1,160 pixels at Δ218. Byte-exact. | +| `svg-filter-blur-edge-mode-drop.svg` | The other applicability of the shared `edgeMode` attribute. On a boundary-discriminating blur, missing, `duplicate`, `wrap`, `none`, and invalid spellings are byte-identical in current Chromium because Blink carries no blur edge-mode field. This committed browser drop joins the complete convolution enum evidence to close the attribute row. Forcing the nonzero blur backend from transparent-edge sampling to repeated-edge sampling makes the exact gate fail on 806 pixels at maximum channel delta 102; restoring it returns the complete gate to green. Byte-exact. | | `svg-filter-source-alpha.svg` · `svg-filter-result-chain.svg` · `svg-filter-empty-graph.svg` · `svg-filter-first-id.svg` · `svg-filter-url-{comments,quoted}.svg` | Graph and reference semantics. `SourceAlpha` clears colour before blur; a named earlier result feeds the next node; a valid empty graph hides its target; duplicate ids resolve to the first filter in document order; comments around the one URL are tokenized; and quoted and unquoted URL tokens select the same resource. Missing/wrong/malformed references and explicit `none` install no filter (measured, not separately celled). All six are byte-exact. | | `svg-filter-region-default.svg` · `svg-filter-region-userspace.svg` · `svg-filter-primitive-region.svg` · `svg-filter-primitive-units-object.svg` · `svg-filter-units-grammar.svg` | Region and coordinate-system evidence. The default object-box effect region is `-10% -10% 120% 120%`; explicit user space uses the viewport; a primitive subregion is a hard crop; and object-box primitive units scale each sigma axis by the target fill box. The eight-panel grammar cell discriminates missing, both valid values, and case-sensitive invalid fallback for both `filterUnits` and `primitiveUnits`, closing those two rows. All five are byte-exact. | | `svg-filter-color-{linear,srgb}.svg` · `svg-filter-{target-rotate,use-instance,stroke,opacity-order,viewbox-nonuniform,nested,scope-order}.svg` | Color and composition. Missing/explicit linearRGB and explicit sRGB take distinct measured kernels. A target transform carries filter space; `` filters at the instance; stroke is part of SourceGraphic; groups isolate before opacity; non-uniform `viewBox` mapping preserves independent axes; filters nest; and the final scope cell hard-cuts blur with the already-landed clip and mask routes, proving filter → mask → opacity → clip. All nine are byte-exact. | -| *(measured, not celled — filter split)* | Scratch matrices used Chromium 149.0.7827.55 through the shared capture module, and every candidate also rendered through the actual CLI. One number equals two equal numbers; leading plus, exponent, and comma spellings are accepted; malformed tails and extra members pass through; negative axes clamp independently. Omitted/empty/unknown first inputs and the unavailable Background/FillPaint/StrokePaint built-ins select SourceGraphic, while their later forms select the previous result. Later duplicate result names win. Explicit `auto` color interpolation equals sRGB, while missing, invalid, and `initial` equal linearRGB; sRGB differs from linearRGB by 636 pixels at Δ73. Missing, `duplicate`, `wrap`, and `none` `edgeMode` values are byte-identical on a discriminating boundary source, matching current Blink's absent blur edge-mode field. A sampled stdDeviation midpoint remained exact to the `3` control. The former third-operation diagnosis was withdrawn by the shadow-graph audit: safe-sigma three-node chains are exact, while a single small effective sigma already differs. The focused refusal now names that measured kernel boundary, not graph depth. A quoted single URL is byte-identical to its unquoted twin and differs from `none` by 1,516 pixels at Δ162; quoted two-URL and URL-plus-function lists likewise match their unquoted twins and differ from `none` by 1,588 pixels at Δ163. Invalid trailing-ident and comma spellings both equal `none`. CSS filter declarations, functions/lists, root and external resources, `href`, unsupported primitives, transparent primitive subregions, non-`px` units, CSS math, `var()`, used-range saturation, color cascade/raw syntax, and the small-kernel boundary make up the sixteen-row remainder. The 26 committed cells are exact; these are the additional probe verdicts and refusal boundaries. | +| *(measured, not celled — filter split)* | Scratch matrices used Chromium 149.0.7827.55 through the shared capture module, and every candidate also rendered through the actual CLI. One number equals two equal numbers; leading plus, exponent, and comma spellings are accepted; malformed tails and extra members pass through; negative axes clamp independently. Omitted/empty/unknown first inputs and the unavailable Background/FillPaint/StrokePaint built-ins select SourceGraphic, while their later forms select the previous result. Later duplicate result names win. Explicit `auto` color interpolation equals sRGB, while missing, invalid, and `initial` equal linearRGB; sRGB differs from linearRGB by 636 pixels at Δ73. Missing, `duplicate`, `wrap`, and `none` `edgeMode` values are byte-identical on a discriminating boundary source, matching current Blink's absent blur edge-mode field; the later convolution rung commits that drop in `svg-filter-blur-edge-mode-drop`. A sampled stdDeviation midpoint remained exact to the `3` control. The former third-operation diagnosis was withdrawn by the shadow-graph audit: safe-sigma three-node chains are exact, while a single small effective sigma already differs. The focused refusal now names that measured kernel boundary, not graph depth. A quoted single URL is byte-identical to its unquoted twin and differs from `none` by 1,516 pixels at Δ162; quoted two-URL and URL-plus-function lists likewise match their unquoted twins and differ from `none` by 1,588 pixels at Δ163. Invalid trailing-ident and comma spellings both equal `none`. CSS filter declarations, functions/lists, root and external resources, `href`, unsupported primitives, transparent primitive subregions, non-`px` units, CSS math, `var()`, used-range saturation, color cascade/raw syntax, and the small-kernel boundary make up the sixteen-row remainder. The 26 original cells are exact; these are the additional probe verdicts and refusal boundaries. | | *(measured, not celled — filter CSS-wide and raw syntax)* | Direct `filter` values `initial`, `unset`, `revert`, `revert-layer`, and an invalid identifier are byte-identical to `none`. A substituted `var()` is byte-identical to its live URL, and `inherit` under a filtered parent is byte-identical to spelling that URL on both parent and child; those two unresolved routes refuse by name. For `color-interpolation-filters`, a CSS comment and an escaped `linearRGB` keyword are byte-identical to literal linearRGB, while a substituted variable is byte-identical to literal sRGB; all three raw/cascade routes refuse by name. Every candidate rendered through the actual CLI: every admitted control was exact, and only the intended `filter` inherit/variable and color comment/escape/variable cases refused. | | *(measured, not celled — filter used-length range)* | With `x=-33554396`, Chromium clamps filter-region widths `33554432` and `33554436` to the used-length ceiling `33554428`; both are byte-identical to that ceiling and differ from the unclamped arithmetic control by 96 pixels at Δ233. The ceiling and control render exactly through the CLI; the two overflowing values refuse under `svg-filter-region-range` before they can expose the wider crop. | | `svg-filter-offset-{zero,missing,basic,negative,number-comma,source-alpha,primitive-units-object,primitive-region,chain,input-region-default,input-region-explicit}.svg` | Integer offset semantics: absent and explicit zero, signs, the measured trailing-comma prefix, source alpha, both primitive unit systems, hard and default input subregions, and a three-operation named chain. All eleven are byte-exact. Source-fractional displacement, mapped-fractional displacement, and blur composition remain the three named precision boundaries below. | @@ -220,6 +221,11 @@ is exactly what the engine renders pixel-for-pixel. | `svg-filter-displacement-{default,scale-zero,scale-positive,scale-negative,scale-fraction,scale-trailing-comma,scale-invalid,selector-default,selector-alpha,selector-red,selector-green,selector-blue,selector-axes,selector-grammar}.svg` | The complete static `feDisplacementMap` parameter grammar in fourteen cells: absent and explicit-zero scale, signed/fractional SVG numbers, the accepted trailing comma and invalid fallback, all four independently selected channels, and case-sensitive selector fallback to alpha. All fourteen are byte-exact. | | `svg-filter-displacement-{color-srgb,color-linear,primitive-units,transparent-map,half-alpha-map,map-region,source-alpha-map,source-rgb-map,generated-color,turbulence-map,turbulence-map-linear,region-percent,scale-transform,quarter-turn,use,viewbox,stroke,path,opacity,empty-generated,input-default-in2,input-unknown-in}.svg` · `svg-filter-turbulence-displacement-map.svg` | Two-input sampling and composition evidence: non-premultiplied map channels in both filter color spaces; Blink's horizontal object-box scale for both displacement axes; transparent, half-alpha, bounded, source, and generated maps; hard regions, safe mappings, ``, `viewBox`, stroke/path sources and opacity; default/unknown graph inputs; generated output over an empty target; and the procedural-noise-to-warp chain. All twenty-three are byte-exact. | | *(measured, not celled — turbulence/displacement split)* | Two twice-deterministic Chromium 149 matrices contain 164 sources, each rendered through both actual CLI admissions. All 156 admitted sources are exact and admission-identical; eight reach one of the three new stable names or an older blur/composition patrol. General rotation and shear are the new mapping boundary: turbulence differs by 3,173px/Δ7 and 3,110px/Δ6, while displacement differs by 280px/Δ13 and 360px/Δ18. A clipped displacement differs by 35px/Δ2. Axis maps, fractional translation/scale, reflection, and exact quarter turns are exact. Missing filter interpolation is linearRGB; `sRGB` changes both the procedural field and displacement sampling. Zero fractal octaves produce the neutral-half field while a negative count is transparent. Empty user-space targets still receive generated output, including with object-box primitive units; object-box filter units on the same empty target paint nothing. Seed-midpoint and tiny adjacent-frequency probes found no second source-number divergence class at this raster size. A review-triggered eighteen-source matrix then isolated procedural-image arithmetic across blend, morphology, matrix, transfer, displacement, and both color-space directions: fifteen sources are admitted and exact after repair, while three reach older shadow/composition patrols. The old byte-image policy changed 349px/Δ1 for linear→sRGB blend, 490px/Δ6 for all-linear blend, 450px/Δ6 for sRGB→linear blend, 2,365px/Δ1 for sRGB→linear morphology, and 393px/Δ1 for blend→morphology. Four further sixteen-mode atlases prove the direct-sRGB byte-product versus promoted-floating split for procedural `difference` and `exclusion`; all sixty-four mode/space/alpha combinations are exact in both admissions. A thirty-four-source chain matrix around offset, blur, matrix, transfer, morphology, prior blend, displacement, merge, and composite admits thirty exact sources and routes four through the existing source-derived multi-input patrol. It also proves that an sRGB blend output materializes before a later blend. Eight hard-edged cells guard the affected product and chain branches. Swapping turbulence with fractal noise and red displacement with alpha made fifty-five original rung cells fail, up to all 4,096 pixels and maximum channel delta 202. Restoring the pre-review procedural policy makes five operation-order cells fail. Replacing final half-up quantization with floor makes forty-one cells fail, up to 3,648px/Δ1, and replacing procedural multiply with normal makes five fail, up to 1,362px/Δ116. Forcing floating products breaks the two direct-sRGB route cells by 3,497 and 3,532 pixels; forcing byte products breaks the four promoted-route cells by 3,287–3,697 pixels. Carrying floating state across the sRGB blend-output boundary breaks the two chain cells by 3,468 and 3,700 pixels. Every restoration returns the complete 700-cell gate to green. The first hosted-x86 run found twenty-two rung cells and 294 pixels at Δ1: eighteen sRGB displacement cells plus four procedural outputs. Scoped exact displacement restore cleared the eighteen displacement failures on the second run, which left four procedural cells and 729 pixels at Δ1—726 in the blend control and one each in three direct procedural controls. Explicit procedural mode arithmetic and composed-result-only half-up quantization cleared the 726-pixel blend control on the third run, leaving three singleton direct-noise pixels. Pinned Skia source then located the final split in uninitialized runtime raster-pipeline dispatch: x86 retained baseline non-fused Perlin arithmetic while ARM used its fused NEON path. Initializing Skia before drawlist replay selects fused AVX2 arithmetic on hosted x86. The complete 700-cell gate is byte-exact on ARM and hosted x86 with no tolerance. The corpus is now 700 cells plus 10 sampled frames, and the named register has 143 rows. | +| `svg-filter-convolve-{order-kernel-grammar,divisor-bias-target-grammar,edge-alpha-kernel-unit-grammar}.svg` | Three dense atlases carry the complete measured source grammar and error behavior: one/two-axis order and truncation, exact kernel arity, malformed and non-positive transparent results, divisor sum/zero/malformed distinctions, signed bias, target defaults and strict integer fallback, all three edge modes, both alpha policies, and Chromium's complete `kernelUnitLength` drop. All three are byte-exact. | +| `svg-filter-convolve-{sharpen,kernel-reversal,source-number-alias,divisor-sum-order,divisor-sum-overflow,empty-bias,bias-large,kernel-uniform-28,kernel-texture-29,kernel-texture-64,kernel-large-65,kernel-max-256,kernel-over-max,target-y}.svg` | Kernel and numeric evidence: a visible sharpen, convolution-versus-correlation reversal, Blink's adjacent-binary32 source-number choice, ordered default-divisor summation and overflow, empty and large bias, asymmetric targets, accepted native strategy boundaries at 28/29/64/65/256 coefficients, and Chromium's transparent 257-coefficient result. All fourteen are byte-exact. | +| `svg-filter-convolve-{source-alpha,source-alpha-preserve,color-default,color-auto,color-linear,color-srgb,primitive-units,region-crop,input-previous,result-reuse,generated-input,blur-before,morphology-after}.svg` | Alpha, color, graph, and operation evidence: convolved versus preserved SourceAlpha, default linearRGB and explicit `auto`/sRGB/linearRGB, object-box units, hard crops, previous and named result routing, generated input, and ordering around blur and morphology. All thirteen are byte-exact. | +| `svg-filter-convolve-{source-path,source-stroke,source-group,use,viewbox,axis-fractional,quarter-turn,target-opacity,target-clip,target-mask}.svg` | Source and composition evidence: direct path, stroke, and group images; `` and non-uniform `viewBox`; safe fractional axis mapping and exact quarter turn; and filter ordering with target opacity, geometric clip, and mask. The binary-mask control is byte-identical to explicit filter-then-mask nesting, differs from the reversed order by 75 pixels at maximum channel delta 99, and differs from no mask by 444 pixels at maximum delta 204. All ten are byte-exact. | +| *(measured, not celled — convolution split)* | Four twice-deterministic Chromium 149 matrices probed grammar, operation semantics, numeric and native-strategy boundaries, source classes, transforms, graph routing, and effect order. Every candidate also rendered through both actual CLI admissions; process success was never treated as pixel proof. After the three patrols below, every admitted candidate is exact and admission-identical. Current Chromium ignores every sampled valid and invalid `kernelUnitLength` spelling. The amplified coefficient `1.000000059604644775390625000000000000000000000001` selects the upper adjacent binary32 value; the shared ordered source-number route is exact. The default divisor uses ordered binary32 summation. General target rotation and shear differ by 462px/Δ15 and 632px/Δ13; source-dependent linear/radial gradient fills and a gradient stroke differ by 1,425px/Δ7, 1,658px/Δ7, and 609px/Δ7. A valid divisor of `1e-45` has a non-finite reciprocal in the resolved arithmetic domain and refuses by its own narrow name. Axis maps, fractional translation/scale, reflection, exact quarter turns, generated input, accepted kernels through 256, ordered sum overflow, and large finite bias are exact. Removing kernel reversal made eleven cells fail: the dedicated witness changed 230px/Δ202, and failures reached 2,814px with maximum Δ250. Restoration returned the complete 741-cell gate to green. The corpus is now 741 cells plus 10 sampled frames, the filter estate has 380 cells, and the named register has 146 rows. | | `svg-gradient-linear.svg` · `svg-gradient-linear-userspace.svg` · `svg-gradient-linear-bbox-offset.svg` | The gradient rung's base cells: the default objectBoundingBox ramp, the byte-identical userSpaceOnUse equivalent (the canary for the box-inverse fold), and a bbox-relative ramp on offset geometry. | | `svg-gradient-transform.svg` · `svg-gradient-css-transform.svg` | `gradientTransform` and an author `transform` declaration are one computed value — the attribute cell and the non-quarter CSS rotation cell (the discriminating measurement: the value applies about the raw origin of gradient space, both spellings). | | `svg-gradient-spread-reflect.svg` · `svg-gradient-spread-repeat.svg` · `svg-gradient-hard-stop.svg` · `svg-gradient-stop-nonmonotonic.svg` | The ramp grammar: both non-pad spread methods with their measured seams, equal-offset hard stops rendering crisp, and non-monotonic offsets clamping to the running maximum (never sorted). | diff --git a/fixtures/web-first/STATUS.md b/fixtures/web-first/STATUS.md index ab653c48..7cab58df 100644 --- a/fixtures/web-first/STATUS.md +++ b/fixtures/web-first/STATUS.md @@ -19,7 +19,7 @@ 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 (700) +## Chromium-baked cells (741) Each renders byte-exact against its committed Chromium oracle (seven curved cells and four gradient ramps carry a declared, bounded @@ -133,6 +133,7 @@ to its fixture source. No new image is committed for this view. svg-filter-blend-transfer-order svg-filter-blend-use svg-filter-blend-viewbox +svg-filter-blur-edge-mode-drop svg-filter-blur-zero-primitive-region svg-filter-color-linear svg-filter-color-matrix-alpha-create @@ -217,6 +218,46 @@ to its fixture source. No new image is committed for this view. svg-filter-composite-region-default svg-filter-composite-region-union svg-filter-composite-xor +svg-filter-convolve-axis-fractional +svg-filter-convolve-bias-large +svg-filter-convolve-blur-before +svg-filter-convolve-color-auto +svg-filter-convolve-color-default +svg-filter-convolve-color-linear +svg-filter-convolve-color-srgb +svg-filter-convolve-divisor-bias-target-grammar +svg-filter-convolve-divisor-sum-order +svg-filter-convolve-divisor-sum-overflow +svg-filter-convolve-edge-alpha-kernel-unit-grammar +svg-filter-convolve-empty-bias +svg-filter-convolve-generated-input +svg-filter-convolve-input-previous +svg-filter-convolve-kernel-large-65 +svg-filter-convolve-kernel-max-256 +svg-filter-convolve-kernel-over-max +svg-filter-convolve-kernel-reversal +svg-filter-convolve-kernel-texture-29 +svg-filter-convolve-kernel-texture-64 +svg-filter-convolve-kernel-uniform-28 +svg-filter-convolve-morphology-after +svg-filter-convolve-order-kernel-grammar +svg-filter-convolve-primitive-units +svg-filter-convolve-quarter-turn +svg-filter-convolve-region-crop +svg-filter-convolve-result-reuse +svg-filter-convolve-sharpen +svg-filter-convolve-source-alpha +svg-filter-convolve-source-alpha-preserve +svg-filter-convolve-source-group +svg-filter-convolve-source-number-alias +svg-filter-convolve-source-path +svg-filter-convolve-source-stroke +svg-filter-convolve-target-clip +svg-filter-convolve-target-mask +svg-filter-convolve-target-opacity +svg-filter-convolve-target-y +svg-filter-convolve-use +svg-filter-convolve-viewbox svg-filter-displacement-color-linear svg-filter-displacement-color-srgb svg-filter-displacement-default @@ -729,7 +770,7 @@ to its fixture source. No new image is committed for this view. svg-visibility-rule-beats-attribute svg-visibility-unhide -## The refusal register (143) +## The refusal register (146) What the slice refuses, by name, in the compiler's own words — **both refuse** is a document-level contract; **declared** renders @@ -763,6 +804,9 @@ its row into the cells above. | `svg-filter-color-raw-syntax` | declared | skipped svg/rect[2]: unsupported SVG filter: color-interpolation-filters presentation attribute contains a CSS comment; the direct attribute decoder does not tokenize comments | | `svg-filter-component-transfer-source-layer-precision` | declared | skipped svg/circle[1]: unsupported SVG filter: feComponentTransfer's source image crosses the pinned-backend table-filter paint-server precision boundary; skipped svg/circle[2]: unsupported SVG filter: feComponentTransfer's source image crosses the pinned-backend table-filter paint-server precision boundary; skipped svg/circle[3]: unsupported SVG filter: feComponentTransfer's source image crosses the pinned-backend table-filter paint-server precision boundary | | `svg-filter-component-transfer-transform-precision` | declared | skipped svg/rect[2]: unsupported SVG filter: feComponentTransfer's target mapping crosses the pinned-backend table-filter transform precision boundary; skipped svg/rect[3]: unsupported SVG filter: feComponentTransfer's target mapping crosses the pinned-backend table-filter transform precision boundary | +| `svg-filter-convolve-arithmetic-range` | declared | skipped svg/path[1]: unsupported SVG filter: feConvolveMatrix divisor or bias crosses the finite native-convolution arithmetic boundary | +| `svg-filter-convolve-paint-server-precision` | declared | skipped svg/path[1]: unsupported SVG filter: feConvolveMatrix's source image crosses the pinned-backend convolution-filter paint-server precision boundary | +| `svg-filter-convolve-transform-precision` | declared | skipped svg/g[1]: unsupported SVG filter: feConvolveMatrix's target mapping crosses the pinned-backend convolution-filter transform precision boundary | | `svg-filter-css-functions` | declared | skipped svg/rect[2]: unsupported SVG filter: filter presentation attribute uses CSS filter functions, which are a separate unresolved operation grammar | | `svg-filter-css-property` | declared | skipped svg/rect[2]: unsupported computed style: style attribute on declares filter, which this cascade does not represent | | `svg-filter-displacement-clip-precision` | declared | skipped svg/path[1]: unsupported SVG filter: feDisplacementMap crosses the pinned-backend filtered clip-path precision boundary | @@ -787,7 +831,7 @@ its row into the cells above. | `svg-filter-offset-blur-precision` | declared | skipped svg/rect[2]: unsupported SVG filter: a filter graph combines feOffset with Gaussian blur, which crosses the pinned-backend composed-operation precision boundary | | `svg-filter-offset-fractional-precision` | declared | skipped svg/rect[2]: unsupported SVG filter: feOffset uses a fractional displacement, which crosses the pinned-backend rasterization boundary | | `svg-filter-offset-transform-precision` | declared | skipped svg/g[1]/rect[1]: unsupported SVG filter: feOffset's target mapping produces a fractional device-space displacement at the pinned-backend rasterization boundary | -| `svg-filter-primitive` | declared | skipped svg/rect[2]: unsupported SVG filter: filter graph contains unsupported primitive | +| `svg-filter-primitive` | declared | skipped svg/rect[2]: unsupported SVG filter: filter graph contains unsupported primitive | | `svg-filter-primitive-empty-region` | declared | skipped svg/rect[2]: unsupported SVG filter: a non-positive filter primitive region is not yet represented as a transparent graph result | | `svg-filter-region-calc` | declared | skipped svg/rect[2]: unsupported SVG filter: filter region x uses calc(), whose computed length is not represented at this Stylo pin | | `svg-filter-region-range` | declared | skipped svg/rect[2]: unsupported SVG filter: filter region width crosses the unimplemented Web used-length range | diff --git a/fixtures/web-first/chromium/svg-filter-blur-edge-mode-drop.png b/fixtures/web-first/chromium/svg-filter-blur-edge-mode-drop.png new file mode 100644 index 00000000..2f3d130b Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-blur-edge-mode-drop.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-axis-fractional.png b/fixtures/web-first/chromium/svg-filter-convolve-axis-fractional.png new file mode 100644 index 00000000..7ff3ee01 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-axis-fractional.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-bias-large.png b/fixtures/web-first/chromium/svg-filter-convolve-bias-large.png new file mode 100644 index 00000000..d9b4b216 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-bias-large.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-blur-before.png b/fixtures/web-first/chromium/svg-filter-convolve-blur-before.png new file mode 100644 index 00000000..8cb605f1 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-blur-before.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-color-auto.png b/fixtures/web-first/chromium/svg-filter-convolve-color-auto.png new file mode 100644 index 00000000..16801357 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-color-auto.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-color-default.png b/fixtures/web-first/chromium/svg-filter-convolve-color-default.png new file mode 100644 index 00000000..1e1381dd Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-color-default.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-color-linear.png b/fixtures/web-first/chromium/svg-filter-convolve-color-linear.png new file mode 100644 index 00000000..1e1381dd Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-color-linear.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-color-srgb.png b/fixtures/web-first/chromium/svg-filter-convolve-color-srgb.png new file mode 100644 index 00000000..16801357 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-color-srgb.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-divisor-bias-target-grammar.png b/fixtures/web-first/chromium/svg-filter-convolve-divisor-bias-target-grammar.png new file mode 100644 index 00000000..19205ad7 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-divisor-bias-target-grammar.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-divisor-sum-order.png b/fixtures/web-first/chromium/svg-filter-convolve-divisor-sum-order.png new file mode 100644 index 00000000..9fc48dcc Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-divisor-sum-order.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-divisor-sum-overflow.png b/fixtures/web-first/chromium/svg-filter-convolve-divisor-sum-overflow.png new file mode 100644 index 00000000..af225634 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-divisor-sum-overflow.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-edge-alpha-kernel-unit-grammar.png b/fixtures/web-first/chromium/svg-filter-convolve-edge-alpha-kernel-unit-grammar.png new file mode 100644 index 00000000..73355181 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-edge-alpha-kernel-unit-grammar.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-empty-bias.png b/fixtures/web-first/chromium/svg-filter-convolve-empty-bias.png new file mode 100644 index 00000000..2c5ade93 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-empty-bias.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-generated-input.png b/fixtures/web-first/chromium/svg-filter-convolve-generated-input.png new file mode 100644 index 00000000..fc6c7e50 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-generated-input.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-input-previous.png b/fixtures/web-first/chromium/svg-filter-convolve-input-previous.png new file mode 100644 index 00000000..2fafa14c Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-input-previous.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-kernel-large-65.png b/fixtures/web-first/chromium/svg-filter-convolve-kernel-large-65.png new file mode 100644 index 00000000..12fe2a8b Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-kernel-large-65.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-kernel-max-256.png b/fixtures/web-first/chromium/svg-filter-convolve-kernel-max-256.png new file mode 100644 index 00000000..59d59beb Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-kernel-max-256.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-kernel-over-max.png b/fixtures/web-first/chromium/svg-filter-convolve-kernel-over-max.png new file mode 100644 index 00000000..b66998a0 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-kernel-over-max.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-kernel-reversal.png b/fixtures/web-first/chromium/svg-filter-convolve-kernel-reversal.png new file mode 100644 index 00000000..9d95cd34 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-kernel-reversal.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-kernel-texture-29.png b/fixtures/web-first/chromium/svg-filter-convolve-kernel-texture-29.png new file mode 100644 index 00000000..4d5f446f Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-kernel-texture-29.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-kernel-texture-64.png b/fixtures/web-first/chromium/svg-filter-convolve-kernel-texture-64.png new file mode 100644 index 00000000..33c2981f Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-kernel-texture-64.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-kernel-uniform-28.png b/fixtures/web-first/chromium/svg-filter-convolve-kernel-uniform-28.png new file mode 100644 index 00000000..fde8a480 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-kernel-uniform-28.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-morphology-after.png b/fixtures/web-first/chromium/svg-filter-convolve-morphology-after.png new file mode 100644 index 00000000..d8ec153b Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-morphology-after.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-order-kernel-grammar.png b/fixtures/web-first/chromium/svg-filter-convolve-order-kernel-grammar.png new file mode 100644 index 00000000..7f9c2c8c Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-order-kernel-grammar.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-primitive-units.png b/fixtures/web-first/chromium/svg-filter-convolve-primitive-units.png new file mode 100644 index 00000000..d8a5a87b Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-primitive-units.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-quarter-turn.png b/fixtures/web-first/chromium/svg-filter-convolve-quarter-turn.png new file mode 100644 index 00000000..bc1ae696 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-quarter-turn.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-region-crop.png b/fixtures/web-first/chromium/svg-filter-convolve-region-crop.png new file mode 100644 index 00000000..bade5fd9 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-region-crop.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-result-reuse.png b/fixtures/web-first/chromium/svg-filter-convolve-result-reuse.png new file mode 100644 index 00000000..2fafa14c Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-result-reuse.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-sharpen.png b/fixtures/web-first/chromium/svg-filter-convolve-sharpen.png new file mode 100644 index 00000000..6c4ec071 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-sharpen.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-source-alpha-preserve.png b/fixtures/web-first/chromium/svg-filter-convolve-source-alpha-preserve.png new file mode 100644 index 00000000..d2cc6692 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-source-alpha-preserve.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-source-alpha.png b/fixtures/web-first/chromium/svg-filter-convolve-source-alpha.png new file mode 100644 index 00000000..e87a9c6d Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-source-alpha.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-source-group.png b/fixtures/web-first/chromium/svg-filter-convolve-source-group.png new file mode 100644 index 00000000..d8a5a87b Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-source-group.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-source-number-alias.png b/fixtures/web-first/chromium/svg-filter-convolve-source-number-alias.png new file mode 100644 index 00000000..00cc0d85 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-source-number-alias.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-source-path.png b/fixtures/web-first/chromium/svg-filter-convolve-source-path.png new file mode 100644 index 00000000..5e80521e Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-source-path.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-source-stroke.png b/fixtures/web-first/chromium/svg-filter-convolve-source-stroke.png new file mode 100644 index 00000000..c09f29af Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-source-stroke.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-target-clip.png b/fixtures/web-first/chromium/svg-filter-convolve-target-clip.png new file mode 100644 index 00000000..2978afba Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-target-clip.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-target-mask.png b/fixtures/web-first/chromium/svg-filter-convolve-target-mask.png new file mode 100644 index 00000000..d5e04436 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-target-mask.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-target-opacity.png b/fixtures/web-first/chromium/svg-filter-convolve-target-opacity.png new file mode 100644 index 00000000..94cb3d26 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-target-opacity.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-target-y.png b/fixtures/web-first/chromium/svg-filter-convolve-target-y.png new file mode 100644 index 00000000..b6e5a3c4 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-target-y.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-use.png b/fixtures/web-first/chromium/svg-filter-convolve-use.png new file mode 100644 index 00000000..0381b497 Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-use.png differ diff --git a/fixtures/web-first/chromium/svg-filter-convolve-viewbox.png b/fixtures/web-first/chromium/svg-filter-convolve-viewbox.png new file mode 100644 index 00000000..c459030d Binary files /dev/null and b/fixtures/web-first/chromium/svg-filter-convolve-viewbox.png differ diff --git a/fixtures/web-first/oracle-bake.json b/fixtures/web-first/oracle-bake.json index fe28ceaf..7fc50f13 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": "15ba5c3156f3ed0bfd0f32b6ad773e1d228c0f678396db08c8de1d972cf5bced", "suite": "primitives.json", - "suite_sha256": "c52554b86bfd62e891dec375bb6bc22fe6f95ebca55294a490a5b184972701b3", + "suite_sha256": "bcd80bb032ccac6bfbbc380eb04958eda717b886001dd5d378d01e2fc579d920", "capture": { "device_scale_factor": 1, "omit_background": true, @@ -964,6 +964,15 @@ "width": 64, "height": 64 }, + { + "id": "svg-filter-blur-edge-mode-drop", + "source": "svg-filter-blur-edge-mode-drop.svg", + "source_sha256": "eab4fddace28da0897e38f3be68526c55a002f3843fe36ac739d879e5accb5ed", + "oracle": "chromium/svg-filter-blur-edge-mode-drop.png", + "oracle_sha256": "0a8e96bfe22b33805f67908fd6daee4a52f1e686ad8c0c60a53a9f2484f21834", + "width": 64, + "height": 64 + }, { "id": "svg-filter-blur-zero-primitive-region", "source": "svg-filter-blur-zero-primitive-region.svg", @@ -1720,6 +1729,366 @@ "width": 64, "height": 64 }, + { + "id": "svg-filter-convolve-axis-fractional", + "source": "svg-filter-convolve-axis-fractional.svg", + "source_sha256": "4f8d541f2f44120b00067a9ef0dda7d1c42f05fe2314799eecfcb09209000176", + "oracle": "chromium/svg-filter-convolve-axis-fractional.png", + "oracle_sha256": "7d7ca81a06b36aedf3e2c4b328bf9a9a5f4a113a59c57a638f869901a4464625", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-bias-large", + "source": "svg-filter-convolve-bias-large.svg", + "source_sha256": "4da7c66c07f579dfab864623d6a90dc474594e7779dfd001424f25d74631f7cb", + "oracle": "chromium/svg-filter-convolve-bias-large.png", + "oracle_sha256": "4f852cfe622067e2872424c8add5d3977db6b7d6ad84a6329f288f6d7da566fa", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-blur-before", + "source": "svg-filter-convolve-blur-before.svg", + "source_sha256": "3b8bd0513e5452519809669066ea4ca92e68b74a0ae41ba8ad291165c9105e81", + "oracle": "chromium/svg-filter-convolve-blur-before.png", + "oracle_sha256": "c2fe4db56c06da02cf6992d0f0cda7f7cb31ee2781d352c8caa8de31f87fe27e", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-color-auto", + "source": "svg-filter-convolve-color-auto.svg", + "source_sha256": "84691f607d152d17d6eab9bcbeb298e8614898159ef62e869163415e6d0f4d53", + "oracle": "chromium/svg-filter-convolve-color-auto.png", + "oracle_sha256": "98920f54e607c03bcc6adb9cd179343baefda3254e9e967a8665680aa526462e", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-color-default", + "source": "svg-filter-convolve-color-default.svg", + "source_sha256": "1667401a38e11f36c73839a24c287155ec52a181c44517f37cd4417a07b3b44c", + "oracle": "chromium/svg-filter-convolve-color-default.png", + "oracle_sha256": "59b650d91901d172920e756ccafbf11e633af3d734ac05ddd7bd1a9a10c2da31", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-color-linear", + "source": "svg-filter-convolve-color-linear.svg", + "source_sha256": "5507eb7f5bf6bd59b7d1d94b82ec38aa6a7e429d0f6908a872dd05ffa8fdbb5a", + "oracle": "chromium/svg-filter-convolve-color-linear.png", + "oracle_sha256": "59b650d91901d172920e756ccafbf11e633af3d734ac05ddd7bd1a9a10c2da31", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-color-srgb", + "source": "svg-filter-convolve-color-srgb.svg", + "source_sha256": "ccbd09ad8247a415b2cff14ae7337c9e51014ad0e246f314846a13fa76b7853b", + "oracle": "chromium/svg-filter-convolve-color-srgb.png", + "oracle_sha256": "98920f54e607c03bcc6adb9cd179343baefda3254e9e967a8665680aa526462e", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-divisor-bias-target-grammar", + "source": "svg-filter-convolve-divisor-bias-target-grammar.svg", + "source_sha256": "47d31abe1cb4e2e89d77357e69266e1121aa6b3aee3b8dfd91c04c923741850b", + "oracle": "chromium/svg-filter-convolve-divisor-bias-target-grammar.png", + "oracle_sha256": "71219de855f4af19025f99c108323ed2e8a5f37a93a2e9a446e9ba5a6f4ed8f5", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-divisor-sum-order", + "source": "svg-filter-convolve-divisor-sum-order.svg", + "source_sha256": "37255c470d4d7674865f5e6a1493937334fa2725aeb4eaef82a8ac7910f5cd8e", + "oracle": "chromium/svg-filter-convolve-divisor-sum-order.png", + "oracle_sha256": "2cbd181a4dcf48ff9e645f27386c7a96058a0070e17624dc7f35ee4675467e91", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-divisor-sum-overflow", + "source": "svg-filter-convolve-divisor-sum-overflow.svg", + "source_sha256": "a3038d3b19c104e8b405a25a29056bcd8b93fd9811e73e2d2725da62f1bbe5f8", + "oracle": "chromium/svg-filter-convolve-divisor-sum-overflow.png", + "oracle_sha256": "ed01368891cdfda17d6002aee41bbc7939dc65dbb6f1bdbd437f787dd1b89d0e", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-edge-alpha-kernel-unit-grammar", + "source": "svg-filter-convolve-edge-alpha-kernel-unit-grammar.svg", + "source_sha256": "c525e41676974bff92d7c4c984b4b2e451408b8bf2a99c36fdf7af223dd3cb42", + "oracle": "chromium/svg-filter-convolve-edge-alpha-kernel-unit-grammar.png", + "oracle_sha256": "4a628e7c5d3ff08387d7c1a628e07f8d7b7cbf07071619cb7df01663bbc44b2d", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-empty-bias", + "source": "svg-filter-convolve-empty-bias.svg", + "source_sha256": "674fff9ca3fd8e7d8ae49b81f7741e46c4b5899ad952e553725b37715323522d", + "oracle": "chromium/svg-filter-convolve-empty-bias.png", + "oracle_sha256": "b6a3069ae2bfbd2bf600dd15b1d2d71739eded670aa74cb7e23beee7e7ac7fe2", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-generated-input", + "source": "svg-filter-convolve-generated-input.svg", + "source_sha256": "2324bedabf7a6d57b3d8e1e31b45f21909307b6941235b93a53ff3244120d652", + "oracle": "chromium/svg-filter-convolve-generated-input.png", + "oracle_sha256": "4c864fd80857e6525bf93caf04ab48f2781258c3f7a85ccd3ff4c064f18fb04e", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-input-previous", + "source": "svg-filter-convolve-input-previous.svg", + "source_sha256": "229c05b866763112bdb2fb4e109a615a538e15fb4ebcb2ecb91f08315b75e126", + "oracle": "chromium/svg-filter-convolve-input-previous.png", + "oracle_sha256": "0ca64272bbc0b8e56f6cc7cc2eb5f4dfaa00ecf17ea8150c021d22f65093186d", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-kernel-large-65", + "source": "svg-filter-convolve-kernel-large-65.svg", + "source_sha256": "029ceb372e976d4088b9f56eda8ea942968676edb32d34ec9fa0d932650fc6d5", + "oracle": "chromium/svg-filter-convolve-kernel-large-65.png", + "oracle_sha256": "7d59042127e2fa833588daeb9d5d2094b512f64a2f83cf77a86976133652ab4f", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-kernel-max-256", + "source": "svg-filter-convolve-kernel-max-256.svg", + "source_sha256": "7825013822dd31a646c4b94d63b3594e96f50dfc0da6084d7a546a1c7c76e8bb", + "oracle": "chromium/svg-filter-convolve-kernel-max-256.png", + "oracle_sha256": "3fa8f8928bf3a5d83c6a531738828ad73e125d9b35d6736c3643ed2b8487013b", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-kernel-over-max", + "source": "svg-filter-convolve-kernel-over-max.svg", + "source_sha256": "b038d5e9452c1fe25b4fb5d9f76d6301cc04f10349fbcb2689a2ad32e0d7740f", + "oracle": "chromium/svg-filter-convolve-kernel-over-max.png", + "oracle_sha256": "58779d0910be6ed5fe936ce99581693514487a4e6deb61e780e23e7cae114241", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-kernel-reversal", + "source": "svg-filter-convolve-kernel-reversal.svg", + "source_sha256": "524c2a26bfa491053ee75de4337f4151e4f3f7bb6efad163bace0dc6d9704db5", + "oracle": "chromium/svg-filter-convolve-kernel-reversal.png", + "oracle_sha256": "e28e8cfbae5583021b09c0b7233cf825e0eb0d77f00ddd39391fe4034e69c327", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-kernel-texture-29", + "source": "svg-filter-convolve-kernel-texture-29.svg", + "source_sha256": "b337a6e66dd917f827c42eaff40c87d28a10a094268b13569ac6cd143c69c23e", + "oracle": "chromium/svg-filter-convolve-kernel-texture-29.png", + "oracle_sha256": "d19626b1755147c893d88e585bdf681c3a06226a245d4d44c9f6e6adc9f29b01", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-kernel-texture-64", + "source": "svg-filter-convolve-kernel-texture-64.svg", + "source_sha256": "62dcc648e610cee929b25a4272e289da05b9e4af0a0e85c4c4d0df3d3cb6eb95", + "oracle": "chromium/svg-filter-convolve-kernel-texture-64.png", + "oracle_sha256": "f978517be9e821c258cfb6e877ac8e054750c73944f27a471831ee24fc6cec39", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-kernel-uniform-28", + "source": "svg-filter-convolve-kernel-uniform-28.svg", + "source_sha256": "d2535ce1ec7a639a877a1854118912cd95cfbed3be011a5570b07d1567c1644f", + "oracle": "chromium/svg-filter-convolve-kernel-uniform-28.png", + "oracle_sha256": "5ae84924a4200942992c4429ab0c4e541d03661b06b4df7058aea8f0f1c9cfda", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-morphology-after", + "source": "svg-filter-convolve-morphology-after.svg", + "source_sha256": "850dcf849a205e459ba9b82546a978ea15e9d96389bfc0c633fae53ce46e58e6", + "oracle": "chromium/svg-filter-convolve-morphology-after.png", + "oracle_sha256": "0d6e0eefea9c68e81231eae63f529a54cfcf5589376db846f63587a603dc4fa1", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-order-kernel-grammar", + "source": "svg-filter-convolve-order-kernel-grammar.svg", + "source_sha256": "62ed6552781993cb3fa35718d93fb2aa6bd8b375baa2be957af77cfd399df551", + "oracle": "chromium/svg-filter-convolve-order-kernel-grammar.png", + "oracle_sha256": "568f1933a6599abf56f74b77b59490c4507c3387a80fb8f3955574c8975a6cb8", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-primitive-units", + "source": "svg-filter-convolve-primitive-units.svg", + "source_sha256": "c60580bd4ff8a34d68c308714bef37532fbec00ccc3710fab5baa4cc13f48577", + "oracle": "chromium/svg-filter-convolve-primitive-units.png", + "oracle_sha256": "c40079d5c7d3ea6cd197e7659b043ca9372dcdc2cb04b59b4ea58a943a624f77", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-quarter-turn", + "source": "svg-filter-convolve-quarter-turn.svg", + "source_sha256": "ba8e4e69e93380a681027c489ba69bc2b827b6704a2e8db8a5b5269bd81423db", + "oracle": "chromium/svg-filter-convolve-quarter-turn.png", + "oracle_sha256": "0f58ddeb5f1ccf7ba93c3ecf28cbe93d664f64e959fb74817f49e25823d139f8", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-region-crop", + "source": "svg-filter-convolve-region-crop.svg", + "source_sha256": "f52382faa1a310dab2e1d1192e86166cffb1258eb7241fc8d1e20d7e6c905f46", + "oracle": "chromium/svg-filter-convolve-region-crop.png", + "oracle_sha256": "ce2c7552b8138ede963880f86b40bd623f2d7a88b5643222de943cf052088064", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-result-reuse", + "source": "svg-filter-convolve-result-reuse.svg", + "source_sha256": "552f2c67529138598c08728d206c70af1f8e92e4ae277995c526bdb76726bcdf", + "oracle": "chromium/svg-filter-convolve-result-reuse.png", + "oracle_sha256": "0ca64272bbc0b8e56f6cc7cc2eb5f4dfaa00ecf17ea8150c021d22f65093186d", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-sharpen", + "source": "svg-filter-convolve-sharpen.svg", + "source_sha256": "e1a9424e5b965194f5e1d67f73971b84056780c92d0ad4fa264edb0e2c2b9eac", + "oracle": "chromium/svg-filter-convolve-sharpen.png", + "oracle_sha256": "20878bcc70724539923ed7cebc8006b4bdd90ee56af316b3456c2687ffc1b06f", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-source-alpha", + "source": "svg-filter-convolve-source-alpha.svg", + "source_sha256": "445082a9fd0413e4c83e044e006132cf1e3dcd78535e6d5f206f19c70fc67293", + "oracle": "chromium/svg-filter-convolve-source-alpha.png", + "oracle_sha256": "317b9151e945fd0ea8fa9984900e8401ff66b5f2702a534d2d500b593202f7ea", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-source-alpha-preserve", + "source": "svg-filter-convolve-source-alpha-preserve.svg", + "source_sha256": "bc0228ff2a69572a99aa4e45e1f51ffa6f5a66385f26b8d0f4ede02c3bb2a7d3", + "oracle": "chromium/svg-filter-convolve-source-alpha-preserve.png", + "oracle_sha256": "98424ef7ae89f8d9630510462fb5c12fe29dc0d3b4839e53acccee5d6e685d94", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-source-group", + "source": "svg-filter-convolve-source-group.svg", + "source_sha256": "d7e6f82a0014496c7c568080db2a2885cfd89cf5af6064c1abd33f30cdab28b1", + "oracle": "chromium/svg-filter-convolve-source-group.png", + "oracle_sha256": "c40079d5c7d3ea6cd197e7659b043ca9372dcdc2cb04b59b4ea58a943a624f77", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-source-number-alias", + "source": "svg-filter-convolve-source-number-alias.svg", + "source_sha256": "91d2664e69f0f7e64c9076fb3f2959f25194a893cf6a60c7cd2531f5c55d74f3", + "oracle": "chromium/svg-filter-convolve-source-number-alias.png", + "oracle_sha256": "c6549096b5a7a8a7cbaeb1971c81a6bb76beda5cef8df73ebdb3cff7076ae1bb", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-source-path", + "source": "svg-filter-convolve-source-path.svg", + "source_sha256": "960832776653053925731879eefab1cb2f377f1ecfc30698b4122b6e9809b4ce", + "oracle": "chromium/svg-filter-convolve-source-path.png", + "oracle_sha256": "bbcd7cfe16c846f5824a13c46c0325a1f9258d34dc89e7ee5c03100e5f9d320a", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-source-stroke", + "source": "svg-filter-convolve-source-stroke.svg", + "source_sha256": "c0b54c39032b51be63d4e8de6ee19653e3f968b14749e80db5c1f30988c7e636", + "oracle": "chromium/svg-filter-convolve-source-stroke.png", + "oracle_sha256": "8d1690f4daa2a0190219ef3b4fcc408456668d78e9b0cdd0fc86edf1f5989e04", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-target-clip", + "source": "svg-filter-convolve-target-clip.svg", + "source_sha256": "bd196967b19f6c6c9e0c43e1f9d4a3d10affcb6f9cd988cca4ca8f74b5de446d", + "oracle": "chromium/svg-filter-convolve-target-clip.png", + "oracle_sha256": "9828603e831e6430b1a537b9e4bb25857f09c659c71dfe61536ff1ed173fad1e", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-target-mask", + "source": "svg-filter-convolve-target-mask.svg", + "source_sha256": "addf9b198a020cfc6816171ff0d81e163065ef21743ed928a003f4cb20afa9b5", + "oracle": "chromium/svg-filter-convolve-target-mask.png", + "oracle_sha256": "04d50021b6b09bb02808657c1df7a222347d4f62e32e28d11955167407e2b5ad", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-target-opacity", + "source": "svg-filter-convolve-target-opacity.svg", + "source_sha256": "a8787e686b91d97c7fd295050614d56736e7cb0012c7c5b8434e0d5aa44e4810", + "oracle": "chromium/svg-filter-convolve-target-opacity.png", + "oracle_sha256": "b17fc409ce5097823e52f2ee5c883da4d4e34c739d1b47d603ec362dbbdc6438", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-target-y", + "source": "svg-filter-convolve-target-y.svg", + "source_sha256": "724dc8a8ba0c3d81b8bd4da734e1095167728c4b006494f7aab10fa7e2902b63", + "oracle": "chromium/svg-filter-convolve-target-y.png", + "oracle_sha256": "4ff684ec73f03d54e4fe9a84caf89b10ce08f13dabfc420935fd50a1524509f0", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-use", + "source": "svg-filter-convolve-use.svg", + "source_sha256": "dc0e781edf010486cda49ae37ad39e0707c035ffb4307a011dbc524e4c06277f", + "oracle": "chromium/svg-filter-convolve-use.png", + "oracle_sha256": "f67a10a0659e8586cc175ce39e2908a83261bcddef2ca4c1c43ad449f5353d12", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-viewbox", + "source": "svg-filter-convolve-viewbox.svg", + "source_sha256": "1836d7aecfdd0d43cf52e6fa7cf2ffba4c4c2a948c3d03d6064745462206c9c9", + "oracle": "chromium/svg-filter-convolve-viewbox.png", + "oracle_sha256": "1d6c2dc7e112ecf274ac74f98549e133e3859e85b89a1e722f7e4ddc8e377968", + "width": 64, + "height": 64 + }, { "id": "svg-filter-displacement-color-linear", "source": "svg-filter-displacement-color-linear.svg", diff --git a/fixtures/web-first/primitives.json b/fixtures/web-first/primitives.json index 7fbbecb6..8a6b2c6a 100644 --- a/fixtures/web-first/primitives.json +++ b/fixtures/web-first/primitives.json @@ -919,6 +919,14 @@ "width": 64, "height": 64 }, + { + "id": "svg-filter-blur-edge-mode-drop", + "source": "svg-filter-blur-edge-mode-drop.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-blur-edge-mode-drop.png", + "width": 64, + "height": 64 + }, { "id": "svg-filter-blur-zero-primitive-region", "source": "svg-filter-blur-zero-primitive-region.svg", @@ -1591,6 +1599,326 @@ "width": 64, "height": 64 }, + { + "id": "svg-filter-convolve-axis-fractional", + "source": "svg-filter-convolve-axis-fractional.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-axis-fractional.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-bias-large", + "source": "svg-filter-convolve-bias-large.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-bias-large.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-blur-before", + "source": "svg-filter-convolve-blur-before.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-blur-before.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-color-auto", + "source": "svg-filter-convolve-color-auto.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-color-auto.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-color-default", + "source": "svg-filter-convolve-color-default.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-color-default.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-color-linear", + "source": "svg-filter-convolve-color-linear.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-color-linear.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-color-srgb", + "source": "svg-filter-convolve-color-srgb.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-color-srgb.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-divisor-bias-target-grammar", + "source": "svg-filter-convolve-divisor-bias-target-grammar.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-divisor-bias-target-grammar.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-divisor-sum-order", + "source": "svg-filter-convolve-divisor-sum-order.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-divisor-sum-order.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-divisor-sum-overflow", + "source": "svg-filter-convolve-divisor-sum-overflow.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-divisor-sum-overflow.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-edge-alpha-kernel-unit-grammar", + "source": "svg-filter-convolve-edge-alpha-kernel-unit-grammar.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-edge-alpha-kernel-unit-grammar.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-empty-bias", + "source": "svg-filter-convolve-empty-bias.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-empty-bias.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-generated-input", + "source": "svg-filter-convolve-generated-input.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-generated-input.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-input-previous", + "source": "svg-filter-convolve-input-previous.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-input-previous.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-kernel-large-65", + "source": "svg-filter-convolve-kernel-large-65.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-kernel-large-65.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-kernel-max-256", + "source": "svg-filter-convolve-kernel-max-256.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-kernel-max-256.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-kernel-over-max", + "source": "svg-filter-convolve-kernel-over-max.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-kernel-over-max.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-kernel-reversal", + "source": "svg-filter-convolve-kernel-reversal.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-kernel-reversal.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-kernel-texture-29", + "source": "svg-filter-convolve-kernel-texture-29.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-kernel-texture-29.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-kernel-texture-64", + "source": "svg-filter-convolve-kernel-texture-64.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-kernel-texture-64.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-kernel-uniform-28", + "source": "svg-filter-convolve-kernel-uniform-28.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-kernel-uniform-28.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-morphology-after", + "source": "svg-filter-convolve-morphology-after.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-morphology-after.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-order-kernel-grammar", + "source": "svg-filter-convolve-order-kernel-grammar.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-order-kernel-grammar.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-primitive-units", + "source": "svg-filter-convolve-primitive-units.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-primitive-units.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-quarter-turn", + "source": "svg-filter-convolve-quarter-turn.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-quarter-turn.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-region-crop", + "source": "svg-filter-convolve-region-crop.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-region-crop.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-result-reuse", + "source": "svg-filter-convolve-result-reuse.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-result-reuse.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-sharpen", + "source": "svg-filter-convolve-sharpen.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-sharpen.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-source-alpha", + "source": "svg-filter-convolve-source-alpha.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-source-alpha.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-source-alpha-preserve", + "source": "svg-filter-convolve-source-alpha-preserve.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-source-alpha-preserve.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-source-group", + "source": "svg-filter-convolve-source-group.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-source-group.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-source-number-alias", + "source": "svg-filter-convolve-source-number-alias.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-source-number-alias.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-source-path", + "source": "svg-filter-convolve-source-path.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-source-path.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-source-stroke", + "source": "svg-filter-convolve-source-stroke.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-source-stroke.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-target-clip", + "source": "svg-filter-convolve-target-clip.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-target-clip.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-target-mask", + "source": "svg-filter-convolve-target-mask.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-target-mask.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-target-opacity", + "source": "svg-filter-convolve-target-opacity.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-target-opacity.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-target-y", + "source": "svg-filter-convolve-target-y.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-target-y.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-use", + "source": "svg-filter-convolve-use.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-use.png", + "width": 64, + "height": 64 + }, + { + "id": "svg-filter-convolve-viewbox", + "source": "svg-filter-convolve-viewbox.svg", + "entry": "standalone-svg", + "oracle": "chromium/svg-filter-convolve-viewbox.png", + "width": 64, + "height": 64 + }, { "id": "svg-filter-displacement-color-linear", "source": "svg-filter-displacement-color-linear.svg", diff --git a/fixtures/web-first/svg-filter-blur-edge-mode-drop.svg b/fixtures/web-first/svg-filter-blur-edge-mode-drop.svg new file mode 100644 index 00000000..21264e9a --- /dev/null +++ b/fixtures/web-first/svg-filter-blur-edge-mode-drop.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-axis-fractional.svg b/fixtures/web-first/svg-filter-convolve-axis-fractional.svg new file mode 100644 index 00000000..8972a764 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-axis-fractional.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-bias-large.svg b/fixtures/web-first/svg-filter-convolve-bias-large.svg new file mode 100644 index 00000000..395193a2 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-bias-large.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-blur-before.svg b/fixtures/web-first/svg-filter-convolve-blur-before.svg new file mode 100644 index 00000000..45673595 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-blur-before.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-color-auto.svg b/fixtures/web-first/svg-filter-convolve-color-auto.svg new file mode 100644 index 00000000..d10929fc --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-color-auto.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-color-default.svg b/fixtures/web-first/svg-filter-convolve-color-default.svg new file mode 100644 index 00000000..07cbabe0 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-color-default.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-color-linear.svg b/fixtures/web-first/svg-filter-convolve-color-linear.svg new file mode 100644 index 00000000..4a371f36 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-color-linear.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-color-srgb.svg b/fixtures/web-first/svg-filter-convolve-color-srgb.svg new file mode 100644 index 00000000..59f9399c --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-color-srgb.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-divisor-bias-target-grammar.svg b/fixtures/web-first/svg-filter-convolve-divisor-bias-target-grammar.svg new file mode 100644 index 00000000..26365aac --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-divisor-bias-target-grammar.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-divisor-sum-order.svg b/fixtures/web-first/svg-filter-convolve-divisor-sum-order.svg new file mode 100644 index 00000000..6aa466c6 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-divisor-sum-order.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-divisor-sum-overflow.svg b/fixtures/web-first/svg-filter-convolve-divisor-sum-overflow.svg new file mode 100644 index 00000000..c5596368 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-divisor-sum-overflow.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-edge-alpha-kernel-unit-grammar.svg b/fixtures/web-first/svg-filter-convolve-edge-alpha-kernel-unit-grammar.svg new file mode 100644 index 00000000..3d8a94e6 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-edge-alpha-kernel-unit-grammar.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-empty-bias.svg b/fixtures/web-first/svg-filter-convolve-empty-bias.svg new file mode 100644 index 00000000..4d3eccf9 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-empty-bias.svg @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-generated-input.svg b/fixtures/web-first/svg-filter-convolve-generated-input.svg new file mode 100644 index 00000000..6aab5839 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-generated-input.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-input-previous.svg b/fixtures/web-first/svg-filter-convolve-input-previous.svg new file mode 100644 index 00000000..c67541e5 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-input-previous.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-kernel-large-65.svg b/fixtures/web-first/svg-filter-convolve-kernel-large-65.svg new file mode 100644 index 00000000..0b6447d6 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-kernel-large-65.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-kernel-max-256.svg b/fixtures/web-first/svg-filter-convolve-kernel-max-256.svg new file mode 100644 index 00000000..ec24532d --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-kernel-max-256.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-kernel-over-max.svg b/fixtures/web-first/svg-filter-convolve-kernel-over-max.svg new file mode 100644 index 00000000..4d9c93b1 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-kernel-over-max.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-kernel-reversal.svg b/fixtures/web-first/svg-filter-convolve-kernel-reversal.svg new file mode 100644 index 00000000..90f44b30 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-kernel-reversal.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-kernel-texture-29.svg b/fixtures/web-first/svg-filter-convolve-kernel-texture-29.svg new file mode 100644 index 00000000..0f740fe0 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-kernel-texture-29.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-kernel-texture-64.svg b/fixtures/web-first/svg-filter-convolve-kernel-texture-64.svg new file mode 100644 index 00000000..3b29f5bc --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-kernel-texture-64.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-kernel-uniform-28.svg b/fixtures/web-first/svg-filter-convolve-kernel-uniform-28.svg new file mode 100644 index 00000000..c89d3bd1 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-kernel-uniform-28.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-morphology-after.svg b/fixtures/web-first/svg-filter-convolve-morphology-after.svg new file mode 100644 index 00000000..f2a3c3db --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-morphology-after.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-order-kernel-grammar.svg b/fixtures/web-first/svg-filter-convolve-order-kernel-grammar.svg new file mode 100644 index 00000000..a0ad24d2 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-order-kernel-grammar.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-primitive-units.svg b/fixtures/web-first/svg-filter-convolve-primitive-units.svg new file mode 100644 index 00000000..07bb6d34 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-primitive-units.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-quarter-turn.svg b/fixtures/web-first/svg-filter-convolve-quarter-turn.svg new file mode 100644 index 00000000..fd46e479 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-quarter-turn.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-region-crop.svg b/fixtures/web-first/svg-filter-convolve-region-crop.svg new file mode 100644 index 00000000..4d1baba3 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-region-crop.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-result-reuse.svg b/fixtures/web-first/svg-filter-convolve-result-reuse.svg new file mode 100644 index 00000000..83fb33ca --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-result-reuse.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-sharpen.svg b/fixtures/web-first/svg-filter-convolve-sharpen.svg new file mode 100644 index 00000000..2140d49f --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-sharpen.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-source-alpha-preserve.svg b/fixtures/web-first/svg-filter-convolve-source-alpha-preserve.svg new file mode 100644 index 00000000..45eb5877 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-source-alpha-preserve.svg @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-source-alpha.svg b/fixtures/web-first/svg-filter-convolve-source-alpha.svg new file mode 100644 index 00000000..e81b93a3 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-source-alpha.svg @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-source-group.svg b/fixtures/web-first/svg-filter-convolve-source-group.svg new file mode 100644 index 00000000..cf5d0568 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-source-group.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-source-number-alias.svg b/fixtures/web-first/svg-filter-convolve-source-number-alias.svg new file mode 100644 index 00000000..0fa18f13 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-source-number-alias.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-filter-convolve-source-path.svg b/fixtures/web-first/svg-filter-convolve-source-path.svg new file mode 100644 index 00000000..656c0a98 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-source-path.svg @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-source-stroke.svg b/fixtures/web-first/svg-filter-convolve-source-stroke.svg new file mode 100644 index 00000000..aab4389d --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-source-stroke.svg @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-target-clip.svg b/fixtures/web-first/svg-filter-convolve-target-clip.svg new file mode 100644 index 00000000..037ddc74 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-target-clip.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-target-mask.svg b/fixtures/web-first/svg-filter-convolve-target-mask.svg new file mode 100644 index 00000000..8f0a2fef --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-target-mask.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-target-opacity.svg b/fixtures/web-first/svg-filter-convolve-target-opacity.svg new file mode 100644 index 00000000..c0e9abe5 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-target-opacity.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-target-y.svg b/fixtures/web-first/svg-filter-convolve-target-y.svg new file mode 100644 index 00000000..af1022dd --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-target-y.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + diff --git a/fixtures/web-first/svg-filter-convolve-use.svg b/fixtures/web-first/svg-filter-convolve-use.svg new file mode 100644 index 00000000..2d056700 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-use.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/svg-filter-convolve-viewbox.svg b/fixtures/web-first/svg-filter-convolve-viewbox.svg new file mode 100644 index 00000000..514e9ef2 --- /dev/null +++ b/fixtures/web-first/svg-filter-convolve-viewbox.svg @@ -0,0 +1 @@ + diff --git a/fixtures/web-first/unsupported/README.md b/fixtures/web-first/unsupported/README.md index f620c9e5..064180a4 100644 --- a/fixtures/web-first/unsupported/README.md +++ b/fixtures/web-first/unsupported/README.md @@ -72,7 +72,10 @@ The scannable, generated view of this register (beside the baked cells) is | `svg-filter-css-functions.svg` · `svg-filter-list.svg` · `svg-filter-list-quoted.svg` | The direct presentation reader carries one same-document URL only. Filter functions and a list of multiple operations are valid members of the wider property grammar and refuse by the stable filter name instead of being mistaken for that single URL. Quoted and unquoted URL tokens take the same branch. | | `svg-filter-external.svg` · `svg-filter-root.svg` | External resource resolution and the root host CSS-layer route stay outside this self-contained SVG-local frame. An external reference skips its target; an active root filter refuses in both admissions because there is no smaller honest hole. | | `svg-filter-href.svg` | Refuse `` inheritance before graph construction. Dropping the template edge could change primitive order, inherited attributes, inputs, and every output pixel. | -| `svg-filter-primitive.svg` | Any unrepresented `fe*` child invalidates graph construction transactionally. The witness has advanced to `feConvolveMatrix` after a supported flood prefix; it skips the whole affected target, so that prefix can never escape as a plausible filtered result. | +| `svg-filter-primitive.svg` | Any unrepresented `fe*` child invalidates graph construction transactionally. The witness has advanced to `feDiffuseLighting` after a supported flood prefix; it skips the whole affected target, so that prefix can never escape as a plausible filtered result. | +| `svg-filter-convolve-transform-precision.svg` | Refuse `feConvolveMatrix` under a target mapping outside axis maps and exact quarter turns. Fractional translation/scale, reflection, and exact quarter turns are exact. A sampled 17-degree rotation differs by 462 pixels at maximum channel delta 15 and a shear by 632 at delta 13; arbitrarily small sampled rotation/shear values reproduce the class (measured, not celled). | +| `svg-filter-convolve-paint-server-precision.svg` | Refuse source-dependent `feConvolveMatrix` when the isolated source uses a paint-server fill or stroke. Sampled linear and radial fills differ by 1,425 and 1,658 pixels at maximum channel delta 7; a gradient stroke differs by 609 at delta 7. Generated-only filter inputs remain exact (measured, not celled). | +| `svg-filter-convolve-arithmetic-range.svg` | Refuse a nonzero `divisor` whose reciprocal overflows finite `f32`. Chromium executes the valid number and the sampled output equals a nearby finite-gain control, while the resolved contract admits only finite gain. This is a narrow arithmetic-range patrol, not a second source parser (measured, not celled). | | `svg-filter-turbulence-transform-precision.svg` | Refuse `feTurbulence` under a general rotation or shear. Axis maps, fractional translation, reflection, and exact quarter turns are exact; a sampled 17-degree rotation differs by 3,173 pixels at maximum channel delta 7 and a shear by 3,110 at delta 6 (measured, not celled). | | `svg-filter-displacement-transform-precision.svg` | Refuse `feDisplacementMap` under a general rotation or shear. Axis maps, fractional translation, reflection, and exact quarter turns are exact; a sampled 17-degree rotation differs by 280 pixels at maximum channel delta 13 and a shear by 360 at delta 18 (measured, not celled). | | `svg-filter-displacement-clip-precision.svg` | Refuse `feDisplacementMap` across a geometric `clip-path`. The sampled path clip differs by 35 pixels at maximum channel delta 2 (measured, not celled); opacity without the clip is exact and celled. | diff --git a/fixtures/web-first/unsupported/svg-filter-convolve-arithmetic-range.svg b/fixtures/web-first/unsupported/svg-filter-convolve-arithmetic-range.svg new file mode 100644 index 00000000..03ee24d8 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-filter-convolve-arithmetic-range.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/fixtures/web-first/unsupported/svg-filter-convolve-paint-server-precision.svg b/fixtures/web-first/unsupported/svg-filter-convolve-paint-server-precision.svg new file mode 100644 index 00000000..ad8b81e3 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-filter-convolve-paint-server-precision.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/fixtures/web-first/unsupported/svg-filter-convolve-transform-precision.svg b/fixtures/web-first/unsupported/svg-filter-convolve-transform-precision.svg new file mode 100644 index 00000000..7c612953 --- /dev/null +++ b/fixtures/web-first/unsupported/svg-filter-convolve-transform-precision.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/fixtures/web-first/unsupported/svg-filter-primitive.svg b/fixtures/web-first/unsupported/svg-filter-primitive.svg index 3ede989a..8852b56e 100644 --- a/fixtures/web-first/unsupported/svg-filter-primitive.svg +++ b/fixtures/web-first/unsupported/svg-filter-primitive.svg @@ -2,7 +2,9 @@ - + + +