@@ -147,6 +147,18 @@ fn main(
147147 {
148148 let bbox = path_bbox [m . path_ix ];
149149 let draw_flags = bbox . draw_flags ;
150+ // Every gradient payload starts with the drawing-to-gradient transform, the inverse
151+ // of the brush's gradient transform, so the geometry that follows is in the
152+ // gradient's own space.
153+ var user_to_gradient = transform_identity ();
154+ if tag_word == DRAWTAG_FILL_LIN_GRADIENT || tag_word == DRAWTAG_FILL_RAD_GRADIENT ||
155+ tag_word == DRAWTAG_FILL_ELLIPTIC_GRADIENT || tag_word == DRAWTAG_FILL_SWEEP_GRADIENT
156+ {
157+ user_to_gradient = Transform (
158+ bitcast <vec4 <f32 >>(vec4 (scene [dd + 1u ], scene [dd + 2u ], scene [dd + 3u ], scene [dd + 4u ])),
159+ bitcast <vec2 <f32 >>(vec2 (scene [dd + 5u ], scene [dd + 6u ])),
160+ vec3 (0 .0 , 0 .0 , 1 .0 ));
161+ }
150162 switch tag_word {
151163 case DRAWTAG_FILL_COLOR : {
152164 info [di ] = draw_flags ;
@@ -159,8 +171,8 @@ fn main(
159171 }
160172 case DRAWTAG_FILL_LIN_GRADIENT : {
161173 info [di ] = draw_flags ;
162- let p0 = bitcast <vec2 <f32 >>(vec2 (scene [dd + 1u ], scene [dd + 2u ]));
163- let p1 = bitcast <vec2 <f32 >>(vec2 (scene [dd + 3u ], scene [dd + 4u ]));
174+ let p0 = bitcast <vec2 <f32 >>(vec2 (scene [dd + 7u ], scene [dd + 8u ]));
175+ let p1 = bitcast <vec2 <f32 >>(vec2 (scene [dd + 9u ], scene [dd + 10u ]));
164176 // Encode the gradient as a line equation so fine can
165177 // evaluate the parameter as t = dot(p, line_xy) + line_c.
166178 let dxy = p1 - p0 ;
@@ -173,6 +185,15 @@ fn main(
173185 line_c = - dot (p0 , line_xy );
174186 }
175187
188+ // The projection is linear, so the drawing-to-gradient transform folds into
189+ // the line equation and fine evaluates it directly in drawing space.
190+ let u = user_to_gradient ;
191+ let folded_xy = vec2 (
192+ u . matrx . x * line_xy . x + u . matrx . y * line_xy . y ,
193+ u . matrx . z * line_xy . x + u . matrx . w * line_xy . y );
194+ line_c = line_c + dot (u . translate , line_xy );
195+ line_xy = folded_xy ;
196+
176197 // The CPU brush defines a zero-length axis as the gradient end. The
177198 // initialized equation therefore evaluates t=1 everywhere without NaN.
178199 info [di + 1u ] = bitcast <u32 >(line_xy . x );
@@ -185,11 +206,10 @@ fn main(
185206 // This epsilon matches what Skia uses
186207 let GRADIENT_EPSILON = 1 .0 / f32 (1u << 12u );
187208 info [di ] = draw_flags ;
188- var p0 = bitcast <vec2 <f32 >>(vec2 (scene [dd + 1u ], scene [dd + 2u ]));
189- var p1 = bitcast <vec2 <f32 >>(vec2 (scene [dd + 3u ], scene [dd + 4u ]));
190- var r0 = bitcast <f32 >(scene [dd + 5u ]);
191- var r1 = bitcast <f32 >(scene [dd + 6u ]);
192- let user_to_gradient = transform_identity ();
209+ var p0 = bitcast <vec2 <f32 >>(vec2 (scene [dd + 7u ], scene [dd + 8u ]));
210+ var p1 = bitcast <vec2 <f32 >>(vec2 (scene [dd + 9u ], scene [dd + 10u ]));
211+ var r0 = bitcast <f32 >(scene [dd + 11u ]);
212+ var r1 = bitcast <f32 >(scene [dd + 12u ]);
193213 var xform = transform_identity ();
194214 var focal_x = 0 .0 ;
195215 var radius = 0 .0 ;
@@ -257,9 +277,9 @@ fn main(
257277 }
258278 case DRAWTAG_FILL_ELLIPTIC_GRADIENT : {
259279 info [di ] = draw_flags ;
260- let center = bitcast <vec2 <f32 >>(vec2 (scene [dd + 1u ], scene [dd + 2u ]));
261- let axis_end = bitcast <vec2 <f32 >>(vec2 (scene [dd + 3u ], scene [dd + 4u ]));
262- let second_end = bitcast <vec2 <f32 >>(vec2 (scene [dd + 5u ], scene [dd + 6u ]));
280+ let center = bitcast <vec2 <f32 >>(vec2 (scene [dd + 7u ], scene [dd + 8u ]));
281+ let axis_end = bitcast <vec2 <f32 >>(vec2 (scene [dd + 9u ], scene [dd + 10u ]));
282+ let second_end = bitcast <vec2 <f32 >>(vec2 (scene [dd + 11u ], scene [dd + 12u ]));
263283 let dxy = axis_end - center ;
264284 let axis = length (dxy );
265285 let second_axis_len = length (second_end - center );
@@ -305,25 +325,36 @@ fn main(
305325 xlat_y = - (m1 * center . x + m3 * center . y );
306326 }
307327
308- info [di + 1u ] = bitcast <u32 >(m0 );
309- info [di + 2u ] = bitcast <u32 >(m1 );
310- info [di + 3u ] = bitcast <u32 >(m2 );
311- info [di + 4u ] = bitcast <u32 >(m3 );
312- info [di + 5u ] = bitcast <u32 >(xlat_x );
313- info [di + 6u ] = bitcast <u32 >(xlat_y );
328+ // Samples pass through the drawing-to-gradient transform before the ellipse
329+ // mapping. Degenerate kinds keep the center as their translation, so it moves
330+ // to its drawing position and the transform folds into the matrix only.
331+ let ellipse = Transform (vec4 (m0 , m1 , m2 , m3 ), vec2 (xlat_x , xlat_y ), vec3 (0 .0 , 0 .0 , 1 .0 ));
332+ var composed = transform_mul (ellipse , user_to_gradient );
333+ if kind != ELLIPTIC_GRAD_KIND_NORMAL {
334+ composed . translate = transform_apply (transform_inverse (user_to_gradient ), center );
335+ }
336+
337+ info [di + 1u ] = bitcast <u32 >(composed . matrx . x );
338+ info [di + 2u ] = bitcast <u32 >(composed . matrx . y );
339+ info [di + 3u ] = bitcast <u32 >(composed . matrx . z );
340+ info [di + 4u ] = bitcast <u32 >(composed . matrx . w );
341+ info [di + 5u ] = bitcast <u32 >(composed . translate . x );
342+ info [di + 6u ] = bitcast <u32 >(composed . translate . y );
314343 info [di + 7u ] = kind ;
315344 }
316345 case DRAWTAG_FILL_SWEEP_GRADIENT : {
317346 info [di ] = draw_flags ;
318- let p0 = bitcast <vec2 <f32 >>(vec2 (scene [dd + 1u ], scene [dd + 2u ]));
319- info [di + 1u ] = bitcast <u32 >(1 .0 );
320- info [di + 2u ] = bitcast <u32 >(0 .0 );
321- info [di + 3u ] = bitcast <u32 >(0 .0 );
322- info [di + 4u ] = bitcast <u32 >(1 .0 );
323- info [di + 5u ] = bitcast <u32 >(- p0 . x );
324- info [di + 6u ] = bitcast <u32 >(- p0 . y );
325- info [di + 7u ] = scene [dd + 3u ];
326- info [di + 8u ] = scene [dd + 4u ];
347+ let p0 = bitcast <vec2 <f32 >>(vec2 (scene [dd + 7u ], scene [dd + 8u ]));
348+ // The sample maps into the gradient's space and then becomes center-relative.
349+ let u = user_to_gradient ;
350+ info [di + 1u ] = bitcast <u32 >(u . matrx . x );
351+ info [di + 2u ] = bitcast <u32 >(u . matrx . y );
352+ info [di + 3u ] = bitcast <u32 >(u . matrx . z );
353+ info [di + 4u ] = bitcast <u32 >(u . matrx . w );
354+ info [di + 5u ] = bitcast <u32 >(u . translate . x - p0 . x );
355+ info [di + 6u ] = bitcast <u32 >(u . translate . y - p0 . y );
356+ info [di + 7u ] = scene [dd + 9u ];
357+ info [di + 8u ] = scene [dd + 10u ];
327358 }
328359 case DRAWTAG_FILL_PATH_GRADIENT : {
329360 info [di ] = draw_flags ;
0 commit comments