mirror of
https://github.com/penpot/penpot.git
synced 2025-05-12 20:06:37 +02:00
🎉 Support for radial gradients with wasm render
This commit is contained in:
parent
0eedc036be
commit
09aa4529f8
5 changed files with 106 additions and 16 deletions
|
@ -28,6 +28,7 @@ pub struct Gradient {
|
|||
opacity: f32,
|
||||
start: (f32, f32),
|
||||
end: (f32, f32),
|
||||
width: f32,
|
||||
}
|
||||
|
||||
impl Gradient {
|
||||
|
@ -36,7 +37,7 @@ impl Gradient {
|
|||
self.offsets.push(offset);
|
||||
}
|
||||
|
||||
fn to_shader(&self, rect: &math::Rect) -> skia::Shader {
|
||||
fn to_linear_shader(&self, rect: &math::Rect) -> skia::Shader {
|
||||
let start = (
|
||||
rect.left + self.start.0 * rect.width(),
|
||||
rect.top + self.start.1 * rect.height(),
|
||||
|
@ -56,6 +57,41 @@ impl Gradient {
|
|||
.unwrap();
|
||||
shader
|
||||
}
|
||||
|
||||
fn to_radial_shader(&self, rect: &math::Rect) -> skia::Shader {
|
||||
let center = skia::Point::new(
|
||||
rect.left + self.start.0 * rect.width(),
|
||||
rect.top + self.start.1 * rect.height(),
|
||||
);
|
||||
let end = skia::Point::new(
|
||||
rect.left + self.end.0 * rect.width(),
|
||||
rect.top + self.end.1 * rect.height(),
|
||||
);
|
||||
|
||||
let direction = end - center;
|
||||
let distance = (direction.x.powi(2) + direction.y.powi(2)).sqrt();
|
||||
let angle = direction.y.atan2(direction.x).to_degrees();
|
||||
|
||||
// Based on the code from frontend/src/app/main/ui/shapes/gradients.cljs
|
||||
let mut transform = skia::Matrix::new_identity();
|
||||
transform.pre_translate((center.x, center.y));
|
||||
transform.pre_rotate(angle + 90., skia::Point::new(0., 0.));
|
||||
// We need an extra transform, because in skia radial gradients are circular and we need them to be ellipses if they must adapt to the shape
|
||||
transform.pre_scale((self.width * rect.width() / rect.height(), 1.), None);
|
||||
transform.pre_translate((-center.x, -center.y));
|
||||
|
||||
let shader = skia::shader::Shader::radial_gradient(
|
||||
center,
|
||||
distance,
|
||||
self.colors.as_slice(),
|
||||
self.offsets.as_slice(),
|
||||
skia::TileMode::Clamp,
|
||||
None,
|
||||
Some(&transform),
|
||||
)
|
||||
.unwrap();
|
||||
shader
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
@ -80,6 +116,7 @@ impl ImageFill {
|
|||
pub enum Fill {
|
||||
Solid(Color),
|
||||
LinearGradient(Gradient),
|
||||
RadialGradient(Gradient),
|
||||
Image(ImageFill),
|
||||
}
|
||||
|
||||
|
@ -91,6 +128,22 @@ impl Fill {
|
|||
opacity,
|
||||
colors: vec![],
|
||||
offsets: vec![],
|
||||
width: 0.,
|
||||
})
|
||||
}
|
||||
pub fn new_radial_gradient(
|
||||
start: (f32, f32),
|
||||
end: (f32, f32),
|
||||
opacity: f32,
|
||||
width: f32,
|
||||
) -> Self {
|
||||
Self::RadialGradient(Gradient {
|
||||
start,
|
||||
end,
|
||||
opacity,
|
||||
colors: vec![],
|
||||
offsets: vec![],
|
||||
width,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -115,7 +168,15 @@ impl Fill {
|
|||
}
|
||||
Self::LinearGradient(gradient) => {
|
||||
let mut p = skia::Paint::default();
|
||||
p.set_shader(gradient.to_shader(&rect));
|
||||
p.set_shader(gradient.to_linear_shader(&rect));
|
||||
p.set_alpha((gradient.opacity * 255.) as u8);
|
||||
p.set_style(skia::PaintStyle::Fill);
|
||||
p.set_blend_mode(skia::BlendMode::SrcOver);
|
||||
p
|
||||
}
|
||||
Self::RadialGradient(gradient) => {
|
||||
let mut p = skia::Paint::default();
|
||||
p.set_shader(gradient.to_radial_shader(&rect));
|
||||
p.set_alpha((gradient.opacity * 255.) as u8);
|
||||
p.set_style(skia::PaintStyle::Fill);
|
||||
p.set_blend_mode(skia::BlendMode::SrcOver);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue