🔧 Enable back clippy rules (#6492)

* 🔧 Fix lint script (rust)

* 🔧 Temporarily add clippy rules to ignore so lint script passes

* 💄 Fix clippy rule crate_in_macro_def

* 💄 Fix clippy rule redundant-static-lifetimes

* 💄 Fix clippy rule unnecessary_cast

* 💄 Fix clippy rule nonminimal_bool

* 💄 Fix clippy rule redundant_pattern_matching

* 💄 Fix clippy rule assign_op_pattern

* 💄 Fix clippy rule needless_lifetimes

* 💄 Fix clippy rule for_kv_map

* 💄 Fix clippy rule ptr_arg

* 💄 Fix clippy rule match_like_matches_macro

* 💄 Fix clippy rule macro_metavars_in_unsafe

* 💄 Fix clippy rule map_clone

* 💄 Fix clippy rule wrong_self_convention

* 💄 Fix clippy rule vec_box

* 💄 Fix clippy rule useless_format

* 💄 Fix clippy rule unwrap_or_default

* 💄 Fix clippy rule unused_unit

* 💄 Fix clippy rule unnecessary_to_owned

* 💄 Fix clippy rule too_many_arguments

* 💄 Fix clippy rule slow_vector_initialization

* 💄 Fix clippy rule single_match

* 💄 Fix clippy rule redundant_field_names

* 💄 Fix clippy rule rendudant_closure

* 💄 Fix clippy rule needless_return

* 💄 Fix clippy rule needless_range_loop

* 💄 Fix clippy rule needless_borrows_for_generic_args

* 💄 Fix clippy rule needless-borrow

* 💄 Fix clippy rule missing_transmute_annotations

* 💄 Fix clippy rule map_entry

* 💄 Fix clippy rule manual_map

* 💄 Fix clippy rule len_zero

* 💄 Fix clippy rule from_over_into

* 💄 Fix clippy rule field_reassign_with_default

* 💄 Fix clippy rule enum_variant_names

* 💄 Fix clippy rule derivable_impls

* 💄 Fix clippy rule clone_on_copy

* 💄 Fix clippy rule box_collection

* 🔧 Make lint script also check test config target

* 🔧 Remove cargo-watch as a lib dependency

* 💄 Fix clippy rule for join_bounds

* 🔧 Fix lint script return code

---------

Co-authored-by: alonso.torres <alonso.torres@kaleidos.net>
This commit is contained in:
Belén Albeza 2025-05-19 11:14:55 +02:00 committed by GitHub
parent 051c2a7e99
commit 8afd217a80
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
35 changed files with 447 additions and 2338 deletions

1868
render-wasm/Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -20,11 +20,13 @@ path = "src/main.rs"
base64 = "0.22.1" base64 = "0.22.1"
gl = "0.14.0" gl = "0.14.0"
indexmap = "2.7.1" indexmap = "2.7.1"
skia-safe = { version = "0.81.0", default-features = false, features = ["gl", "svg", "textlayout", "binary-cache"]} skia-safe = { version = "0.81.0", default-features = false, features = [
"gl",
"svg",
"textlayout",
"binary-cache",
] }
uuid = { version = "1.11.0", features = ["v4"] } uuid = { version = "1.11.0", features = ["v4"] }
[dev-dependencies]
cargo-watch = "8.5.3"
[profile.release] [profile.release]
opt-level = "s" opt-level = "s"

View file

@ -10,45 +10,30 @@ fi
. ./_build_env . ./_build_env
ALLOWED_RULES=" export CARGO_BUILD_TARGET=${CARGO_BUILD_TARGET:-"wasm32-unknown-emscripten"};
-A clippy::box_collection \ export SKIA_BINARIES_URL=${SKIA_BINARIES_URL:-"https://github.com/penpot/skia-binaries/releases/download/0.81.0-3/skia-binaries-24dee32a277b6c7b5357-wasm32-unknown-emscripten-gl-svg-textlayout-binary-cache.tar.gz"}
-A clippy::clone_on_copy \
-A clippy::derivable_impls \
-A clippy::enum_variant_names \ ALLOWED_RULES="-D static_mut_refs"
-A clippy::field_reassign_with_default \
-A clippy::from_over_into \
-A clippy::len_zero \
-A clippy::manual_map \
-A clippy::map_entry \
-A clippy::missing_safety_doc \
-A clippy::missing_transmute_annotations \
-A clippy::needless_borrow \
-A clippy::needless_borrows_for_generic_args \
-A clippy::needless_range_loop \
-A clippy::needless_return \
-A clippy::redundant_closure \
-A clippy::redundant_field_names \
-A clippy::single_match \
-A clippy::slow_vector_initialization \
-A clippy::too_many_arguments \
-A clippy::unnecessary_to_owned \
-A clippy::unused_unit \
-A clippy::unwrap_or_default \
-A clippy::useless_format \
-A clippy::wrong_self_convention \
-D static_mut_refs"
# ./lint --fix # ./lint --fix
if [[ "$1" == "--fix" ]]; then if [[ "$1" == "--fix" ]]; then
cargo clippy \ cargo clippy \
--fix --allow-dirty \ --fix --allow-dirty \
--target=wasm32-unknown-emscripten \ --target=wasm32-unknown-emscripten \
--all-targets \
-- -D warnings \ -- -D warnings \
$ALLOWED_RULES $ALLOWED_RULES
else else
cargo clippy \ cargo clippy \
--target=wasm32-unknown-emscripten \ --target=wasm32-unknown-emscripten \
--all-targets \
-- -D warnings \ -- -D warnings \
$ALLOWED_RULES $ALLOWED_RULES
fi fi
RESULT=$?
popd popd
exit $RESULT

View file

@ -435,8 +435,7 @@ pub extern "C" fn propagate_apply() -> *mut u8 {
let center = result_bound.center(); let center = result_bound.center();
let transform = result_bound.transform_matrix().unwrap_or(Matrix::default()); let transform = result_bound.transform_matrix().unwrap_or(Matrix::default());
let mut bytes = Vec::<u8>::with_capacity(40); let mut bytes = vec![0; 40];
bytes.resize(40, 0);
bytes[0..4].clone_from_slice(&width.to_le_bytes()); bytes[0..4].clone_from_slice(&width.to_le_bytes());
bytes[4..8].clone_from_slice(&height.to_le_bytes()); bytes[4..8].clone_from_slice(&height.to_le_bytes());
bytes[8..12].clone_from_slice(&center.x.to_le_bytes()); bytes[8..12].clone_from_slice(&center.x.to_le_bytes());
@ -447,8 +446,9 @@ pub extern "C" fn propagate_apply() -> *mut u8 {
bytes[28..32].clone_from_slice(&transform[4].to_le_bytes()); bytes[28..32].clone_from_slice(&transform[4].to_le_bytes());
bytes[32..36].clone_from_slice(&transform[2].to_le_bytes()); bytes[32..36].clone_from_slice(&transform[2].to_le_bytes());
bytes[36..40].clone_from_slice(&transform[5].to_le_bytes()); bytes[36..40].clone_from_slice(&transform[5].to_le_bytes());
return mem::write_bytes(bytes);
}); mem::write_bytes(bytes)
})
} }
#[no_mangle] #[no_mangle]

View file

@ -64,7 +64,7 @@ impl Bounds {
Self { nw, ne, se, sw } Self { nw, ne, se, sw }
} }
pub fn join_bounds(bounds: &Vec<&Bounds>) -> Self { pub fn join_bounds(bounds: &[&Bounds]) -> Self {
let (min_x, min_y, max_x, max_y) = let (min_x, min_y, max_x, max_y) =
bounds bounds
.iter() .iter()
@ -133,11 +133,13 @@ impl Bounds {
self.sw = mtx.map_point(self.sw); self.sw = mtx.map_point(self.sw);
} }
// FIXME: this looks like this should be a try_from static method or similar
pub fn box_bounds(&self, other: &Self) -> Option<Self> { pub fn box_bounds(&self, other: &Self) -> Option<Self> {
self.from_points(other.points()) self.with_points(other.points())
} }
pub fn from_points(&self, points: Vec<Point>) -> Option<Self> { // FIXME: this looks like this should be a try_from static method or similar
pub fn with_points(&self, points: Vec<Point>) -> Option<Self> {
let hv = self.horizontal_vec(); let hv = self.horizontal_vec();
let vv = self.vertical_vec(); let vv = self.vertical_vec();
@ -312,17 +314,17 @@ impl Bounds {
// TODO: Probably we can improve performance here removing the access // TODO: Probably we can improve performance here removing the access
pub fn flip_x(&self) -> bool { pub fn flip_x(&self) -> bool {
let m = self.transform_matrix().unwrap_or(Matrix::default()); let m = self.transform_matrix().unwrap_or_default();
m.scale_x() < 0.0 m.scale_x() < 0.0
} }
// TODO: Probably we can improve performance here removing the access // TODO: Probably we can improve performance here removing the access
pub fn flip_y(&self) -> bool { pub fn flip_y(&self) -> bool {
let m = self.transform_matrix().unwrap_or(Matrix::default()); let m = self.transform_matrix().unwrap_or_default();
m.scale_y() < 0.0 m.scale_y() < 0.0
} }
pub fn to_rect(&self) -> Rect { pub fn to_rect(self) -> Rect {
Rect::from_ltrb(self.min_x(), self.min_y(), self.max_x(), self.max_y()) Rect::from_ltrb(self.min_x(), self.min_y(), self.max_x(), self.max_y())
} }
@ -387,11 +389,7 @@ pub fn intersect_rays_t(ray1: &Ray, ray2: &Ray) -> Option<f32> {
} }
pub fn intersect_rays(ray1: &Ray, ray2: &Ray) -> Option<Point> { pub fn intersect_rays(ray1: &Ray, ray2: &Ray) -> Option<Point> {
if let Some(t) = intersect_rays_t(ray1, ray2) { intersect_rays_t(ray1, ray2).map(|t| ray1.t(t))
Some(ray1.t(t))
} else {
None
}
} }
/* /*
@ -409,9 +407,7 @@ pub fn resize_matrix(
let scale_height = new_height / child_bounds.height(); let scale_height = new_height / child_bounds.height();
let center = child_bounds.center(); let center = child_bounds.center();
let mut parent_transform = parent_bounds let mut parent_transform = parent_bounds.transform_matrix().unwrap_or_default();
.transform_matrix()
.unwrap_or(Matrix::default());
parent_transform.post_translate(center); parent_transform.post_translate(center);
parent_transform.pre_translate(-center); parent_transform.pre_translate(-center);
@ -423,7 +419,7 @@ pub fn resize_matrix(
scale.post_translate(origin); scale.post_translate(origin);
scale.post_concat(&parent_transform); scale.post_concat(&parent_transform);
scale.pre_translate(-origin); scale.pre_translate(-origin);
scale.pre_concat(&parent_transform_inv); scale.pre_concat(parent_transform_inv);
result.post_concat(&scale); result.post_concat(&scale);
result result
} }

View file

@ -4,7 +4,7 @@ use std::sync::Mutex;
const LAYOUT_ALIGN: usize = 4; const LAYOUT_ALIGN: usize = 4;
static BUFFERU8: Mutex<Option<Box<Vec<u8>>>> = Mutex::new(None); static BUFFERU8: Mutex<Option<Vec<u8>>> = Mutex::new(None);
#[no_mangle] #[no_mangle]
pub extern "C" fn alloc_bytes(len: usize) -> *mut u8 { pub extern "C" fn alloc_bytes(len: usize) -> *mut u8 {
@ -16,28 +16,27 @@ pub extern "C" fn alloc_bytes(len: usize) -> *mut u8 {
unsafe { unsafe {
let layout = Layout::from_size_align_unchecked(len, LAYOUT_ALIGN); let layout = Layout::from_size_align_unchecked(len, LAYOUT_ALIGN);
let ptr = alloc(layout) as *mut u8; let ptr = alloc(layout);
if ptr.is_null() { if ptr.is_null() {
panic!("Allocation failed"); panic!("Allocation failed");
} }
// TODO: Maybe this could be removed. // TODO: Maybe this could be removed.
ptr::write_bytes(ptr, 0, len); ptr::write_bytes(ptr, 0, len);
*guard = Some(Box::new(Vec::from_raw_parts(ptr, len, len))); *guard = Some(Vec::from_raw_parts(ptr, len, len));
ptr ptr
} }
} }
pub fn write_bytes(bytes: Vec<u8>) -> *mut u8 { pub fn write_bytes(mut bytes: Vec<u8>) -> *mut u8 {
let mut guard = BUFFERU8.lock().unwrap(); let mut guard = BUFFERU8.lock().unwrap();
if guard.is_some() { if guard.is_some() {
panic!("Bytes already allocated"); panic!("Bytes already allocated");
} }
let mut new_buffer = Box::new(bytes); let ptr = bytes.as_mut_ptr();
let ptr = new_buffer.as_mut_ptr();
*guard = Some(new_buffer); *guard = Some(bytes);
ptr ptr
} }
@ -50,16 +49,12 @@ pub extern "C" fn free_bytes() {
pub fn bytes() -> Vec<u8> { pub fn bytes() -> Vec<u8> {
let mut guard = BUFFERU8.lock().unwrap(); let mut guard = BUFFERU8.lock().unwrap();
guard.take().expect("Buffer is not initialized")
guard
.take()
.map_or_else(|| panic!("Buffer is not initialized"), |buffer| *buffer)
} }
pub fn bytes_or_empty() -> Vec<u8> { pub fn bytes_or_empty() -> Vec<u8> {
let mut guard = BUFFERU8.lock().unwrap(); let mut guard = BUFFERU8.lock().unwrap();
guard.take().unwrap_or_default()
guard.take().map_or_else(|| Vec::new(), |buffer| *buffer)
} }
pub trait SerializableResult { pub trait SerializableResult {
@ -77,14 +72,13 @@ pub trait SerializableResult {
pub fn write_vec<T: SerializableResult>(result: Vec<T>) -> *mut u8 { pub fn write_vec<T: SerializableResult>(result: Vec<T>) -> *mut u8 {
let elem_size = size_of::<T::BytesType>(); let elem_size = size_of::<T::BytesType>();
let bytes_len = 4 + result.len() * elem_size; let bytes_len = 4 + result.len() * elem_size;
let mut result_bytes = Vec::<u8>::with_capacity(bytes_len); let mut result_bytes = vec![0; bytes_len];
result_bytes.resize(bytes_len, 0);
result_bytes[0..4].clone_from_slice(&result.len().to_le_bytes()); result_bytes[0..4].clone_from_slice(&result.len().to_le_bytes());
for i in 0..result.len() { for (i, item) in result.iter().enumerate() {
let base = 4 + i * elem_size; let base = 4 + i * elem_size;
result[i].clone_to_slice(&mut result_bytes[base..base + elem_size]); item.clone_to_slice(&mut result_bytes[base..base + elem_size]);
} }
write_bytes(result_bytes) write_bytes(result_bytes)

View file

@ -20,7 +20,7 @@ macro_rules! mark {
($name:expr) => { ($name:expr) => {
#[cfg(all(feature = "profile-macros", target_arch = "wasm32"))] #[cfg(all(feature = "profile-macros", target_arch = "wasm32"))]
{ {
use crate::run_script; use $crate::run_script;
run_script!(format!("performance.mark('{}')", $name)); run_script!(format!("performance.mark('{}')", $name));
} }
}; };
@ -31,14 +31,14 @@ macro_rules! measure {
($name:expr) => { ($name:expr) => {
#[cfg(all(feature = "profile-macros", target_arch = "wasm32"))] #[cfg(all(feature = "profile-macros", target_arch = "wasm32"))]
{ {
use crate::run_script; use $crate::run_script;
run_script!(format!("performance.measure('{}')", $name)); run_script!(format!("performance.measure('{}')", $name));
} }
}; };
($name:expr, $mark_begin:expr) => { ($name:expr, $mark_begin:expr) => {
#[cfg(all(feature = "profile-macros", target_arch = "wasm32"))] #[cfg(all(feature = "profile-macros", target_arch = "wasm32"))]
{ {
use crate::run_script; use $crate::run_script;
run_script!(format!( run_script!(format!(
"performance.measure('{}','{}')", "performance.measure('{}','{}')",
$name, $mark_begin $name, $mark_begin
@ -48,7 +48,7 @@ macro_rules! measure {
($name:expr, $mark_begin:expr, $mark_end:expr) => { ($name:expr, $mark_begin:expr, $mark_end:expr) => {
#[cfg(all(feature = "profile-macros", target_arch = "wasm32"))] #[cfg(all(feature = "profile-macros", target_arch = "wasm32"))]
{ {
use crate::run_script; use $crate::run_script;
run_script!(format!( run_script!(format!(
"performance.measure('{}','{}','{}')", "performance.measure('{}','{}','{}')",
$name, $mark_begin, $mark_end $name, $mark_begin, $mark_end
@ -76,7 +76,7 @@ macro_rules! measure_marks {
($name:expr) => { ($name:expr) => {
#[cfg(all(feature = "profile-macros", target_arch = "wasm32"))] #[cfg(all(feature = "profile-macros", target_arch = "wasm32"))]
{ {
use crate::{begin_mark_name, end_mark_name, measure}; use $crate::{begin_mark_name, end_mark_name, measure};
measure!($name, begin_mark_name!($name), end_mark_name!($name)); measure!($name, begin_mark_name!($name), end_mark_name!($name));
} }
}; };
@ -85,7 +85,7 @@ macro_rules! measure_marks {
#[macro_export] #[macro_export]
macro_rules! clear_marks { macro_rules! clear_marks {
() => { () => {
use crate::run_script; use $crate::run_script;
run_script!("performance.clearMarks()"); run_script!("performance.clearMarks()");
}; };
($($name:expr),*) => { ($($name:expr),*) => {
@ -96,7 +96,7 @@ macro_rules! clear_marks {
#[macro_export] #[macro_export]
macro_rules! clear_measures { macro_rules! clear_measures {
() => { () => {
use crate::run_script; use $crate::run_script;
run_script!("performance.clearMeasures()"); run_script!("performance.clearMeasures()");
}; };
($($name:expr),*) => { ($($name:expr),*) => {
@ -109,14 +109,14 @@ macro_rules! begin_measure {
($name:expr) => { ($name:expr) => {
#[cfg(all(feature = "profile-macros", target_arch = "wasm32"))] #[cfg(all(feature = "profile-macros", target_arch = "wasm32"))]
{ {
use crate::{begin_mark_name, mark}; use $crate::{begin_mark_name, mark};
mark!(begin_mark_name!($name)); mark!(begin_mark_name!($name));
} }
}; };
($name:expr, $clear_marks:expr) => { ($name:expr, $clear_marks:expr) => {
#[cfg(all(feature = "profile-macros", target_arch = "wasm32"))] #[cfg(all(feature = "profile-macros", target_arch = "wasm32"))]
{ {
use crate::{begin_mark_name, clear_marks, end_mark_name, mark}; use $crate::{begin_mark_name, clear_marks, end_mark_name, mark};
if $clear_marks { if $clear_marks {
clear_marks!(begin_mark_name!($name), end_mark_name($name)); clear_marks!(begin_mark_name!($name), end_mark_name($name));
} }
@ -130,7 +130,7 @@ macro_rules! end_measure {
($name:expr) => { ($name:expr) => {
#[cfg(all(feature = "profile-macros", target_arch = "wasm32"))] #[cfg(all(feature = "profile-macros", target_arch = "wasm32"))]
{ {
use crate::{end_mark_name, mark, measure_marks}; use $crate::{end_mark_name, mark, measure_marks};
mark!(end_mark_name!($name)); mark!(end_mark_name!($name));
measure_marks!($name); measure_marks!($name);
} }
@ -138,7 +138,7 @@ macro_rules! end_measure {
($name:expr, $clear_marks:expr) => { ($name:expr, $clear_marks:expr) => {
#[cfg(all(feature = "profile-macros", target_arch = "wasm32"))] #[cfg(all(feature = "profile-macros", target_arch = "wasm32"))]
{ {
use crate::{begin_mark_name, clear_marks, end_mark_name, mark, measure_marks}; use $crate::{begin_mark_name, clear_marks, end_mark_name, mark, measure_marks};
mark!(end_mark_name!($name)); mark!(end_mark_name!($name));
measure_marks!($name); measure_marks!($name);
if $clear_marks { if $clear_marks {

View file

@ -343,7 +343,7 @@ impl RenderState {
let mut shape = shape.clone(); let mut shape = shape.clone();
if let Some(modifiers) = modifiers { if let Some(modifiers) = modifiers {
shape.apply_transform(&modifiers); shape.apply_transform(modifiers);
} }
let center = shape.center(); let center = shape.center();
@ -354,14 +354,14 @@ impl RenderState {
match &shape.shape_type { match &shape.shape_type {
Type::SVGRaw(sr) => { Type::SVGRaw(sr) => {
if let Some(modifiers) = modifiers { if let Some(modifiers) = modifiers {
self.surfaces.canvas(SurfaceId::Fills).concat(&modifiers); self.surfaces.canvas(SurfaceId::Fills).concat(modifiers);
} }
self.surfaces.canvas(SurfaceId::Fills).concat(&matrix); self.surfaces.canvas(SurfaceId::Fills).concat(&matrix);
if let Some(svg) = shape.svg.as_ref() { if let Some(svg) = shape.svg.as_ref() {
svg.render(self.surfaces.canvas(SurfaceId::Fills)) svg.render(self.surfaces.canvas(SurfaceId::Fills))
} else { } else {
let font_manager = skia::FontMgr::from(self.fonts().font_provider().clone()); let font_manager = skia::FontMgr::from(self.fonts().font_provider().clone());
let dom_result = skia::svg::Dom::from_str(sr.content.to_string(), font_manager); let dom_result = skia::svg::Dom::from_str(&sr.content, font_manager);
match dom_result { match dom_result {
Ok(dom) => { Ok(dom) => {
dom.render(self.surfaces.canvas(SurfaceId::Fills)); dom.render(self.surfaces.canvas(SurfaceId::Fills));
@ -380,7 +380,7 @@ impl RenderState {
}); });
let text_content = text_content.new_bounds(shape.selrect()); let text_content = text_content.new_bounds(shape.selrect());
let paragraphs = text_content.get_skia_paragraphs(&self.fonts.font_collection()); let paragraphs = text_content.get_skia_paragraphs(self.fonts.font_collection());
shadows::render_text_drop_shadows(self, &shape, &paragraphs, antialias); shadows::render_text_drop_shadows(self, &shape, &paragraphs, antialias);
text::render(self, &shape, &paragraphs, None, None); text::render(self, &shape, &paragraphs, None, None);
@ -390,9 +390,9 @@ impl RenderState {
if let Fill::Image(image_fill) = &stroke.fill { if let Fill::Image(image_fill) = &stroke.fill {
image = self.images.get(&image_fill.id()).cloned(); image = self.images.get(&image_fill.id()).cloned();
} }
let stroke_paints = shape.get_text_stroke_paint(&stroke, image.as_ref()); let stroke_paints = shape.get_text_stroke_paint(stroke, image.as_ref());
let stroke_paragraphs = text_content let stroke_paragraphs = text_content
.get_skia_stroke_paragraphs(&self.fonts.font_collection(), &stroke_paints); .get_skia_stroke_paragraphs(self.fonts.font_collection(), &stroke_paints);
shadows::render_text_drop_shadows(self, &shape, &stroke_paragraphs, antialias); shadows::render_text_drop_shadows(self, &shape, &stroke_paragraphs, antialias);
text::render( text::render(
self, self,
@ -602,8 +602,7 @@ impl RenderState {
// the content and the second one rendering the mask so we need to do // the content and the second one rendering the mask so we need to do
// an extra save_layer to keep all the masked group separate from // an extra save_layer to keep all the masked group separate from
// other already drawn elements. // other already drawn elements.
match element.shape_type { if let Type::Group(group) = element.shape_type {
Type::Group(group) => {
if group.masked { if group.masked {
let paint = skia::Paint::default(); let paint = skia::Paint::default();
let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint); let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint);
@ -612,8 +611,6 @@ impl RenderState {
.save_layer(&layer_rec); .save_layer(&layer_rec);
} }
} }
_ => {}
}
let mut paint = skia::Paint::default(); let mut paint = skia::Paint::default();
paint.set_blend_mode(element.blend_mode().into()); paint.set_blend_mode(element.blend_mode().into());
@ -646,14 +643,11 @@ impl RenderState {
// Because masked groups needs two rendering passes (first drawing // Because masked groups needs two rendering passes (first drawing
// the content and then drawing the mask), we need to do an // the content and then drawing the mask), we need to do an
// extra restore. // extra restore.
match element.shape_type { if let Type::Group(group) = element.shape_type {
Type::Group(group) => {
if group.masked { if group.masked {
self.surfaces.canvas(SurfaceId::Current).restore(); self.surfaces.canvas(SurfaceId::Current).restore();
} }
} }
_ => {}
}
} }
self.surfaces.canvas(SurfaceId::Current).restore(); self.surfaces.canvas(SurfaceId::Current).restore();
} }
@ -746,14 +740,13 @@ impl RenderState {
// If the shape is not in the tile set, then we update // If the shape is not in the tile set, then we update
// it. // it.
if let None = self.tiles.get_tiles_of(node_id) { if self.tiles.get_tiles_of(node_id).is_none() {
self.update_tile_for(element); self.update_tile_for(element);
} }
if visited_children { if visited_children {
if !visited_mask { if !visited_mask {
match element.shape_type { if let Type::Group(group) = element.shape_type {
Type::Group(group) => {
// When we're dealing with masked groups we need to // When we're dealing with masked groups we need to
// do a separate extra step to draw the mask (the last // do a separate extra step to draw the mask (the last
// element of a masked group) and blend (using // element of a masked group) and blend (using
@ -778,8 +771,6 @@ impl RenderState {
} }
} }
} }
_ => {}
}
} }
self.render_shape_exit(element, visited_mask); self.render_shape_exit(element, visited_mask);
continue; continue;
@ -806,7 +797,7 @@ impl RenderState {
if !node_render_state.id.is_nil() { if !node_render_state.id.is_nil() {
self.render_shape(element, modifiers.get(&element.id), clip_bounds); self.render_shape(element, modifiers.get(&element.id), clip_bounds);
} else { } else {
self.apply_drawing_to_render_canvas(Some(&element)); self.apply_drawing_to_render_canvas(Some(element));
} }
// Set the node as visited_children before processing children // Set the node as visited_children before processing children
@ -815,7 +806,7 @@ impl RenderState {
visited_children: true, visited_children: true,
clip_bounds: None, clip_bounds: None,
visited_mask: false, visited_mask: false,
mask: mask, mask,
}); });
if element.is_recursive() { if element.is_recursive() {
@ -874,7 +865,7 @@ impl RenderState {
let Some(root) = tree.get(&Uuid::nil()) else { let Some(root) = tree.get(&Uuid::nil()) else {
return Err(String::from("Root shape not found")); return Err(String::from("Root shape not found"));
}; };
let root_ids = modified_children_ids(&root, structure.get(&root.id)); let root_ids = modified_children_ids(root, structure.get(&root.id));
// If we finish processing every node rendering is complete // If we finish processing every node rendering is complete
// let's check if there are more pending nodes // let's check if there are more pending nodes
@ -912,7 +903,7 @@ impl RenderState {
self.render_in_progress = false; self.render_in_progress = false;
// Cache target surface in a texture // Cache target surface in a texture
self.cached_viewbox = self.viewbox.clone(); self.cached_viewbox = self.viewbox;
self.cached_target_snapshot = Some(self.surfaces.snapshot(SurfaceId::Cache)); self.cached_target_snapshot = Some(self.surfaces.snapshot(SurfaceId::Cache));
if self.options.is_debug_visible() { if self.options.is_debug_visible() {

View file

@ -12,17 +12,17 @@ impl Default for BlendMode {
impl From<i32> for BlendMode { impl From<i32> for BlendMode {
fn from(value: i32) -> Self { fn from(value: i32) -> Self {
if value <= skia::BlendMode::Luminosity as i32 { if value <= skia::BlendMode::Luminosity as i32 {
unsafe { Self(std::mem::transmute(value)) } unsafe { Self(std::mem::transmute::<i32, skia_safe::BlendMode>(value)) }
} else { } else {
Self::default() Self::default()
} }
} }
} }
impl Into<skia::BlendMode> for BlendMode { impl From<BlendMode> for skia::BlendMode {
fn into(self) -> skia::BlendMode { fn from(val: BlendMode) -> Self {
match self { match val {
Self(skia_blend) => skia_blend, BlendMode(skia_blend) => skia_blend,
} }
} }
} }

View file

@ -23,7 +23,7 @@ fn render_debug_view(render_state: &mut RenderState) {
paint.set_color(skia::Color::from_rgb(255, 0, 255)); paint.set_color(skia::Color::from_rgb(255, 0, 255));
paint.set_stroke_width(1.); paint.set_stroke_width(1.);
let rect = get_debug_rect(render_state.viewbox.area.clone()); let rect = get_debug_rect(render_state.viewbox.area);
render_state render_state
.surfaces .surfaces
.canvas(SurfaceId::Debug) .canvas(SurfaceId::Debug)
@ -55,7 +55,7 @@ pub fn render_wasm_label(render_state: &mut RenderState) {
let p = skia::Point::new(width as f32 - 25.0 - scalar, height as f32 - 25.0); let p = skia::Point::new(width as f32 - 25.0 - scalar, height as f32 - 25.0);
let debug_font = render_state.fonts.debug_font(); let debug_font = render_state.fonts.debug_font();
canvas.draw_str(str, p, &debug_font, &paint); canvas.draw_str(str, p, debug_font, &paint);
} }
pub fn render_debug_shape(render_state: &mut RenderState, element: &Shape, intersected: bool) { pub fn render_debug_shape(render_state: &mut RenderState, element: &Shape, intersected: bool) {
@ -90,12 +90,7 @@ pub fn render_debug_tiles_for_viewbox(
let str_rect = format!("{} {} {} {}", sx, sy, ex, ey); let str_rect = format!("{} {} {} {}", sx, sy, ex, ey);
let debug_font = render_state.fonts.debug_font(); let debug_font = render_state.fonts.debug_font();
canvas.draw_str( canvas.draw_str(str_rect, skia::Point::new(100.0, 150.0), debug_font, &paint);
str_rect,
skia::Point::new(100.0, 150.0),
&debug_font,
&paint,
);
} }
// Renders the tiles in the viewbox // Renders the tiles in the viewbox
@ -111,12 +106,7 @@ pub fn render_debug_viewbox_tiles(render_state: &mut RenderState) {
let str_rect = format!("{} {} {} {}", sx, sy, ex, ey); let str_rect = format!("{} {} {} {}", sx, sy, ex, ey);
let debug_font = render_state.fonts.debug_font(); let debug_font = render_state.fonts.debug_font();
canvas.draw_str( canvas.draw_str(str_rect, skia::Point::new(100.0, 100.0), debug_font, &paint);
str_rect,
skia::Point::new(100.0, 100.0),
&debug_font,
&paint,
);
let tile_size = tiles::get_tile_size(scale); let tile_size = tiles::get_tile_size(scale);
for y in sy..=ey { for y in sy..=ey {
@ -131,8 +121,8 @@ pub fn render_debug_viewbox_tiles(render_state: &mut RenderState) {
let p = skia::Point::new(debug_rect.x(), debug_rect.y() - 1.); let p = skia::Point::new(debug_rect.x(), debug_rect.y() - 1.);
let str = format!("{}:{}", x, y); let str = format!("{}:{}", x, y);
let debug_font = render_state.fonts.debug_font(); let debug_font = render_state.fonts.debug_font();
canvas.draw_str(str, p, &debug_font, &paint); canvas.draw_str(str, p, debug_font, &paint);
canvas.draw_rect(&debug_rect, &paint); canvas.draw_rect(debug_rect, &paint);
} }
} }
} }
@ -166,8 +156,8 @@ pub fn render_debug_tiles(render_state: &mut RenderState) {
let str = format!("{}:{} {}", x, y, shape_count); let str = format!("{}:{} {}", x, y, shape_count);
let debug_font = render_state.fonts.debug_font(); let debug_font = render_state.fonts.debug_font();
canvas.draw_str(str, p, &debug_font, &paint); canvas.draw_str(str, p, debug_font, &paint);
canvas.draw_rect(&debug_rect, &paint); canvas.draw_rect(debug_rect, &paint);
} }
} }
} }
@ -219,11 +209,11 @@ pub fn render_workspace_current_tile(
let mut p = skia::Paint::default(); let mut p = skia::Paint::default();
p.set_stroke_width(1.); p.set_stroke_width(1.);
p.set_style(skia::PaintStyle::Stroke); p.set_style(skia::PaintStyle::Stroke);
canvas.draw_rect(&rect, &p); canvas.draw_rect(rect, &p);
let point = skia::Point::new(rect.x() + 10., rect.y() + 20.); let point = skia::Point::new(rect.x() + 10., rect.y() + 20.);
p.set_stroke_width(1.); p.set_stroke_width(1.);
let str = format!("{prefix} {}:{}", tile.0, tile.1); let str = format!("{prefix} {}:{}", tile.0, tile.1);
let debug_font = render_state.fonts.debug_font(); let debug_font = render_state.fonts.debug_font();
canvas.draw_str(str, point, &debug_font, &p); canvas.draw_str(str, point, debug_font, &p);
} }

View file

@ -62,7 +62,7 @@ fn draw_image_fill(
corners: Some(corners), corners: Some(corners),
.. ..
}) => { }) => {
let rrect: RRect = RRect::new_rect_radii(container, &corners); let rrect: RRect = RRect::new_rect_radii(container, corners);
canvas.clip_rrect(rrect, skia::ClipOp::Intersect, antialias); canvas.clip_rrect(rrect, skia::ClipOp::Intersect, antialias);
} }
Type::Rect(_) | Type::Frame(_) => { Type::Rect(_) | Type::Frame(_) => {
@ -77,7 +77,7 @@ fn draw_image_fill(
if let Some(path) = shape_type.path() { if let Some(path) = shape_type.path() {
if let Some(path_transform) = path_transform { if let Some(path_transform) = path_transform {
canvas.clip_path( canvas.clip_path(
&path.to_skia_path().transform(&path_transform), path.to_skia_path().transform(&path_transform),
skia::ClipOp::Intersect, skia::ClipOp::Intersect,
antialias, antialias,
); );
@ -98,7 +98,7 @@ fn draw_image_fill(
None, None,
dest_rect, dest_rect,
render_state.sampling_options, render_state.sampling_options,
&paint, paint,
); );
} }

View file

@ -3,7 +3,7 @@ use skia_safe::{self as skia, textlayout, Font, FontMgr};
use crate::shapes::{FontFamily, FontStyle}; use crate::shapes::{FontFamily, FontStyle};
use crate::uuid::Uuid; use crate::uuid::Uuid;
pub static DEFAULT_EMOJI_FONT: &'static str = "noto-color-emoji"; pub static DEFAULT_EMOJI_FONT: &str = "noto-color-emoji";
const DEFAULT_FONT_BYTES: &[u8] = include_bytes!("../fonts/sourcesanspro-regular.ttf"); const DEFAULT_FONT_BYTES: &[u8] = include_bytes!("../fonts/sourcesanspro-regular.ttf");

View file

@ -1,20 +1,11 @@
use crate::options; use crate::options;
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq, Default)]
pub struct RenderOptions { pub struct RenderOptions {
pub flags: u32, pub flags: u32,
pub dpr: Option<f32>, pub dpr: Option<f32>,
} }
impl Default for RenderOptions {
fn default() -> Self {
Self {
flags: 0x00,
dpr: None,
}
}
}
impl RenderOptions { impl RenderOptions {
pub fn is_debug_visible(&self) -> bool { pub fn is_debug_visible(&self) -> bool {
self.flags & options::DEBUG_VISIBLE == options::DEBUG_VISIBLE self.flags & options::DEBUG_VISIBLE == options::DEBUG_VISIBLE

View file

@ -8,7 +8,7 @@ use skia_safe::{textlayout::Paragraph, Paint};
pub fn render_fill_drop_shadows(render_state: &mut RenderState, shape: &Shape, antialias: bool) { pub fn render_fill_drop_shadows(render_state: &mut RenderState, shape: &Shape, antialias: bool) {
if shape.has_fills() { if shape.has_fills() {
for shadow in shape.drop_shadows().rev().filter(|s| !s.hidden()) { for shadow in shape.drop_shadows().rev().filter(|s| !s.hidden()) {
render_fill_drop_shadow(render_state, &shape, &shadow, antialias); render_fill_drop_shadow(render_state, shape, shadow, antialias);
} }
} }
} }
@ -26,7 +26,7 @@ fn render_fill_drop_shadow(
pub fn render_fill_inner_shadows(render_state: &mut RenderState, shape: &Shape, antialias: bool) { pub fn render_fill_inner_shadows(render_state: &mut RenderState, shape: &Shape, antialias: bool) {
if shape.has_fills() { if shape.has_fills() {
for shadow in shape.inner_shadows().rev().filter(|s| !s.hidden()) { for shadow in shape.inner_shadows().rev().filter(|s| !s.hidden()) {
render_fill_inner_shadow(render_state, &shape, &shadow, antialias); render_fill_inner_shadow(render_state, shape, shadow, antialias);
} }
} }
} }
@ -52,7 +52,7 @@ pub fn render_stroke_drop_shadows(
let filter = shadow.get_drop_shadow_filter(); let filter = shadow.get_drop_shadow_filter();
strokes::render( strokes::render(
render_state, render_state,
&shape, shape,
stroke, stroke,
Some(SurfaceId::Strokes), // FIXME Some(SurfaceId::Strokes), // FIXME
filter.as_ref(), filter.as_ref(),
@ -73,7 +73,7 @@ pub fn render_stroke_inner_shadows(
let filter = shadow.get_inner_shadow_filter(); let filter = shadow.get_inner_shadow_filter();
strokes::render( strokes::render(
render_state, render_state,
&shape, shape,
stroke, stroke,
Some(SurfaceId::Strokes), // FIXME Some(SurfaceId::Strokes), // FIXME
filter.as_ref(), filter.as_ref(),
@ -90,7 +90,7 @@ pub fn render_text_drop_shadows(
antialias: bool, antialias: bool,
) { ) {
for shadow in shape.drop_shadows().rev().filter(|s| !s.hidden()) { for shadow in shape.drop_shadows().rev().filter(|s| !s.hidden()) {
render_text_drop_shadow(render_state, &shape, &shadow, &paragraphs, antialias); render_text_drop_shadow(render_state, shape, shadow, paragraphs, antialias);
} }
} }
@ -101,12 +101,12 @@ pub fn render_text_drop_shadow(
paragraphs: &[Vec<Paragraph>], paragraphs: &[Vec<Paragraph>],
antialias: bool, antialias: bool,
) { ) {
let paint = &shadow.get_drop_shadow_paint(antialias); let paint = shadow.get_drop_shadow_paint(antialias);
text::render( text::render(
render_state, render_state,
shape, shape,
&paragraphs, paragraphs,
Some(SurfaceId::DropShadows), Some(SurfaceId::DropShadows),
Some(paint), Some(paint),
); );
@ -119,7 +119,7 @@ pub fn render_text_inner_shadows(
antialias: bool, antialias: bool,
) { ) {
for shadow in shape.inner_shadows().rev().filter(|s| !s.hidden()) { for shadow in shape.inner_shadows().rev().filter(|s| !s.hidden()) {
render_text_inner_shadow(render_state, &shape, &shadow, &paragraphs, antialias); render_text_inner_shadow(render_state, shape, shadow, paragraphs, antialias);
} }
} }
@ -130,12 +130,12 @@ pub fn render_text_inner_shadow(
paragraphs: &[Vec<Paragraph>], paragraphs: &[Vec<Paragraph>],
antialias: bool, antialias: bool,
) { ) {
let paint = &shadow.get_inner_shadow_paint(antialias); let paint = shadow.get_inner_shadow_paint(antialias);
text::render( text::render(
render_state, render_state,
shape, shape,
&paragraphs, paragraphs,
Some(SurfaceId::InnerShadows), Some(SurfaceId::InnerShadows),
Some(paint), Some(paint),
); );

View file

@ -7,6 +7,8 @@ use skia_safe::{self as skia, ImageFilter, RRect};
use super::{RenderState, SurfaceId}; use super::{RenderState, SurfaceId};
// FIXME: See if we can simplify these arguments
#[allow(clippy::too_many_arguments)]
fn draw_stroke_on_rect( fn draw_stroke_on_rect(
canvas: &skia::Canvas, canvas: &skia::Canvas,
stroke: &Stroke, stroke: &Stroke,
@ -36,11 +38,13 @@ fn draw_stroke_on_rect(
canvas.draw_rrect(rrect, &paint); canvas.draw_rrect(rrect, &paint);
} }
None => { None => {
canvas.draw_rect(&stroke_rect, &paint); canvas.draw_rect(stroke_rect, &paint);
} }
} }
} }
// FIXME: See if we can simplify these arguments
#[allow(clippy::too_many_arguments)]
fn draw_stroke_on_circle( fn draw_stroke_on_circle(
canvas: &skia::Canvas, canvas: &skia::Canvas,
stroke: &Stroke, stroke: &Stroke,
@ -62,9 +66,11 @@ fn draw_stroke_on_circle(
paint.set_image_filter(filter.clone()); paint.set_image_filter(filter.clone());
} }
canvas.draw_oval(&stroke_rect, &paint); canvas.draw_oval(stroke_rect, &paint);
} }
// FIXME: See if we can simplify these arguments
#[allow(clippy::too_many_arguments)]
pub fn draw_stroke_on_path( pub fn draw_stroke_on_path(
canvas: &skia::Canvas, canvas: &skia::Canvas,
stroke: &Stroke, stroke: &Stroke,
@ -90,18 +96,18 @@ pub fn draw_stroke_on_path(
// Draw the different kind of strokes for a path requires different strategies: // Draw the different kind of strokes for a path requires different strategies:
match stroke.render_kind(is_open) { match stroke.render_kind(is_open) {
// For inner stroke we draw a center stroke (with double width) and clip to the original path (that way the extra outer stroke is removed) // For inner stroke we draw a center stroke (with double width) and clip to the original path (that way the extra outer stroke is removed)
StrokeKind::InnerStroke => { StrokeKind::Inner => {
canvas.save(); // As we are using clear for surfaces we use save and restore here to still be able to clean the full surface canvas.save(); // As we are using clear for surfaces we use save and restore here to still be able to clean the full surface
canvas.clip_path(&skia_path, skia::ClipOp::Intersect, antialias); canvas.clip_path(&skia_path, skia::ClipOp::Intersect, antialias);
canvas.draw_path(&skia_path, &paint); canvas.draw_path(&skia_path, &paint);
canvas.restore(); canvas.restore();
} }
// For center stroke we don't need to do anything extra // For center stroke we don't need to do anything extra
StrokeKind::CenterStroke => { StrokeKind::Center => {
canvas.draw_path(&skia_path, &paint); canvas.draw_path(&skia_path, &paint);
} }
// For outer stroke we draw a center stroke (with double width) and use another path with blend mode clear to remove the inner stroke added // For outer stroke we draw a center stroke (with double width) and use another path with blend mode clear to remove the inner stroke added
StrokeKind::OuterStroke => { StrokeKind::Outer => {
let mut outer_paint = skia::Paint::default(); let mut outer_paint = skia::Paint::default();
outer_paint.set_blend_mode(skia::BlendMode::SrcOver); outer_paint.set_blend_mode(skia::BlendMode::SrcOver);
outer_paint.set_anti_alias(antialias); outer_paint.set_anti_alias(antialias);
@ -121,7 +127,7 @@ pub fn draw_stroke_on_path(
handle_stroke_caps( handle_stroke_caps(
&mut skia_path, &mut skia_path,
stroke, stroke,
&selrect, selrect,
canvas, canvas,
is_open, is_open,
svg_attrs, svg_attrs,
@ -144,31 +150,33 @@ fn handle_stroke_cap(
StrokeCap::None => {} StrokeCap::None => {}
StrokeCap::Line => { StrokeCap::Line => {
// We also draw this square cap to fill the gap between the path and the arrow // We also draw this square cap to fill the gap between the path and the arrow
draw_square_cap(canvas, &paint, p1, p2, width, 0.); draw_square_cap(canvas, paint, p1, p2, width, 0.);
paint.set_style(skia::PaintStyle::Stroke); paint.set_style(skia::PaintStyle::Stroke);
draw_arrow_cap(canvas, &paint, p1, p2, width * 4.); draw_arrow_cap(canvas, paint, p1, p2, width * 4.);
} }
StrokeCap::Triangle => { StrokeCap::Triangle => {
draw_triangle_cap(canvas, &paint, p1, p2, width * 4.); draw_triangle_cap(canvas, paint, p1, p2, width * 4.);
} }
StrokeCap::Rectangle => { StrokeCap::Rectangle => {
draw_square_cap(canvas, &paint, p1, p2, width * 4., 0.); draw_square_cap(canvas, paint, p1, p2, width * 4., 0.);
} }
StrokeCap::Circle => { StrokeCap::Circle => {
canvas.draw_circle((p1.x, p1.y), width * 2., &paint); canvas.draw_circle((p1.x, p1.y), width * 2., paint);
} }
StrokeCap::Diamond => { StrokeCap::Diamond => {
draw_square_cap(canvas, &paint, p1, p2, width * 4., 45.); draw_square_cap(canvas, paint, p1, p2, width * 4., 45.);
} }
StrokeCap::Round => { StrokeCap::Round => {
canvas.draw_circle((p1.x, p1.y), width / 2.0, &paint); canvas.draw_circle((p1.x, p1.y), width / 2.0, paint);
} }
StrokeCap::Square => { StrokeCap::Square => {
draw_square_cap(canvas, &paint, p1, p2, width, 0.); draw_square_cap(canvas, paint, p1, p2, width, 0.);
} }
} }
} }
// FIXME: See if we can simplify these arguments
#[allow(clippy::too_many_arguments)]
fn handle_stroke_caps( fn handle_stroke_caps(
path: &mut skia::Path, path: &mut skia::Path,
stroke: &Stroke, stroke: &Stroke,
@ -238,7 +246,7 @@ fn draw_square_cap(
Point::new(rect.left(), rect.bottom()), Point::new(rect.left(), rect.bottom()),
]; ];
let mut transformed_points = points.clone(); let mut transformed_points = points;
matrix.map_points(&mut transformed_points, &points); matrix.map_points(&mut transformed_points, &points);
let mut path = skia::Path::new(); let mut path = skia::Path::new();
@ -272,7 +280,7 @@ fn draw_arrow_cap(
Point::new(center.x + size, center.y + half_height), Point::new(center.x + size, center.y + half_height),
]; ];
let mut transformed_points = points.clone(); let mut transformed_points = points;
matrix.map_points(&mut transformed_points, &points); matrix.map_points(&mut transformed_points, &points);
let mut path = skia::Path::new(); let mut path = skia::Path::new();
@ -306,7 +314,7 @@ fn draw_triangle_cap(
Point::new(center.x + size, center.y + half_height), Point::new(center.x + size, center.y + half_height),
]; ];
let mut transformed_points = points.clone(); let mut transformed_points = points;
matrix.map_points(&mut transformed_points, &points); matrix.map_points(&mut transformed_points, &points);
let mut path = skia::Path::new(); let mut path = skia::Path::new();
@ -406,11 +414,11 @@ fn draw_image_stroke_in_container(
path.transform(&path_transform.unwrap()); path.transform(&path_transform.unwrap());
let stroke_kind = stroke.render_kind(p.is_open()); let stroke_kind = stroke.render_kind(p.is_open());
match stroke_kind { match stroke_kind {
StrokeKind::InnerStroke => { StrokeKind::Inner => {
canvas.clip_path(&path, skia::ClipOp::Intersect, antialias); canvas.clip_path(&path, skia::ClipOp::Intersect, antialias);
} }
StrokeKind::CenterStroke => {} StrokeKind::Center => {}
StrokeKind::OuterStroke => { StrokeKind::Outer => {
canvas.clip_path(&path, skia::ClipOp::Difference, antialias); canvas.clip_path(&path, skia::ClipOp::Difference, antialias);
} }
} }
@ -418,7 +426,7 @@ fn draw_image_stroke_in_container(
let mut paint = let mut paint =
stroke.to_stroked_paint(is_open, &outer_rect, svg_attrs, scale, antialias); stroke.to_stroked_paint(is_open, &outer_rect, svg_attrs, scale, antialias);
canvas.draw_path(&path, &paint); canvas.draw_path(&path, &paint);
if stroke.render_kind(is_open) == StrokeKind::OuterStroke { if stroke.render_kind(is_open) == StrokeKind::Outer {
// Small extra inner stroke to overlap with the fill // Small extra inner stroke to overlap with the fill
// and avoid unnecesary artifacts. // and avoid unnecesary artifacts.
paint.set_stroke_width(1. / scale); paint.set_stroke_width(1. / scale);
@ -461,7 +469,7 @@ fn draw_image_stroke_in_container(
// Clear outer stroke for paths if necessary. When adding an outer stroke we need to empty the stroke added too in the inner area. // Clear outer stroke for paths if necessary. When adding an outer stroke we need to empty the stroke added too in the inner area.
if let Type::Path(p) = &shape.shape_type { if let Type::Path(p) = &shape.shape_type {
if stroke.render_kind(p.is_open()) == StrokeKind::OuterStroke { if stroke.render_kind(p.is_open()) == StrokeKind::Outer {
let mut path = p.to_skia_path(); let mut path = p.to_skia_path();
path.transform(&path_transform.unwrap()); path.transform(&path_transform.unwrap());
let mut clear_paint = skia::Paint::default(); let mut clear_paint = skia::Paint::default();
@ -494,7 +502,7 @@ pub fn render(
let path_transform = shape.to_path_transform(); let path_transform = shape.to_path_transform();
let svg_attrs = &shape.svg_attrs; let svg_attrs = &shape.svg_attrs;
if !shadow.is_some() && matches!(stroke.fill, Fill::Image(_)) { if shadow.is_none() && matches!(stroke.fill, Fill::Image(_)) {
if let Fill::Image(image_fill) = &stroke.fill { if let Fill::Image(image_fill) = &stroke.fill {
draw_image_stroke_in_container(render_state, shape, stroke, image_fill, antialias); draw_image_stroke_in_container(render_state, shape, stroke, image_fill, antialias);
} }

View file

@ -105,7 +105,7 @@ impl Surfaces {
let encoded_image = image let encoded_image = image
.encode(context.as_mut(), skia::EncodedImageFormat::PNG, None) .encode(context.as_mut(), skia::EncodedImageFormat::PNG, None)
.unwrap(); .unwrap();
general_purpose::STANDARD.encode(&encoded_image.as_bytes()) general_purpose::STANDARD.encode(encoded_image.as_bytes())
} }
pub fn base64_snapshot_rect(&mut self, id: SurfaceId, irect: skia::IRect) -> Option<String> { pub fn base64_snapshot_rect(&mut self, id: SurfaceId, irect: skia::IRect) -> Option<String> {
@ -115,7 +115,7 @@ impl Surfaces {
let encoded_image = image let encoded_image = image
.encode(context.as_mut(), skia::EncodedImageFormat::PNG, None) .encode(context.as_mut(), skia::EncodedImageFormat::PNG, None)
.unwrap(); .unwrap();
return Some(general_purpose::STANDARD.encode(&encoded_image.as_bytes())); return Some(general_purpose::STANDARD.encode(encoded_image.as_bytes()));
} }
None None
} }
@ -137,7 +137,7 @@ impl Surfaces {
.draw(self.canvas(to), (0.0, 0.0), sampling_options, paint); .draw(self.canvas(to), (0.0, 0.0), sampling_options, paint);
} }
pub fn apply_mut(&mut self, ids: &[SurfaceId], mut f: impl FnMut(&mut skia::Surface) -> ()) { pub fn apply_mut(&mut self, ids: &[SurfaceId], mut f: impl FnMut(&mut skia::Surface)) {
for id in ids { for id in ids {
let surface = self.get_mut(*id); let surface = self.get_mut(*id);
f(surface); f(surface);
@ -257,10 +257,10 @@ impl Surfaces {
self.current.height() - TILE_SIZE_MULTIPLIER * self.margins.height, self.current.height() - TILE_SIZE_MULTIPLIER * self.margins.height,
); );
if let Some(snapshot) = self.current.image_snapshot_with_bounds(&rect) { if let Some(snapshot) = self.current.image_snapshot_with_bounds(rect) {
self.tiles.add(tile, snapshot.clone()); self.tiles.add(tile, snapshot.clone());
self.cache.canvas().draw_image_rect( self.cache.canvas().draw_image_rect(
&snapshot.clone(), snapshot.clone(),
None, None,
tile_rect, tile_rect,
&skia::Paint::default(), &skia::Paint::default(),
@ -302,7 +302,7 @@ impl TileTextureCache {
} }
pub fn has(&mut self, tile: Tile) -> bool { pub fn has(&mut self, tile: Tile) -> bool {
return self.grid.contains_key(&tile); self.grid.contains_key(&tile)
} }
fn remove_list(&mut self, marked: Vec<Tile>) { fn remove_list(&mut self, marked: Vec<Tile>) {
@ -318,7 +318,7 @@ impl TileTextureCache {
.iter_mut() .iter_mut()
.filter_map(|(tile, _)| { .filter_map(|(tile, _)| {
if !self.visited.contains_key(tile) { if !self.visited.contains_key(tile) {
Some(tile.clone()) Some(*tile)
} else { } else {
None None
} }

View file

@ -1,15 +1,15 @@
use super::{RenderState, Shape, SurfaceId}; use super::{RenderState, Shape, SurfaceId};
use skia_safe::{self as skia, canvas::SaveLayerRec, paint, textlayout::Paragraph}; use skia_safe::{self as skia, canvas::SaveLayerRec, textlayout::Paragraph};
pub fn render( pub fn render(
render_state: &mut RenderState, render_state: &mut RenderState,
shape: &Shape, shape: &Shape,
paragraphs: &[Vec<Paragraph>], paragraphs: &[Vec<Paragraph>],
surface_id: Option<SurfaceId>, surface_id: Option<SurfaceId>,
paint: Option<&paint::Paint>, paint: Option<skia::Paint>,
) { ) {
let default_paint = skia::Paint::default(); let mask_paint = paint.unwrap_or_default();
let mask = SaveLayerRec::default().paint(&paint.unwrap_or(&default_paint)); let mask = SaveLayerRec::default().paint(&mask_paint);
let canvas = render_state let canvas = render_state
.surfaces .surfaces
.canvas(surface_id.unwrap_or(SurfaceId::Fills)); .canvas(surface_id.unwrap_or(SurfaceId::Fills));

View file

@ -74,7 +74,7 @@ impl TileHashMap {
} }
pub fn get_shapes_at(&mut self, tile: Tile) -> Option<&IndexSet<Uuid>> { pub fn get_shapes_at(&mut self, tile: Tile) -> Option<&IndexSet<Uuid>> {
return self.grid.get(&tile); self.grid.get(&tile)
} }
pub fn remove_shape_at(&mut self, tile: Tile, id: Uuid) { pub fn remove_shape_at(&mut self, tile: Tile, id: Uuid) {
@ -92,13 +92,8 @@ impl TileHashMap {
} }
pub fn add_shape_at(&mut self, tile: Tile, shape_id: Uuid) { pub fn add_shape_at(&mut self, tile: Tile, shape_id: Uuid) {
if !self.grid.contains_key(&tile) { self.grid.entry(tile).or_default();
self.grid.insert(tile, IndexSet::new()); self.index.entry(shape_id).or_default();
}
if !self.index.contains_key(&shape_id) {
self.index.insert(shape_id, HashSet::new());
}
let tile_set = self.grid.get_mut(&tile).unwrap(); let tile_set = self.grid.get_mut(&tile).unwrap();
tile_set.insert(shape_id); tile_set.insert(shape_id);

View file

@ -224,31 +224,26 @@ impl Shape {
} }
pub fn has_layout(&self) -> bool { pub fn has_layout(&self) -> bool {
match self.shape_type { matches!(
self.shape_type,
Type::Frame(Frame { Type::Frame(Frame {
layout: Some(_), .. layout: Some(_),
}) => true, ..
_ => false, })
} )
} }
pub fn set_selrect(&mut self, left: f32, top: f32, right: f32, bottom: f32) { pub fn set_selrect(&mut self, left: f32, top: f32, right: f32, bottom: f32) {
self.selrect.set_ltrb(left, top, right, bottom); self.selrect.set_ltrb(left, top, right, bottom);
match self.shape_type { if let Type::Text(ref mut text) = self.shape_type {
Type::Text(ref mut text) => {
text.set_xywh(left, top, right - left, bottom - top); text.set_xywh(left, top, right - left, bottom - top);
} }
_ => {}
}
} }
pub fn set_masked(&mut self, masked: bool) { pub fn set_masked(&mut self, masked: bool) {
match &mut self.shape_type { if let Type::Group(data) = &mut self.shape_type {
Type::Group(data) => {
data.masked = masked; data.masked = masked;
} }
_ => {}
}
} }
pub fn set_clip(&mut self, value: bool) { pub fn set_clip(&mut self, value: bool) {
@ -272,7 +267,7 @@ impl Shape {
} }
pub fn constraint_h(&self, default: ConstraintH) -> ConstraintH { pub fn constraint_h(&self, default: ConstraintH) -> ConstraintH {
self.constraint_h.clone().unwrap_or(default) self.constraint_h.unwrap_or(default)
} }
pub fn set_constraint_v(&mut self, constraint: Option<ConstraintV>) { pub fn set_constraint_v(&mut self, constraint: Option<ConstraintV>) {
@ -280,13 +275,15 @@ impl Shape {
} }
pub fn constraint_v(&self, default: ConstraintV) -> ConstraintV { pub fn constraint_v(&self, default: ConstraintV) -> ConstraintV {
self.constraint_v.clone().unwrap_or(default) self.constraint_v.unwrap_or(default)
} }
pub fn set_hidden(&mut self, value: bool) { pub fn set_hidden(&mut self, value: bool) {
self.hidden = value; self.hidden = value;
} }
// FIXME: These arguments could be grouped or simplified
#[allow(clippy::too_many_arguments)]
pub fn set_flex_layout_child_data( pub fn set_flex_layout_child_data(
&mut self, &mut self,
margin_top: f32, margin_top: f32,
@ -320,6 +317,8 @@ impl Shape {
}); });
} }
// FIXME: These arguments could be grouped or simplified
#[allow(clippy::too_many_arguments)]
pub fn set_flex_layout_data( pub fn set_flex_layout_data(
&mut self, &mut self,
direction: FlexDirection, direction: FlexDirection,
@ -335,8 +334,7 @@ impl Shape {
padding_bottom: f32, padding_bottom: f32,
padding_left: f32, padding_left: f32,
) { ) {
match &mut self.shape_type { if let Type::Frame(data) = &mut self.shape_type {
Type::Frame(data) => {
let layout_data = LayoutData { let layout_data = LayoutData {
align_items, align_items,
align_content, align_content,
@ -357,10 +355,10 @@ impl Shape {
data.layout = Some(Layout::FlexLayout(layout_data, flex_data)); data.layout = Some(Layout::FlexLayout(layout_data, flex_data));
} }
_ => {}
}
} }
// FIXME: These arguments could be grouped or simplified
#[allow(clippy::too_many_arguments)]
pub fn set_grid_layout_data( pub fn set_grid_layout_data(
&mut self, &mut self,
direction: GridDirection, direction: GridDirection,
@ -375,8 +373,7 @@ impl Shape {
padding_bottom: f32, padding_bottom: f32,
padding_left: f32, padding_left: f32,
) { ) {
match &mut self.shape_type { if let Type::Frame(data) = &mut self.shape_type {
Type::Frame(data) => {
let layout_data = LayoutData { let layout_data = LayoutData {
align_items, align_items,
align_content, align_content,
@ -394,8 +391,6 @@ impl Shape {
grid_data.direction = direction; grid_data.direction = direction;
data.layout = Some(Layout::GridLayout(layout_data, grid_data)); data.layout = Some(Layout::GridLayout(layout_data, grid_data));
} }
_ => {}
}
} }
pub fn set_grid_columns(&mut self, tracks: Vec<RawGridTrack>) { pub fn set_grid_columns(&mut self, tracks: Vec<RawGridTrack>) {
@ -578,7 +573,7 @@ impl Shape {
); );
let center = self.center(); let center = self.center();
let mut matrix = self.transform.clone(); let mut matrix = self.transform;
matrix.post_translate(center); matrix.post_translate(center);
matrix.pre_translate(-center); matrix.pre_translate(-center);
@ -595,7 +590,7 @@ impl Shape {
let mut rect = self.bounds().to_rect(); let mut rect = self.bounds().to_rect();
for shadow in self.shadows.iter() { for shadow in self.shadows.iter() {
let (x, y) = shadow.offset; let (x, y) = shadow.offset;
let mut shadow_rect = rect.clone(); let mut shadow_rect = rect;
shadow_rect.left += x; shadow_rect.left += x;
shadow_rect.right += x; shadow_rect.right += x;
shadow_rect.top += y; shadow_rect.top += y;
@ -717,13 +712,10 @@ impl Shape {
} }
pub fn clear_text(&mut self) { pub fn clear_text(&mut self) {
match &self.shape_type { if let Type::Text(old_text_content) = &self.shape_type {
Type::Text(old_text_content) => {
let new_text_content = TextContent::new(self.selrect, old_text_content.grow_type()); let new_text_content = TextContent::new(self.selrect, old_text_content.grow_type());
self.shape_type = Type::Text(new_text_content); self.shape_type = Type::Text(new_text_content);
} }
_ => {}
}
} }
pub fn get_skia_path(&self) -> Option<skia::Path> { pub fn get_skia_path(&self) -> Option<skia::Path> {
@ -745,8 +737,8 @@ impl Shape {
let mut center = self.selrect.center(); let mut center = self.selrect.center();
center = transform.map_point(center); center = transform.map_point(center);
let bounds = self.bounds().transform(&transform); let bounds = self.bounds().transform(transform);
self.transform = bounds.transform_matrix().unwrap_or(Matrix::default()); self.transform = bounds.transform_matrix().unwrap_or_default();
let width = bounds.width(); let width = bounds.width();
let height = bounds.height(); let height = bounds.height();
@ -761,15 +753,12 @@ impl Shape {
} }
pub fn apply_transform(&mut self, transform: &Matrix) { pub fn apply_transform(&mut self, transform: &Matrix) {
self.transform_selrect(&transform); self.transform_selrect(transform);
match &mut self.shape_type { if let shape_type @ (Type::Path(_) | Type::Bool(_)) = &mut self.shape_type {
shape_type @ (Type::Path(_) | Type::Bool(_)) => {
if let Some(path) = shape_type.path_mut() { if let Some(path) = shape_type.path_mut() {
path.transform(&transform); path.transform(transform);
} }
} }
_ => {}
}
} }
pub fn is_absolute(&self) -> bool { pub fn is_absolute(&self) -> bool {
@ -852,7 +841,7 @@ impl Shape {
let mut paints = Vec::new(); let mut paints = Vec::new();
match stroke.kind { match stroke.kind {
StrokeKind::InnerStroke => { StrokeKind::Inner => {
let mut paint = skia::Paint::default(); let mut paint = skia::Paint::default();
paint.set_blend_mode(skia::BlendMode::DstOver); paint.set_blend_mode(skia::BlendMode::DstOver);
paint.set_anti_alias(true); paint.set_anti_alias(true);
@ -868,7 +857,7 @@ impl Shape {
paints.push(paint); paints.push(paint);
} }
StrokeKind::CenterStroke => { StrokeKind::Center => {
let mut paint = skia::Paint::default(); let mut paint = skia::Paint::default();
paint.set_style(skia::PaintStyle::Stroke); paint.set_style(skia::PaintStyle::Stroke);
paint.set_anti_alias(true); paint.set_anti_alias(true);
@ -878,7 +867,7 @@ impl Shape {
paints.push(paint); paints.push(paint);
} }
StrokeKind::OuterStroke => { StrokeKind::Outer => {
let mut paint = skia::Paint::default(); let mut paint = skia::Paint::default();
paint.set_style(skia::PaintStyle::Stroke); paint.set_style(skia::PaintStyle::Stroke);
paint.set_blend_mode(skia::BlendMode::DstOver); paint.set_blend_mode(skia::BlendMode::DstOver);
@ -908,7 +897,7 @@ pub fn modified_children_ids(
structure: Option<&Vec<StructureEntry>>, structure: Option<&Vec<StructureEntry>>,
) -> IndexSet<Uuid> { ) -> IndexSet<Uuid> {
if let Some(structure) = structure { if let Some(structure) = structure {
let mut result: Vec<Uuid> = Vec::from_iter(element.children_ids().iter().map(|id| *id)); let mut result: Vec<Uuid> = Vec::from_iter(element.children_ids().iter().copied());
let mut to_remove = HashSet::<&Uuid>::new(); let mut to_remove = HashSet::<&Uuid>::new();
for st in structure { for st in structure {
@ -925,7 +914,7 @@ pub fn modified_children_ids(
let ret: IndexSet<Uuid> = result let ret: IndexSet<Uuid> = result
.iter() .iter()
.filter(|id| !to_remove.contains(id)) .filter(|id| !to_remove.contains(id))
.map(|id| *id) .copied()
.collect(); .collect();
ret ret
@ -949,7 +938,7 @@ mod tests {
shape.add_fill(Fill::Solid(SolidColor(Color::TRANSPARENT))); shape.add_fill(Fill::Solid(SolidColor(Color::TRANSPARENT)));
assert_eq!( assert_eq!(
shape.fills.get(0), shape.fills.first(),
Some(&Fill::Solid(SolidColor(Color::TRANSPARENT))) Some(&Fill::Solid(SolidColor(Color::TRANSPARENT)))
) )
} }
@ -969,7 +958,7 @@ mod tests {
]) ])
); );
} else { } else {
assert!(false); unreachable!();
} }
} }
@ -980,9 +969,9 @@ mod tests {
shape.set_masked(true); shape.set_masked(true);
if let Type::Group(Group { masked, .. }) = shape.shape_type { if let Type::Group(Group { masked, .. }) = shape.shape_type {
assert_eq!(masked, true); assert!(masked);
} else { } else {
assert!(false); unreachable!()
} }
} }

View file

@ -312,26 +312,23 @@ pub struct FlexData {
impl FlexData { impl FlexData {
pub fn is_reverse(&self) -> bool { pub fn is_reverse(&self) -> bool {
match &self.direction { matches!(
FlexDirection::RowReverse | FlexDirection::ColumnReverse => true, &self.direction,
_ => false, FlexDirection::RowReverse | FlexDirection::ColumnReverse
} )
} }
pub fn is_row(&self) -> bool { pub fn is_row(&self) -> bool {
match &self.direction { matches!(
FlexDirection::RowReverse | FlexDirection::Row => true, &self.direction,
_ => false, FlexDirection::RowReverse | FlexDirection::Row
} )
} }
} }
impl FlexData { impl FlexData {
pub fn is_wrap(&self) -> bool { pub fn is_wrap(&self) -> bool {
match self.wrap_type { matches!(self.wrap_type, WrapType::Wrap)
WrapType::Wrap => true,
_ => false,
}
} }
} }

View file

@ -25,7 +25,7 @@ fn propagate_children(
) -> VecDeque<Modifier> { ) -> VecDeque<Modifier> {
let children_ids = modified_children_ids(shape, structure.get(&shape.id)); let children_ids = modified_children_ids(shape, structure.get(&shape.id));
if children_ids.len() == 0 || identitish(transform) { if children_ids.is_empty() || identitish(transform) {
return VecDeque::new(); return VecDeque::new();
} }
@ -67,8 +67,8 @@ fn propagate_children(
}; };
let transform = constraints::propagate_shape_constraints( let transform = constraints::propagate_shape_constraints(
&parent_bounds_before, parent_bounds_before,
&parent_bounds_after, parent_bounds_after,
&child_bounds, &child_bounds,
constraint_h, constraint_h,
constraint_v, constraint_v,
@ -87,7 +87,7 @@ fn calculate_group_bounds(
bounds: &HashMap<Uuid, Bounds>, bounds: &HashMap<Uuid, Bounds>,
structure: &HashMap<Uuid, Vec<StructureEntry>>, structure: &HashMap<Uuid, Vec<StructureEntry>>,
) -> Option<Bounds> { ) -> Option<Bounds> {
let shape_bounds = bounds.find(&shape); let shape_bounds = bounds.find(shape);
let mut result = Vec::<Point>::new(); let mut result = Vec::<Point>::new();
let children_ids = modified_children_ids(shape, structure.get(&shape.id)); let children_ids = modified_children_ids(shape, structure.get(&shape.id));
@ -100,12 +100,12 @@ fn calculate_group_bounds(
result.append(&mut child_bounds.points()); result.append(&mut child_bounds.points());
} }
shape_bounds.from_points(result) shape_bounds.with_points(result)
} }
pub fn propagate_modifiers( pub fn propagate_modifiers(
state: &State, state: &State,
modifiers: &Vec<TransformEntry>, modifiers: &[TransformEntry],
) -> (Vec<TransformEntry>, HashMap<Uuid, Bounds>) { ) -> (Vec<TransformEntry>, HashMap<Uuid, Bounds>) {
let shapes = &state.shapes; let shapes = &state.shapes;
@ -115,7 +115,7 @@ pub fn propagate_modifiers(
.map(|entry| Modifier::Transform(entry.clone())) .map(|entry| Modifier::Transform(entry.clone()))
.collect(); .collect();
for (id, _) in &state.structure { for id in state.structure.keys() {
if id != &Uuid::nil() { if id != &Uuid::nil() {
entries.push_back(Modifier::Reflow(*id)); entries.push_back(Modifier::Reflow(*id));
} }
@ -140,7 +140,7 @@ pub fn propagate_modifiers(
continue; continue;
}; };
let shape_bounds_before = bounds.find(&shape); let shape_bounds_before = bounds.find(shape);
let mut shape_bounds_after = shape_bounds_before.transform(&entry.transform); let mut shape_bounds_after = shape_bounds_before.transform(&entry.transform);
let mut transform = entry.transform; let mut transform = entry.transform;
@ -176,9 +176,7 @@ pub fn propagate_modifiers(
bounds.insert(shape.id, shape_bounds_after); bounds.insert(shape.id, shape_bounds_after);
let default_matrix = Matrix::default(); let mut shape_modif = modifiers.get(&shape.id).copied().unwrap_or_default();
let mut shape_modif =
modifiers.get(&shape.id).unwrap_or(&default_matrix).clone();
shape_modif.post_concat(&transform); shape_modif.post_concat(&transform);
modifiers.insert(shape.id, shape_modif); modifiers.insert(shape.id, shape_modif);
@ -230,7 +228,7 @@ pub fn propagate_modifiers(
let children_ids = let children_ids =
modified_children_ids(shape, state.structure.get(&shape.id)); modified_children_ids(shape, state.structure.get(&shape.id));
if let Some(child) = shapes.get(&children_ids[0]) { if let Some(child) = shapes.get(&children_ids[0]) {
let child_bounds = bounds.find(&child); let child_bounds = bounds.find(child);
bounds.insert(shape.id, child_bounds); bounds.insert(shape.id, child_bounds);
reflow_parent = true; reflow_parent = true;
} }
@ -269,11 +267,11 @@ pub fn propagate_modifiers(
} }
for id in layout_reflows.iter() { for id in layout_reflows.iter() {
if reflown.contains(&id) { if reflown.contains(id) {
continue; continue;
} }
let Some(shape) = state.shapes.get(&id) else { let Some(shape) = state.shapes.get(id) else {
continue; continue;
}; };

View file

@ -10,8 +10,6 @@ pub trait GetBounds {
impl GetBounds for HashMap<Uuid, Bounds> { impl GetBounds for HashMap<Uuid, Bounds> {
fn find(&self, shape: &Shape) -> Bounds { fn find(&self, shape: &Shape) -> Bounds {
self.get(&shape.id) self.get(&shape.id).copied().unwrap_or(shape.bounds())
.map(|b| b.clone())
.unwrap_or(shape.bounds())
} }
} }

View file

@ -120,16 +120,14 @@ pub fn propagate_shape_constraints(
if let Some((scale_width, scale_height)) = calculate_resize( if let Some((scale_width, scale_height)) = calculate_resize(
constraint_h, constraint_h,
constraint_v, constraint_v,
&parent_bounds_before, parent_bounds_before,
&parent_bounds_after, parent_bounds_after,
&child_bounds_before, child_bounds_before,
&child_bounds_after, &child_bounds_after,
) { ) {
let center = child_bounds_before.center(); let center = child_bounds_before.center();
let mut parent_transform = parent_bounds_after let mut parent_transform = parent_bounds_after.transform_matrix().unwrap_or_default();
.transform_matrix()
.unwrap_or(Matrix::default());
parent_transform.post_translate(center); parent_transform.post_translate(center);
parent_transform.pre_translate(-center); parent_transform.pre_translate(-center);
@ -140,7 +138,7 @@ pub fn propagate_shape_constraints(
scale.post_translate(origin); scale.post_translate(origin);
scale.post_concat(&parent_transform); scale.post_concat(&parent_transform);
scale.pre_translate(-origin); scale.pre_translate(-origin);
scale.pre_concat(&parent_transform_inv); scale.pre_concat(parent_transform_inv);
child_bounds_after.transform_mut(&scale); child_bounds_after.transform_mut(&scale);
transform.post_concat(&scale); transform.post_concat(&scale);
@ -150,9 +148,9 @@ pub fn propagate_shape_constraints(
if let Some((delta_x, delta_y)) = calculate_displacement( if let Some((delta_x, delta_y)) = calculate_displacement(
constraint_h, constraint_h,
constraint_v, constraint_v,
&parent_bounds_before, parent_bounds_before,
&parent_bounds_after, parent_bounds_after,
&child_bounds_before, child_bounds_before,
&child_bounds_after, &child_bounds_after,
) { ) {
let th = parent_bounds_after.hv(delta_x); let th = parent_bounds_after.hv(delta_x);

View file

@ -141,7 +141,7 @@ impl ChildAxis {
is_fill_main: child.is_layout_horizontal_fill(), is_fill_main: child.is_layout_horizontal_fill(),
is_fill_across: child.is_layout_vertical_fill(), is_fill_across: child.is_layout_vertical_fill(),
z_index: layout_item.map(|i| i.z_index).unwrap_or(0), z_index: layout_item.map(|i| i.z_index).unwrap_or(0),
bounds: child_bounds.clone(), bounds: *child_bounds,
} }
} else { } else {
Self { Self {
@ -159,7 +159,7 @@ impl ChildAxis {
is_fill_main: child.is_layout_vertical_fill(), is_fill_main: child.is_layout_vertical_fill(),
is_fill_across: child.is_layout_horizontal_fill(), is_fill_across: child.is_layout_horizontal_fill(),
z_index: layout_item.map(|i| i.z_index).unwrap_or(0), z_index: layout_item.map(|i| i.z_index).unwrap_or(0),
bounds: child_bounds.clone(), bounds: *child_bounds,
} }
}; };
@ -267,7 +267,7 @@ fn initialize_tracks(
} }
// Resize main axis fill // Resize main axis fill
fn distribute_fill_main_space(layout_axis: &LayoutAxis, tracks: &mut Vec<TrackData>) { fn distribute_fill_main_space(layout_axis: &LayoutAxis, tracks: &mut [TrackData]) {
for track in tracks.iter_mut() { for track in tracks.iter_mut() {
let mut left_space = layout_axis.main_space() - track.main_size; let mut left_space = layout_axis.main_space() - track.main_size;
let mut to_resize_children: Vec<&mut ChildAxis> = Vec::new(); let mut to_resize_children: Vec<&mut ChildAxis> = Vec::new();
@ -284,9 +284,9 @@ fn distribute_fill_main_space(layout_axis: &LayoutAxis, tracks: &mut Vec<TrackDa
let child = &mut to_resize_children[i]; let child = &mut to_resize_children[i];
let delta = let delta =
f32::min(child.max_main_size, child.main_size + current) - child.main_size; f32::min(child.max_main_size, child.main_size + current) - child.main_size;
child.main_size = child.main_size + delta; child.main_size += delta;
left_space = left_space - delta; left_space -= delta;
track.main_size = track.main_size + delta; track.main_size += delta;
if (child.main_size - child.max_main_size).abs() < MIN_SIZE { if (child.main_size - child.max_main_size).abs() < MIN_SIZE {
to_resize_children.remove(i); to_resize_children.remove(i);
@ -296,7 +296,7 @@ fn distribute_fill_main_space(layout_axis: &LayoutAxis, tracks: &mut Vec<TrackDa
} }
} }
fn distribute_fill_across_space(layout_axis: &LayoutAxis, tracks: &mut Vec<TrackData>) { fn distribute_fill_across_space(layout_axis: &LayoutAxis, tracks: &mut [TrackData]) {
let total_across_size = tracks.iter().map(|t| t.across_size).sum::<f32>() let total_across_size = tracks.iter().map(|t| t.across_size).sum::<f32>()
+ (tracks.len() - 1) as f32 * layout_axis.gap_across; + (tracks.len() - 1) as f32 * layout_axis.gap_across;
let mut left_space = layout_axis.across_space() - total_across_size; let mut left_space = layout_axis.across_space() - total_across_size;
@ -314,8 +314,8 @@ fn distribute_fill_across_space(layout_axis: &LayoutAxis, tracks: &mut Vec<Track
let track = &mut to_resize_tracks[i]; let track = &mut to_resize_tracks[i];
let delta = let delta =
f32::min(track.max_across_size, track.across_size + current) - track.across_size; f32::min(track.max_across_size, track.across_size + current) - track.across_size;
track.across_size = track.across_size + delta; track.across_size += delta;
left_space = left_space - delta; left_space -= delta;
if (track.across_size - track.max_across_size).abs() < MIN_SIZE { if (track.across_size - track.max_across_size).abs() < MIN_SIZE {
to_resize_tracks.remove(i); to_resize_tracks.remove(i);
@ -342,7 +342,7 @@ fn distribute_fill_across_space(layout_axis: &LayoutAxis, tracks: &mut Vec<Track
fn stretch_tracks_sizes( fn stretch_tracks_sizes(
layout_axis: &LayoutAxis, layout_axis: &LayoutAxis,
tracks: &mut Vec<TrackData>, tracks: &mut [TrackData],
total_across_size: f32, total_across_size: f32,
) { ) {
let total_across_size = total_across_size + (tracks.len() - 1) as f32 * layout_axis.gap_across; let total_across_size = total_across_size + (tracks.len() - 1) as f32 * layout_axis.gap_across;
@ -350,7 +350,7 @@ fn stretch_tracks_sizes(
let delta = left_space / tracks.len() as f32; let delta = left_space / tracks.len() as f32;
for track in tracks.iter_mut() { for track in tracks.iter_mut() {
track.across_size = track.across_size + delta; track.across_size += delta;
} }
} }
@ -358,7 +358,7 @@ fn calculate_track_positions(
layout_data: &LayoutData, layout_data: &LayoutData,
layout_axis: &LayoutAxis, layout_axis: &LayoutAxis,
layout_bounds: &Bounds, layout_bounds: &Bounds,
tracks: &mut Vec<TrackData>, tracks: &mut [TrackData],
total_across_size: f32, total_across_size: f32,
) { ) {
let mut align_content = &layout_data.align_content; let mut align_content = &layout_data.align_content;
@ -411,7 +411,7 @@ fn calculate_track_positions(
for track in tracks.iter_mut() { for track in tracks.iter_mut() {
track.anchor = next_anchor; track.anchor = next_anchor;
next_anchor = next_anchor + layout_axis.across_v * real_gap; next_anchor += layout_axis.across_v * real_gap;
} }
} }
@ -450,7 +450,7 @@ fn calculate_track_data(
} }
calculate_track_positions( calculate_track_positions(
&layout_data, layout_data,
&layout_axis, &layout_axis,
layout_bounds, layout_bounds,
&mut tracks, &mut tracks,
@ -556,7 +556,7 @@ pub fn reflow_flex_layout(
structure: &HashMap<Uuid, Vec<StructureEntry>>, structure: &HashMap<Uuid, Vec<StructureEntry>>,
) -> VecDeque<Modifier> { ) -> VecDeque<Modifier> {
let mut result = VecDeque::new(); let mut result = VecDeque::new();
let layout_bounds = &bounds.find(&shape); let layout_bounds = &bounds.find(shape);
let layout_axis = LayoutAxis::new(shape, layout_bounds, layout_data, flex_data); let layout_axis = LayoutAxis::new(shape, layout_bounds, layout_data, flex_data);
let tracks = calculate_track_data( let tracks = calculate_track_data(
shape, shape,
@ -570,7 +570,7 @@ pub fn reflow_flex_layout(
for track in tracks.iter() { for track in tracks.iter() {
let total_shapes_size = track.shapes.iter().map(|s| s.main_size).sum::<f32>(); let total_shapes_size = track.shapes.iter().map(|s| s.main_size).sum::<f32>();
let mut shape_anchor = first_anchor(&layout_data, &layout_axis, track, total_shapes_size); let mut shape_anchor = first_anchor(layout_data, &layout_axis, track, total_shapes_size);
for child_axis in track.shapes.iter() { for child_axis in track.shapes.iter() {
let child_id = child_axis.id; let child_id = child_axis.id;
@ -602,7 +602,7 @@ pub fn reflow_flex_layout(
{ {
transform.post_concat(&math::resize_matrix( transform.post_concat(&math::resize_matrix(
layout_bounds, layout_bounds,
&child_bounds, child_bounds,
new_width, new_width,
new_height, new_height,
)); ));
@ -615,10 +615,10 @@ pub fn reflow_flex_layout(
result.push_back(Modifier::transform(child.id, transform)); result.push_back(Modifier::transform(child.id, transform));
shape_anchor = next_anchor( shape_anchor = next_anchor(
&layout_data, layout_data,
&layout_axis, &layout_axis,
&child_axis, child_axis,
&track, track,
shape_anchor, shape_anchor,
total_shapes_size, total_shapes_size,
); );
@ -681,9 +681,7 @@ pub fn reflow_flex_layout(
) )
}; };
let parent_transform = layout_bounds let parent_transform = layout_bounds.transform_matrix().unwrap_or_default();
.transform_matrix()
.unwrap_or(Matrix::default());
let parent_transform_inv = &parent_transform.invert().unwrap(); let parent_transform_inv = &parent_transform.invert().unwrap();
let origin = parent_transform_inv.map_point(layout_bounds.nw); let origin = parent_transform_inv.map_point(layout_bounds.nw);
@ -692,7 +690,7 @@ pub fn reflow_flex_layout(
scale.post_translate(origin); scale.post_translate(origin);
scale.post_concat(&parent_transform); scale.post_concat(&parent_transform);
scale.pre_translate(-origin); scale.pre_translate(-origin);
scale.pre_concat(&parent_transform_inv); scale.pre_concat(parent_transform_inv);
let layout_bounds_after = layout_bounds.transform(&scale); let layout_bounds_after = layout_bounds.transform(&scale);
result.push_back(Modifier::parent(shape.id, scale)); result.push_back(Modifier::parent(shape.id, scale));

View file

@ -33,6 +33,8 @@ struct TrackData {
anchor_end: Point, anchor_end: Point,
} }
// FIXME: We might be able to simplify these arguments
#[allow(clippy::too_many_arguments)]
fn calculate_tracks( fn calculate_tracks(
is_column: bool, is_column: bool,
shape: &Shape, shape: &Shape,
@ -61,11 +63,12 @@ fn calculate_tracks(
set_flex_multi_span(is_column, &mut tracks, cells, shapes, bounds); set_flex_multi_span(is_column, &mut tracks, cells, shapes, bounds);
set_fr_value(is_column, shape, layout_data, &mut tracks, layout_size); set_fr_value(is_column, shape, layout_data, &mut tracks, layout_size);
stretch_tracks(is_column, shape, layout_data, &mut tracks, layout_size); stretch_tracks(is_column, shape, layout_data, &mut tracks, layout_size);
assign_anchors(is_column, layout_data, &layout_bounds, &mut tracks); assign_anchors(is_column, layout_data, layout_bounds, &mut tracks);
return tracks;
tracks
} }
fn init_tracks(track: &Vec<GridTrack>, size: f32) -> Vec<TrackData> { fn init_tracks(track: &[GridTrack], size: f32) -> Vec<TrackData> {
track track
.iter() .iter()
.map(|t| { .map(|t| {
@ -103,7 +106,7 @@ fn min_size(column: bool, shape: &Shape, bounds: &HashMap<Uuid, Bounds>) -> f32
// Go through cells to adjust auto sizes for span=1. Base is the max of its children // Go through cells to adjust auto sizes for span=1. Base is the max of its children
fn set_auto_base_size( fn set_auto_base_size(
column: bool, column: bool,
tracks: &mut Vec<TrackData>, tracks: &mut [TrackData],
cells: &Vec<GridCell>, cells: &Vec<GridCell>,
shapes: &HashMap<Uuid, &mut Shape>, shapes: &HashMap<Uuid, &mut Shape>,
bounds: &HashMap<Uuid, Bounds>, bounds: &HashMap<Uuid, Bounds>,
@ -146,7 +149,7 @@ fn track_index(is_column: bool, c: &GridCell) -> (usize, usize) {
} }
} }
fn has_flex(is_column: bool, cell: &GridCell, tracks: &mut Vec<TrackData>) -> bool { fn has_flex(is_column: bool, cell: &GridCell, tracks: &mut [TrackData]) -> bool {
let (start, end) = track_index(is_column, cell); let (start, end) = track_index(is_column, cell);
(start..end).any(|i| tracks[i].track_type == GridTrackType::Flex) (start..end).any(|i| tracks[i].track_type == GridTrackType::Flex)
} }
@ -154,8 +157,8 @@ fn has_flex(is_column: bool, cell: &GridCell, tracks: &mut Vec<TrackData>) -> bo
// Adjust multi-spaned cells with no flex columns // Adjust multi-spaned cells with no flex columns
fn set_auto_multi_span( fn set_auto_multi_span(
column: bool, column: bool,
tracks: &mut Vec<TrackData>, tracks: &mut [TrackData],
cells: &Vec<GridCell>, cells: &[GridCell],
shapes: &HashMap<Uuid, &mut Shape>, shapes: &HashMap<Uuid, &mut Shape>,
bounds: &HashMap<Uuid, Bounds>, bounds: &HashMap<Uuid, Bounds>,
) { ) {
@ -193,11 +196,11 @@ fn set_auto_multi_span(
let (start, end) = track_index(column, cell); let (start, end) = track_index(column, cell);
// Distribute the size between the tracks that already have a set value // Distribute the size between the tracks that already have a set value
for i in start..end { for track in tracks[start..end].iter() {
dist = dist - tracks[i].size; dist -= track.size;
if tracks[i].track_type == GridTrackType::Auto { if track.track_type == GridTrackType::Auto {
num_auto = num_auto + 1; num_auto += 1;
} }
} }
@ -206,19 +209,19 @@ fn set_auto_multi_span(
let rest = dist / num_auto as f32; let rest = dist / num_auto as f32;
// Distribute the space between auto tracks // Distribute the space between auto tracks
for i in start..end { for track in tracks[start..end].iter_mut() {
if tracks[i].track_type == GridTrackType::Auto { if track.track_type == GridTrackType::Auto {
// dist = dist - track[i].size; // dist = dist - track[i].size;
let new_size = if tracks[i].size + rest < tracks[i].max_size { let new_size = if track.size + rest < track.max_size {
tracks[i].size + rest track.size + rest
} else { } else {
num_auto = num_auto - 1; num_auto -= 1;
tracks[i].max_size track.max_size
}; };
let aloc = new_size - tracks[i].size; let aloc = new_size - track.size;
dist = dist - aloc; dist -= aloc;
tracks[i].size = tracks[i].size + aloc; track.size += aloc;
} }
} }
} }
@ -228,8 +231,8 @@ fn set_auto_multi_span(
// Adjust multi-spaned cells with flex columns // Adjust multi-spaned cells with flex columns
fn set_flex_multi_span( fn set_flex_multi_span(
column: bool, column: bool,
tracks: &mut Vec<TrackData>, tracks: &mut [TrackData],
cells: &Vec<GridCell>, cells: &[GridCell],
shapes: &HashMap<Uuid, &mut Shape>, shapes: &HashMap<Uuid, &mut Shape>,
bounds: &HashMap<Uuid, Bounds>, bounds: &HashMap<Uuid, Bounds>,
) { ) {
@ -269,16 +272,16 @@ fn set_flex_multi_span(
let (start, end) = track_index(column, cell); let (start, end) = track_index(column, cell);
// Distribute the size between the tracks that already have a set value // Distribute the size between the tracks that already have a set value
for i in start..end { for track in tracks[start..end].iter() {
dist = dist - tracks[i].size; dist -= track.size;
match tracks[i].track_type { match track.track_type {
GridTrackType::Flex => { GridTrackType::Flex => {
num_flex = num_flex + tracks[i].value; num_flex += track.value;
num_auto = num_auto + 1; num_auto += 1;
} }
GridTrackType::Auto => { GridTrackType::Auto => {
num_auto = num_auto + 1; num_auto += 1;
} }
_ => {} _ => {}
} }
@ -289,15 +292,15 @@ fn set_flex_multi_span(
continue; continue;
} }
let rest = dist / num_flex as f32; let rest = dist / num_flex;
// Distribute the space between flex tracks in proportion to the division // Distribute the space between flex tracks in proportion to the division
for i in start..end { for track in tracks[start..end].iter_mut() {
if tracks[i].track_type == GridTrackType::Flex { if track.track_type == GridTrackType::Flex {
let new_size = f32::min(tracks[i].size + rest, tracks[i].max_size); let new_size = f32::min(track.size + rest, track.max_size);
let aloc = new_size - tracks[i].size; let aloc = new_size - track.size;
dist = dist - aloc; dist -= aloc;
tracks[i].size = tracks[i].size + aloc; track.size += aloc;
} }
} }
@ -305,20 +308,20 @@ fn set_flex_multi_span(
while dist > MIN_SIZE && num_auto > 0 { while dist > MIN_SIZE && num_auto > 0 {
let rest = dist / num_auto as f32; let rest = dist / num_auto as f32;
for i in start..end { for track in tracks[start..end].iter_mut() {
if tracks[i].track_type == GridTrackType::Auto if track.track_type == GridTrackType::Auto
|| tracks[i].track_type == GridTrackType::Flex || track.track_type == GridTrackType::Flex
{ {
let new_size = if tracks[i].size + rest < tracks[i].max_size { let new_size = if track.size + rest < track.max_size {
tracks[i].size + rest track.size + rest
} else { } else {
num_auto = num_auto - 1; num_auto -= 1;
tracks[i].max_size track.max_size
}; };
let aloc = new_size - tracks[i].size; let aloc = new_size - track.size;
dist = dist - aloc; dist -= aloc;
tracks[i].size = tracks[i].size + aloc; track.size += aloc;
} }
} }
} }
@ -330,7 +333,7 @@ fn set_fr_value(
column: bool, column: bool,
shape: &Shape, shape: &Shape,
layout_data: &LayoutData, layout_data: &LayoutData,
tracks: &mut Vec<TrackData>, tracks: &mut [TrackData],
layout_size: f32, layout_size: f32,
) { ) {
let tot_gap: f32 = if column { let tot_gap: f32 = if column {
@ -380,7 +383,7 @@ fn stretch_tracks(
column: bool, column: bool,
shape: &Shape, shape: &Shape,
layout_data: &LayoutData, layout_data: &LayoutData,
tracks: &mut Vec<TrackData>, tracks: &mut [TrackData],
layout_size: f32, layout_size: f32,
) { ) {
if (column if (column
@ -481,7 +484,7 @@ fn assign_anchors(
_ => (padding_start + 0.0, gap), _ => (padding_start + 0.0, gap),
}; };
cursor = cursor + (v * real_margin); cursor += v * real_margin;
for track in tracks { for track in tracks {
track.anchor_start = cursor; track.anchor_start = cursor;
@ -511,8 +514,8 @@ fn create_cell_data<'a>(
children: &IndexSet<Uuid>, children: &IndexSet<Uuid>,
shapes: &'a HashMap<Uuid, &mut Shape>, shapes: &'a HashMap<Uuid, &mut Shape>,
cells: &Vec<GridCell>, cells: &Vec<GridCell>,
column_tracks: &Vec<TrackData>, column_tracks: &[TrackData],
row_tracks: &Vec<TrackData>, row_tracks: &[TrackData],
) -> Vec<CellData<'a>> { ) -> Vec<CellData<'a>> {
let mut result = Vec::<CellData<'a>>::new(); let mut result = Vec::<CellData<'a>>::new();
@ -614,11 +617,11 @@ fn child_position(
cell.anchor + vv * vpos + hv * hpos cell.anchor + vv * vpos + hv * hpos
} }
pub fn reflow_grid_layout<'a>( pub fn reflow_grid_layout(
shape: &Shape, shape: &Shape,
layout_data: &LayoutData, layout_data: &LayoutData,
grid_data: &GridData, grid_data: &GridData,
shapes: &'a HashMap<Uuid, &mut Shape>, shapes: &HashMap<Uuid, &mut Shape>,
bounds: &mut HashMap<Uuid, Bounds>, bounds: &mut HashMap<Uuid, Bounds>,
structure: &HashMap<Uuid, Vec<StructureEntry>>, structure: &HashMap<Uuid, Vec<StructureEntry>>,
) -> VecDeque<Modifier> { ) -> VecDeque<Modifier> {
@ -693,9 +696,9 @@ pub fn reflow_grid_layout<'a>(
} }
let position = child_position( let position = child_position(
&child, child,
&layout_bounds, &layout_bounds,
&layout_data, layout_data,
&child_bounds, &child_bounds,
child.layout_item, child.layout_item,
cell, cell,
@ -733,9 +736,7 @@ pub fn reflow_grid_layout<'a>(
scale_height = auto_height / height; scale_height = auto_height / height;
} }
let parent_transform = layout_bounds let parent_transform = layout_bounds.transform_matrix().unwrap_or_default();
.transform_matrix()
.unwrap_or(Matrix::default());
let parent_transform_inv = &parent_transform.invert().unwrap(); let parent_transform_inv = &parent_transform.invert().unwrap();
let origin = parent_transform_inv.map_point(layout_bounds.nw); let origin = parent_transform_inv.map_point(layout_bounds.nw);
@ -744,7 +745,7 @@ pub fn reflow_grid_layout<'a>(
scale.post_translate(origin); scale.post_translate(origin);
scale.post_concat(&parent_transform); scale.post_concat(&parent_transform);
scale.pre_translate(-origin); scale.pre_translate(-origin);
scale.pre_concat(&parent_transform_inv); scale.pre_concat(parent_transform_inv);
let layout_bounds_after = layout_bounds.transform(&scale); let layout_bounds_after = layout_bounds.transform(&scale);
result.push_back(Modifier::parent(shape.id, scale)); result.push_back(Modifier::parent(shape.id, scale));

View file

@ -4,7 +4,7 @@ use std::array::TryFromSliceError;
type Point = (f32, f32); type Point = (f32, f32);
fn stringify_slice_err(_: TryFromSliceError) -> String { fn stringify_slice_err(_: TryFromSliceError) -> String {
format!("Error deserializing path") "Error deserializing path".to_string()
} }
#[derive(Debug)] #[derive(Debug)]
@ -89,7 +89,7 @@ impl TryFrom<Vec<RawPathData>> for Path {
let mut open = true; let mut open = true;
let segments = value let segments = value
.into_iter() .into_iter()
.map(|raw| Segment::try_from(raw)) .map(Segment::try_from)
.collect::<Result<Vec<Segment>, String>>()?; .collect::<Result<Vec<Segment>, String>>()?;
let mut skia_path = skia::Path::new(); let mut skia_path = skia::Path::new();

View file

@ -52,9 +52,9 @@ impl From<u8> for StrokeCap {
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum StrokeKind { pub enum StrokeKind {
InnerStroke, Inner,
OuterStroke, Outer,
CenterStroke, Center,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -71,7 +71,7 @@ impl Stroke {
// Strokes for open shapes should be rendered as if they were centered. // Strokes for open shapes should be rendered as if they were centered.
pub fn render_kind(&self, is_open: bool) -> StrokeKind { pub fn render_kind(&self, is_open: bool) -> StrokeKind {
if is_open { if is_open {
StrokeKind::CenterStroke StrokeKind::Center
} else { } else {
self.kind self.kind
} }
@ -84,7 +84,7 @@ impl Stroke {
style: StrokeStyle::from(style), style: StrokeStyle::from(style),
cap_end: StrokeCap::from(cap_end), cap_end: StrokeCap::from(cap_end),
cap_start: StrokeCap::from(cap_start), cap_start: StrokeCap::from(cap_start),
kind: StrokeKind::CenterStroke, kind: StrokeKind::Center,
} }
} }
@ -95,7 +95,7 @@ impl Stroke {
style: StrokeStyle::from(style), style: StrokeStyle::from(style),
cap_end: StrokeCap::from(cap_end), cap_end: StrokeCap::from(cap_end),
cap_start: StrokeCap::from(cap_start), cap_start: StrokeCap::from(cap_start),
kind: StrokeKind::InnerStroke, kind: StrokeKind::Inner,
} }
} }
@ -106,30 +106,28 @@ impl Stroke {
style: StrokeStyle::from(style), style: StrokeStyle::from(style),
cap_end: StrokeCap::from(cap_end), cap_end: StrokeCap::from(cap_end),
cap_start: StrokeCap::from(cap_start), cap_start: StrokeCap::from(cap_start),
kind: StrokeKind::OuterStroke, kind: StrokeKind::Outer,
} }
} }
pub fn delta(&self) -> f32 { pub fn delta(&self) -> f32 {
match self.kind { match self.kind {
StrokeKind::InnerStroke => 0., StrokeKind::Inner => 0.,
StrokeKind::CenterStroke => self.width, StrokeKind::Center => self.width,
StrokeKind::OuterStroke => self.width * 2., StrokeKind::Outer => self.width * 2.,
} }
} }
pub fn outer_rect(&self, rect: &Rect) -> Rect { pub fn outer_rect(&self, rect: &Rect) -> Rect {
match self.kind { match self.kind {
StrokeKind::InnerStroke => Rect::from_xywh( StrokeKind::Inner => Rect::from_xywh(
rect.left + (self.width / 2.), rect.left + (self.width / 2.),
rect.top + (self.width / 2.), rect.top + (self.width / 2.),
rect.width() - self.width, rect.width() - self.width,
rect.height() - self.width, rect.height() - self.width,
), ),
StrokeKind::CenterStroke => { StrokeKind::Center => Rect::from_xywh(rect.left, rect.top, rect.width(), rect.height()),
Rect::from_xywh(rect.left, rect.top, rect.width(), rect.height()) StrokeKind::Outer => Rect::from_xywh(
}
StrokeKind::OuterStroke => Rect::from_xywh(
rect.left - (self.width / 2.), rect.left - (self.width / 2.),
rect.top - (self.width / 2.), rect.top - (self.width / 2.),
rect.width() + self.width, rect.width() + self.width,
@ -140,12 +138,12 @@ impl Stroke {
pub fn outer_corners(&self, corners: &Corners) -> Corners { pub fn outer_corners(&self, corners: &Corners) -> Corners {
let offset = match self.kind { let offset = match self.kind {
StrokeKind::CenterStroke => 0.0, StrokeKind::Center => 0.0,
StrokeKind::InnerStroke => -self.width / 2.0, StrokeKind::Inner => -self.width / 2.0,
StrokeKind::OuterStroke => self.width / 2.0, StrokeKind::Outer => self.width / 2.0,
}; };
let mut outer = corners.clone(); let mut outer = *corners;
for corner in outer.iter_mut() { for corner in outer.iter_mut() {
corner.offset((offset, offset)) corner.offset((offset, offset))
} }
@ -163,9 +161,9 @@ impl Stroke {
paint.set_style(skia::PaintStyle::Stroke); paint.set_style(skia::PaintStyle::Stroke);
let width = match self.kind { let width = match self.kind {
StrokeKind::InnerStroke => self.width, StrokeKind::Inner => self.width,
StrokeKind::CenterStroke => self.width, StrokeKind::Center => self.width,
StrokeKind::OuterStroke => self.width + (1. / scale), StrokeKind::Outer => self.width + (1. / scale),
}; };
paint.set_stroke_width(width); paint.set_stroke_width(width);
@ -184,9 +182,9 @@ impl Stroke {
StrokeStyle::Dotted => { StrokeStyle::Dotted => {
let mut circle_path = skia::Path::new(); let mut circle_path = skia::Path::new();
let width = match self.kind { let width = match self.kind {
StrokeKind::InnerStroke => self.width, StrokeKind::Inner => self.width,
StrokeKind::CenterStroke => self.width / 2.0, StrokeKind::Center => self.width / 2.0,
StrokeKind::OuterStroke => self.width, StrokeKind::Outer => self.width,
}; };
circle_path.add_circle((0.0, 0.0), width, None); circle_path.add_circle((0.0, 0.0), width, None);
let advance = self.width + 5.0; let advance = self.width + 5.0;
@ -227,11 +225,11 @@ impl Stroke {
) -> skia::Paint { ) -> skia::Paint {
let mut paint = self.to_paint(rect, svg_attrs, scale, antialias); let mut paint = self.to_paint(rect, svg_attrs, scale, antialias);
match self.render_kind(is_open) { match self.render_kind(is_open) {
StrokeKind::InnerStroke => { StrokeKind::Inner => {
paint.set_stroke_width(2. * paint.stroke_width()); paint.set_stroke_width(2. * paint.stroke_width());
} }
StrokeKind::CenterStroke => {} StrokeKind::Center => {}
StrokeKind::OuterStroke => { StrokeKind::Outer => {
paint.set_stroke_width(2. * paint.stroke_width()); paint.set_stroke_width(2. * paint.stroke_width());
} }
} }

View file

@ -1,4 +1,4 @@
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq, Default)]
pub struct SVGRaw { pub struct SVGRaw {
pub content: String, pub content: String,
} }
@ -8,11 +8,3 @@ impl SVGRaw {
SVGRaw { content: svg } SVGRaw { content: svg }
} }
} }
impl Default for SVGRaw {
fn default() -> Self {
Self {
content: String::from(""),
}
}
}

View file

@ -51,10 +51,11 @@ pub fn set_paragraphs_width(width: f32, paragraphs: &mut Vec<Vec<skia::textlayou
impl TextContent { impl TextContent {
pub fn new(bounds: Rect, grow_type: GrowType) -> Self { pub fn new(bounds: Rect, grow_type: GrowType) -> Self {
let mut res = Self::default(); Self {
res.bounds = bounds; bounds,
res.grow_type = grow_type; grow_type,
res ..Self::default()
}
} }
pub fn new_bounds(&self, bounds: Rect) -> Self { pub fn new_bounds(&self, bounds: Rect) -> Self {
@ -125,7 +126,7 @@ impl TextContent {
let paragraph_style = paragraph.paragraph_to_style(); let paragraph_style = paragraph.paragraph_to_style();
let mut builder = ParagraphBuilder::new(&paragraph_style, fonts); let mut builder = ParagraphBuilder::new(&paragraph_style, fonts);
for leaf in &paragraph.children { for leaf in &paragraph.children {
let stroke_style = leaf.to_stroke_style(paragraph, &stroke_paint); let stroke_style = leaf.to_stroke_style(paragraph, stroke_paint);
let text: String = leaf.apply_text_transform(paragraph.text_transform); let text: String = leaf.apply_text_transform(paragraph.text_transform);
builder.push_style(&stroke_style); builder.push_style(&stroke_style);
builder.add_text(&text); builder.add_text(&text);
@ -217,6 +218,8 @@ impl Default for Paragraph {
} }
impl Paragraph { impl Paragraph {
// FIXME: These arguments could be grouped or simplified
#[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
text_align: u8, text_align: u8,
text_decoration: u8, text_decoration: u8,
@ -542,13 +545,13 @@ impl From<&Vec<u8>> for RawTextData {
} }
} }
pub fn auto_width(paragraphs: &Vec<Vec<skia::textlayout::Paragraph>>) -> f32 { pub fn auto_width(paragraphs: &[Vec<skia::textlayout::Paragraph>]) -> f32 {
paragraphs.iter().flatten().fold(0.0, |auto_width, p| { paragraphs.iter().flatten().fold(0.0, |auto_width, p| {
f32::max(p.max_intrinsic_width(), auto_width) f32::max(p.max_intrinsic_width(), auto_width)
}) })
} }
pub fn auto_height(paragraphs: &Vec<Vec<skia::textlayout::Paragraph>>) -> f32 { pub fn auto_height(paragraphs: &[Vec<skia::textlayout::Paragraph>]) -> f32 {
paragraphs paragraphs
.iter() .iter()
.flatten() .flatten()

View file

@ -1,4 +1,4 @@
use std::collections::HashMap; use std::collections::{hash_map::Entry, HashMap};
use skia_safe as skia; use skia_safe as skia;
@ -24,6 +24,8 @@ use crate::uuid::Uuid;
/// state shapes attribute /// state shapes attribute
pub(crate) struct ShapesPool { pub(crate) struct ShapesPool {
// We need a box so that pushing here doesn't invalidate state.shapes references // We need a box so that pushing here doesn't invalidate state.shapes references
// FIXME: See if we can avoid this
#[allow(clippy::vec_box)]
shapes: Vec<Box<Shape>>, shapes: Vec<Box<Shape>>,
counter: usize, counter: usize,
} }
@ -116,9 +118,9 @@ impl<'a> State<'a> {
} }
pub fn use_shape(&'a mut self, id: Uuid) { pub fn use_shape(&'a mut self, id: Uuid) {
if !self.shapes.contains_key(&id) { if let Entry::Vacant(e) = self.shapes.entry(id) {
let new_shape = self.shapes_pool.add_shape(id); let new_shape = self.shapes_pool.add_shape(id);
self.shapes.insert(id, new_shape); e.insert(new_shape);
} }
self.current_id = Some(id); self.current_id = Some(id);
self.current_shape = self.shapes.get_mut(&id).map(|r| &mut **r); self.current_shape = self.shapes.get_mut(&id).map(|r| &mut **r);
@ -127,7 +129,7 @@ impl<'a> State<'a> {
pub fn delete_shape(&mut self, id: Uuid) { pub fn delete_shape(&mut self, id: Uuid) {
// We don't really do a self.shapes.remove so that redo/undo keep working // We don't really do a self.shapes.remove so that redo/undo keep working
if let Some(shape) = self.shapes.get(&id) { if let Some(shape) = self.shapes.get(&id) {
let (rsx, rsy, rex, rey) = self.render_state.get_tiles_for_shape(&shape); let (rsx, rsy, rex, rey) = self.render_state.get_tiles_for_shape(shape);
for x in rsx..=rex { for x in rsx..=rex {
for y in rsy..=rey { for y in rsy..=rey {
let tile = (x, y); let tile = (x, y);
@ -152,7 +154,7 @@ impl<'a> State<'a> {
shape.set_selrect(left, top, right, bottom); shape.set_selrect(left, top, right, bottom);
// We don't need to update the tile for the root shape. // We don't need to update the tile for the root shape.
if !shape.id.is_nil() { if !shape.id.is_nil() {
self.render_state.update_tile_for(&shape); self.render_state.update_tile_for(shape);
} }
} }
None => panic!("Invalid current shape"), None => panic!("Invalid current shape"),
@ -165,7 +167,7 @@ impl<'a> State<'a> {
// We don't need to update the tile for the root shape. // We don't need to update the tile for the root shape.
// We can also have deleted the selected shape // We can also have deleted the selected shape
if !shape.id.is_nil() && self.shapes.contains_key(&shape.id) { if !shape.id.is_nil() && self.shapes.contains_key(&shape.id) {
self.render_state.update_tile_for(&shape); self.render_state.update_tile_for(shape);
} }
} }
None => panic!("Invalid current shape"), None => panic!("Invalid current shape"),

View file

@ -63,7 +63,7 @@ impl SerializableResult for Uuid {
fn as_bytes(&self) -> Self::BytesType { fn as_bytes(&self) -> Self::BytesType {
let mut result: Self::BytesType = [0; 16]; let mut result: Self::BytesType = [0; 16];
let (a, b, c, d) = uuid_to_u32_quartet(&self); let (a, b, c, d) = uuid_to_u32_quartet(self);
result[0..4].clone_from_slice(&a.to_le_bytes()); result[0..4].clone_from_slice(&a.to_le_bytes());
result[4..8].clone_from_slice(&b.to_le_bytes()); result[4..8].clone_from_slice(&b.to_le_bytes());
result[8..12].clone_from_slice(&c.to_le_bytes()); result[8..12].clone_from_slice(&c.to_le_bytes());

View file

@ -25,12 +25,13 @@ impl Default for Viewbox {
impl Viewbox { impl Viewbox {
pub fn new(width: f32, height: f32) -> Self { pub fn new(width: f32, height: f32) -> Self {
let mut res = Self::default(); let area = Rect::from_xywh(0., 0., width, height);
res.width = width; Self {
res.height = height; width,
res.area.set_xywh(0., 0., width, height); height,
area,
res ..Self::default()
}
} }
pub fn set_all(&mut self, zoom: f32, pan_x: f32, pan_y: f32) { pub fn set_all(&mut self, zoom: f32, pan_x: f32, pan_y: f32) {

View file

@ -24,12 +24,13 @@ macro_rules! cancel_animation_frame {
} }
{ {
let frame_id = $frame_id;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
unsafe { unsafe {
wapi_cancelAnimationFrame($frame_id) wapi_cancelAnimationFrame(frame_id)
}; };
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
let _ = $frame_id; let _ = frame_id;
} }
}; };
} }

View file

@ -24,12 +24,9 @@ pub extern "C" fn store_font(
.fonts_mut() .fonts_mut()
.add(family, &font_bytes, is_emoji); .add(family, &font_bytes, is_emoji);
match res { if let Err(msg) = res {
Err(msg) => {
eprintln!("{}", msg); eprintln!("{}", msg);
} }
_ => {}
}
}); });
} }
@ -40,6 +37,6 @@ pub extern "C" fn is_font_uploaded(a: u32, b: u32, c: u32, d: u32, weight: u32,
let family = FontFamily::new(id, weight, style.into()); let family = FontFamily::new(id, weight, style.into());
let res = state.render_state().fonts().has_family(&family); let res = state.render_state().fonts().has_family(&family);
return res; res
}); })
} }

View file

@ -49,17 +49,13 @@ pub extern "C" fn get_text_dimensions() -> *mut u8 {
if let Type::Text(content) = &shape.shape_type { if let Type::Text(content) = &shape.shape_type {
let paragraphs = content.get_skia_paragraphs(font_col); let paragraphs = content.get_skia_paragraphs(font_col);
height = auto_height(&paragraphs).ceil(); height = auto_height(&paragraphs).ceil();
match content.grow_type() { if content.grow_type() == GrowType::AutoWidth {
GrowType::AutoWidth => {
width = auto_width(&paragraphs).ceil(); width = auto_width(&paragraphs).ceil();
} }
_ => {}
}
} }
}); });
let mut bytes = Vec::<u8>::with_capacity(8); let mut bytes = vec![0; 8];
bytes.resize(8, 0);
bytes[0..4].clone_from_slice(&width.to_le_bytes()); bytes[0..4].clone_from_slice(&width.to_le_bytes());
bytes[4..8].clone_from_slice(&height.to_le_bytes()); bytes[4..8].clone_from_slice(&height.to_le_bytes());
mem::write_bytes(bytes) mem::write_bytes(bytes)