mirror of
https://github.com/penpot/penpot.git
synced 2026-05-06 00:28:43 +00:00
⚡ Translation-only fast paths for Shape and Path transforms
This commit is contained in:
parent
f6bd991968
commit
4a0cd0b7ce
@ -1015,6 +1015,7 @@ impl Shape {
|
||||
}
|
||||
|
||||
pub fn calculate_extrect(&self, shapes_pool: ShapesPoolRef, scale: f32) -> math::Rect {
|
||||
// `scale` is forwarded to children but intentionally NOT part of the cache key.
|
||||
if let Some(cached_extrect) = *self.extrect_cache.borrow() {
|
||||
return cached_extrect;
|
||||
}
|
||||
@ -1346,8 +1347,10 @@ impl Shape {
|
||||
pub fn get_skia_path(&self) -> Option<skia::Path> {
|
||||
if let Some(path) = self.shape_type.path() {
|
||||
let mut skia_path = path.to_skia_path(self.svg_attrs.as_ref());
|
||||
if let Some(path_transform) = self.to_path_transform() {
|
||||
skia_path = skia_path.make_transform(&path_transform);
|
||||
if !math::identitish(&self.transform) {
|
||||
if let Some(path_transform) = self.to_path_transform() {
|
||||
skia_path = skia_path.make_transform(&path_transform);
|
||||
}
|
||||
}
|
||||
Some(skia_path)
|
||||
} else {
|
||||
@ -1356,6 +1359,19 @@ impl Shape {
|
||||
}
|
||||
|
||||
fn transform_selrect(&mut self, transform: &Matrix) {
|
||||
if math::is_move_only_matrix(transform) {
|
||||
let tx = transform.translate_x();
|
||||
let ty = transform.translate_y();
|
||||
// `self.transform` (rotation/scale around center) is unchanged by translation.
|
||||
self.selrect = math::Rect::from_xywh(
|
||||
self.selrect.left + tx,
|
||||
self.selrect.top + ty,
|
||||
self.selrect.width(),
|
||||
self.selrect.height(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let mut center = self.selrect.center();
|
||||
center = transform.map_point(center);
|
||||
|
||||
@ -1377,9 +1393,23 @@ impl Shape {
|
||||
pub fn apply_transform(&mut self, transform: &Matrix) {
|
||||
self.transform_selrect(transform);
|
||||
|
||||
// TODO: See if we can change this invalidation to a transformation
|
||||
self.invalidate_extrect();
|
||||
self.invalidate_bounds();
|
||||
// Outsets (strokes, shadows, blur, children) are translation-invariant,
|
||||
// so the cached extrect can be shifted instead of invalidated.
|
||||
if math::is_move_only_matrix(transform) {
|
||||
let tx = transform.translate_x();
|
||||
let ty = transform.translate_y();
|
||||
if let Some(rect) = self.extrect_cache.borrow_mut().as_mut() {
|
||||
*rect = math::Rect::from_xywh(
|
||||
rect.left + tx,
|
||||
rect.top + ty,
|
||||
rect.width(),
|
||||
rect.height(),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
self.invalidate_extrect();
|
||||
self.invalidate_bounds();
|
||||
}
|
||||
|
||||
if let shape_type @ (Type::Path(_) | Type::Bool(_)) = &mut self.shape_type {
|
||||
if let Some(path) = shape_type.path_mut() {
|
||||
|
||||
@ -259,15 +259,21 @@ pub fn get_fill_shader(fill: &Fill, bounding_box: &Rect) -> Option<skia::Shader>
|
||||
}
|
||||
|
||||
pub fn merge_fills(fills: &[Fill], bounding_box: Rect) -> skia::Paint {
|
||||
let mut combined_shader: Option<skia::Shader> = None;
|
||||
let mut fills_paint = skia::Paint::default();
|
||||
|
||||
if fills.is_empty() {
|
||||
combined_shader = Some(skia::shaders::color(skia::Color::TRANSPARENT));
|
||||
fills_paint.set_shader(combined_shader);
|
||||
fills_paint.set_color(skia::Color::TRANSPARENT);
|
||||
return fills_paint;
|
||||
}
|
||||
|
||||
if fills.len() == 1 {
|
||||
if let Fill::Solid(SolidColor(color)) = &fills[0] {
|
||||
fills_paint.set_color(*color);
|
||||
return fills_paint;
|
||||
}
|
||||
}
|
||||
|
||||
let mut combined_shader: Option<skia::Shader> = None;
|
||||
for fill in fills {
|
||||
let shader = get_fill_shader(fill, &bounding_box);
|
||||
|
||||
@ -287,7 +293,7 @@ pub fn merge_fills(fills: &[Fill], bounding_box: Rect) -> skia::Paint {
|
||||
}
|
||||
}
|
||||
|
||||
fills_paint.set_shader(combined_shader.clone());
|
||||
fills_paint.set_shader(combined_shader);
|
||||
fills_paint
|
||||
}
|
||||
|
||||
|
||||
@ -236,6 +236,28 @@ impl Path {
|
||||
}
|
||||
|
||||
pub fn transform(&mut self, mtx: &Matrix) {
|
||||
if math::is_move_only_matrix(mtx) {
|
||||
let tx = mtx.translate_x();
|
||||
let ty = mtx.translate_y();
|
||||
self.segments.iter_mut().for_each(|s| match s {
|
||||
Segment::MoveTo(p) | Segment::LineTo(p) => {
|
||||
p.0 += tx;
|
||||
p.1 += ty;
|
||||
}
|
||||
Segment::CurveTo((c1, c2, p)) => {
|
||||
c1.0 += tx;
|
||||
c1.1 += ty;
|
||||
c2.0 += tx;
|
||||
c2.1 += ty;
|
||||
p.0 += tx;
|
||||
p.1 += ty;
|
||||
}
|
||||
_ => {}
|
||||
});
|
||||
self.skia_path = self.skia_path.with_offset((tx, ty));
|
||||
return;
|
||||
}
|
||||
|
||||
self.segments.iter_mut().for_each(|s| match s {
|
||||
Segment::MoveTo(p) => {
|
||||
let np = mtx.map_point(skia::Point::new(p.0, p.1));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user