@@ -14,8 +14,8 @@ use core_types::transform::Footprint;
1414use core_types:: uuid:: { NodeId , generate_uuid} ;
1515use core_types:: {
1616 ATTR_BACKGROUND , ATTR_BLEND_MODE , ATTR_CLIP , ATTR_CLIPPING_MASK , ATTR_DIMENSIONS , ATTR_EDITOR_CLICK_TARGET , ATTR_EDITOR_LAYER_PATH , ATTR_EDITOR_MERGED_LAYERS , ATTR_EDITOR_TEXT_FRAME , ATTR_FONT ,
17- ATTR_FONT_SIZE , ATTR_GRADIENT_TYPE , ATTR_LETTER_SPACING , ATTR_LETTER_TILT , ATTR_LINE_HEIGHT , ATTR_LOCATION , ATTR_MAX_HEIGHT , ATTR_MAX_WIDTH , ATTR_OPACITY , ATTR_OPACITY_FILL , ATTR_SPREAD_METHOD ,
18- ATTR_TEXT_ALIGN , ATTR_TRANSFORM ,
17+ ATTR_FONT_SIZE , ATTR_GRADIENT_LEGACY , ATTR_GRADIENT_TYPE , ATTR_GRADIENT_UNITS , ATTR_LETTER_SPACING , ATTR_LETTER_TILT , ATTR_LINE_HEIGHT , ATTR_LOCATION , ATTR_MAX_HEIGHT , ATTR_MAX_WIDTH ,
18+ ATTR_OPACITY , ATTR_OPACITY_FILL , ATTR_SPREAD_METHOD , ATTR_TEXT_ALIGN , ATTR_TRANSFORM ,
1919} ;
2020use dyn_any:: DynAny ;
2121use glam:: { DAffine2 , DMat2 , DVec2 } ;
@@ -39,7 +39,7 @@ use std::fmt::Write;
3939use std:: hash:: Hash ;
4040use std:: ops:: Deref ;
4141use std:: sync:: { Arc , LazyLock } ;
42- use vector_types:: gradient:: GradientSpreadMethod ;
42+ use vector_types:: gradient:: { GradientSpreadMethod , GradientUnits } ;
4343use vello:: * ;
4444
4545#[ derive( Clone , Copy , Debug , PartialEq ) ]
@@ -2064,12 +2064,14 @@ impl Render for List<GradientStops> {
20642064 for index in 0 ..self . len ( ) {
20652065 let Some ( gradient) = self . element ( index) else { continue } ;
20662066 let transform: DAffine2 = self . attribute_cloned_or_default ( ATTR_TRANSFORM , index) ;
2067+ let mut gradient_units: GradientUnits = self . attribute_cloned_or_default ( ATTR_GRADIENT_UNITS , index) ;
20672068 let blend_mode: BlendMode = self . attribute_cloned_or_default ( ATTR_BLEND_MODE , index) ;
20682069 let opacity_attr: f64 = self . attribute_cloned_or ( ATTR_OPACITY , index, 1. ) ;
20692070 let opacity_fill_attr: f64 = self . attribute_cloned_or ( ATTR_OPACITY_FILL , index, 1. ) ;
20702071 let spread_method: GradientSpreadMethod = self . attribute_cloned_or_default ( ATTR_SPREAD_METHOD , index) ;
20712072 let gradient_type: GradientType = self . attribute_cloned_or_default ( ATTR_GRADIENT_TYPE , index) ;
20722073 let tag = if thumbnail_rect. is_some ( ) { "rect" } else { "polyline" } ;
2074+ const MAX : f64 = 1e7 ;
20732075 render. leaf_tag ( tag, |attributes| {
20742076 if let Some ( ( min, size) ) = thumbnail_rect {
20752077 attributes. push ( "x" , min. x . to_string ( ) ) ;
@@ -2080,7 +2082,6 @@ impl Render for List<GradientStops> {
20802082 // Stand-in for an infinite background. Chrome's SVG renderer keeps internal coordinates in f32 and loses
20812083 // precision past ~2^24 (~16.7 million), causing tile-boundary artifacts that pop in and out during panning.
20822084 // 1e7 stays under that limit while still being far larger than any practical document extent.
2083- const MAX : f64 = 1e7 ;
20842085 attributes. push ( "points" , format ! ( "{MAX},{MAX} -{MAX},{MAX} -{MAX},-{MAX} {MAX},-{MAX}" ) ) ;
20852086 }
20862087
@@ -2097,7 +2098,16 @@ impl Render for List<GradientStops> {
20972098 }
20982099
20992100 // render_thumbnail already added the footprint transform
2100- let gradient_transform = if render_params. thumbnail { transform } else { render_params. footprint . transform * transform } ;
2101+ let mut gradient_transform = if render_params. thumbnail { transform } else { render_params. footprint . transform * transform } ;
2102+ if gradient_units == GradientUnits :: ObjectBoundingBox {
2103+ let ( min, size) = thumbnail_rect. unwrap_or ( ( DVec2 :: splat ( -MAX ) , DVec2 :: splat ( MAX * 2. ) ) ) ;
2104+ let bounds = DAffine2 :: from_scale_angle_translation ( size, 0. , min) ;
2105+ if transform_is_invertible ( bounds) {
2106+ gradient_transform = bounds. inverse ( ) * gradient_transform;
2107+ } else {
2108+ gradient_units = GradientUnits :: UserSpaceOnUse ;
2109+ }
2110+ }
21012111 let gradient_transform_matrix = format_transform_matrix ( gradient_transform) ;
21022112 let gradient_transform_attribute = if gradient_transform_matrix. is_empty ( ) {
21032113 String :: new ( )
@@ -2117,13 +2127,15 @@ impl Render for List<GradientStops> {
21172127 GradientType :: Linear => {
21182128 let _ = write ! (
21192129 & mut attributes. 0 . svg_defs,
2120- r#"<linearGradient id="{gradient_id}" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="1" y2="0"{spread_method_attribute}{gradient_transform_attribute}>{stop_string}</linearGradient>"#
2130+ r#"<linearGradient id="{gradient_id}" gradientUnits="{}" x1="0" y1="0" x2="1" y2="0"{spread_method_attribute}{gradient_transform_attribute}>{stop_string}</linearGradient>"# ,
2131+ gradient_units. svg_name( )
21212132 ) ;
21222133 }
21232134 GradientType :: Radial => {
21242135 let _ = write ! (
21252136 & mut attributes. 0 . svg_defs,
2126- r#"<radialGradient id="{gradient_id}" gradientUnits="userSpaceOnUse" cx="0" cy="0" r="1"{spread_method_attribute}{gradient_transform_attribute}>{stop_string}</radialGradient>"#
2137+ r#"<radialGradient id="{gradient_id}" gradientUnits="{}" cx="0" cy="0" r="1"{spread_method_attribute}{gradient_transform_attribute}>{stop_string}</radialGradient>"# ,
2138+ gradient_units. svg_name( )
21272139 ) ;
21282140 }
21292141 }
0 commit comments