From f2aa570aac4f3f0dff7140f0c6dc36fdad01cac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Sun, 17 Aug 2025 22:31:58 +0200 Subject: [PATCH] Introduce `draw_with_bounds` to `canvas::Cache` Also: - Change `Rectangle::INFINITE` to have coordinates at `f32::NEG_INFINITY` - Change `Frame::with_clip` to _not_ adjust the coordinate system - Rename `Size::INFINITY` to `INFINITE` --- core/src/layout/limits.rs | 2 +- core/src/rectangle.rs | 7 +++++-- core/src/size.rs | 2 +- graphics/src/geometry.rs | 6 +++--- graphics/src/geometry/cache.rs | 24 +++++++++++++++++++----- graphics/src/geometry/frame.rs | 10 +++++++++- renderer/src/fallback.rs | 6 +++--- tiny_skia/src/geometry.rs | 17 +++++------------ tiny_skia/src/lib.rs | 4 ++-- wgpu/src/geometry.rs | 13 +++---------- wgpu/src/lib.rs | 4 ++-- widget/src/tooltip.rs | 4 ++-- winit/src/window.rs | 2 +- 13 files changed, 56 insertions(+), 45 deletions(-) diff --git a/core/src/layout/limits.rs b/core/src/layout/limits.rs index 7fbc7b9d..1aaed526 100644 --- a/core/src/layout/limits.rs +++ b/core/src/layout/limits.rs @@ -12,7 +12,7 @@ impl Limits { /// No limits pub const NONE: Limits = Limits { min: Size::ZERO, - max: Size::INFINITY, + max: Size::INFINITE, }; /// Creates new [`Limits`] with the given minimum and maximum [`Size`]. diff --git a/core/src/rectangle.rs b/core/src/rectangle.rs index 8adb272f..9f2808dd 100644 --- a/core/src/rectangle.rs +++ b/core/src/rectangle.rs @@ -34,8 +34,11 @@ where } impl Rectangle { - /// A rectangle starting at [`Point::ORIGIN`] with infinite width and height. - pub const INFINITE: Self = Self::new(Point::ORIGIN, Size::INFINITY); + /// A rectangle starting at negative infinity and with infinite width and height. + pub const INFINITE: Self = Self::new( + Point::new(f32::NEG_INFINITY, f32::NEG_INFINITY), + Size::INFINITE, + ); /// Creates a new [`Rectangle`] with its top-left corner in the given /// [`Point`] and with the provided [`Size`]. diff --git a/core/src/size.rs b/core/src/size.rs index 9503cf59..539135bc 100644 --- a/core/src/size.rs +++ b/core/src/size.rs @@ -24,7 +24,7 @@ impl Size { pub const UNIT: Size = Size::new(1., 1.); /// A [`Size`] with infinite width and height. - pub const INFINITY: Size = Size::new(f32::INFINITY, f32::INFINITY); + pub const INFINITE: Size = Size::new(f32::INFINITY, f32::INFINITY); /// Returns the minimum of each component of this size and another. pub fn min(self, other: Self) -> Self { diff --git a/graphics/src/geometry.rs b/graphics/src/geometry.rs index 2b4b45a6..b32387f8 100644 --- a/graphics/src/geometry.rs +++ b/graphics/src/geometry.rs @@ -20,7 +20,7 @@ pub use crate::core::{Image, Svg}; pub use crate::gradient::{self, Gradient}; use crate::cache::Cached; -use crate::core::{self, Size}; +use crate::core::{self, Rectangle}; /// A renderer capable of drawing some [`Self::Geometry`]. pub trait Renderer: core::Renderer { @@ -31,7 +31,7 @@ pub trait Renderer: core::Renderer { type Frame: frame::Backend; /// Creates a new [`Self::Frame`]. - fn new_frame(&self, size: Size) -> Self::Frame; + fn new_frame(&self, bounds: Rectangle) -> Self::Frame; /// Draws the given [`Self::Geometry`]. fn draw_geometry(&mut self, geometry: Self::Geometry); @@ -42,7 +42,7 @@ impl Renderer for () { type Geometry = (); type Frame = (); - fn new_frame(&self, _size: Size) -> Self::Frame {} + fn new_frame(&self, _bounds: Rectangle) -> Self::Frame {} fn draw_geometry(&mut self, _geometry: Self::Geometry) {} } diff --git a/graphics/src/geometry/cache.rs b/graphics/src/geometry/cache.rs index d70cee0b..e17506a3 100644 --- a/graphics/src/geometry/cache.rs +++ b/graphics/src/geometry/cache.rs @@ -1,5 +1,5 @@ use crate::cache::{self, Cached}; -use crate::core::Size; +use crate::core::{Rectangle, Size}; use crate::geometry::{self, Frame}; pub use cache::Group; @@ -17,7 +17,7 @@ where #[derive(Debug, Clone)] struct Data { - bounds: Size, + bounds: Rectangle, geometry: T, } @@ -53,7 +53,7 @@ where /// [`Cache`]. /// /// The closure will only be called when - /// - the bounds have changed since the previous draw call. + /// - the size has changed since the previous draw call. /// - the [`Cache`] is empty or has been explicitly cleared. /// /// Otherwise, the previously stored geometry will be returned. The @@ -62,7 +62,21 @@ where pub fn draw( &self, renderer: &Renderer, - bounds: Size, + size: Size, + draw_fn: impl FnOnce(&mut Frame), + ) -> Renderer::Geometry { + self.draw_with_bounds(renderer, Rectangle::with_size(size), draw_fn) + } + + /// Draws geometry using the provided closure and stores it in the + /// [`Cache`]. + /// + /// Analogous to [`draw`](Self::draw), but takes a clipping [`Rectangle`] instead of + /// a [`Size`]. + pub fn draw_with_bounds( + &self, + renderer: &Renderer, + bounds: Rectangle, draw_fn: impl FnOnce(&mut Frame), ) -> Renderer::Geometry { use std::ops::Deref; @@ -82,7 +96,7 @@ where } }; - let mut frame = Frame::new(renderer, bounds); + let mut frame = Frame::with_bounds(renderer, bounds); draw_fn(&mut frame); let geometry = frame.into_geometry().cache(self.raw.group(), previous); diff --git a/graphics/src/geometry/frame.rs b/graphics/src/geometry/frame.rs index 29b534f8..5372ec16 100644 --- a/graphics/src/geometry/frame.rs +++ b/graphics/src/geometry/frame.rs @@ -16,9 +16,17 @@ where Renderer: geometry::Renderer, { /// Creates a new [`Frame`] with the given dimensions. + /// + /// Any geometry drawn outside of the dimensions will be clipped. + /// If you need further control, use [`with_bounds`](Self::with_bounds). pub fn new(renderer: &Renderer, size: Size) -> Self { + Self::with_bounds(renderer, Rectangle::with_size(size)) + } + + /// Creates a new [`Frame`] with the given clip bounds. + pub fn with_bounds(renderer: &Renderer, bounds: Rectangle) -> Self { Self { - raw: renderer.new_frame(size), + raw: renderer.new_frame(bounds), } } diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index 411b5862..d8d04d45 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -409,13 +409,13 @@ mod geometry { type Geometry = Geometry; type Frame = Frame; - fn new_frame(&self, size: iced_graphics::core::Size) -> Self::Frame { + fn new_frame(&self, bounds: Rectangle) -> Self::Frame { match self { Self::Primary(renderer) => { - Frame::Primary(renderer.new_frame(size)) + Frame::Primary(renderer.new_frame(bounds)) } Self::Secondary(renderer) => { - Frame::Secondary(renderer.new_frame(size)) + Frame::Secondary(renderer.new_frame(bounds)) } } } diff --git a/tiny_skia/src/geometry.rs b/tiny_skia/src/geometry.rs index af55f2a5..a1c0d8a6 100644 --- a/tiny_skia/src/geometry.rs +++ b/tiny_skia/src/geometry.rs @@ -64,21 +64,14 @@ pub struct Frame { } impl Frame { - pub fn new(size: Size) -> Self { - Self::with_clip(Rectangle::with_size(size)) - } - - pub fn with_clip(clip_bounds: Rectangle) -> Self { + pub fn new(bounds: Rectangle) -> Self { Self { - clip_bounds, + clip_bounds: bounds, stack: Vec::new(), primitives: Vec::new(), images: Vec::new(), text: Vec::new(), - transform: tiny_skia::Transform::from_translate( - clip_bounds.x, - clip_bounds.y, - ), + transform: tiny_skia::Transform::identity(), } } } @@ -238,7 +231,7 @@ impl geometry::frame::Backend for Frame { align_x: text.align_x, align_y: text.align_y, shaping: text.shaping, - clip_bounds: Rectangle::with_size(Size::INFINITY), + clip_bounds: Rectangle::with_size(Size::INFINITE), }); } else { text.draw_with(|path, color| self.fill(&path, color)); @@ -265,7 +258,7 @@ impl geometry::frame::Backend for Frame { } fn draft(&mut self, clip_bounds: Rectangle) -> Self { - Self::with_clip(clip_bounds) + Self::new(clip_bounds) } fn paste(&mut self, frame: Self) { diff --git a/tiny_skia/src/lib.rs b/tiny_skia/src/lib.rs index bc379981..ca00737f 100644 --- a/tiny_skia/src/lib.rs +++ b/tiny_skia/src/lib.rs @@ -294,8 +294,8 @@ impl graphics::geometry::Renderer for Renderer { type Geometry = Geometry; type Frame = geometry::Frame; - fn new_frame(&self, size: core::Size) -> Self::Frame { - geometry::Frame::new(size) + fn new_frame(&self, bounds: Rectangle) -> Self::Frame { + geometry::Frame::new(bounds) } fn draw_geometry(&mut self, geometry: Self::Geometry) { diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs index c3c66464..18e26794 100644 --- a/wgpu/src/geometry.rs +++ b/wgpu/src/geometry.rs @@ -105,13 +105,8 @@ pub struct Frame { } impl Frame { - /// Creates a new [`Frame`] with the given [`Size`]. - pub fn new(size: Size) -> Frame { - Self::with_clip(Rectangle::with_size(size)) - } - /// Creates a new [`Frame`] with the given clip bounds. - pub fn with_clip(bounds: Rectangle) -> Frame { + pub fn new(bounds: Rectangle) -> Frame { Frame { clip_bounds: bounds, buffers: BufferStack::new(), @@ -120,9 +115,7 @@ impl Frame { text: Vec::new(), transforms: Transforms { previous: Vec::new(), - current: Transform(lyon::math::Transform::translation( - bounds.x, bounds.y, - )), + current: Transform(lyon::math::Transform::identity()), }, fill_tessellator: tessellation::FillTessellator::new(), stroke_tessellator: tessellation::StrokeTessellator::new(), @@ -409,7 +402,7 @@ impl geometry::frame::Backend for Frame { } fn draft(&mut self, clip_bounds: Rectangle) -> Frame { - Frame::with_clip(clip_bounds) + Frame::new(clip_bounds) } fn paste(&mut self, frame: Frame) { diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 4361d605..28f6cb48 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -760,8 +760,8 @@ impl graphics::geometry::Renderer for Renderer { type Geometry = Geometry; type Frame = geometry::Frame; - fn new_frame(&self, size: core::Size) -> Self::Frame { - geometry::Frame::new(size) + fn new_frame(&self, bounds: Rectangle) -> Self::Frame { + geometry::Frame::new(bounds) } fn draw_geometry(&mut self, geometry: Self::Geometry) { diff --git a/widget/src/tooltip.rs b/widget/src/tooltip.rs index 78543f7f..f3dea455 100644 --- a/widget/src/tooltip.rs +++ b/widget/src/tooltip.rs @@ -394,7 +394,7 @@ where if self.snap_within_viewport { viewport.size() } else { - Size::INFINITY + Size::INFINITE }, ) .shrink(Padding::new(self.padding)), @@ -508,7 +508,7 @@ where &defaults, layout.children().next().unwrap(), cursor_position, - &Rectangle::with_size(Size::INFINITY), + &Rectangle::with_size(Size::INFINITE), ); } } diff --git a/winit/src/window.rs b/winit/src/window.rs index e9a058af..f2d12677 100644 --- a/winit/src/window.rs +++ b/winit/src/window.rs @@ -346,7 +346,7 @@ where self.content = Renderer::Paragraph::with_spans(Text { content: &spans, - bounds: Size::INFINITY, + bounds: Size::INFINITE, size: preedit .text_size .unwrap_or_else(|| renderer.default_size()),