pub struct Canvas<'a> { /* private fields */ }Expand description
A clipped, writable pixel target.
Every operation is clipped to Canvas::clip, which starts as the whole frame
and only ever shrinks. Clipping is rectangular: that covers scrolling regions,
damage-restricted repaint and nested panels, which is all a UI actually needs.
Arbitrary clip shapes are not planned.
Coordinates are physical pixels relative to the frame origin, never relative to the clip.
Implementations§
Source§impl<'a> Canvas<'a>
impl<'a> Canvas<'a>
Sourcepub fn new(frame: &'a mut Frame<'_>) -> Self
pub fn new(frame: &'a mut Frame<'_>) -> Self
Borrows a frame for drawing, clipped to the whole frame.
Sourcepub fn from_pixels(
pixels: &'a mut [u32],
size: Size,
stride: u32,
format: PixelFormat,
) -> Option<Self>
pub fn from_pixels( pixels: &'a mut [u32], size: Size, stride: u32, format: PixelFormat, ) -> Option<Self>
Wraps a raw pixel slice. Returns None if it is too small for the geometry.
Prefer Canvas::new; this exists for offscreen buffers and benchmarks that
have no Frame to hand.
Sourcepub fn pen(&mut self) -> Pen<'_>
pub fn pen(&mut self) -> Pen<'_>
A Pen drawing through this canvas.
The bridge from a concrete rasteriser to the painter-agnostic API widgets and the text engine take.
Sourcepub const fn format(&self) -> PixelFormat
pub const fn format(&self) -> PixelFormat
Word layout of the target.
Sourcepub fn with_clip(&mut self, rect: Rect) -> Canvas<'_>
pub fn with_clip(&mut self, rect: Rect) -> Canvas<'_>
A canvas over the same pixels with a tighter clip.
The borrow ends when the returned canvas is dropped, so this is how a parent hands a child a region to draw in without either being able to escape it.
Sourcepub const fn is_clipped_out(&self) -> bool
pub const fn is_clipped_out(&self) -> bool
Returns true if the clip admits no pixels, so drawing can be skipped.
Sourcepub fn scroll_rows(&mut self, rect: Rect, dy: i32) -> bool
pub fn scroll_rows(&mut self, rect: Rect, dy: i32) -> bool
Moves the pixels inside rect up by dy rows, or down by -dy rows
when dy is negative, within the clip, leaving the rows that came into
view as they were. Painter::scroll_rows
for a buffer of words, which is the one kind of target that can: a
copy_within per row, top to bottom when the content moves up and
bottom to top when it moves down, so the destination always trails the
source. Answers false only when there is nothing to copy — no rows
inside the clip, or a move further than the rectangle is tall.
Sourcepub fn clear(&mut self, color: Color)
pub fn clear(&mut self, color: Color)
Fills the entire clip with an opaque colour.
This is the full-frame clear when the clip is untouched, and the damage-restricted clear when it is not.
Sourcepub fn copy_from(&mut self, src: &PixelView<'_>, regions: &[Rect])
pub fn copy_from(&mut self, src: &PixelView<'_>, regions: &[Rect])
Copies matching regions out of another buffer.
Source and destination coordinates are the same, so this is the damage-driven “publish what changed” blit a double-buffered backend needs — not a general blitter. Regions are clipped to both buffers.
Source§impl Canvas<'_>
impl Canvas<'_>
Source§impl Canvas<'_>
impl Canvas<'_>
Sourcepub fn fill_circle(
&mut self,
centre: Point,
radius: i32,
color: impl Into<Paint>,
)
pub fn fill_circle( &mut self, centre: Point, radius: i32, color: impl Into<Paint>, )
Fills a circle of radius around centre, anti-aliased.
Exactly Canvas::fill_rounded_rect on the bounding square — this name
exists so the intent is readable and the radius impossible to get wrong.
The painted diameter is 2 * radius pixels.
Sourcepub fn stroke_circle(
&mut self,
centre: Point,
radius: i32,
thickness: i32,
color: impl Into<Paint>,
)
pub fn stroke_circle( &mut self, centre: Point, radius: i32, thickness: i32, color: impl Into<Paint>, )
Draws a ring of thickness pixels just inside the circle of radius
around centre, anti-aliased.
Sourcepub fn stroke_arc(
&mut self,
centre: Point,
radius: i32,
thickness: i32,
start: i32,
sweep: i32,
color: impl Into<Paint>,
)
pub fn stroke_arc( &mut self, centre: Point, radius: i32, thickness: i32, start: i32, sweep: i32, color: impl Into<Paint>, )
Draws part of a ring: from start, sweeping sweep, both in units of
TURN. Angle 0 is twelve o’clock and positive sweeps go clockwise;
a negative sweep goes the other way. The ends are cut flat along the
radius — butt caps.
A sweep of at least a full TURN is exactly Canvas::stroke_circle,
which is what lets a progress ring pass done * TURN / total without
special-casing 100%. A thickness of at least radius fills to the
centre, which makes a pie slice.
The cost is proportional to the pixels the arc actually covers, not to its bounding square — a thin spinner touches a thin ring of pixels. What to damage for an animated arc is the caller’s business, but the same property means a conservative bounding rectangle only costs rasterising the ring inside it, not the square.
Source§impl Canvas<'_>
impl Canvas<'_>
Sourcepub fn blit(&mut self, src: &PixelView<'_>, at: Point)
pub fn blit(&mut self, src: &PixelView<'_>, at: Point)
Draws src with its top-left corner at at, one source pixel per
destination pixel, composited with source-over alpha.
Source pixels are premultiplied 0xAARRGGBB — see the
module docs. Clipped to the canvas clip like every other
operation; any part of the image outside it is simply not drawn.
Sourcepub fn blit_scaled(&mut self, src: &PixelView<'_>, dest: Rect)
pub fn blit_scaled(&mut self, src: &PixelView<'_>, dest: Rect)
Draws all of src into dest, nearest-neighbour resampled, composited
with source-over alpha.
Source pixels are premultiplied 0xAARRGGBB — see the
module docs. When dest is exactly the source size this is
Canvas::blit. Sampling is at pixel centres, so an integer upscale
turns each source pixel into an even block, and a downscale picks
representative pixels rather than always the top-left ones.
Sourcepub fn blit_rounded(
&mut self,
src: &PixelView<'_>,
dest: Rect,
shape: Rect,
radius: i32,
)
pub fn blit_rounded( &mut self, src: &PixelView<'_>, dest: Rect, shape: Rect, radius: i32, )
Draws all of src into dest, masked to shape with rounded corners
of radius, anti-aliased.
shape is the rectangle whose corners are rounded and outside which
nothing is drawn; sampling is still mapped from the whole of dest.
They are separate arguments because they genuinely differ in the Cover
case — an image scaled past its box so the box is filled edge to edge —
where dest overflows and shape is the box. When the picture and the
mask are the same rectangle, pass it twice. radius is clamped to half
of shape’s shorter side, so a full radius on a square shape is a
circle — the avatar crop. Zero draws exactly Canvas::blit_scaled
restricted to shape.
The mask must not come from the clip: the clip is damage, and a damage-restricted repaint of half an image has to round the image’s corners, never the damage rectangle’s.
Source§impl Canvas<'_>
impl Canvas<'_>
Sourcepub fn draw_icon(&mut self, icon: &Icon, rect: Rect, fore: Color, back: Color)
pub fn draw_icon(&mut self, icon: &Icon, rect: Rect, fore: Color, back: Color)
Draws an icon into rect, scaled from its grid.
fore is the content colour and back is whatever the icon is sitting
on — a shape marked Ink::Back is drawn in it, which is how an outline
or a cut-out is made.
The icon is scaled to rect and not kept square: give it a square
rectangle if you want it square. Anything beyond
MAX_SHAPES is ignored rather than drawn wrong.
Source§impl Canvas<'_>
impl Canvas<'_>
Sourcepub fn draw_line(&mut self, a: Point, b: Point, color: impl Into<Paint>)
pub fn draw_line(&mut self, a: Point, b: Point, color: impl Into<Paint>)
Draws a one-pixel line between two pixel centres, anti-aliased.
Axis-aligned lines take an exact integer path and get no anti-aliasing, because a horizontal rule that has been softened to 97% grey looks like a rendering bug, not like quality. Everything else is a Wu-style two-pixel blend along the minor axis.
Thickness is not a parameter. Borders come from Canvas::stroke_rect and
Canvas::stroke_rounded_rect; thick arbitrary-angle lines are not
something a UI toolkit needs before it can draw a chart, and that is not
this milestone.
Source§impl Canvas<'_>
impl Canvas<'_>
Sourcepub fn fill_star(
&mut self,
centre: Point,
outer_radius: i32,
inner_radius: i32,
points: u32,
rotation: i32,
color: impl Into<Paint>,
)
pub fn fill_star( &mut self, centre: Point, outer_radius: i32, inner_radius: i32, points: u32, rotation: i32, color: impl Into<Paint>, )
Fills a star, anti-aliased.
points is the number of spikes — five for the familiar one. Vertices
alternate between outer_radius at the tips and inner_radius at the
valleys, so the ratio between them is how pointed the star looks: about
0.38 of the outer radius is the classic pentagram, and an inner radius
approaching the outer one is a polygon with 2 × points sides.
rotation is in the same binary turns as the arcs — see TURN — and
zero puts a tip at twelve o’clock.
Vertices are computed to sub-pixel precision even though the centre is whole pixels, which is what keeps a small star from looking chewed.
§A five-pointed star is not exactly five-fold symmetric
TURN is a power of two, so it divides exactly by two, four and eight
and not by five. A five-pointed star’s vertex angles are therefore each
rounded to the nearest unit — at most half a unit in 65536, which is
under a hundredth of a pixel at any radius a screen can show, and
invisible. But it does mean a star rotated by TURN / 5 is not the
bit-identical picture, only the same one. Anything that needs exactness
should compare against a tolerance rather than against pixels.
Source§impl Canvas<'_>
impl Canvas<'_>
Sourcepub fn fill_rect(&mut self, rect: Rect, color: impl Into<Paint>)
pub fn fill_rect(&mut self, rect: Rect, color: impl Into<Paint>)
Fills rect, compositing with the destination if the paint has alpha.
Sourcepub fn fill_rects(&mut self, rects: &[Rect], color: impl Into<Paint>)
pub fn fill_rects(&mut self, rects: &[Rect], color: impl Into<Paint>)
Fills every rectangle. Overlapping rectangles composite twice.
Sourcepub fn stroke_rect(
&mut self,
rect: Rect,
thickness: i32,
color: impl Into<Paint>,
)
pub fn stroke_rect( &mut self, rect: Rect, thickness: i32, color: impl Into<Paint>, )
Draws a border of thickness pixels inside rect.
The four bands are cut so they do not overlap. Drawing them as four full-length rectangles would composite the corners twice, which is invisible at full alpha and obvious at anything less.
Source§impl Canvas<'_>
impl Canvas<'_>
Sourcepub fn fill_rounded_rect(
&mut self,
rect: Rect,
radius: i32,
color: impl Into<Paint>,
)
pub fn fill_rounded_rect( &mut self, rect: Rect, radius: i32, color: impl Into<Paint>, )
Fills a rectangle with rounded corners, anti-aliased.
radius is clamped to half the shorter side; a radius of zero is exactly
Canvas::fill_rect.
Trait Implementations§
Source§impl Painter for Canvas<'_>
impl Painter for Canvas<'_>
Source§fn format(&self) -> PixelFormat
fn format(&self) -> PixelFormat
Source§fn push_clip(&mut self, rect: Rect) -> ClipToken
fn push_clip(&mut self, rect: Rect) -> ClipToken
rect, returning the old one. Read moreSource§fn fill_rounded_rect(&mut self, rect: Rect, radius: i32, paint: Paint)
fn fill_rounded_rect(&mut self, rect: Rect, radius: i32, paint: Paint)
Source§fn stroke_rounded_rect(
&mut self,
rect: Rect,
radius: i32,
thickness: i32,
paint: Paint,
)
fn stroke_rounded_rect( &mut self, rect: Rect, radius: i32, thickness: i32, paint: Paint, )
Source§fn stroke_circle(
&mut self,
centre: Point,
radius: i32,
thickness: i32,
paint: Paint,
)
fn stroke_circle( &mut self, centre: Point, radius: i32, thickness: i32, paint: Paint, )
Source§fn stroke_arc(
&mut self,
centre: Point,
radius: i32,
thickness: i32,
start: i32,
sweep: i32,
paint: Paint,
)
fn stroke_arc( &mut self, centre: Point, radius: i32, thickness: i32, start: i32, sweep: i32, paint: Paint, )
start through sweep binary turns.Source§fn fill_polygon_fx(&mut self, points: &[(i32, i32)], paint: Paint)
fn fill_polygon_fx(&mut self, points: &[(i32, i32)], paint: Paint)
Source§fn blit_mask(&mut self, at: Point, mask: &Mask<'_>, paint: Paint)
fn blit_mask(&mut self, at: Point, mask: &Mask<'_>, paint: Paint)
Source§fn blit(&mut self, src: &PixelView<'_>, at: Point)
fn blit(&mut self, src: &PixelView<'_>, at: Point)
at.Source§fn blit_scaled(&mut self, src: &PixelView<'_>, dest: Rect)
fn blit_scaled(&mut self, src: &PixelView<'_>, dest: Rect)
dest.Source§fn blit_rounded(
&mut self,
src: &PixelView<'_>,
dest: Rect,
shape: Rect,
radius: i32,
)
fn blit_rounded( &mut self, src: &PixelView<'_>, dest: Rect, shape: Rect, radius: i32, )
dest and masked to a rounded
shape.Source§fn scroll_rows(&mut self, rect: Rect, dy: i32) -> bool
fn scroll_rows(&mut self, rect: Rect, dy: i32) -> bool
rect up by dy rows, or down by -dy rows
when dy is negative, within the clip. The dy rows that come into
view at the trailing edge are left as they were, for the caller to
paint. Answers false when this target cannot move its own pixels, in
which case nothing has changed and the caller repaints the lot. Read moreSource§fn blit_image(&mut self, src: &ImageRef<'_>, dest: Rect)
fn blit_image(&mut self, src: &ImageRef<'_>, dest: Rect)
dest. Read moreSource§fn blit_image_rounded(
&mut self,
src: &ImageRef<'_>,
dest: Rect,
shape: Rect,
radius: i32,
)
fn blit_image_rounded( &mut self, src: &ImageRef<'_>, dest: Rect, shape: Rect, radius: i32, )
Source§fn is_clipped_out(&self) -> bool
fn is_clipped_out(&self) -> bool
true if the clip admits no pixels, so drawing can be skipped.