Skip to content

Commit ec61217

Browse files
authored
Fix gradient transformation (#588)
* Fix with perfect circle * Actually fix rotated gradient * Gradient transform & fix on rotated canvas * Cleanup & remove logging
1 parent 61fc11e commit ec61217

File tree

4 files changed

+46
-15
lines changed

4 files changed

+46
-15
lines changed

editor/src/viewport_tools/tools/gradient_tool.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,12 @@ impl Default for GradientToolFsmState {
8181

8282
/// Computes the transform from gradient space to layer space (where gradient space is 0..1 in layer space)
8383
fn gradient_space_transform(path: &[LayerId], layer: &Layer, document: &DocumentMessageHandler) -> DAffine2 {
84-
let bounds = layer.aabounding_box().unwrap();
84+
let bounds = layer.aabounding_box_for_transform(DAffine2::IDENTITY).unwrap();
8585
let bound_transform = DAffine2::from_scale_angle_translation(bounds[1] - bounds[0], 0., bounds[0]);
8686

87-
document.graphene_document.multiply_transforms(&path[..path.len() - 1]).unwrap() * bound_transform
87+
let multiplied = document.graphene_document.multiply_transforms(path).unwrap();
88+
89+
multiplied * bound_transform
8890
}
8991

9092
/// Contains info on the overlays for a single gradient
@@ -225,7 +227,7 @@ impl SelectedGradient {
225227
self.gradient.end = mouse;
226228
}
227229

228-
self.gradient.transform = self.transform.inverse();
230+
self.gradient.transform = self.transform;
229231
let fill = Fill::LinearGradient(self.gradient.clone());
230232
let path = self.path.clone();
231233
responses.push_back(Operation::SetLayerFill { path, fill }.into());

graphene/src/layers/shape_layer.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ pub struct ShapeLayer {
3232
impl LayerData for ShapeLayer {
3333
fn render(&mut self, svg: &mut String, svg_defs: &mut String, transforms: &mut Vec<DAffine2>, view_mode: ViewMode) {
3434
let mut path = self.path.clone();
35+
36+
let kurbo::Rect { x0, y0, x1, y1 } = path.bounding_box();
37+
let layer_bounds = [(x0, y0).into(), (x1, y1).into()];
38+
3539
let transform = self.transform(transforms, view_mode);
3640
let inverse = transform.inverse();
3741
if !inverse.is_finite() {
@@ -40,12 +44,20 @@ impl LayerData for ShapeLayer {
4044
}
4145
path.apply_affine(glam_to_kurbo(transform));
4246

47+
let kurbo::Rect { x0, y0, x1, y1 } = path.bounding_box();
48+
let transformed_bounds = [(x0, y0).into(), (x1, y1).into()];
49+
4350
let _ = writeln!(svg, r#"<g transform="matrix("#);
4451
inverse.to_cols_array().iter().enumerate().for_each(|(i, entry)| {
4552
let _ = svg.write_str(&(entry.to_string() + if i == 5 { "" } else { "," }));
4653
});
4754
let _ = svg.write_str(r#")">"#);
48-
let _ = write!(svg, r#"<path d="{}" {} />"#, path.to_svg(), self.style.render(view_mode, svg_defs));
55+
let _ = write!(
56+
svg,
57+
r#"<path d="{}" {} />"#,
58+
path.to_svg(),
59+
self.style.render(view_mode, svg_defs, transform, layer_bounds, transformed_bounds)
60+
);
4961
let _ = svg.write_str("</g>");
5062
}
5163

graphene/src/layers/style/mod.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,19 +61,25 @@ impl Gradient {
6161
}
6262

6363
/// Adds the gradient def with the uuid specified
64-
fn render_defs(&self, svg_defs: &mut String) {
64+
fn render_defs(&self, svg_defs: &mut String, multiplied_transform: DAffine2, bounds: [DVec2; 2], transformed_bounds: [DVec2; 2]) {
65+
let bound_transform = DAffine2::from_scale_angle_translation(bounds[1] - bounds[0], 0., bounds[0]);
66+
let transformed_bound_transform = DAffine2::from_scale_angle_translation(transformed_bounds[1] - transformed_bounds[0], 0., transformed_bounds[0]);
67+
let updated_transform = multiplied_transform * bound_transform;
68+
6569
let positions = self
6670
.positions
6771
.iter()
6872
.filter_map(|(pos, color)| color.map(|color| (pos, color)))
6973
.map(|(position, color)| format!(r##"<stop offset="{}" stop-color="#{}" />"##, position, color.rgba_hex()))
7074
.collect::<String>();
7175

72-
let start = self.transform.inverse().transform_point2(self.start);
73-
let end = self.transform.inverse().transform_point2(self.end);
76+
let mod_gradient = transformed_bound_transform.inverse();
77+
let mod_points = mod_gradient.inverse() * transformed_bound_transform.inverse() * updated_transform;
78+
79+
let start = mod_points.transform_point2(self.start);
80+
let end = mod_points.transform_point2(self.end);
7481

75-
let transform = self
76-
.transform
82+
let transform = mod_gradient
7783
.to_cols_array()
7884
.iter()
7985
.enumerate()
@@ -122,12 +128,12 @@ impl Fill {
122128
}
123129

124130
/// Renders the fill, adding necessary defs.
125-
pub fn render(&self, svg_defs: &mut String) -> String {
131+
pub fn render(&self, svg_defs: &mut String, multiplied_transform: DAffine2, bounds: [DVec2; 2], transformed_bounds: [DVec2; 2]) -> String {
126132
match self {
127133
Self::None => r#" fill="none""#.to_string(),
128134
Self::Solid(color) => format!(r##" fill="#{}"{}"##, color.rgb_hex(), format_opacity("fill", color.a())),
129135
Self::LinearGradient(gradient) => {
130-
gradient.render_defs(svg_defs);
136+
gradient.render_defs(svg_defs, multiplied_transform, bounds, transformed_bounds);
131137
format!(r##" fill="url('#{}')""##, gradient.uuid)
132138
}
133139
}
@@ -430,10 +436,10 @@ impl PathStyle {
430436
self.stroke = None;
431437
}
432438

433-
pub fn render(&self, view_mode: ViewMode, svg_defs: &mut String) -> String {
439+
pub fn render(&self, view_mode: ViewMode, svg_defs: &mut String, multiplied_transform: DAffine2, bounds: [DVec2; 2], transformed_bounds: [DVec2; 2]) -> String {
434440
let fill_attribute = match (view_mode, &self.fill) {
435-
(ViewMode::Outline, _) => Fill::None.render(svg_defs),
436-
(_, fill) => fill.render(svg_defs),
441+
(ViewMode::Outline, _) => Fill::None.render(svg_defs, multiplied_transform, bounds, transformed_bounds),
442+
(_, fill) => fill.render(svg_defs, multiplied_transform, bounds, transformed_bounds),
437443
};
438444
let stroke_attribute = match (view_mode, &self.stroke) {
439445
(ViewMode::Outline, _) => Stroke::new(LAYER_OUTLINE_STROKE_COLOR, LAYER_OUTLINE_STROKE_WIDTH).render(),

graphene/src/layers/text_layer/mod.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,20 @@ impl LayerData for TextLayer {
6363
} else {
6464
let mut path = self.to_bez_path();
6565

66+
let kurbo::Rect { x0, y0, x1, y1 } = path.bounding_box();
67+
let bounds = [(x0, y0).into(), (x1, y1).into()];
68+
6669
path.apply_affine(glam_to_kurbo(transform));
6770

68-
let _ = write!(svg, r#"<path d="{}" {} />"#, path.to_svg(), self.style.render(view_mode, svg_defs));
71+
let kurbo::Rect { x0, y0, x1, y1 } = path.bounding_box();
72+
let transformed_bounds = [(x0, y0).into(), (x1, y1).into()];
73+
74+
let _ = write!(
75+
svg,
76+
r#"<path d="{}" {} />"#,
77+
path.to_svg(),
78+
self.style.render(view_mode, svg_defs, transform, bounds, transformed_bounds)
79+
);
6980
}
7081
let _ = svg.write_str("</g>");
7182
}

0 commit comments

Comments
 (0)