mirror of
https://github.com/penpot/penpot.git
synced 2025-01-21 06:02:32 -05:00
wip
This commit is contained in:
parent
c855b9ed4c
commit
f2619461bc
4 changed files with 231 additions and 52 deletions
|
@ -219,9 +219,12 @@
|
|||
color (:stroke-color stroke)
|
||||
gradient (:stroke-color-gradient stroke)
|
||||
image (:stroke-image stroke)
|
||||
width (:stroke-width stroke)]
|
||||
(println "-------_add_shape_center_stroke" stroke)
|
||||
(h/call internal-module "_add_shape_center_stroke" width)
|
||||
width (:stroke-width stroke)
|
||||
align (:stroke-alignment stroke)]
|
||||
(case align
|
||||
:inner (h/call internal-module "_add_shape_inner_stroke" width)
|
||||
:outer (h/call internal-module "_add_shape_outer_stroke" width)
|
||||
(h/call internal-module "_add_shape_center_stroke" width))
|
||||
|
||||
(cond
|
||||
(some? gradient)
|
||||
|
@ -266,7 +269,7 @@
|
|||
(dm/get-prop image :height))
|
||||
(when (== cached-image? 0)
|
||||
(store-image id)))
|
||||
|
||||
|
||||
(some? color)
|
||||
(let [rgba (rgba-from-hex color opacity)]
|
||||
(h/call internal-module "_add_shape_stroke_solid_fill" rgba)))))
|
||||
|
|
|
@ -354,12 +354,30 @@ pub extern "C" fn add_shape_center_stroke(width: f32) {
|
|||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn add_shape_inner_stroke(width: f32) {
|
||||
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
||||
if let Some(shape) = state.current_shape() {
|
||||
shape.add_stroke(shapes::Stroke::new_inner_stroke(width))
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn add_shape_outer_stroke(width: f32) {
|
||||
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
||||
if let Some(shape) = state.current_shape() {
|
||||
shape.add_stroke(shapes::Stroke::new_outer_stroke(width))
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn add_shape_stroke_solid_fill(raw_color: u32) {
|
||||
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
||||
if let Some(shape) = state.current_shape() {
|
||||
let color = skia::Color::new(raw_color);
|
||||
shape.set_stroke_fill(shapes::Fill::Solid(color));
|
||||
shape
|
||||
.set_stroke_fill(shapes::Fill::Solid(color))
|
||||
.expect("could not add stroke solid fill");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -373,11 +391,13 @@ pub extern "C" fn add_shape_stroke_linear_fill(
|
|||
) {
|
||||
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
||||
if let Some(shape) = state.current_shape() {
|
||||
shape.set_stroke_fill(shapes::Fill::new_linear_gradient(
|
||||
(start_x, start_y),
|
||||
(end_x, end_y),
|
||||
opacity,
|
||||
));
|
||||
shape
|
||||
.set_stroke_fill(shapes::Fill::new_linear_gradient(
|
||||
(start_x, start_y),
|
||||
(end_x, end_y),
|
||||
opacity,
|
||||
))
|
||||
.expect("could not add stroke linear fill");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -392,12 +412,14 @@ pub extern "C" fn add_shape_stroke_radial_fill(
|
|||
) {
|
||||
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
||||
if let Some(shape) = state.current_shape() {
|
||||
shape.set_stroke_fill(shapes::Fill::new_radial_gradient(
|
||||
(start_x, start_y),
|
||||
(end_x, end_y),
|
||||
opacity,
|
||||
width,
|
||||
));
|
||||
shape
|
||||
.set_stroke_fill(shapes::Fill::new_radial_gradient(
|
||||
(start_x, start_y),
|
||||
(end_x, end_y),
|
||||
opacity,
|
||||
width,
|
||||
))
|
||||
.expect("could not add stroke radial fill");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,11 +453,13 @@ pub extern "C" fn add_shape_image_stroke(
|
|||
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
if let Some(shape) = state.current_shape() {
|
||||
shape.set_stroke_fill(shapes::Fill::new_image_fill(
|
||||
id,
|
||||
(alpha * 0xff as f32).floor() as u8,
|
||||
(width, height),
|
||||
));
|
||||
shape
|
||||
.set_stroke_fill(shapes::Fill::new_image_fill(
|
||||
id,
|
||||
(alpha * 0xff as f32).floor() as u8,
|
||||
(width, height),
|
||||
))
|
||||
.expect("could not add stroke image fill");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ fn render_fill(
|
|||
(Fill::Image(image_fill), kind) => {
|
||||
let image = images.get(&image_fill.id());
|
||||
if let Some(image) = image {
|
||||
draw_image_in_container(
|
||||
draw_image_fill_in_container(
|
||||
surface.canvas(),
|
||||
&image,
|
||||
image_fill.size(),
|
||||
|
@ -121,12 +121,12 @@ fn render_stroke(
|
|||
if let Fill::Image(image_fill) = stroke.clone().fill() {
|
||||
let image = images.get(&image_fill.id());
|
||||
if let Some(image) = image {
|
||||
draw_image_in_container(
|
||||
draw_image_stroke_in_container(
|
||||
surface.canvas(),
|
||||
&image,
|
||||
image_fill.size(),
|
||||
kind,
|
||||
&stroke.to_paint(&selrect),
|
||||
stroke.clone().width(),
|
||||
&selrect,
|
||||
path_transform,
|
||||
);
|
||||
|
@ -134,22 +134,44 @@ fn render_stroke(
|
|||
} else {
|
||||
match kind {
|
||||
Kind::Rect(rect) => {
|
||||
surface.canvas().draw_rect(rect, &stroke.to_paint(&selrect));
|
||||
let stroke_rect = stroke.clone().outer_rect(rect);
|
||||
surface
|
||||
.canvas()
|
||||
.draw_rect(&stroke_rect, &stroke.to_paint(&selrect));
|
||||
}
|
||||
Kind::Circle(rect) => {
|
||||
surface.canvas().draw_oval(rect, &stroke.to_paint(&selrect));
|
||||
let stroke_rect = stroke.clone().outer_rect(rect);
|
||||
surface
|
||||
.canvas()
|
||||
.draw_oval(&stroke_rect, &stroke.to_paint(&selrect));
|
||||
}
|
||||
Kind::Path(path) => {
|
||||
//TODO
|
||||
surface.canvas().save();
|
||||
let mut stroke_rect = stroke.clone().outer_rect(&selrect);
|
||||
let mut fill_paint = skia::Paint::default();
|
||||
fill_paint.set_blend_mode(skia::BlendMode::SrcOver);
|
||||
fill_paint.set_anti_alias(true);
|
||||
surface.canvas().draw_path(
|
||||
&path.to_skia_path().transform(path_transform.unwrap()),
|
||||
&stroke.to_paint(&selrect),
|
||||
&fill_paint,
|
||||
);
|
||||
let mut path_paint = skia::Paint::default();
|
||||
path_paint.set_blend_mode(skia::BlendMode::SrcOut);
|
||||
path_paint.set_style(skia::PaintStyle::Stroke);
|
||||
path_paint.set_stroke_width(2. * stroke.clone().width());
|
||||
path_paint.set_anti_alias(true);
|
||||
surface.canvas().draw_path(
|
||||
&path.to_skia_path().transform(path_transform.unwrap()),
|
||||
&path_paint,
|
||||
);
|
||||
surface.canvas().restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_image_in_container(
|
||||
pub fn draw_image_fill_in_container(
|
||||
canvas: &skia::Canvas,
|
||||
image: &Image,
|
||||
size: (i32, i32),
|
||||
|
@ -158,8 +180,73 @@ pub fn draw_image_in_container(
|
|||
container: &Rect,
|
||||
path_transform: Option<&skia::Matrix>,
|
||||
) {
|
||||
// TODO: param
|
||||
let border_width = 20.0; // Width of the border
|
||||
let width = size.0 as f32;
|
||||
let height = size.1 as f32;
|
||||
let image_aspect_ratio = width / height;
|
||||
|
||||
// Container size
|
||||
let container_width = container.width();
|
||||
let container_height = container.height();
|
||||
let container_aspect_ratio = container_width / container_height;
|
||||
|
||||
// Calculate scale to ensure the image covers the container
|
||||
let scale = if image_aspect_ratio > container_aspect_ratio {
|
||||
// Image is wider, scale based on height to cover container
|
||||
container_height / height
|
||||
} else {
|
||||
// Image is taller, scale based on width to cover container
|
||||
container_width / width
|
||||
};
|
||||
|
||||
// Scaled size of the image
|
||||
let scaled_width = width * scale;
|
||||
let scaled_height = height * scale;
|
||||
|
||||
let dest_rect = Rect::from_xywh(
|
||||
container.left - (scaled_width - container_width) / 2.0,
|
||||
container.top - (scaled_height - container_height) / 2.0,
|
||||
scaled_width,
|
||||
scaled_height,
|
||||
);
|
||||
|
||||
// Save the current canvas state
|
||||
canvas.save();
|
||||
|
||||
// Set the clipping rectangle to the container bounds
|
||||
match kind {
|
||||
Kind::Rect(_) => {
|
||||
canvas.clip_rect(container, skia::ClipOp::Intersect, true);
|
||||
}
|
||||
Kind::Circle(_) => {
|
||||
let mut oval_path = skia::Path::new();
|
||||
oval_path.add_oval(container, None);
|
||||
canvas.clip_path(&oval_path, skia::ClipOp::Intersect, true);
|
||||
}
|
||||
Kind::Path(p) => {
|
||||
canvas.clip_path(
|
||||
&p.to_skia_path().transform(path_transform.unwrap()),
|
||||
skia::ClipOp::Intersect,
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the image with the calculated destination rectangle
|
||||
canvas.draw_image_rect(image, None, dest_rect, &paint);
|
||||
|
||||
// Restore the canvas to remove the clipping
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
pub fn draw_image_stroke_in_container(
|
||||
canvas: &skia::Canvas,
|
||||
image: &Image,
|
||||
size: (i32, i32),
|
||||
kind: &Kind,
|
||||
border_width: f32,
|
||||
container: &Rect,
|
||||
path_transform: Option<&skia::Matrix>,
|
||||
) {
|
||||
let width = size.0 as f32;
|
||||
let height = size.1 as f32;
|
||||
let image_aspect_ratio = width / height;
|
||||
|
@ -200,9 +287,9 @@ pub fn draw_image_in_container(
|
|||
canvas.save();
|
||||
|
||||
let mut path_paint = skia::Paint::default();
|
||||
path_paint.set_stroke_width(border_width); // Ancho del contorno
|
||||
path_paint.set_style(skia::paint::Style::Stroke); // Solo contorno
|
||||
path_paint.set_blend_mode(skia::BlendMode::SrcOver); // Recortar la imagen según el path
|
||||
path_paint.set_stroke_width(border_width);
|
||||
path_paint.set_style(skia::paint::Style::Stroke);
|
||||
path_paint.set_blend_mode(skia::BlendMode::SrcOver);
|
||||
path_paint.set_anti_alias(true);
|
||||
|
||||
// Set the clipping rectangle to the container bounds
|
||||
|
|
|
@ -5,20 +5,20 @@ use skia_safe as skia;
|
|||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum StrokeStyle {
|
||||
Solid,
|
||||
Dotted,
|
||||
Dashed,
|
||||
Mixed,
|
||||
// Dotted,
|
||||
// Dashed,
|
||||
// Mixed,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum StrokeCap {
|
||||
None,
|
||||
Line,
|
||||
Triangle,
|
||||
Circle,
|
||||
Diamond,
|
||||
Round,
|
||||
Square,
|
||||
// Line,
|
||||
// Triangle,
|
||||
// Circle,
|
||||
// Diamond,
|
||||
// Round,
|
||||
// Square,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
@ -49,6 +49,28 @@ impl Stroke {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn new_inner_stroke(width: f32) -> Self {
|
||||
let transparent = skia::Color::from_argb(0, 0, 0, 0);
|
||||
Self::InnerStroke(StrokeAttrs {
|
||||
fill: Fill::Solid(transparent),
|
||||
width: width,
|
||||
style: StrokeStyle::Solid,
|
||||
cap_end: StrokeCap::None,
|
||||
cap_start: StrokeCap::None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_outer_stroke(width: f32) -> Self {
|
||||
let transparent = skia::Color::from_argb(0, 0, 0, 0);
|
||||
Self::OuterStroke(StrokeAttrs {
|
||||
fill: Fill::Solid(transparent),
|
||||
width: width,
|
||||
style: StrokeStyle::Solid,
|
||||
cap_end: StrokeCap::None,
|
||||
cap_start: StrokeCap::None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn fill(self) -> Fill {
|
||||
match self {
|
||||
Stroke::InnerStroke(attrs) => attrs.fill,
|
||||
|
@ -57,6 +79,47 @@ impl Stroke {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn outer_rect(self, rect: &math::Rect) -> math::Rect {
|
||||
match self {
|
||||
Stroke::InnerStroke(attrs) => math::Rect::from_xywh(
|
||||
rect.left + (attrs.width / 2.),
|
||||
rect.top + (attrs.width / 2.),
|
||||
rect.width() - attrs.width,
|
||||
rect.height() - attrs.width,
|
||||
),
|
||||
Stroke::CenterStroke(attrs) => {
|
||||
math::Rect::from_xywh(rect.left, rect.top, rect.width(), rect.height())
|
||||
}
|
||||
Stroke::OuterStroke(attrs) => math::Rect::from_xywh(
|
||||
rect.left - (attrs.width / 2.),
|
||||
rect.top - (attrs.width / 2.),
|
||||
rect.width() + attrs.width,
|
||||
rect.height() + attrs.width,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn outer_path(self, path: &skia::Path) -> skia::Path {
|
||||
// match self {
|
||||
// Stroke::InnerStroke(attrs) => math::Rect::from_xywh(
|
||||
// rect.left + (attrs.width / 2.),
|
||||
// rect.top + (attrs.width / 2.),
|
||||
// rect.width() - attrs.width,
|
||||
// rect.height() - attrs.width,
|
||||
// ),
|
||||
// Stroke::CenterStroke(attrs) => {
|
||||
// math::Rect::from_xywh(rect.left, rect.top, rect.width(), rect.height())
|
||||
// }
|
||||
// Stroke::OuterStroke(attrs) => math::Rect::from_xywh(
|
||||
// rect.left - (attrs.width / 2.),
|
||||
// rect.top - (attrs.width / 2.),
|
||||
// rect.width() + attrs.width,
|
||||
// rect.height() + attrs.width,
|
||||
// ),
|
||||
// }
|
||||
path.clone()
|
||||
}
|
||||
|
||||
pub fn fill_mut(&mut self) -> &mut Fill {
|
||||
match self {
|
||||
Stroke::InnerStroke(attrs) => &mut attrs.fill,
|
||||
|
@ -74,6 +137,7 @@ impl Stroke {
|
|||
}
|
||||
|
||||
pub fn to_paint(&self, rect: &math::Rect) -> skia::Paint {
|
||||
// TODO antialias
|
||||
match self {
|
||||
Stroke::InnerStroke(attrs) => {
|
||||
let mut paint = attrs.fill.to_paint(rect);
|
||||
|
@ -85,17 +149,18 @@ impl Stroke {
|
|||
paint.set_stroke_cap(skia::paint::Cap::Butt); // Termina la línea sin agregar espacio adicional
|
||||
paint
|
||||
}
|
||||
Stroke::OuterStroke(attrs) => {
|
||||
let mut paint = attrs.fill.to_paint(rect);
|
||||
paint.set_style(skia::PaintStyle::Stroke);
|
||||
paint.set_stroke_width(attrs.width);
|
||||
paint.set_blend_mode(skia::BlendMode::SrcOver);
|
||||
paint.set_stroke_join(skia::paint::Join::Miter); // Unión en pico
|
||||
paint.set_stroke_miter(10.0); // Longitud de la muesca para picos más pronunciados
|
||||
paint.set_stroke_cap(skia::paint::Cap::Butt); // Termina la línea sin agregar espacio adicional
|
||||
paint
|
||||
}
|
||||
|
||||
Stroke::CenterStroke(attrs) => {
|
||||
let mut paint = attrs.fill.to_paint(rect);
|
||||
paint.set_style(skia::PaintStyle::Stroke);
|
||||
paint.set_stroke_width(attrs.width);
|
||||
paint.set_blend_mode(skia::BlendMode::SrcOver);
|
||||
paint.set_stroke_join(skia::paint::Join::Miter); // Unión en pico
|
||||
paint.set_stroke_miter(10.0); // Longitud de la muesca para picos más pronunciados
|
||||
paint.set_stroke_cap(skia::paint::Cap::Butt); // Termina la línea sin agregar espacio adicional
|
||||
paint
|
||||
}
|
||||
Stroke::OuterStroke(attrs) => {
|
||||
let mut paint = attrs.fill.to_paint(rect);
|
||||
paint.set_style(skia::PaintStyle::Stroke);
|
||||
paint.set_stroke_width(attrs.width);
|
||||
|
|
Loading…
Add table
Reference in a new issue