From 51e10d0474791b9646ae65c852bd8ca270c5ebf7 Mon Sep 17 00:00:00 2001 From: t800-x Date: Sun, 29 Mar 2026 07:36:11 +0530 Subject: [PATCH 1/3] Add smooth scroll to the scroll view. --- src/views/scroll.rs | 198 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 167 insertions(+), 31 deletions(-) diff --git a/src/views/scroll.rs b/src/views/scroll.rs index 3552c8e11..cc3c86e90 100644 --- a/src/views/scroll.rs +++ b/src/views/scroll.rs @@ -2,9 +2,9 @@ //! Scroll View use floem_reactive::Effect; -use peniko::kurbo::{Affine, Axis, Point, Rect, RoundedRect, RoundedRectRadii, Stroke, Vec2}; +use peniko::kurbo::{Affine, Axis, Point, Rect, RoundedRect, RoundedRectRadii, Stroke, Vec2, Size}; use peniko::{Brush, Color}; -use std::time::Duration; +use std::time::{Duration, Instant}; use std::{cell::RefCell, rc::Rc}; use taffy::Overflow; use ui_events::pointer::{PointerButton, PointerEvent, PointerId}; @@ -54,6 +54,7 @@ enum ScrollState { ScrollTo(Point), ScrollToPercent(f32), ScrollToElement(ElementId), + AnimTick, } struct ScrollEventResult { @@ -530,6 +531,11 @@ prop!( pub VerticalScrollAsHorizontal: bool {} = false ); +prop!( + /// When true, scroll wheel events are animated smoothly instead of jumping instantly. + pub SmoothScroll: bool {} = true +); + prop_extractor!(ScrollStyle { vertical_bar_inset: VerticalInset, horizontal_bar_inset: HorizontalInset, @@ -540,6 +546,7 @@ prop_extractor!(ScrollStyle { overflow_x: OverflowX, overflow_y: OverflowY, scrollbar_width: ScrollbarWidth, + smooth_scroll: SmoothScroll, }); const HANDLE_COLOR: Brush = Brush::Solid(Color::from_rgba8(0, 0, 0, 120)); @@ -555,11 +562,18 @@ pub struct Scroll { child: ViewId, // any time this changes, we must update the scroll_offset in the ViewState. scroll_offset: Vec2, + target_offset: Vec2, v_handle: ScrollHandle, h_handle: ScrollHandle, v_track: ScrollTrack, h_track: ScrollTrack, scroll_style: ScrollStyle, + is_animating: bool, + anim_start_time: Option, + anim_start_offset: Vec2, + cached_viewport: Rect, + cached_full_rect: Rect, + cached_content_size: peniko::kurbo::Size, } /// Create a new scroll view @@ -595,11 +609,18 @@ impl Scroll { id, child: child_id, scroll_offset: Vec2::ZERO, + target_offset: Vec2::ZERO, v_track: ScrollTrack::new(id, v_handle.element_id, Axis::Vertical), h_track: ScrollTrack::new(id, h_handle.element_id, Axis::Horizontal), v_handle, h_handle, scroll_style: Default::default(), + is_animating: false, + anim_start_time: None, + anim_start_offset: Vec2::ZERO, + cached_viewport: Rect::ZERO, + cached_full_rect: Rect::ZERO, + cached_content_size: Size::ZERO, } .class(ScrollClass) } @@ -730,7 +751,7 @@ impl Scroll { } if change { - self.set_positions(); + self.id.request_layout(); Some(self.scroll_offset - old_scroll_offset) } else { None @@ -839,9 +860,9 @@ impl Scroll { } fn set_positions(&mut self) { - let viewport = self.id.get_content_rect_local(); - let full_rect = self.id.get_layout_rect_local(); - let content_size = self.child.get_layout_rect_local().size(); + let viewport = self.cached_viewport; + let full_rect = self.cached_full_rect; + let content_size = self.cached_content_size; let scrollbar_width = self.scroll_style.scrollbar_width().0; let v_bar_inset = self.scroll_style.vertical_bar_inset().0; let h_bar_inset = self.scroll_style.horizontal_bar_inset().0; @@ -878,6 +899,49 @@ impl Scroll { h_bar_inset, ); } + + /// Helper function to clamp the scroll target so that it doesn't move out of bounds. + fn clamp_scroll(&self, offset: Vec2) -> Vec2 { + let viewport_size = self.id.get_content_rect_local().size(); + let content_size = self.child.get_layout_rect_local().size(); + + let max_x = (content_size.width - viewport_size.width).max(0.0); + let max_y = (content_size.height - viewport_size.height).max(0.0); + + Vec2::new( + offset.x.clamp(0.0, max_x), + offset.y.clamp(0.0, max_y), + ) + } + + fn advance_animation(&mut self) -> bool { + if !self.is_animating { + return false; + } + + let now = Instant::now(); + let elapsed = self.anim_start_time + .map(|t| now.duration_since(t).as_secs_f64()) + .unwrap_or(0.0); + + let duration = 0.1; // seconds + let t = (elapsed / duration).min(1.0); + + let target = self.target_offset; + let start = self.anim_start_offset; + let new_pos = start + (target - start) * t; + let delta = new_pos - self.scroll_offset; + + self.apply_scroll_delta(delta); + + if t >= 1.0 { + self.is_animating = false; + self.anim_start_time = None; + return false; + } + + true + } } impl View for Scroll { @@ -926,8 +990,15 @@ impl View for Scroll { ScrollState::ScrollToElement(id) => { self.do_scroll_to_element(ScrollTo { id, rect: None }); } + ScrollState::AnimTick => { + if self.advance_animation() { + // We are still moving, queue up the next frame + self.id.update_state_deferred(ScrollState::AnimTick); + } + } } self.id.request_box_tree_update_for_view(); + self.id.request_paint(); } } @@ -959,6 +1030,14 @@ impl View for Scroll { fn event(&mut self, cx: &mut EventCx) -> EventPropagation { // in order to use this we had to set `id.has_layout_listener`. if UpdatePhaseLayout::extract(&cx.event).is_some() { + // queries while tree is still clean + self.cached_viewport = self.id.get_content_rect_local(); + self.cached_full_rect = self.id.get_layout_rect_local(); + self.cached_content_size = self.child.get_layout_rect_local().size(); + + // this apply scroll delta of zero is cheap. + // it is here in the case that the available delta changed, this will catch it and update it to a better size + self.apply_scroll_delta(Vec2::ZERO); self.set_positions(); return EventPropagation::Stop; } @@ -975,6 +1054,10 @@ impl View for Scroll { .apply_scroll_delta(new_offset - self.scroll_offset) .is_some() { + self.cached_viewport = self.id.get_content_rect_local(); + self.cached_full_rect = self.id.get_layout_rect_local(); + self.cached_content_size = self.child.get_layout_rect_local().size(); + self.set_positions(); cx.window_state.request_paint(self.id); } return result.propagation; @@ -986,6 +1069,10 @@ impl View for Scroll { .apply_scroll_delta(new_offset - self.scroll_offset) .is_some() { + self.cached_viewport = self.id.get_content_rect_local(); + self.cached_full_rect = self.id.get_layout_rect_local(); + self.cached_content_size = self.child.get_layout_rect_local().size(); + self.set_positions(); cx.window_state.request_paint(self.id); } return result.propagation; @@ -997,6 +1084,10 @@ impl View for Scroll { .apply_scroll_delta(new_offset - self.scroll_offset) .is_some() { + self.cached_viewport = self.id.get_content_rect_local(); + self.cached_full_rect = self.id.get_layout_rect_local(); + self.cached_content_size = self.child.get_layout_rect_local().size(); + self.set_positions(); cx.window_state.request_paint(self.id); } return result.propagation; @@ -1008,6 +1099,10 @@ impl View for Scroll { .apply_scroll_delta(new_offset - self.scroll_offset) .is_some() { + self.cached_viewport = self.id.get_content_rect_local(); + self.cached_full_rect = self.id.get_layout_rect_local(); + self.cached_content_size = self.child.get_layout_rect_local().size(); + self.set_positions(); cx.window_state.request_paint(self.id); } return result.propagation; @@ -1015,38 +1110,73 @@ impl View for Scroll { } // Handle scroll wheel events in bubble phase - if let Event::Pointer(PointerEvent::Scroll(pse)) = &cx.event { - let size = self.id.get_layout_rect_local().size(); - let delta = pse.resolve_to_points(None, Some(size)); - let delta = -if self.scroll_style.vertical_scroll_as_horizontal() - && delta.x == 0.0 - && delta.y != 0.0 - { - Vec2::new(delta.y, delta.x) - } else { - delta - }; - - let change = self.apply_scroll_delta(delta); - - if change.is_some() { - cx.window_state.request_paint(self.id); - } + // Only handle this in the bubble phase, otherwise it fires multiple times + if cx.phase == Phase::Bubble { + if let Event::Pointer(PointerEvent::Scroll(pse)) = &cx.event { + let size = self.id.get_layout_rect_local().size(); + let delta = pse.resolve_to_points(None, Some(size)); + let delta = -if self.scroll_style.vertical_scroll_as_horizontal() + && delta.x == 0.0 + && delta.y != 0.0 + { + Vec2::new(delta.y, delta.x) + } else { + delta + }; + + if self.scroll_style.smooth_scroll() { + if !self.is_animating { + self.target_offset = self.scroll_offset; + } + let old_target = self.target_offset; + self.target_offset = self.clamp_scroll(self.target_offset + delta); + + if self.target_offset == old_target && !self.is_animating { + return if self.scroll_style.propagate_pointer_wheel() { + EventPropagation::Continue + } else { + EventPropagation::Stop + }; + } + + if !self.is_animating { + self.target_offset = self.scroll_offset; + } + self.target_offset = self.clamp_scroll(self.target_offset + delta); + + // Always reset start to current position and restart the clock. + self.anim_start_offset = self.scroll_offset; + self.anim_start_time = Some(Instant::now()); + + if !self.is_animating { + self.is_animating = true; + self.id.update_state(ScrollState::AnimTick); + } + + return EventPropagation::Stop; + } else { + let change = self.apply_scroll_delta(delta); + self.set_positions(); + + if change.is_some() { + cx.window_state.request_paint(self.id); + } + + return if self.scroll_style.propagate_pointer_wheel() && change.is_none() { + EventPropagation::Continue + } else { + EventPropagation::Stop + }; + } - return if self.scroll_style.propagate_pointer_wheel() && change.is_none() { - EventPropagation::Continue - } else { - EventPropagation::Stop - }; + + } } EventPropagation::Continue } fn paint(&mut self, cx: &mut crate::context::PaintCx) { - // this apply scroll delta of zero is cheap. - // it is here in the case that the available delta changed, this will catch it and update it to a better size - self.apply_scroll_delta(Vec2::ZERO); // Check which visual node we're painting // Scroll view creates multiple visual IDs for scrollbars/tracks @@ -1216,6 +1346,12 @@ impl ScrollCustomStyle { self = Self(self.0.set(ShowBarsWhenIdle, show)); self } + + /// Sets whether scroll wheel events should animate smoothly. + pub fn smooth_scroll(mut self, smooth: impl Into) -> Self { + self = Self(self.0.set(SmoothScroll, smooth)); + self + } } /// A trait that adds a `scroll` method to any type that implements `IntoView`. From eab542d267632700a9a42c042b77c748cf3e2a50 Mon Sep 17 00:00:00 2001 From: t800-x Date: Wed, 1 Apr 2026 05:29:49 +0530 Subject: [PATCH 2/3] Switch to a Transition prop for scroll animation instead of a bool --- src/style/transition.rs | 7 +++ src/style/values.rs | 1 + src/views/scroll.rs | 128 +++++++++++++++------------------------- 3 files changed, 57 insertions(+), 79 deletions(-) diff --git a/src/style/transition.rs b/src/style/transition.rs index 707b59659..c636d5a20 100644 --- a/src/style/transition.rs +++ b/src/style/transition.rs @@ -273,6 +273,13 @@ impl Transition { } } +impl PartialEq for Transition { + //For the purpose of style caching, comparing just the duration is fine + fn eq(&self, other: &Self) -> bool { + self.duration == other.duration + } +} + /// Direct transition controller using TransitionState without the Style system. /// /// This allows you to animate any value that implements `StylePropValue` by managing diff --git a/src/style/values.rs b/src/style/values.rs index b3a6aafd5..fb8dc5c93 100644 --- a/src/style/values.rs +++ b/src/style/values.rs @@ -163,6 +163,7 @@ impl StylePropValue for MinMax {} impl StylePropValue for Line {} impl StylePropValue for taffy::GridAutoFlow {} impl StylePropValue for GridPlacement {} +impl StylePropValue for Transition {} /// How the content of a replaced element, such as an img, should be resized to fit its container. /// Corresponds to the CSS `object-fit` property. diff --git a/src/views/scroll.rs b/src/views/scroll.rs index cc3c86e90..53e9476a2 100644 --- a/src/views/scroll.rs +++ b/src/views/scroll.rs @@ -15,7 +15,7 @@ use crate::event::{ }; use crate::prelude::EventListenerTrait; use crate::prelude::el::UpdatePhaseLayout; -use crate::style::ScrollbarWidth; +use crate::style::{DirectTransition, ScrollbarWidth, StylePropValue, Transition}; use crate::{ BoxTree, ElementId, Renderer, context::{EventCx, PaintCx, StyleCx}, @@ -80,6 +80,19 @@ impl Vec2Ext for Vec2 { } } +/// Wrapper for target scroll delta +#[derive(Debug, Clone, PartialEq)] +pub struct ScrollVec2(pub Vec2); + +impl StylePropValue for ScrollVec2 { + fn interpolate(&self, other: &Self, t: f64) -> Option { + Some(ScrollVec2(Vec2::new( + self.0.x * (1.0 - t) + other.0.x * t, + self.0.y * (1.0 - t) + other.0.y * t, + ))) + } +} + #[derive(Debug, Clone)] struct ScrollHandle { element_id: ElementId, @@ -532,8 +545,8 @@ prop!( ); prop!( - /// When true, scroll wheel events are animated smoothly instead of jumping instantly. - pub SmoothScroll: bool {} = true + /// Configures the scroll wheel animation. Pass `None` to disable smooth scrolling. + pub ScrollAnimation: Option {} = Some(Transition::linear(Duration::from_millis(100))) ); prop_extractor!(ScrollStyle { @@ -546,7 +559,7 @@ prop_extractor!(ScrollStyle { overflow_x: OverflowX, overflow_y: OverflowY, scrollbar_width: ScrollbarWidth, - smooth_scroll: SmoothScroll, + scroll_animation: ScrollAnimation, }); const HANDLE_COLOR: Brush = Brush::Solid(Color::from_rgba8(0, 0, 0, 120)); @@ -562,18 +575,15 @@ pub struct Scroll { child: ViewId, // any time this changes, we must update the scroll_offset in the ViewState. scroll_offset: Vec2, - target_offset: Vec2, v_handle: ScrollHandle, h_handle: ScrollHandle, v_track: ScrollTrack, h_track: ScrollTrack, scroll_style: ScrollStyle, - is_animating: bool, - anim_start_time: Option, - anim_start_offset: Vec2, cached_viewport: Rect, cached_full_rect: Rect, cached_content_size: peniko::kurbo::Size, + scroll_anim: DirectTransition, } /// Create a new scroll view @@ -609,18 +619,18 @@ impl Scroll { id, child: child_id, scroll_offset: Vec2::ZERO, - target_offset: Vec2::ZERO, v_track: ScrollTrack::new(id, v_handle.element_id, Axis::Vertical), h_track: ScrollTrack::new(id, h_handle.element_id, Axis::Horizontal), v_handle, h_handle, scroll_style: Default::default(), - is_animating: false, - anim_start_time: None, - anim_start_offset: Vec2::ZERO, cached_viewport: Rect::ZERO, cached_full_rect: Rect::ZERO, cached_content_size: Size::ZERO, + scroll_anim: DirectTransition::new( + ScrollVec2(Vec2::ZERO), + Some(Transition::linear(Duration::from_millis(100))) + ), } .class(ScrollClass) } @@ -914,34 +924,6 @@ impl Scroll { ) } - fn advance_animation(&mut self) -> bool { - if !self.is_animating { - return false; - } - - let now = Instant::now(); - let elapsed = self.anim_start_time - .map(|t| now.duration_since(t).as_secs_f64()) - .unwrap_or(0.0); - - let duration = 0.1; // seconds - let t = (elapsed / duration).min(1.0); - - let target = self.target_offset; - let start = self.anim_start_offset; - let new_pos = start + (target - start) * t; - let delta = new_pos - self.scroll_offset; - - self.apply_scroll_delta(delta); - - if t >= 1.0 { - self.is_animating = false; - self.anim_start_time = None; - return false; - } - - true - } } impl View for Scroll { @@ -991,8 +973,11 @@ impl View for Scroll { self.do_scroll_to_element(ScrollTo { id, rect: None }); } ScrollState::AnimTick => { - if self.advance_animation() { - // We are still moving, queue up the next frame + let now = Instant::now(); + if self.scroll_anim.step(&now) { + let new_pos = self.scroll_anim.get().0; + let delta = new_pos - self.scroll_offset; + self.apply_scroll_delta(delta); self.id.update_state_deferred(ScrollState::AnimTick); } } @@ -1005,6 +990,10 @@ impl View for Scroll { fn style_pass(&mut self, cx: &mut crate::context::StyleCx<'_>) { self.scroll_style.read(cx); + if self.scroll_style.read(cx) { + self.scroll_anim.set_transition(self.scroll_style.scroll_animation()); + } + // If the reason implies nested style maps must be resolved, restyle everything. if cx.reason.needs_resolve_nested_maps() { self.v_handle.style(cx); @@ -1124,44 +1113,23 @@ impl View for Scroll { delta }; - if self.scroll_style.smooth_scroll() { - if !self.is_animating { - self.target_offset = self.scroll_offset; - } - let old_target = self.target_offset; - self.target_offset = self.clamp_scroll(self.target_offset + delta); - - if self.target_offset == old_target && !self.is_animating { - return if self.scroll_style.propagate_pointer_wheel() { - EventPropagation::Continue - } else { - EventPropagation::Stop - }; - } - - if !self.is_animating { - self.target_offset = self.scroll_offset; - } - self.target_offset = self.clamp_scroll(self.target_offset + delta); - - // Always reset start to current position and restart the clock. - self.anim_start_offset = self.scroll_offset; - self.anim_start_time = Some(Instant::now()); + let new_target = self.clamp_scroll(self.scroll_anim.target().0 + delta); - if !self.is_animating { - self.is_animating = true; - self.id.update_state(ScrollState::AnimTick); - } + // If target didn't move, propagate to parent if configured + if new_target == self.scroll_anim.target().0 && !self.scroll_anim.is_active() { + return if self.scroll_style.propagate_pointer_wheel() { + EventPropagation::Continue + } else { + EventPropagation::Stop + }; + } - return EventPropagation::Stop; + let started = self.scroll_anim.transition_to(ScrollVec2(new_target)); + if started { + self.id.update_state(ScrollState::AnimTick); } else { + let delta = new_target - self.scroll_offset; let change = self.apply_scroll_delta(delta); - self.set_positions(); - - if change.is_some() { - cx.window_state.request_paint(self.id); - } - return if self.scroll_style.propagate_pointer_wheel() && change.is_none() { EventPropagation::Continue } else { @@ -1169,6 +1137,8 @@ impl View for Scroll { }; } + return EventPropagation::Stop; + } } @@ -1347,9 +1317,9 @@ impl ScrollCustomStyle { self } - /// Sets whether scroll wheel events should animate smoothly. - pub fn smooth_scroll(mut self, smooth: impl Into) -> Self { - self = Self(self.0.set(SmoothScroll, smooth)); + /// Pass a `Transition` to enable smooth scrolling, or `None` to disable it. + pub fn scroll_animation(mut self, transition: Option) -> Self { + self = Self(self.0.set(ScrollAnimation, transition)); self } } From 3082d715dfb468e30c46067344e34afa2cc9fb07 Mon Sep 17 00:00:00 2001 From: t800-x Date: Wed, 1 Apr 2026 05:43:11 +0530 Subject: [PATCH 3/3] Rebase, fix clippy warnings, formatting --- src/views/scroll.rs | 84 ++++++++++++++++++++------------------------ tiny_skia/src/lib.rs | 12 +++---- 2 files changed, 44 insertions(+), 52 deletions(-) diff --git a/src/views/scroll.rs b/src/views/scroll.rs index 53e9476a2..a1f7c51f7 100644 --- a/src/views/scroll.rs +++ b/src/views/scroll.rs @@ -2,7 +2,7 @@ //! Scroll View use floem_reactive::Effect; -use peniko::kurbo::{Affine, Axis, Point, Rect, RoundedRect, RoundedRectRadii, Stroke, Vec2, Size}; +use peniko::kurbo::{Affine, Axis, Point, Rect, RoundedRect, RoundedRectRadii, Size, Stroke, Vec2}; use peniko::{Brush, Color}; use std::time::{Duration, Instant}; use std::{cell::RefCell, rc::Rc}; @@ -629,7 +629,7 @@ impl Scroll { cached_content_size: Size::ZERO, scroll_anim: DirectTransition::new( ScrollVec2(Vec2::ZERO), - Some(Transition::linear(Duration::from_millis(100))) + Some(Transition::linear(Duration::from_millis(100))), ), } .class(ScrollClass) @@ -918,12 +918,8 @@ impl Scroll { let max_x = (content_size.width - viewport_size.width).max(0.0); let max_y = (content_size.height - viewport_size.height).max(0.0); - Vec2::new( - offset.x.clamp(0.0, max_x), - offset.y.clamp(0.0, max_y), - ) + Vec2::new(offset.x.clamp(0.0, max_x), offset.y.clamp(0.0, max_y)) } - } impl View for Scroll { @@ -991,7 +987,8 @@ impl View for Scroll { self.scroll_style.read(cx); if self.scroll_style.read(cx) { - self.scroll_anim.set_transition(self.scroll_style.scroll_animation()); + self.scroll_anim + .set_transition(self.scroll_style.scroll_animation()); } // If the reason implies nested style maps must be resolved, restyle everything. @@ -1100,54 +1097,51 @@ impl View for Scroll { // Handle scroll wheel events in bubble phase // Only handle this in the bubble phase, otherwise it fires multiple times - if cx.phase == Phase::Bubble { - if let Event::Pointer(PointerEvent::Scroll(pse)) = &cx.event { - let size = self.id.get_layout_rect_local().size(); - let delta = pse.resolve_to_points(None, Some(size)); - let delta = -if self.scroll_style.vertical_scroll_as_horizontal() - && delta.x == 0.0 - && delta.y != 0.0 - { - Vec2::new(delta.y, delta.x) + if cx.phase == Phase::Bubble + && let Event::Pointer(PointerEvent::Scroll(pse)) = &cx.event + { + let size = self.id.get_layout_rect_local().size(); + let delta = pse.resolve_to_points(None, Some(size)); + let delta = -if self.scroll_style.vertical_scroll_as_horizontal() + && delta.x == 0.0 + && delta.y != 0.0 + { + Vec2::new(delta.y, delta.x) + } else { + delta + }; + + let new_target = self.clamp_scroll(self.scroll_anim.target().0 + delta); + + // If target didn't move, propagate to parent if configured + if new_target == self.scroll_anim.target().0 && !self.scroll_anim.is_active() { + return if self.scroll_style.propagate_pointer_wheel() { + EventPropagation::Continue } else { - delta + EventPropagation::Stop }; + } - let new_target = self.clamp_scroll(self.scroll_anim.target().0 + delta); - - // If target didn't move, propagate to parent if configured - if new_target == self.scroll_anim.target().0 && !self.scroll_anim.is_active() { - return if self.scroll_style.propagate_pointer_wheel() { - EventPropagation::Continue - } else { - EventPropagation::Stop - }; - } - - let started = self.scroll_anim.transition_to(ScrollVec2(new_target)); - if started { - self.id.update_state(ScrollState::AnimTick); + let started = self.scroll_anim.transition_to(ScrollVec2(new_target)); + if started { + self.id.update_state(ScrollState::AnimTick); + } else { + let delta = new_target - self.scroll_offset; + let change = self.apply_scroll_delta(delta); + return if self.scroll_style.propagate_pointer_wheel() && change.is_none() { + EventPropagation::Continue } else { - let delta = new_target - self.scroll_offset; - let change = self.apply_scroll_delta(delta); - return if self.scroll_style.propagate_pointer_wheel() && change.is_none() { - EventPropagation::Continue - } else { - EventPropagation::Stop - }; - } - - return EventPropagation::Stop; - - + EventPropagation::Stop + }; } + + return EventPropagation::Stop; } EventPropagation::Continue } fn paint(&mut self, cx: &mut crate::context::PaintCx) { - // Check which visual node we're painting // Scroll view creates multiple visual IDs for scrollbars/tracks if cx.target_id == self.id.get_element_id() { diff --git a/tiny_skia/src/lib.rs b/tiny_skia/src/lib.rs index aa5f45449..e713ba3ef 100644 --- a/tiny_skia/src/lib.rs +++ b/tiny_skia/src/lib.rs @@ -369,14 +369,12 @@ impl Layer { Transform::identity(), ); } + } else if clip.simple_rect.is_some() { + self.fill_mask_rect(clip.rect); } else { - if clip.simple_rect.is_some() { - self.fill_mask_rect(clip.rect); - } else { - self.mask.clear(); - self.mask - .fill_path(&clip.path, FillRule::Winding, false, Transform::identity()); - } + self.mask.clear(); + self.mask + .fill_path(&clip.path, FillRule::Winding, false, Transform::identity()); } self.clip = Some(clip_rect);